Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Bug: #[CoversNothing] is ignored in Cest tests with PHPUnit 13 / php-code-coverage 12 #6940

Copy link
Copy link

Description

@alex-lar-newgen-vision
Issue body actions

##Bug: #[CoversNothing] is ignored in Cest tests with PHPUnit 13 / php-code-coverage 12

Environment

  • codeception/codeception: ^5.3.5
  • phpunit/phpunit: ^13.0
  • phpunit/php-code-coverage: ^12.0

Steps to reproduce

use PHPUnit\Framework\Attributes\CoversNothing;

#[CoversNothing]
class SomeCest
{
    public function someTest(\AcceptanceTester $I): void
    {
        // ...
    }
}

Run: vendor/bin/codecept run --coverage

Expected: test does not contribute to code coverage.
Actual: TypeError crash — or, if getLinesToBeCovered() returns [],
the test silently contributes to coverage as if the attribute were absent.


Root cause (two-part)

Part 1 — Cest::getLinesToBeCovered() does not handle CoversNothing

PHPUnit\Metadata\Api\CodeCoverage::coversTargets() in PHPUnit 13 handles only
CoversClass, CoversMethod, CoversTrait, etc.
It does not handle #[CoversNothing] — it simply returns an empty TargetCollection.

The correct PHPUnit 13 API for CoversNothing is shouldCodeCoverageBeCollectedFor():

// PHPUnit 13 — PHPUnit\Metadata\Api\CodeCoverage
public function shouldCodeCoverageBeCollectedFor(TestCase $test): bool
{
    if ($parser->forClass($test::class)->isCoversNothing()->isNotEmpty()) {
        return false;
    }
    return true;
}

But Cest::getLinesToBeCovered() never calls it, so CoversNothing is lost.

Part 2 — CodeCoverage trait does not handle false return value for php-code-coverage ≥ 12

Historically getLinesToBeCovered() returned false for @coversNothing.
In Feature/CodeCoverage.php, when php-code-coverage >= 12, the result is passed
directly to TargetCollection::fromArray(), which does not accept false:

Proposed fix

1. src/Codeception/Test/Cest.php — check CoversNothing before delegating to coversTargets():

public function getLinesToBeCovered(): array|bool
{
    if (PHPUnitVersion::series() < 10) {
        return TestUtil::getLinesToBeCovered($this->testClass, $this->testMethod);
    }

    $metadata = \PHPUnit\Metadata\Parser\Registry::parser()
        ->forClassAndMethod($this->testClass, $this->testMethod);

    if ($metadata->isCoversNothing()->isNotEmpty()) {
        return false;
    }

    if (version_compare(CodeCoverageVersion::id(), '12', '>=')) {
        return (new CodeCoverage())->coversTargets($this->testClass, $this->testMethod)->asArray();
    }

    return (new CodeCoverage())->linesToBeCovered($this->testClass, $this->testMethod);
}

2. src/Codeception/Test/Feature/CodeCoverage.php — handle false before calling TargetCollection::fromArray():

if (version_compare(CodeCoverageVersion::id(), '12', '>=')) {
    $tcClass = 'SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollection';
    if (class_exists($tcClass) && method_exists($tcClass, 'fromArray')) {
        if ($linesToBeCovered === false) {
            $codeCoverage->stop(false, $status);
            return;
        }
        $linesToBeCovered = $tcClass::fromArray($linesToBeCovered);
        $linesToBeUsed    = $tcClass::fromArray($linesToBeUsed);
    }
}
$codeCoverage->stop(true, $status, $linesToBeCovered, $linesToBeUsed);

Both changes are needed: the first makes CoversNothing detectable again,
the second prevents the TypeError crash when the false value reaches fromArray().

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.