From 70c2f6d1ee27b66134634f064d19a183ce6ac30d Mon Sep 17 00:00:00 2001 From: TavoNiievez Date: Thu, 1 May 2025 21:10:29 -0500 Subject: [PATCH 1/4] Update codebase to PHP 8.2 --- .github/workflows/main.yml | 2 +- composer.json | 2 +- readme.md | 2 +- src/Codeception/Module/Asserts.php | 13 +++++++------ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d273d49..79314d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: - php: [8.1, 8.2, 8.3, 8.4] + php: [8.2, 8.3, 8.4] steps: - name: Checkout code diff --git a/composer.json b/composer.json index b0f7f69..3f7cd00 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ ], "homepage": "https://codeception.com/", "require": { - "php": "^8.1", + "php": "^8.2", "codeception/codeception": "*@dev", "codeception/lib-asserts": "^2.2" }, diff --git a/readme.md b/readme.md index 0a4ab33..aadb37e 100644 --- a/readme.md +++ b/readme.md @@ -9,7 +9,7 @@ A Codeception module containing various assertions. ## Requirements -* `PHP 8.1` or higher. +* `PHP 8.2` or higher. ## Installation diff --git a/src/Codeception/Module/Asserts.php b/src/Codeception/Module/Asserts.php index 869faa3..707db6a 100644 --- a/src/Codeception/Module/Asserts.php +++ b/src/Codeception/Module/Asserts.php @@ -4,6 +4,9 @@ namespace Codeception\Module; +use Throwable; +use function get_debug_type; + /** * Special module for using asserts in your tests. */ @@ -31,10 +34,8 @@ class Asserts extends AbstractAsserts * $this->doSomethingBad(); * }); * ``` - * - * @param \Throwable|string $throwable */ - public function expectThrowable($throwable, callable $callback): void + public function expectThrowable(string|Throwable $throwable, callable $callback): void { if (is_object($throwable)) { $class = get_class($throwable); @@ -48,7 +49,7 @@ public function expectThrowable($throwable, callable $callback): void try { $callback(); - } catch (\Throwable $t) { + } catch (Throwable $t) { $this->checkThrowable($t, $class, $msg, $code); return; } @@ -60,13 +61,13 @@ public function expectThrowable($throwable, callable $callback): void * Check if the given throwable matches the expected data, * fail (throws an exception) if it does not. */ - protected function checkThrowable(\Throwable $throwable, string $expectedClass, ?string $expectedMsg, $expectedCode = null): void + protected function checkThrowable(Throwable $throwable, string $expectedClass, ?string $expectedMsg, int|null $expectedCode = null): void { if (!($throwable instanceof $expectedClass)) { $this->fail(sprintf( "Exception of class '%s' expected to be thrown, but class '%s' was caught", $expectedClass, - get_class($throwable) + get_debug_type($throwable) )); } From 3aac619402b37207178f8702a11d9888c0aaeb35 Mon Sep 17 00:00:00 2001 From: TavoNiievez Date: Thu, 1 May 2025 21:11:05 -0500 Subject: [PATCH 2/4] Update tests to Codeception 5 dir structure --- codeception.yml | 13 +++++++++---- tests/{_data => Support/Data}/DummyClass.php | 4 +++- tests/{_data => Support/Data}/data1.json | 0 tests/{_data => Support/Data}/data1.txt | 0 tests/{_data => Support/Data}/data1.xml | 0 tests/{_data => Support/Data}/data2.json | 0 tests/{_data => Support/Data}/data2.txt | 0 tests/{_data => Support/Data}/data2.xml | 0 tests/{_data => Support/Data}/data3.txt | 0 .../{_data => Support/Data}/expectedFileFormat.txt | 0 tests/{_support => Support}/UnitTester.php | 13 ++++++++----- tests/Support/_generated/.gitignore | 2 ++ tests/_support/_generated/.gitignore | 1 - tests/unit.suite.yml | 9 ++++----- 14 files changed, 26 insertions(+), 16 deletions(-) rename tests/{_data => Support/Data}/DummyClass.php (80%) rename tests/{_data => Support/Data}/data1.json (100%) rename tests/{_data => Support/Data}/data1.txt (100%) rename tests/{_data => Support/Data}/data1.xml (100%) rename tests/{_data => Support/Data}/data2.json (100%) rename tests/{_data => Support/Data}/data2.txt (100%) rename tests/{_data => Support/Data}/data2.xml (100%) rename tests/{_data => Support/Data}/data3.txt (100%) rename tests/{_data => Support/Data}/expectedFileFormat.txt (100%) rename tests/{_support => Support}/UnitTester.php (77%) create mode 100644 tests/Support/_generated/.gitignore delete mode 100644 tests/_support/_generated/.gitignore diff --git a/codeception.yml b/codeception.yml index 779d777..a2ad109 100644 --- a/codeception.yml +++ b/codeception.yml @@ -1,7 +1,12 @@ +namespace: Tests +support_namespace: Support + +settings: + shuffle: true + lint: true paths: tests: tests output: tests/_output - data: tests/_data - support: tests/_support - envs: tests/_envs -actor_suffix: Tester + support: tests/Support + data: tests/Support/Data + \ No newline at end of file diff --git a/tests/_data/DummyClass.php b/tests/Support/Data/DummyClass.php similarity index 80% rename from tests/_data/DummyClass.php rename to tests/Support/Data/DummyClass.php index 85d2a2c..6967cfd 100644 --- a/tests/_data/DummyClass.php +++ b/tests/Support/Data/DummyClass.php @@ -2,9 +2,11 @@ declare(strict_types=1); +namespace Support\Data; + class DummyClass { private int $foo; - + private static int $staticFoo; } \ No newline at end of file diff --git a/tests/_data/data1.json b/tests/Support/Data/data1.json similarity index 100% rename from tests/_data/data1.json rename to tests/Support/Data/data1.json diff --git a/tests/_data/data1.txt b/tests/Support/Data/data1.txt similarity index 100% rename from tests/_data/data1.txt rename to tests/Support/Data/data1.txt diff --git a/tests/_data/data1.xml b/tests/Support/Data/data1.xml similarity index 100% rename from tests/_data/data1.xml rename to tests/Support/Data/data1.xml diff --git a/tests/_data/data2.json b/tests/Support/Data/data2.json similarity index 100% rename from tests/_data/data2.json rename to tests/Support/Data/data2.json diff --git a/tests/_data/data2.txt b/tests/Support/Data/data2.txt similarity index 100% rename from tests/_data/data2.txt rename to tests/Support/Data/data2.txt diff --git a/tests/_data/data2.xml b/tests/Support/Data/data2.xml similarity index 100% rename from tests/_data/data2.xml rename to tests/Support/Data/data2.xml diff --git a/tests/_data/data3.txt b/tests/Support/Data/data3.txt similarity index 100% rename from tests/_data/data3.txt rename to tests/Support/Data/data3.txt diff --git a/tests/_data/expectedFileFormat.txt b/tests/Support/Data/expectedFileFormat.txt similarity index 100% rename from tests/_data/expectedFileFormat.txt rename to tests/Support/Data/expectedFileFormat.txt diff --git a/tests/_support/UnitTester.php b/tests/Support/UnitTester.php similarity index 77% rename from tests/_support/UnitTester.php rename to tests/Support/UnitTester.php index e19544a..710bfbd 100644 --- a/tests/_support/UnitTester.php +++ b/tests/Support/UnitTester.php @@ -1,10 +1,13 @@ Date: Thu, 1 May 2025 21:11:19 -0500 Subject: [PATCH 3/4] Fix testMarkTestSkipped compatibility --- tests/unit/Codeception/Module/AssertsTest.php | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/unit/Codeception/Module/AssertsTest.php b/tests/unit/Codeception/Module/AssertsTest.php index 11d833f..12ce769 100644 --- a/tests/unit/Codeception/Module/AssertsTest.php +++ b/tests/unit/Codeception/Module/AssertsTest.php @@ -12,7 +12,9 @@ use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Constraint\IsEqual; use PHPUnit\Framework\IncompleteTestError; +use PHPUnit\Framework\SkippedTestError; use PHPUnit\Framework\SkippedWithMessageException; +use PHPUnit\Runner\Version as PHPUnitVersion; use RuntimeException; use stdClass; @@ -46,14 +48,14 @@ public function testPHPUnitAsserts() { $this->module->assertArrayHasKey('one', ['one' => 1, 'two' => 2]); $this->module->assertArrayNotHasKey('three', ['one' => 1, 'two' => 2]); - $this->module->assertClassHasAttribute('foo', \DummyClass::class); - $this->module->assertClassHasStaticAttribute('staticFoo', \DummyClass::class); - $this->module->assertClassNotHasAttribute('bar', \DummyClass::class); - $this->module->assertClassNotHasStaticAttribute('staticBar', \DummyClass::class); + $this->module->assertClassHasAttribute('foo', \Support\Data\DummyClass::class); + $this->module->assertClassHasStaticAttribute('staticFoo', \Support\Data\DummyClass::class); + $this->module->assertClassNotHasAttribute('bar', \Support\Data\DummyClass::class); + $this->module->assertClassNotHasStaticAttribute('staticBar', \Support\Data\DummyClass::class); $this->module->assertContains(1, [1, 2]); $this->module->assertContainsEquals(2, [1, 2]); - $this->module->assertContainsOnly(\DummyClass::class, [new \DummyClass(), new \DummyClass()]); - $this->module->assertContainsOnlyInstancesOf(\DummyClass::class, [new \DummyClass(), new \DummyClass()]); + $this->module->assertContainsOnly(\Support\Data\DummyClass::class, [new \Support\Data\DummyClass(), new \Support\Data\DummyClass()]); + $this->module->assertContainsOnlyInstancesOf(\Support\Data\DummyClass::class, [new \Support\Data\DummyClass(), new \Support\Data\DummyClass()]); $this->module->assertCount(3, [1, 2, 3]); $this->module->assertDirectoryDoesNotExist(__DIR__.'notExist'); $this->module->assertDirectoryExists(__DIR__); @@ -130,7 +132,7 @@ public function testPHPUnitAsserts() $this->module->assertNan(sqrt(-1)); $this->module->assertNotContains('three', ['one', 'two']); $this->module->assertNotContainsEquals(3, [1, 2]); - $this->module->assertNotContainsOnly(\DummyClass::class, [new \DummyClass(), new Exception()]); + $this->module->assertNotContainsOnly(\Support\Data\DummyClass::class, [new \Support\Data\DummyClass(), new Exception()]); $this->module->assertNotCount(1, ['one', 'two']); $this->module->assertNotEmpty([1]); $this->module->assertNotEquals(true, false); @@ -150,8 +152,8 @@ public function testPHPUnitAsserts() $this->module->assertNotTrue(null); $this->module->assertNotTrue('foo'); $this->module->assertNull(null); - $this->module->assertObjectHasAttribute('foo', new \DummyClass()); - $this->module->assertObjectNotHasAttribute('bar', new \DummyClass()); + $this->module->assertObjectHasAttribute('foo', new \Support\Data\DummyClass()); + $this->module->assertObjectNotHasAttribute('bar', new \Support\Data\DummyClass()); $this->module->assertSame(1, 1); $this->module->assertSameSize([1, 2, 3], [1, 2, 3]); $this->module->assertStringContainsString('bar', 'foobar'); @@ -280,8 +282,12 @@ public function testMarkTestIncomplete() public function testMarkTestSkipped() { - $this->expectException(SkippedWithMessageException::class); $this->expectExceptionMessage('foobar'); + if (PHPUnitVersion::series() < 10) { + $this->expectException(SkippedTestError::class); + } else { + $this->expectException(SkippedWithMessageException::class); + } $this->module->markTestSkipped('foobar'); } From b05b62865ccd320046cae47900c711b9bf126a2d Mon Sep 17 00:00:00 2001 From: TavoNiievez Date: Thu, 1 May 2025 21:23:39 -0500 Subject: [PATCH 4/4] Add PHPStan and PHP Code Sniffer --- .github/workflows/main.yml | 33 +++++++++++++--------- src/Codeception/Module/AbstractAsserts.php | 2 +- src/Codeception/Module/Asserts.php | 12 ++++++-- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79314d3..e8c6cc8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,20 +11,27 @@ jobs: php: [8.2, 8.3, 8.4] steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + tools: phpstan, phpcs - - name: Validate composer.json and composer.lock - run: composer validate + - name: Validate composer.json and composer.lock + run: composer validate - - name: Install dependencies - run: composer install --prefer-dist --no-progress --no-interaction --no-suggest + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction --no-suggest - - name: Run test suite - run: php vendor/bin/codecept run + - name: Run PHPStan + run: phpstan analyse src + + - name: Run PHPCS + run: phpcs --standard=PSR12 src + + - name: Run test suite + run: php vendor/bin/codecept run diff --git a/src/Codeception/Module/AbstractAsserts.php b/src/Codeception/Module/AbstractAsserts.php index 6855f3a..da1fb93 100644 --- a/src/Codeception/Module/AbstractAsserts.php +++ b/src/Codeception/Module/AbstractAsserts.php @@ -147,4 +147,4 @@ abstract class AbstractAsserts extends Module markTestIncomplete as public; markTestSkipped as public; } -} \ No newline at end of file +} diff --git a/src/Codeception/Module/Asserts.php b/src/Codeception/Module/Asserts.php index 707db6a..24cf98e 100644 --- a/src/Codeception/Module/Asserts.php +++ b/src/Codeception/Module/Asserts.php @@ -5,6 +5,7 @@ namespace Codeception\Module; use Throwable; + use function get_debug_type; /** @@ -26,6 +27,7 @@ class Asserts extends AbstractAsserts * $this->doSomethingBad(); * }); * ``` + * * If you want to check message or throwable code, you can pass them with throwable instance: * ```php * getMessage(); - $code = $throwable->getCode(); + $code = (int) $throwable->getCode(); } else { $class = $throwable; $msg = null; @@ -61,8 +63,12 @@ public function expectThrowable(string|Throwable $throwable, callable $callback) * Check if the given throwable matches the expected data, * fail (throws an exception) if it does not. */ - protected function checkThrowable(Throwable $throwable, string $expectedClass, ?string $expectedMsg, int|null $expectedCode = null): void - { + protected function checkThrowable( + Throwable $throwable, + string $expectedClass, + ?string $expectedMsg, + int|null $expectedCode = null + ): void { if (!($throwable instanceof $expectedClass)) { $this->fail(sprintf( "Exception of class '%s' expected to be thrown, but class '%s' was caught",