Skip to content

fix: restore coverage paths when the covered files share only the root directory - #49

Open
mechgw wants to merge 2 commits into
pestphp:5.xfrom
mechgw:fix/coverage-paths-sharing-root
Open

mechgw wants to merge 2 commits into
pestphp:5.xfrom
mechgw:fix/coverage-paths-sharing-root

Conversation

@mechgw

@mechgw mechgw commented Oct 16, 2026

Copy link
Copy Markdown

What:

  • Bug Fix
  • New Feature

Description:

When the covered files share only the root directory, every mutation is reported as uncovered, and --covered-only creates no mutation at all. This happens, for example, with one source directory under /tmp and another under /home.

Since phpunit/php-code-coverage 14, --coverage-php writes the file keys relative to a basePath computed by PathReducer. When the only common ancestor is /, PathReducer strips it from every key and returns an empty basePath. MutationTestRunner::run() restores the paths only when basePath !== '', so the keys stay relative (home/runner/...). They then match no mutated file, which is looked up by its real path.

Windows is not affected the same way. Files on the same drive get a basePath such as C:, and files on different drives have no common ancestor and keep their absolute paths. That is why this only shows on Linux and macOS.

The fix. The restoring moves to CoveragePaths::restore():

  • a non-empty basePath is prepended as before;
  • with an empty basePath, a path starting with a drive letter stays as is;
  • any other path gets back its leading separator.

Tests.

  • tests/Unit/Support/CoveragePathsTest.php reduces the paths with PathReducer exactly as --coverage-php does and checks that they are restored. It covers a single file, files sharing a directory, and files sharing only /, plus a same-drive and a different-drives case that only run on Windows.
  • tests/Features/CoveragePathsTest.php runs pest --mutate end to end with a covered class in the system temporary directory, outside the repository. It expects the mutations to be tested, with and without --covered-only.

CI. The workflows ran on a fork with the full matrix and fail-fast: false. COMPOSER_ROOT_VERSION=5.x-dev was set there only because Composer cannot guess the root version of a feature branch. The results were compared, job by job, with the same workflows on unmodified 5.x (d0c8711):

  • this branch: Tests, Static Analysis — prefer-lowest: 324 passed, 2 skipped (the Windows-only cases);
  • the tests without the fix: Tests — exactly the 2 new end-to-end tests fail;
  • 5.x: Tests, Static Analysis — prefer-lowest: 319 passed.

Apart from the new tests, the set of failures is identical in every job:

  • the 3 Tests\Visual\* snapshots fail in the prefer-stable jobs, because current PHPUnit prints a deprecation warning for the cacheResult attribute of phpunit.xml;
  • PHPStan reports 2 errors, both in files this PR does not touch.

🤖 Generated with Claude Code

mechgw and others added 2 commits October 15, 2026 19:12
…t directory

Since phpunit/php-code-coverage 14, `--coverage-php` writes the file keys
relative to `basePath`. When the covered files share only the root
directory (e.g. /tmp/x/A.php and /home/y/B.php), the path reducer returns
an empty base path and the keys lose their leading separator, so they no
longer match the real paths of the mutated files: every mutation becomes
uncovered and `--covered-only` skips the files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Runs `--mutate` with and without `--covered-only` for a class generated in
the temporary directory and covered together with a class of the
repository. Skipped on Windows, where the file finder takes the paths with
a drive letter for relative paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 16, 2026 17:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants