diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index c32176cf..ddd88be3 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -92,7 +92,10 @@ jobs: - name: Determine PHPUnit config file to use id: phpunit_config run: | - if [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }}" == "true" ]; then + if [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }}" == "true" ]; then + echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT + echo 'EXTRA_ARGS=' >> $GITHUB_OUTPUT + elif [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }}" == "true" ]; then echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT echo 'EXTRA_ARGS=' >> $GITHUB_OUTPUT else diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 324897f1..f3638206 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -213,7 +213,10 @@ jobs: - name: Determine PHPUnit config file to use id: phpunit_config run: | - if [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }}" == "true" ]; then + if [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }}" == "true" ]; then + echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT + echo 'EXTRA_ARGS=' >> $GITHUB_OUTPUT + elif [ "${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }}" == "true" ]; then echo 'FILE=phpunit10.xml.dist' >> $GITHUB_OUTPUT echo 'EXTRA_ARGS=' >> $GITHUB_OUTPUT else @@ -338,21 +341,21 @@ jobs: # As of PHPUnit 9.3.4, a cache warming option is available. # Using that option prevents issues with PHP-Parser backfilling PHP tokens when PHPCS does not (yet), # which would otherwise cause tests to fail on tokens being available when they shouldn't be. - # As coverage is only run on high/low PHP, the high PHP version will use PHPUnit 10, so just check for that. + # As coverage is only run on high/low PHP, the high PHP version will use PHPUnit 11, so just check for that. - name: "Warm the PHPUnit cache (PHPUnit 9.3+)" - if: ${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }} - run: vendor/bin/phpunit -c phpunit10.xml.dist --coverage-cache ./build/phpunit-cache --warm-coverage-cache + if: ${{ startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }} + run: vendor/bin/phpunit -c phpunit10.xml.dist --warm-coverage-cache - name: "Run the unit tests without caching with code coverage (PHPUnit < 10)" - if: ${{ ! startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }} + if: ${{ ! startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }} run: vendor/bin/phpunit env: PHPCS_VERSION: ${{ matrix.phpcs_version }} PHPCSUTILS_USE_CACHE: false - name: "Run the unit tests without caching with code coverage (PHPUnit 10+)" - if: ${{ startsWith( steps.phpunit_version.outputs.VERSION, '10.' ) }} - run: vendor/bin/phpunit -c phpunit10.xml.dist --coverage-cache ./build/phpunit-cache + if: ${{ startsWith( steps.phpunit_version.outputs.VERSION, '11.' ) }} + run: vendor/bin/phpunit -c phpunit10.xml.dist env: PHPCS_VERSION: ${{ matrix.phpcs_version }} PHPCSUTILS_USE_CACHE: false diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index 98ad8bce..5fa81154 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -20,6 +20,9 @@ use PHPCSUtils\Exceptions\TestMarkerNotFound; use PHPCSUtils\Exceptions\TestTargetNotFound; use PHPCSUtils\TestUtils\ConfigDouble; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; use PHPUnit\Framework\TestCase; use ReflectionClass; use ReflectionProperty; @@ -30,7 +33,7 @@ * This class is compatible with PHP_CodeSniffer 3.x and contains preliminary compatibility with 4.x * based on its currently known state/roadmap. * - * This class is compatible with {@link https://phpunit.de/ PHPUnit} 4.5 - 9.x providing the PHPCSUtils + * This class is compatible with {@link https://phpunit.de/ PHPUnit} 4.5 - 11.x providing the PHPCSUtils * autoload file is included in the test bootstrap. For more information about that, please consult * the project's {@link https://github.com/PHPCSStandards/PHPCSUtils/blob/develop/README.md README}. * @@ -105,6 +108,8 @@ * for the PHPCSUtils utility functions themselves. * * @since 1.0.0 + * @since 1.0.7 Compatible with PHPUnit 10. + * @since 1.1.0 Compatible with PHPUnit 11. */ abstract class UtilityMethodTestCase extends TestCase { @@ -194,6 +199,7 @@ abstract class UtilityMethodTestCase extends TestCase * * @return void */ + #[BeforeClass] public static function setUpTestFile() { parent::setUpBeforeClass(); @@ -283,6 +289,7 @@ protected static function parseFile($caseFile, Ruleset $ruleset, Config $config) * * @return void */ + #[Before] public function skipJSCSSTestsOnPHPCS4() { if (static::$fileExtension !== 'js' && static::$fileExtension !== 'css') { @@ -308,6 +315,7 @@ public function skipJSCSSTestsOnPHPCS4() * * @return void */ + #[AfterClass] public static function resetTestFile() { /* diff --git a/README.md b/README.md index c971fe4e..3c0eb958 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ These classes take most of the heavy lifting away for some frequently occurring ### Test utilities An abstract `UtilityMethodTestCase` class to support testing of your utility methods written for PHP_CodeSniffer. -Supports PHPUnit 4.x up to 9.x. +Supports PHPUnit 4.x up to 11.x. ### Use the latest version of PHP_CodeSniffer native utility functions diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index 086f8f31..a2e9957e 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -287,8 +287,9 @@ public function testMultiLineLongArrayKeysTrailingComma() [self::$phpcsFile, $target + 7, $target + 8, 1], [self::$phpcsFile, $target + 15, $target + 16, 2], [self::$phpcsFile, $target + 23, $target + 24, 3], - ] - )->will($this->onConsecutiveCalls(null, null, true)); // Testing short-circuiting the loop. + ], + [null, null, true] // Testing short-circuiting the loop. + ); $this->setExpectationWithConsecutiveArgs( $mockObj, @@ -665,16 +666,18 @@ public function testBowOutOnUnfinishedArray() */ private function getMockedClassUnderTest() { - $mockedObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff'); + $mockedObj = $this->getMockBuilder( + '\PHPCSUtils\Tests\AbstractSniffs\AbstractArrayDeclaration\ArrayDeclarationSniffMock' + ); if (\method_exists($mockedObj, 'onlyMethods')) { // PHPUnit 8+. return $mockedObj->onlyMethods($this->methodsToMock) - ->getMockForAbstractClass(); + ->getMock(); } // PHPUnit < 8. return $mockedObj->setMethods($this->methodsToMock) - ->getMockForAbstractClass(); + ->getMock(); } } diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffMock.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffMock.php new file mode 100644 index 00000000..0bc812c4 --- /dev/null +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffMock.php @@ -0,0 +1,22 @@ +withConsecutive()` method could be used to test * this, but that method was removed in PHPUnit 10.0. * + * Furthermore, the use of `->will($this->onConsecutiveCalls(...))` was deprecated in PHPUnit 10/11 + * and will be removed in PHPUnit 12.0. The typical replacement for this is `->willReturn(...)`. + * However, as this helper already uses `->willReturnCallback()`, if these two deprecations/removals + * collide in the same expectation setting, it would break, so this is now also worked around via the + * `$returnValues` parameter. + * * @since 1.0.7 + * @since 1.1.0 Now also works round the deprecation of `->will($this->onConsecutiveCalls(...))` + * via the new optional `$returnValues` parameter. */ trait ExpectWithConsecutiveArgs { @@ -30,11 +38,17 @@ trait ExpectWithConsecutiveArgs * @param string $methodName The name of the method on which to set the expectations. * @param array> $expectedArgs Multi-dimentional array of arguments expected to be passed in * consecutive calls. + * @param array $returnValues Optional. Array of values to return on consecutive calls. * * @return object Expectation object. */ - final public function setExpectationWithConsecutiveArgs($mockObject, $countMatcher, $methodName, $expectedArgs) - { + final public function setExpectationWithConsecutiveArgs( + $mockObject, + $countMatcher, + $methodName, + $expectedArgs, + $returnValues = [] + ) { $methodExpectation = $mockObject->expects($countMatcher) ->method($methodName); @@ -48,12 +62,18 @@ final public function setExpectationWithConsecutiveArgs($mockObject, $countMatch } } - return \call_user_func_array([$methodExpectation, 'withConsecutive'], $expectationsArray); + $methodExpectation = \call_user_func_array([$methodExpectation, 'withConsecutive'], $expectationsArray); + + if (empty($returnValues)) { + return $methodExpectation; + } + + return $methodExpectation->will(\call_user_func_array([$this, 'onConsecutiveCalls'], $returnValues)); } // PHPUnit 10+. return $methodExpectation->willReturnCallback( - function () use (&$expectedArgs, $countMatcher, $methodName) { + function () use (&$expectedArgs, $countMatcher, $methodName, $returnValues) { $actualArgs = \func_get_args(); $expected = \array_shift($expectedArgs); @@ -76,6 +96,10 @@ function () use (&$expectedArgs, $countMatcher, $methodName) { $methodName ) ); + + if (empty($returnValues) === false) { + return $returnValues[($countMatcher->numberOfInvocations() - 1)]; + } } ); } diff --git a/Tests/PolyfilledTestCase.php b/Tests/PolyfilledTestCase.php index 7bb6b70a..68f33b88 100644 --- a/Tests/PolyfilledTestCase.php +++ b/Tests/PolyfilledTestCase.php @@ -17,6 +17,7 @@ use PHPCSUtils\Tests\ExpectWithConsecutiveArgs; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use Yoast\PHPUnitPolyfills\Autoload; +use Yoast\PHPUnitPolyfills\Polyfills\AssertArrayWithListKeys; use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource; use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations; use Yoast\PHPUnitPolyfills\Polyfills\AssertFileDirectory; @@ -27,6 +28,7 @@ use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType; use Yoast\PHPUnitPolyfills\Polyfills\AssertNumericType; use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals; +use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals; use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectProperty; use Yoast\PHPUnitPolyfills\Polyfills\AssertStringContains; use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations; @@ -34,10 +36,50 @@ use Yoast\PHPUnitPolyfills\Polyfills\ExpectExceptionMessageMatches; use Yoast\PHPUnitPolyfills\Polyfills\ExpectExceptionObject; use Yoast\PHPUnitPolyfills\Polyfills\ExpectPHPException; +use Yoast\PHPUnitPolyfills\Polyfills\ExpectUserDeprecation; -if (\version_compare(Autoload::VERSION, '2.0.0', '>=')) { +if (\version_compare(Autoload::VERSION, '3.0.0', '>=')) { /** - * Abstract utility method base test case which includes all available polyfills (PHPUnit Polyfills 2.x compaible). + * Abstract utility method base test case which includes all available polyfills (PHPUnit Polyfills 3.x compatible). + * + * This test case includes all polyfills from the PHPUnit Polyfill library to make them + * available to the tests. + * + * Generally speaking, this testcase only needs to be used when the concrete test class will + * use functionality which has changed in PHPUnit cross-version. + * In all other cases, the `UtilityMethodTestCase` can be extended directly. + * + * {@internal The list of included polyfill traits should be reviewed after each new + * release of the PHPUnit Polyfill library.} + * + * @since 1.1.0 + */ + abstract class PolyfilledTestCase extends UtilityMethodTestCase + { + // PHPCSUtils native helpers. + use AssertPropertySame; + use ExpectWithConsecutiveArgs; + + // PHPUnit Polyfills. + use AssertArrayWithListKeys; + use AssertClosedResource; + use AssertEqualsSpecializations; + use AssertFileEqualsSpecializations; + use AssertIgnoringLineEndings; + use AssertionRenames; + use AssertIsList; + use AssertIsType; + use AssertObjectEquals; + use AssertObjectNotEquals; + use AssertObjectProperty; + use AssertStringContains; + use EqualToSpecializations; + use ExpectExceptionMessageMatches; + use ExpectUserDeprecation; + } +} elseif (\version_compare(Autoload::VERSION, '2.0.0', '>=')) { + /** + * Abstract utility method base test case which includes all available polyfills (PHPUnit Polyfills 2.x compatible). * * This test case includes all polyfills from the PHPUnit Polyfill library to make them * available to the tests. @@ -74,7 +116,7 @@ abstract class PolyfilledTestCase extends UtilityMethodTestCase } } else { /** - * Abstract utility method base test case which includes all available polyfills (PHPUnit Polyfills 1.x compaible). + * Abstract utility method base test case which includes all available polyfills (PHPUnit Polyfills 1.x compatible). * * This test case includes all polyfills from the PHPUnit Polyfill library to make them * available to the tests. diff --git a/composer.json b/composer.json index 80167bcb..6a9f5527 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "phpcsstandards/phpcsdevcs": "^1.1.6", "php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-console-highlighter": "^1.0", - "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0" + "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 78108e0d..34bd3a2f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -27,7 +27,7 @@