From 0fc9d4dfe0260827fc2fd9c6fce07ed99508fcc8 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sun, 8 Jun 2025 15:29:23 +0100 Subject: [PATCH] feat: adds phpunit `12.2.1` support --- composer.json | 5 +- .../Parallel/Paratest/ResultPrinter.php | 4 +- .../Parallel/Paratest/WrapperRunner.php | 6 +- ...isual_snapshot_of_help_command_output.snap | 3 + tests/.snapshots/success.txt | 18 ++++-- tests/Features/Covers.php | 59 ------------------- tests/Features/Covers/ClassCoverage.php | 13 ++++ tests/Features/Covers/CoversNothing.php | 10 ++++ tests/Features/Covers/ExceptionHandling.php | 10 ++++ tests/Features/Covers/FunctionCoverage.php | 12 ++++ tests/Features/Covers/GuessCoverage.php | 17 ++++++ tests/Features/Covers/TraitCoverage.php | 11 ++++ 12 files changed, 99 insertions(+), 69 deletions(-) delete mode 100644 tests/Features/Covers.php create mode 100644 tests/Features/Covers/ClassCoverage.php create mode 100644 tests/Features/Covers/CoversNothing.php create mode 100644 tests/Features/Covers/ExceptionHandling.php create mode 100644 tests/Features/Covers/FunctionCoverage.php create mode 100644 tests/Features/Covers/GuessCoverage.php create mode 100644 tests/Features/Covers/TraitCoverage.php diff --git a/composer.json b/composer.json index a9800dab..da76ff30 100644 --- a/composer.json +++ b/composer.json @@ -20,16 +20,15 @@ "php": "^8.3.0", "brianium/paratest": "^7.10.1", "nunomaduro/collision": "^8.8.0", - "nunomaduro/pokio": "dev-main", "nunomaduro/termwind": "^2.3.1", "pestphp/pest-plugin": "^4.0.0", "pestphp/pest-plugin-arch": "^4.0.0", "pestphp/pest-plugin-mutate": "^4.0.0", - "phpunit/phpunit": "^12.1.6" + "phpunit/phpunit": "^12.2.1" }, "conflict": { "filp/whoops": "<2.16.0", - "phpunit/phpunit": ">12.1.6", + "phpunit/phpunit": ">12.2.1", "sebastian/exporter": "<7.0.0", "webmozart/assert": "<1.11.0" }, diff --git a/src/Plugins/Parallel/Paratest/ResultPrinter.php b/src/Plugins/Parallel/Paratest/ResultPrinter.php index bd416e1e..e7a1c24d 100644 --- a/src/Plugins/Parallel/Paratest/ResultPrinter.php +++ b/src/Plugins/Parallel/Paratest/ResultPrinter.php @@ -59,10 +59,10 @@ final class ResultPrinter private readonly OutputInterface $output, private readonly Options $options ) { - $this->printer = new class($this->output) implements Printer + $this->printer = new readonly class($this->output) implements Printer { public function __construct( - private readonly OutputInterface $output, + private OutputInterface $output, ) {} public function print(string $buffer): void diff --git a/src/Plugins/Parallel/Paratest/WrapperRunner.php b/src/Plugins/Parallel/Paratest/WrapperRunner.php index 877a7373..469f2aa6 100644 --- a/src/Plugins/Parallel/Paratest/WrapperRunner.php +++ b/src/Plugins/Parallel/Paratest/WrapperRunner.php @@ -17,6 +17,7 @@ use ParaTest\WrapperRunner\WrapperWorker; use Pest\Result; use Pest\TestSuite; use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; use PHPUnit\Event\TestRunner\WarningTriggered; use PHPUnit\Runner\CodeCoverage; use PHPUnit\Runner\ResultCache\DefaultResultCache; @@ -313,12 +314,15 @@ final class WrapperRunner implements RunnerInterface $testResult = unserialize($contents); assert($testResult instanceof TestResult); + /** @var list $failedEvents */ + $failedEvents = array_merge_recursive($testResultSum->testFailedEvents(), $testResult->testFailedEvents()); + $testResultSum = new TestResult( (int) $testResultSum->hasTests() + (int) $testResult->hasTests(), $testResultSum->numberOfTestsRun() + $testResult->numberOfTestsRun(), $testResultSum->numberOfAssertions() + $testResult->numberOfAssertions(), array_merge_recursive($testResultSum->testErroredEvents(), $testResult->testErroredEvents()), - array_merge_recursive($testResultSum->testFailedEvents(), $testResult->testFailedEvents()), + $failedEvents, array_merge_recursive($testResultSum->testConsideredRiskyEvents(), $testResult->testConsideredRiskyEvents()), array_merge_recursive($testResultSum->testSuiteSkippedEvents(), $testResult->testSuiteSkippedEvents()), array_merge_recursive($testResultSum->testSkippedEvents(), $testResult->testSkippedEvents()), diff --git a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap index 09fe9928..b2f7a23f 100644 --- a/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap +++ b/tests/.pest/snapshots/Visual/Help/visual_snapshot_of_help_command_output.snap @@ -100,10 +100,12 @@ --testdox ................ Replace default result output with TestDox format --testdox-summary Repeat TestDox output for tests with errors, failures, or issues --debug Replace default progress and result output with debugging information + --with-telemetry Include telemetry information in debugging information output --compact ................ Replace default result output with Compact format LOGGING OPTIONS: --log-junit [file] .......... Write test results in JUnit XML format to file + --log-otr [file] Write test results in Open Test Reporting XML format to file --log-teamcity [file] ........ Write test results in TeamCity format to file --testdox-html [file] .. Write test results in TestDox format (HTML) to file --testdox-text [file] Write test results in TestDox format (plain text) to file @@ -115,6 +117,7 @@ --coverage ..... Generate code coverage report and output to standard output --coverage --min Set the minimum required coverage percentage, and fail if not met --coverage-clover [file] Write code coverage report in Clover XML format to file + --coverage-openclover [file] Write code coverage report in OpenClover XML format to file --coverage-cobertura [file] Write code coverage report in Cobertura XML format to file --coverage-crap4j [file] Write code coverage report in Crap4J XML format to file --coverage-html [dir] Write code coverage report in HTML format to directory diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 513a804e..5245e72c 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -68,14 +68,24 @@ ✓ it adds coverage if --min exist ✓ it generates coverage based on file input - PASS Tests\Features\Covers + PASS Tests\Features\Covers\ClassCoverage ✓ it uses the correct PHPUnit attribute for class - ✓ it uses the correct PHPUnit attribute for function - ✓ it guesses if the given argument is a class or function - ✓ it uses the correct PHPUnit attribute for trait + + PASS Tests\Features\Covers\CoversNothing ✓ it uses the correct PHPUnit attribute for covers nothing + + PASS Tests\Features\Covers\ExceptionHandling ✓ it throws exception if no class nor method has been found + PASS Tests\Features\Covers\FunctionCoverage + ✓ it uses the correct PHPUnit attribute for function + + PASS Tests\Features\Covers\GuessCoverage + ✓ it guesses if the given argument is a class or function + + PASS Tests\Features\Covers\TraitCoverage + ✓ it uses the correct PHPUnit attribute for trait + PASS Tests\Features\DatasetsTests - 1 todo ✓ it throws exception if dataset does not exist ✓ it throws exception if dataset already exist diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php deleted file mode 100644 index 386d523f..00000000 --- a/tests/Features/Covers.php +++ /dev/null @@ -1,59 +0,0 @@ -getAttributes(); - - expect($attributes[1]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); - expect($attributes[1]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversClass1'); -}); - -it('uses the correct PHPUnit attribute for function', function () { - $attributes = (new ReflectionClass($this))->getAttributes(); - - expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); - expect($attributes[3]->getArguments()[0])->toBe('testCoversFunction'); -})->coversFunction('testCoversFunction'); - -it('guesses if the given argument is a class or function', function () { - $attributes = (new ReflectionClass($this))->getAttributes(); - - expect($attributes[5]->getName())->toBe(CoversClass::class); - expect($attributes[5]->getArguments()[0])->toBe(CoversClass3::class); - - expect($attributes[6]->getName())->toBe(CoversFunction::class); - expect($attributes[6]->getArguments()[0])->toBe('testCoversFunction'); -})->covers(CoversClass3::class, 'testCoversFunction'); - -it('uses the correct PHPUnit attribute for trait', function () { - $attributes = (new ReflectionClass($this))->getAttributes(); - - expect($attributes[8]->getName())->toBe('PHPUnit\Framework\Attributes\CoversTrait'); - expect($attributes[8]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversTrait'); -})->coversTrait(CoversTrait::class); - -it('uses the correct PHPUnit attribute for covers nothing', function () { - $attributes = (new ReflectionMethod($this, $this->name()))->getAttributes(); - - expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversNothing'); - expect($attributes[3]->getArguments())->toHaveCount(0); -})->coversNothing(); - -it('throws exception if no class nor method has been found', function () { - $testCall = new TestCall(TestSuite::getInstance(), 'filename', 'description', fn () => 'closure'); - - $testCall->covers('fakeName'); -})->throws(InvalidArgumentException::class, 'No class, trait or method named "fakeName" has been found.'); diff --git a/tests/Features/Covers/ClassCoverage.php b/tests/Features/Covers/ClassCoverage.php new file mode 100644 index 00000000..ab805e17 --- /dev/null +++ b/tests/Features/Covers/ClassCoverage.php @@ -0,0 +1,13 @@ +getAttributes(); + + expect($attributes[1]->getName())->toBe(CoversClass::class); + expect($attributes[1]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversClass1'); +}); diff --git a/tests/Features/Covers/CoversNothing.php b/tests/Features/Covers/CoversNothing.php new file mode 100644 index 00000000..6918414c --- /dev/null +++ b/tests/Features/Covers/CoversNothing.php @@ -0,0 +1,10 @@ +name()))->getAttributes(); + + expect($attributes[2]->getName())->toBe(CoversNothing::class); + expect($attributes[2]->getArguments())->toHaveCount(0); +})->coversNothing(); diff --git a/tests/Features/Covers/ExceptionHandling.php b/tests/Features/Covers/ExceptionHandling.php new file mode 100644 index 00000000..de86bb02 --- /dev/null +++ b/tests/Features/Covers/ExceptionHandling.php @@ -0,0 +1,10 @@ + 'closure'); + + $testCall->covers('fakeName'); +})->throws(InvalidArgumentException::class, 'No class, trait or method named "fakeName" has been found.'); diff --git a/tests/Features/Covers/FunctionCoverage.php b/tests/Features/Covers/FunctionCoverage.php new file mode 100644 index 00000000..fba97080 --- /dev/null +++ b/tests/Features/Covers/FunctionCoverage.php @@ -0,0 +1,12 @@ +getAttributes(); + + expect($attributes[1]->getName())->toBe(CoversFunction::class); + expect($attributes[1]->getArguments()[0])->toBe('testCoversFunction'); +})->coversFunction('testCoversFunction'); diff --git a/tests/Features/Covers/GuessCoverage.php b/tests/Features/Covers/GuessCoverage.php new file mode 100644 index 00000000..e8a84035 --- /dev/null +++ b/tests/Features/Covers/GuessCoverage.php @@ -0,0 +1,17 @@ +getAttributes(); + + expect($attributes[1]->getName())->toBe(CoversClass::class); + expect($attributes[1]->getArguments()[0])->toBe(CoversClass3::class); + + expect($attributes[2]->getName())->toBe(CoversFunction::class); + expect($attributes[2]->getArguments()[0])->toBe('testCoversFunction2'); +})->covers(CoversClass3::class, 'testCoversFunction2'); diff --git a/tests/Features/Covers/TraitCoverage.php b/tests/Features/Covers/TraitCoverage.php new file mode 100644 index 00000000..57bc3680 --- /dev/null +++ b/tests/Features/Covers/TraitCoverage.php @@ -0,0 +1,11 @@ +getAttributes(); + + expect($attributes[1]->getName())->toBe(PHPUnitCoversTrait::class); + expect($attributes[1]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversTrait'); +})->coversTrait(CoversTrait::class);