[Bug]: `--coverage` console report fails on macOS for large suites: `require` of a >2 GiB `coverage.php` hits the 2 GiB single-syscall limit
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 11.7k
- Forks
- 538
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 8
Description
What happens
On macOS, running a large suite with --coverage — either vendor/bin/pest --coverage or php artisan test --coverage (via nunomaduro/collision) — fails while building the console coverage report:
Cannot write to /.../coverage.php
…and even if the file is produced, reading it back fails symmetrically.
Root cause
The console report round-trips the merged coverage through a var_export'd PHP file and pulls it back with require:
// vendor/pestphp/pest/src/Support/Coverage.php (mirror in nunomaduro/collision Coverage::report())
$codeCoverage = require $reportPath; // coverage.php
unlink($reportPath);
For a large suite that coverage.php exceeds 2 GiB, because it serializes the full per-test coverage map (which test touched which line), not just the aggregate. macOS caps a single read()/write() at 2 GiB (EINVAL at ≥ 0x7fffffff bytes), so:
- writing the file (
file_put_contentsof thevar_exportstring) fails once it crosses 2 GiB, and require $reportPathfails the same way — it reads the whole file in one operation.
Crucially, chunking the write into < 2 GiB pieces does not fix it, because the read is an atomic require that can't be chunked. (php-code-coverage 14.x already dropped its own PHP report format, so this var_export/require handoff is now Pest/Collision's own.)
Why the size is avoidable
The same coverage, emitted as a Clover XML report for the same suite, is a few MB. The multi-GB size is purely the per-test granularity of the PHP dump. The console --coverage report only needs aggregate per-file/line coverage — the per-test map is only needed by TIA.
Suggested direction
- For the console-report handoff, serialize aggregate coverage (orders of magnitude smaller) rather than the full per-test map; or
- split the handoff into < 2 GiB chunk files and
require/merge each, so no single read/write crosses the macOS limit; or - hand the report a compact serialization (Clover/XML) instead of a
var_export'd PHP file — consistent with php-code-coverage 14.x having removed itsPHPformat.
TIA's per-test needs (CoverageMerger) can keep their own, chunked serialization independent of the console report.
Workaround (for reference)
We bypass the console report entirely in CI/local: emit --coverage-clover and render a Pest-style per-file "uncovered lines" listing from the XML (a small Artisan command). A few MB, fast, no 2 GiB wall. Happy to share the command if useful.
Environment
- macOS (2 GiB single-syscall
read/writelimit) pestphp/pest5.0.2,nunomaduro/collision8.9.5,phpunit/php-code-coverage14.2.3, PHP 8.5- Suite: ~10k tests, PCOV coverage; serialized
coverage.php> 2 GB
How to Reproduce
- On macOS, with a suite whose serialized per-test coverage crosses 2 GiB (we hit it around ~10k tests with broad coverage — the
coverage.phphandoff carries the full per-test map, not just the aggregate). - Run
vendor/bin/pest --coverage(orphp artisan test --coverage). - Building the console report fails:
Cannot write to /.../coverage.phpon the write side, andrequire $reportPathfails the same way once the file exists.
The trigger is purely file size and independent of the coverage driver (PCOV here): on macOS any valid PHP file ≥ 2 GiB can be neither file_put_contents'd nor required in a single call (EINVAL at ≥ 0x7fffffff bytes), so Coverage::report() breaks the moment coverage.php crosses that line.
Pest Version
5.0.2
PHP Version
8.5.8
Operation System
macOS
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Coverage.php console-report handoff in Pest and the mirrored Coverage::report() implementation in nunomaduro/collision, focusing on the var_export/file_put_contents and require path described in the issue. Compare the console handoff with the aggregate coverage needs and verify the chosen approach using a macOS suite whose coverage exceeds 2 GiB; done means the console report completes without the single-read/write failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- cli, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100