Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. CodeCoverage.php

class CodeCoverage

Same name in this branch
  1. 11.1.x vendor/phpunit/php-code-coverage/src/CodeCoverage.php \SebastianBergmann\CodeCoverage\CodeCoverage
  2. 11.1.x vendor/phpunit/phpunit/src/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php \PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage
  3. 11.1.x vendor/phpunit/phpunit/src/Metadata/Api/CodeCoverage.php \PHPUnit\Metadata\Api\CodeCoverage

@no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit

@internal This class is not covered by the backward compatibility promise for PHPUnit

@codeCoverageIgnore

Hierarchy

  • class \PHPUnit\Runner\CodeCoverage

Expanded class hierarchy of CodeCoverage

3 files declare their use of CodeCoverage
AbstractPhpProcess.php in vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
Application.php in vendor/phpunit/phpunit/src/TextUI/Application.php
TestRunner.php in vendor/phpunit/phpunit/src/Framework/TestRunner.php

File

vendor/phpunit/phpunit/src/Runner/CodeCoverage.php, line 47

Namespace

PHPUnit\Runner
View source
final class CodeCoverage {
    private static ?self $instance = null;
    private ?\SebastianBergmann\CodeCoverage\CodeCoverage $codeCoverage = null;
    private ?Driver $driver = null;
    private bool $collecting = false;
    private ?TestCase $test = null;
    private ?Timer $timer = null;
    
    /**
     * @psalm-var array<string,list<int>>
     */
    private array $linesToBeIgnored = [];
    public static function instance() : self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function init(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry, bool $extensionRequiresCodeCoverageCollection) : void {
        $codeCoverageFilterRegistry->init($configuration);
        if (!$configuration->hasCoverageReport() && !$extensionRequiresCodeCoverageCollection) {
            return;
        }
        $this->activate($codeCoverageFilterRegistry->get(), $configuration->pathCoverage());
        if (!$this->isActive()) {
            return;
        }
        if ($configuration->hasCoverageCacheDirectory()) {
            $this->codeCoverage()
                ->cacheStaticAnalysis($configuration->coverageCacheDirectory());
        }
        $this->codeCoverage()
            ->excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(Comparator::class);
        if ($configuration->strictCoverage()) {
            $this->codeCoverage()
                ->enableCheckForUnintentionallyCoveredCode();
        }
        if ($configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage()) {
            $this->codeCoverage()
                ->ignoreDeprecatedCode();
        }
        else {
            $this->codeCoverage()
                ->doNotIgnoreDeprecatedCode();
        }
        if ($configuration->disableCodeCoverageIgnore()) {
            $this->codeCoverage()
                ->disableAnnotationsForIgnoringCode();
        }
        else {
            $this->codeCoverage()
                ->enableAnnotationsForIgnoringCode();
        }
        if ($configuration->includeUncoveredFiles()) {
            $this->codeCoverage()
                ->includeUncoveredFiles();
        }
        else {
            $this->codeCoverage()
                ->excludeUncoveredFiles();
        }
        if ($codeCoverageFilterRegistry->get()
            ->isEmpty()) {
            if (!$codeCoverageFilterRegistry->configured()) {
                EventFacade::emitter()->testRunnerTriggeredWarning('No filter is configured, code coverage will not be processed');
            }
            else {
                EventFacade::emitter()->testRunnerTriggeredWarning('Incorrect filter configuration, code coverage will not be processed');
            }
            $this->deactivate();
        }
    }
    
    /**
     * @psalm-assert-if-true !null $this->instance
     */
    public function isActive() : bool {
        return $this->codeCoverage !== null;
    }
    public function codeCoverage() : \SebastianBergmann\CodeCoverage\CodeCoverage {
        return $this->codeCoverage;
    }
    public function driver() : Driver {
        return $this->driver;
    }
    
    /**
     * @throws MoreThanOneDataSetFromDataProviderException
     */
    public function start(TestCase $test) : void {
        if ($this->collecting) {
            return;
        }
        $size = TestSize::unknown();
        if ($test->size()
            ->isSmall()) {
            $size = TestSize::small();
        }
        elseif ($test->size()
            ->isMedium()) {
            $size = TestSize::medium();
        }
        elseif ($test->size()
            ->isLarge()) {
            $size = TestSize::large();
        }
        $this->test = $test;
        $this->codeCoverage
            ->start($test->valueObjectForEvents()
            ->id(), $size);
        $this->collecting = true;
    }
    public function stop(bool $append = true, array|false $linesToBeCovered = [], array $linesToBeUsed = []) : void {
        if (!$this->collecting) {
            return;
        }
        $status = TestStatus::unknown();
        if ($this->test !== null) {
            if ($this->test
                ->status()
                ->isSuccess()) {
                $status = TestStatus::success();
            }
            else {
                $status = TestStatus::failure();
            }
        }
        
        /* @noinspection UnusedFunctionResultInspection */
        $this->codeCoverage
            ->stop($append, $status, $linesToBeCovered, $linesToBeUsed, $this->linesToBeIgnored);
        $this->test = null;
        $this->collecting = false;
    }
    public function deactivate() : void {
        $this->driver = null;
        $this->codeCoverage = null;
        $this->test = null;
    }
    public function generateReports(Printer $printer, Configuration $configuration) : void {
        if (!$this->isActive()) {
            return;
        }
        if ($configuration->hasCoveragePhp()) {
            $this->codeCoverageGenerationStart($printer, 'PHP');
            try {
                $writer = new PhpReport();
                $writer->process($this->codeCoverage(), $configuration->coveragePhp());
                $this->codeCoverageGenerationSucceeded($printer);
                unset($writer);
            } catch (CodeCoverageException $e) {
                $this->codeCoverageGenerationFailed($printer, $e);
            }
        }
        if ($configuration->hasCoverageClover()) {
            $this->codeCoverageGenerationStart($printer, 'Clover XML');
            try {
                $writer = new CloverReport();
                $writer->process($this->codeCoverage(), $configuration->coverageClover());
                $this->codeCoverageGenerationSucceeded($printer);
                unset($writer);
            } catch (CodeCoverageException $e) {
                $this->codeCoverageGenerationFailed($printer, $e);
            }
        }
        if ($configuration->hasCoverageCobertura()) {
            $this->codeCoverageGenerationStart($printer, 'Cobertura XML');
            try {
                $writer = new CoberturaReport();
                $writer->process($this->codeCoverage(), $configuration->coverageCobertura());
                $this->codeCoverageGenerationSucceeded($printer);
                unset($writer);
            } catch (CodeCoverageException $e) {
                $this->codeCoverageGenerationFailed($printer, $e);
            }
        }
        if ($configuration->hasCoverageCrap4j()) {
            $this->codeCoverageGenerationStart($printer, 'Crap4J XML');
            try {
                $writer = new Crap4jReport($configuration->coverageCrap4jThreshold());
                $writer->process($this->codeCoverage(), $configuration->coverageCrap4j());
                $this->codeCoverageGenerationSucceeded($printer);
                unset($writer);
            } catch (CodeCoverageException $e) {
                $this->codeCoverageGenerationFailed($printer, $e);
            }
        }
        if ($configuration->hasCoverageHtml()) {
            $this->codeCoverageGenerationStart($printer, 'HTML');
            try {
                $customCssFile = CustomCssFile::default();
                if ($configuration->hasCoverageHtmlCustomCssFile()) {
                    $customCssFile = CustomCssFile::from($configuration->coverageHtmlCustomCssFile());
                }
                $writer = new HtmlReport(sprintf(' and <a href="https://phpunit.de/">PHPUnit %s</a>', Version::id()), Colors::from($configuration->coverageHtmlColorSuccessLow(), $configuration->coverageHtmlColorSuccessMedium(), $configuration->coverageHtmlColorSuccessHigh(), $configuration->coverageHtmlColorWarning(), $configuration->coverageHtmlColorDanger()), Thresholds::from($configuration->coverageHtmlLowUpperBound(), $configuration->coverageHtmlHighLowerBound()), $customCssFile);
                $writer->process($this->codeCoverage(), $configuration->coverageHtml());
                $this->codeCoverageGenerationSucceeded($printer);
                unset($writer);
            } catch (CodeCoverageException $e) {
                $this->codeCoverageGenerationFailed($printer, $e);
            }
        }
        if ($configuration->hasCoverageText()) {
            $processor = new TextReport(Thresholds::default(), $configuration->coverageTextShowUncoveredFiles(), $configuration->coverageTextShowOnlySummary());
            $textReport = $processor->process($this->codeCoverage(), $configuration->colors());
            if ($configuration->coverageText() === 'php://stdout') {
                if (!$configuration->noOutput() && !$configuration->debug()) {
                    $printer->print($textReport);
                }
            }
            else {
                file_put_contents($configuration->coverageText(), $textReport);
            }
        }
        if ($configuration->hasCoverageXml()) {
            $this->codeCoverageGenerationStart($printer, 'PHPUnit XML');
            try {
                $writer = new XmlReport(Version::id());
                $writer->process($this->codeCoverage(), $configuration->coverageXml());
                $this->codeCoverageGenerationSucceeded($printer);
                unset($writer);
            } catch (CodeCoverageException $e) {
                $this->codeCoverageGenerationFailed($printer, $e);
            }
        }
    }
    
    /**
     * @psalm-param array<string,list<int>> $linesToBeIgnored
     */
    public function ignoreLines(array $linesToBeIgnored) : void {
        $this->linesToBeIgnored = $linesToBeIgnored;
    }
    
    /**
     * @psalm-return array<string,list<int>>
     */
    public function linesToBeIgnored() : array {
        return $this->linesToBeIgnored;
    }
    private function activate(Filter $filter, bool $pathCoverage) : void {
        try {
            if ($pathCoverage) {
                $this->driver = (new Selector())->forLineAndPathCoverage($filter);
            }
            else {
                $this->driver = (new Selector())->forLineCoverage($filter);
            }
            $this->codeCoverage = new \SebastianBergmann\CodeCoverage\CodeCoverage($this->driver, $filter);
        } catch (CodeCoverageException $e) {
            EventFacade::emitter()->testRunnerTriggeredWarning($e->getMessage());
        }
    }
    private function codeCoverageGenerationStart(Printer $printer, string $format) : void {
        $printer->print(sprintf("\nGenerating code coverage report in %s format ... ", $format));
        $this->timer()
            ->start();
    }
    
    /**
     * @throws NoActiveTimerException
     */
    private function codeCoverageGenerationSucceeded(Printer $printer) : void {
        $printer->print(sprintf("done [%s]\n", $this->timer()
            ->stop()
            ->asString()));
    }
    
    /**
     * @throws NoActiveTimerException
     */
    private function codeCoverageGenerationFailed(Printer $printer, CodeCoverageException $e) : void {
        $printer->print(sprintf("failed [%s]\n%s\n", $this->timer()
            ->stop()
            ->asString(), $e->getMessage()));
    }
    private function timer() : Timer {
        if ($this->timer === null) {
            $this->timer = new Timer();
        }
        return $this->timer;
    }

}

Members

Title Sort descending Modifiers Object type Summary
CodeCoverage::$codeCoverage private property
CodeCoverage::$collecting private property
CodeCoverage::$driver private property
CodeCoverage::$instance private static property
CodeCoverage::$linesToBeIgnored private property @psalm-var array&lt;string,list&lt;int&gt;&gt;
CodeCoverage::$test private property
CodeCoverage::$timer private property
CodeCoverage::activate private function
CodeCoverage::codeCoverage public function
CodeCoverage::codeCoverageGenerationFailed private function
CodeCoverage::codeCoverageGenerationStart private function
CodeCoverage::codeCoverageGenerationSucceeded private function
CodeCoverage::deactivate public function
CodeCoverage::driver public function
CodeCoverage::generateReports public function
CodeCoverage::ignoreLines public function @psalm-param array&lt;string,list&lt;int&gt;&gt; $linesToBeIgnored
CodeCoverage::init public function
CodeCoverage::instance public static function
CodeCoverage::isActive public function @psalm-assert-if-true !null $this-&gt;instance
CodeCoverage::linesToBeIgnored public function @psalm-return array&lt;string,list&lt;int&gt;&gt;
CodeCoverage::start public function
CodeCoverage::stop public function
CodeCoverage::timer private function

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal