diff --git a/config/sets/composer-based.php b/config/sets/composer-based.php index 0140d5f6..31361fa3 100644 --- a/config/sets/composer-based.php +++ b/config/sets/composer-based.php @@ -20,11 +20,17 @@ use Rector\PHPUnit\PHPUnit110\Rector\ClassMethod\MockObjectArgCreateStubToCreateMockRector; use Rector\PHPUnit\PHPUnit120\Rector\CallLike\CreateStubInCoalesceArgRector; use Rector\PHPUnit\PHPUnit120\Rector\CallLike\CreateStubOverCreateMockArgRector; +use Rector\PHPUnit\PHPUnit120\Rector\Class_\AllowMockObjectsForDataProviderRector; +use Rector\PHPUnit\PHPUnit120\Rector\Class_\AllowMockObjectsWhereParentClassRector; +use Rector\PHPUnit\PHPUnit120\Rector\Class_\AllowMockObjectsWithoutExpectationsAttributeRector; use Rector\PHPUnit\PHPUnit120\Rector\Class_\AssertIsTypeMethodCallRector; use Rector\PHPUnit\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector; +use Rector\PHPUnit\PHPUnit120\Rector\Class_\RemoveOverrideFinalConstructTestCaseRector; use Rector\PHPUnit\PHPUnit120\Rector\ClassMethod\ExpressionCreateMockToCreateStubRector; use Rector\PHPUnit\PHPUnit120\Rector\Property\MockObjectVarToStubRector; use Rector\PHPUnit\ValueObject\AnnotationWithValueToAttribute; +use Rector\Renaming\Rector\MethodCall\RenameMethodRector; +use Rector\Renaming\ValueObject\MethodCallRename; /** * Rules and configuration bound to the PHPUnit version installed in the analysed project, @@ -61,6 +67,14 @@ // deprecated in PHPUnit 11.5 AssertContainsOnlyMethodCallRector::class, AssertIsTypeMethodCallRector::class, + + // the TestCase::__construct() is final since PHPUnit 12.0.3 + RemoveOverrideFinalConstructTestCaseRector::class, + + // the AllowMockObjectsWithoutExpectations attribute exists since PHPUnit 12.5.2 + AllowMockObjectsWhereParentClassRector::class, + AllowMockObjectsForDataProviderRector::class, + AllowMockObjectsWithoutExpectationsAttributeRector::class, ]); // both attributes were added in PHPUnit 10.0 @@ -87,4 +101,69 @@ 'PHPUnit\Framework\Attributes\RunClassInSeparateProcess' ), ], 'phpunit/phpunit', '>=10.0 <13.0'); + + // the MockBuilder::onlyMethods() method was added in PHPUnit 8.3 + // @see https://github.com/sebastianbergmann/phpunit/pull/3687 + $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ + new MethodCallRename('PHPUnit\Framework\MockObject\MockBuilder', 'setMethods', 'onlyMethods'), + ], 'phpunit/phpunit', '>=8.3'); + + // the expectExceptionMessageMatches() method was added in PHPUnit 8.4 + // @see https://github.com/sebastianbergmann/phpunit/issues/3957 + $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ + new MethodCallRename( + 'PHPUnit\Framework\TestCase', + 'expectExceptionMessageRegExp', + 'expectExceptionMessageMatches' + ), + ], 'phpunit/phpunit', '>=8.4'); + + // all these assert methods were added in PHPUnit 9.1 + // @see https://github.com/sebastianbergmann/phpunit/blob/9.1.0/ChangeLog-9.1.md + $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ + new MethodCallRename('PHPUnit\Framework\Assert', 'assertRegExp', 'assertMatchesRegularExpression'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertNotRegExp', 'assertDoesNotMatchRegularExpression'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertFileNotExists', 'assertFileDoesNotExist'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertFileNotIsReadable', 'assertFileIsNotReadable'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertDirectoryNotExists', 'assertDirectoryDoesNotExist'), + new MethodCallRename( + 'PHPUnit\Framework\Assert', + 'assertDirectoryNotIsReadable', + 'assertDirectoryIsNotReadable' + ), + new MethodCallRename( + 'PHPUnit\Framework\Assert', + 'assertDirectoryNotIsWritable', + 'assertDirectoryIsNotWritable' + ), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertNotIsReadable', 'assertIsNotReadable'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertNotIsWritable', 'assertIsNotWritable'), + ], 'phpunit/phpunit', '>=9.1'); + + // the numberOfInvocations() method was added in PHPUnit 10.0 + // @see https://github.com/sebastianbergmann/phpunit/commit/2ba8b7fded44a1a75cf5712a3b7310a8de0b6bb8 + $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ + new MethodCallRename( + 'PHPUnit\Framework\MockObject\Rule\InvocationOrder', + 'getInvocationCount', + 'numberOfInvocations' + ), + ], 'phpunit/phpunit', '>=10.0'); + + // the assertObjectHasProperty() and assertObjectNotHasProperty() methods were added in PHPUnit 10.1 + // @see https://github.com/sebastianbergmann/phpunit/issues/5220 + $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ + new MethodCallRename('PHPUnit\Framework\Assert', 'assertObjectHasAttribute', 'assertObjectHasProperty'), + new MethodCallRename('PHPUnit\Framework\Assert', 'assertObjectNotHasAttribute', 'assertObjectNotHasProperty'), + ], 'phpunit/phpunit', '>=10.1'); + + // the expectExceptionMessageIsOrContains() method was added in PHPUnit 13.2 + // @see https://github.com/sebastianbergmann/phpunit/issues/6560 + $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ + new MethodCallRename( + 'PHPUnit\Framework\TestCase', + 'expectExceptionMessage', + 'expectExceptionMessageIsOrContains' + ), + ], 'phpunit/phpunit', '>=13.2'); }; diff --git a/rules/CodeQuality/Rector/ClassMethod/ChangeMockObjectReturnUnionToIntersectionRector.php b/rules/CodeQuality/Rector/ClassMethod/ChangeMockObjectReturnUnionToIntersectionRector.php index fba4ac70..375d1693 100644 --- a/rules/CodeQuality/Rector/ClassMethod/ChangeMockObjectReturnUnionToIntersectionRector.php +++ b/rules/CodeQuality/Rector/ClassMethod/ChangeMockObjectReturnUnionToIntersectionRector.php @@ -17,13 +17,15 @@ use Rector\PHPUnit\Enum\PHPUnitClassName; use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** * @see \Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\ChangeMockObjectReturnUnionToIntersectionRector\ChangeMockObjectReturnUnionToIntersectionRectorTest */ -final class ChangeMockObjectReturnUnionToIntersectionRector extends AbstractRector +final class ChangeMockObjectReturnUnionToIntersectionRector extends AbstractRector implements ComposerPackageConstraintInterface { public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, @@ -32,6 +34,11 @@ public function __construct( ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=11.0'); + } + public function getNodeTypes(): array { return [ClassMethod::class]; diff --git a/rules/CodeQuality/Rector/Class_/InlineStubPropertyToCreateStubMethodCallRector.php b/rules/CodeQuality/Rector/Class_/InlineStubPropertyToCreateStubMethodCallRector.php index 8483ed20..72a94722 100644 --- a/rules/CodeQuality/Rector/Class_/InlineStubPropertyToCreateStubMethodCallRector.php +++ b/rules/CodeQuality/Rector/Class_/InlineStubPropertyToCreateStubMethodCallRector.php @@ -27,13 +27,15 @@ use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; use Rector\ValueObject\MethodName; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** * @see \Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\InlineStubPropertyToCreateStubMethodCallRector\InlineStubPropertyToCreateStubMethodCallRectorTest */ -final class InlineStubPropertyToCreateStubMethodCallRector extends AbstractRector +final class InlineStubPropertyToCreateStubMethodCallRector extends AbstractRector implements ComposerPackageConstraintInterface { public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, @@ -44,6 +46,11 @@ public function __construct( ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=11.0'); + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( diff --git a/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php b/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php index ff63e4da..5ef989dd 100644 --- a/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php +++ b/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php @@ -11,19 +11,26 @@ use PHPUnit\Framework\MockObject\MockObject; use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** * @see \Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\SingleMockPropertyTypeRector\SingleMockPropertyTypeRectorTest */ -final class SingleMockPropertyTypeRector extends AbstractRector +final class SingleMockPropertyTypeRector extends AbstractRector implements ComposerPackageConstraintInterface { public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=11.0'); + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( diff --git a/rules/PHPUnit120/Rector/Class_/AllowMockObjectsForDataProviderRector.php b/rules/PHPUnit120/Rector/Class_/AllowMockObjectsForDataProviderRector.php index ff717fa2..f1761bd6 100644 --- a/rules/PHPUnit120/Rector/Class_/AllowMockObjectsForDataProviderRector.php +++ b/rules/PHPUnit120/Rector/Class_/AllowMockObjectsForDataProviderRector.php @@ -16,14 +16,20 @@ use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; use Rector\ValueObject\PhpVersionFeature; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; use Rector\VersionBonding\Contract\MinPhpVersionInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** + * The AllowMockObjectsWithoutExpectations attribute was added in PHPUnit 12.5.2 + * * @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsForDataProviderRector\AllowMockObjectsForDataProviderRectorTest + * + * @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43 */ -final class AllowMockObjectsForDataProviderRector extends AbstractRector implements MinPhpVersionInterface +final class AllowMockObjectsForDataProviderRector extends AbstractRector implements MinPhpVersionInterface, ComposerPackageConstraintInterface { public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, @@ -33,6 +39,11 @@ public function __construct( ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=12.5.2'); + } + public function getNodeTypes(): array { return [Class_::class]; diff --git a/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWhereParentClassRector.php b/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWhereParentClassRector.php index 38cbcd2f..a390f021 100644 --- a/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWhereParentClassRector.php +++ b/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWhereParentClassRector.php @@ -18,16 +18,20 @@ use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; use Rector\ValueObject\PhpVersionFeature; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; use Rector\VersionBonding\Contract\MinPhpVersionInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** + * The AllowMockObjectsWithoutExpectations attribute was added in PHPUnit 12.5.2 + * * @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsWhereParentClassRector\AllowMockObjectsWhereParentClassRectorTest * * @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43 */ -final class AllowMockObjectsWhereParentClassRector extends AbstractRector implements MinPhpVersionInterface +final class AllowMockObjectsWhereParentClassRector extends AbstractRector implements MinPhpVersionInterface, ComposerPackageConstraintInterface { /** * @var string[] @@ -41,6 +45,11 @@ public function __construct( ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=12.5.2'); + } + public function getNodeTypes(): array { return [Class_::class]; diff --git a/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php b/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php index 136467c4..78e6636e 100644 --- a/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php +++ b/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php @@ -25,16 +25,20 @@ use Rector\Rector\AbstractRector; use Rector\ValueObject\MethodName; use Rector\ValueObject\PhpVersionFeature; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; use Rector\VersionBonding\Contract\MinPhpVersionInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** + * The AllowMockObjectsWithoutExpectations attribute was added in PHPUnit 12.5.2 + * * @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsWithoutExpectationsAttributeRector\AllowMockObjectsWithoutExpectationsAttributeRectorTest * * @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43 */ -final class AllowMockObjectsWithoutExpectationsAttributeRector extends AbstractRector implements MinPhpVersionInterface +final class AllowMockObjectsWithoutExpectationsAttributeRector extends AbstractRector implements MinPhpVersionInterface, ComposerPackageConstraintInterface { public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, @@ -44,6 +48,11 @@ public function __construct( ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=12.5.2'); + } + public function getNodeTypes(): array { return [Class_::class]; diff --git a/rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php b/rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php index 9b426557..12722c7c 100644 --- a/rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php +++ b/rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php @@ -10,19 +10,30 @@ use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; use Rector\Rector\AbstractRector; use Rector\ValueObject\MethodName; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** + * The TestCase::__construct() was declared final in PHPUnit 12.0.3, overriding it is a fatal error since then + * * @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\RemoveOverrideFinalConstructTestCaseRector\RemoveOverrideFinalConstructTestCaseRectorTest + * + * @see https://github.com/sebastianbergmann/phpunit/commit/3263f4c62d4af44777ff1c81d093ee88eafccdad */ -final class RemoveOverrideFinalConstructTestCaseRector extends AbstractRector +final class RemoveOverrideFinalConstructTestCaseRector extends AbstractRector implements ComposerPackageConstraintInterface { public function __construct( private readonly TestsNodeAnalyzer $testsNodeAnalyzer, ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('phpunit/phpunit', '>=12.0.3'); + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( diff --git a/tests/ComposerBased/Fixture/remove_override_final_construct.php.inc b/tests/ComposerBased/Fixture/remove_override_final_construct.php.inc new file mode 100644 index 00000000..91f9d404 --- /dev/null +++ b/tests/ComposerBased/Fixture/remove_override_final_construct.php.inc @@ -0,0 +1,23 @@ + +----- + diff --git a/tests/ComposerBased/Fixture/version_bound_method_renames.php.inc b/tests/ComposerBased/Fixture/version_bound_method_renames.php.inc new file mode 100644 index 00000000..002e20b2 --- /dev/null +++ b/tests/ComposerBased/Fixture/version_bound_method_renames.php.inc @@ -0,0 +1,29 @@ +assertObjectHasAttribute('someProperty', new stdClass()); + $this->expectExceptionMessage('some message'); + } +} + +?> +----- +assertObjectHasProperty('someProperty', new stdClass()); + $this->expectExceptionMessageIsOrContains('some message'); + } +} + +?>