From 2ec11a7c7c6b34d0e528cb1f266fd1df477ddf8a Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 7 Oct 2026 13:54:44 -0500 Subject: [PATCH 1/2] feat: support PHP 8.4 and PHPUnit 13 --- .github/workflows/ci.yml | 10 ++++++---- .gitignore | 2 ++ README.md | 2 +- composer.json | 6 +++--- phpunit.xml.dist | 11 ++++------- src/AsyncTestCase.php | 27 +++------------------------ test/AsyncTestCaseTest.php | 20 +++++++++----------- test/InvalidAsyncTestCaseTest.php | 2 +- 8 files changed, 29 insertions(+), 51 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fde518..76cdec8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,14 +10,17 @@ jobs: matrix: include: - operating-system: 'ubuntu-latest' - php-version: '8.1' + php-version: '8.4' + + - operating-system: 'ubuntu-latest' + php-version: '8.5' - operating-system: 'windows-latest' - php-version: '8.1' + php-version: '8.4' job-description: 'on Windows' - operating-system: 'macos-latest' - php-version: '8.1' + php-version: '8.4' job-description: 'on macOS' name: PHP ${{ matrix.php-version }} ${{ matrix.job-description }} @@ -37,7 +40,6 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} - extensions: fiber-amphp/ext-fiber@master - name: Get Composer cache directory id: composer-cache diff --git a/.gitignore b/.gitignore index f870cdd..8bab7d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .php_cs.cache +.php-cs-fixer.cache build composer.lock phpunit.xml vendor +.phpunit.cache .phpunit.result.cache diff --git a/README.md b/README.md index 0f25e92..a275a85 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This package can be installed as a [Composer](https://getcomposer.org/) dependen composer require --dev amphp/phpunit-util ``` -The package requires PHP 8.1 or later. +The package requires PHP 8.4 or later and PHPUnit 13. ## Usage diff --git a/composer.json b/composer.json index edfc481..e793626 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,10 @@ "issues": "https://github.com/amphp/phpunit-util/issues" }, "require": { - "php": ">=8.1", + "php": ">=8.4", "amphp/amp": "^3", - "phpunit/phpunit": "^9", - "revolt/event-loop": "^1 || ^0.2" + "phpunit/phpunit": "^13", + "revolt/event-loop": "^1" }, "require-dev": { "amphp/php-cs-fixer-config": "^2" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index c8b5fad..a6fd7d7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,13 @@ @@ -20,9 +17,9 @@ test - + src - + diff --git a/src/AsyncTestCase.php b/src/AsyncTestCase.php index 9bdcf93..8be19fc 100644 --- a/src/AsyncTestCase.php +++ b/src/AsyncTestCase.php @@ -22,20 +22,8 @@ abstract class AsyncTestCase extends PHPUnitTestCase /** @var float Minimum runtime in seconds. */ private float $minimumRuntime = 0; - /** @var string Temporary storage for actual test name. */ - private string $realTestName; - private bool $setUpInvoked = false; - /** - * @codeCoverageIgnore Invoked before code coverage data is being collected. - */ - final public function setName(string $name): void - { - parent::setName($name); - $this->realTestName = $name; - } - protected function setUp(): void { $this->setUpInvoked = true; @@ -50,8 +38,7 @@ protected function setUp(): void }); } - /** @internal */ - final protected function runAsyncTest(mixed ...$args): mixed + final protected function invokeTestMethod(string $methodName, array $testArguments): mixed { if (!$this->setUpInvoked) { self::fail(\sprintf( @@ -61,16 +48,14 @@ final protected function runAsyncTest(mixed ...$args): mixed )); } - parent::setName($this->realTestName); - $start = now(); try { [, $returnValue] = Future\await([ $this->deferredFuture->getFuture(), - async(function () use ($args): mixed { + async(function () use ($methodName, $testArguments): mixed { try { - $result = ([$this, $this->realTestName])(...$args); + $result = parent::invokeTestMethod($methodName, $testArguments); if ($result instanceof Future) { $result = $result->await(); } @@ -112,12 +97,6 @@ final protected function runAsyncTest(mixed ...$args): mixed return $returnValue; } - final protected function runTest(): mixed - { - parent::setName('runAsyncTest'); - return parent::runTest(); - } - /** * Fails the test if it does not run for at least the given amount of time. * diff --git a/test/AsyncTestCaseTest.php b/test/AsyncTestCaseTest.php index f800ec9..c0f8d78 100644 --- a/test/AsyncTestCaseTest.php +++ b/test/AsyncTestCaseTest.php @@ -5,6 +5,8 @@ use Amp\DeferredFuture; use Amp\Future; use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; use Revolt\EventLoop; use function Amp\async; use function Amp\delay; @@ -66,7 +68,7 @@ public function testExpectingAnExceptionThrown(): Future }; $this->expectException(TestException::class); - $this->expectExceptionMessage('threw the error'); + $this->expectExceptionMessageIsOrContains('threw the error'); return async($throwException); } @@ -80,16 +82,14 @@ public function testExpectingAnErrorThrown(): Future }); } - public function provideArguments(): array + public static function provideArguments(): array { return [ ['foo', 42, true], ]; } - /** - * @dataProvider provideArguments - */ + #[DataProvider('provideArguments')] public function testArgumentSupport(string $foo, int $bar, bool $baz): void { self::assertSame('foo', $foo); @@ -97,10 +97,8 @@ public function testArgumentSupport(string $foo, int $bar, bool $baz): void self::assertTrue($baz); } - /** - * @depends testReturningFuture - */ - public function testReturnValueFromDependentTest(string $value = null): void + #[Depends('testReturningFuture')] + public function testReturnValueFromDependentTest(?string $value = null): void { self::assertSame('value', $value); } @@ -128,7 +126,7 @@ public function testSetTimeoutWithFuture(): Future $this->setTimeout(0.1); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('Expected test to complete before 0.100s time limit'); + $this->expectExceptionMessageIsOrContains('Expected test to complete before 0.100s time limit'); $deferred = new DeferredFuture; @@ -142,7 +140,7 @@ public function testSetTimeoutWithAwait(): void $this->setTimeout(0.1); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('Expected test to complete before 0.100s time limit'); + $this->expectExceptionMessageIsOrContains('Expected test to complete before 0.100s time limit'); delay(0.2); } diff --git a/test/InvalidAsyncTestCaseTest.php b/test/InvalidAsyncTestCaseTest.php index 87b7738..29b19b8 100644 --- a/test/InvalidAsyncTestCaseTest.php +++ b/test/InvalidAsyncTestCaseTest.php @@ -11,7 +11,7 @@ protected function setUp(): void // No call to parent::setUp() $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('without calling the parent method'); + $this->expectExceptionMessageIsOrContains('without calling the parent method'); } public function testMethod() From f4ada05a51aae663a500459aa60e650de6d31ff7 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 7 Oct 2026 14:17:18 -0500 Subject: [PATCH 2/2] ci: update checkout and cache to v4 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76cdec8..3b7d374 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: git config --global core.eol lf - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -46,7 +46,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-dir)" - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }}-${{ matrix.composer-flags }}