Skip to content

Commit 89f684a

Browse files
committed
Bond version-specific rules to composer package constraints
Add ComposerPackageConstraintInterface to rules that emit APIs which only exist since a specific PHPUnit version, with each version verified against the phpunit/phpunit git history: * AllowMockObjectsWhereParentClassRector, AllowMockObjectsForDataProviderRector and AllowMockObjectsWithoutExpectationsAttributeRector >=12.5.2, as the #[AllowMockObjectsWithoutExpectations] attribute was added there * RemoveOverrideFinalConstructTestCaseRector >=12.0.3, as TestCase::__construct() was declared final there * InlineStubPropertyToCreateStubMethodCallRector, SingleMockPropertyTypeRector and ChangeMockObjectReturnUnionToIntersectionRector >=11.0, to match their already bonded stub/mock siblings Register the method renames of the generic RenameMethodRector in the same way, each bound to the PHPUnit version that added the target method: * setMethods() => onlyMethods() since 8.3 * expectExceptionMessageRegExp() => expectExceptionMessageMatches() since 8.4 * the assertRegExp(), assertFileNotExists() and assert*Not*() family since 9.1 * getInvocationCount() => numberOfInvocations() since 10.0 * assertObjectHasAttribute() => assertObjectHasProperty() since 10.1 * expectExceptionMessage() => expectExceptionMessageIsOrContains() since 13.2 Everything lands in the composer-based set, so it applies to any project with a matching PHPUnit version. The per-version sets keep their current registrations, so their behavior stays backward compatible.
1 parent afebdca commit 89f684a

10 files changed

Lines changed: 199 additions & 7 deletions

‎config/sets/composer-based.php‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@
2020
use Rector\PHPUnit\PHPUnit110\Rector\ClassMethod\MockObjectArgCreateStubToCreateMockRector;
2121
use Rector\PHPUnit\PHPUnit120\Rector\CallLike\CreateStubInCoalesceArgRector;
2222
use Rector\PHPUnit\PHPUnit120\Rector\CallLike\CreateStubOverCreateMockArgRector;
23+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\AllowMockObjectsForDataProviderRector;
24+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\AllowMockObjectsWhereParentClassRector;
25+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\AllowMockObjectsWithoutExpectationsAttributeRector;
2326
use Rector\PHPUnit\PHPUnit120\Rector\Class_\AssertIsTypeMethodCallRector;
2427
use Rector\PHPUnit\PHPUnit120\Rector\Class_\PropertyCreateMockToCreateStubRector;
28+
use Rector\PHPUnit\PHPUnit120\Rector\Class_\RemoveOverrideFinalConstructTestCaseRector;
2529
use Rector\PHPUnit\PHPUnit120\Rector\ClassMethod\ExpressionCreateMockToCreateStubRector;
2630
use Rector\PHPUnit\PHPUnit120\Rector\Property\MockObjectVarToStubRector;
2731
use Rector\PHPUnit\ValueObject\AnnotationWithValueToAttribute;
32+
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
33+
use Rector\Renaming\ValueObject\MethodCallRename;
2834

2935
/**
3036
* Rules and configuration bound to the PHPUnit version installed in the analysed project,
@@ -61,6 +67,14 @@
6167
// deprecated in PHPUnit 11.5
6268
AssertContainsOnlyMethodCallRector::class,
6369
AssertIsTypeMethodCallRector::class,
70+
71+
// the TestCase::__construct() is final since PHPUnit 12.0.3
72+
RemoveOverrideFinalConstructTestCaseRector::class,
73+
74+
// the AllowMockObjectsWithoutExpectations attribute exists since PHPUnit 12.5.2
75+
AllowMockObjectsWhereParentClassRector::class,
76+
AllowMockObjectsForDataProviderRector::class,
77+
AllowMockObjectsWithoutExpectationsAttributeRector::class,
6478
]);
6579

6680
// both attributes were added in PHPUnit 10.0
@@ -87,4 +101,69 @@
87101
'PHPUnit\Framework\Attributes\RunClassInSeparateProcess'
88102
),
89103
], 'phpunit/phpunit', '>=10.0 <13.0');
104+
105+
// the MockBuilder::onlyMethods() method was added in PHPUnit 8.3
106+
// @see https://github.com/sebastianbergmann/phpunit/pull/3687
107+
$rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [
108+
new MethodCallRename('PHPUnit\Framework\MockObject\MockBuilder', 'setMethods', 'onlyMethods'),
109+
], 'phpunit/phpunit', '>=8.3');
110+
111+
// the expectExceptionMessageMatches() method was added in PHPUnit 8.4
112+
// @see https://github.com/sebastianbergmann/phpunit/issues/3957
113+
$rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [
114+
new MethodCallRename(
115+
'PHPUnit\Framework\TestCase',
116+
'expectExceptionMessageRegExp',
117+
'expectExceptionMessageMatches'
118+
),
119+
], 'phpunit/phpunit', '>=8.4');
120+
121+
// all these assert methods were added in PHPUnit 9.1
122+
// @see https://github.com/sebastianbergmann/phpunit/blob/9.1.0/ChangeLog-9.1.md
123+
$rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [
124+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertRegExp', 'assertMatchesRegularExpression'),
125+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertNotRegExp', 'assertDoesNotMatchRegularExpression'),
126+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertFileNotExists', 'assertFileDoesNotExist'),
127+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertFileNotIsReadable', 'assertFileIsNotReadable'),
128+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertDirectoryNotExists', 'assertDirectoryDoesNotExist'),
129+
new MethodCallRename(
130+
'PHPUnit\Framework\Assert',
131+
'assertDirectoryNotIsReadable',
132+
'assertDirectoryIsNotReadable'
133+
),
134+
new MethodCallRename(
135+
'PHPUnit\Framework\Assert',
136+
'assertDirectoryNotIsWritable',
137+
'assertDirectoryIsNotWritable'
138+
),
139+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertNotIsReadable', 'assertIsNotReadable'),
140+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertNotIsWritable', 'assertIsNotWritable'),
141+
], 'phpunit/phpunit', '>=9.1');
142+
143+
// the numberOfInvocations() method was added in PHPUnit 10.0
144+
// @see https://github.com/sebastianbergmann/phpunit/commit/2ba8b7fded44a1a75cf5712a3b7310a8de0b6bb8
145+
$rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [
146+
new MethodCallRename(
147+
'PHPUnit\Framework\MockObject\Rule\InvocationOrder',
148+
'getInvocationCount',
149+
'numberOfInvocations'
150+
),
151+
], 'phpunit/phpunit', '>=10.0');
152+
153+
// the assertObjectHasProperty() and assertObjectNotHasProperty() methods were added in PHPUnit 10.1
154+
// @see https://github.com/sebastianbergmann/phpunit/issues/5220
155+
$rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [
156+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertObjectHasAttribute', 'assertObjectHasProperty'),
157+
new MethodCallRename('PHPUnit\Framework\Assert', 'assertObjectNotHasAttribute', 'assertObjectNotHasProperty'),
158+
], 'phpunit/phpunit', '>=10.1');
159+
160+
// the expectExceptionMessageIsOrContains() method was added in PHPUnit 13.2
161+
// @see https://github.com/sebastianbergmann/phpunit/issues/6560
162+
$rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [
163+
new MethodCallRename(
164+
'PHPUnit\Framework\TestCase',
165+
'expectExceptionMessage',
166+
'expectExceptionMessageIsOrContains'
167+
),
168+
], 'phpunit/phpunit', '>=13.2');
90169
};

‎rules/CodeQuality/Rector/ClassMethod/ChangeMockObjectReturnUnionToIntersectionRector.php‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
use Rector\PHPUnit\Enum\PHPUnitClassName;
1818
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
1919
use Rector\Rector\AbstractRector;
20+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
21+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
2022
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2123
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2224

2325
/**
2426
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\ChangeMockObjectReturnUnionToIntersectionRector\ChangeMockObjectReturnUnionToIntersectionRectorTest
2527
*/
26-
final class ChangeMockObjectReturnUnionToIntersectionRector extends AbstractRector
28+
final class ChangeMockObjectReturnUnionToIntersectionRector extends AbstractRector implements ComposerPackageConstraintInterface
2729
{
2830
public function __construct(
2931
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
@@ -32,6 +34,11 @@ public function __construct(
3234
) {
3335
}
3436

37+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
38+
{
39+
return new ComposerPackageConstraint('phpunit/phpunit', '>=11.0');
40+
}
41+
3542
public function getNodeTypes(): array
3643
{
3744
return [ClassMethod::class];

‎rules/CodeQuality/Rector/Class_/InlineStubPropertyToCreateStubMethodCallRector.php‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
2828
use Rector\Rector\AbstractRector;
2929
use Rector\ValueObject\MethodName;
30+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
31+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
3032
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
3133
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
3234

3335
/**
3436
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\InlineStubPropertyToCreateStubMethodCallRector\InlineStubPropertyToCreateStubMethodCallRectorTest
3537
*/
36-
final class InlineStubPropertyToCreateStubMethodCallRector extends AbstractRector
38+
final class InlineStubPropertyToCreateStubMethodCallRector extends AbstractRector implements ComposerPackageConstraintInterface
3739
{
3840
public function __construct(
3941
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
@@ -44,6 +46,11 @@ public function __construct(
4446
) {
4547
}
4648

49+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
50+
{
51+
return new ComposerPackageConstraint('phpunit/phpunit', '>=11.0');
52+
}
53+
4754
public function getRuleDefinition(): RuleDefinition
4855
{
4956
return new RuleDefinition(

‎rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,26 @@
1111
use PHPUnit\Framework\MockObject\MockObject;
1212
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
1313
use Rector\Rector\AbstractRector;
14+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
15+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
1416
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
1517
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
1618

1719
/**
1820
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\SingleMockPropertyTypeRector\SingleMockPropertyTypeRectorTest
1921
*/
20-
final class SingleMockPropertyTypeRector extends AbstractRector
22+
final class SingleMockPropertyTypeRector extends AbstractRector implements ComposerPackageConstraintInterface
2123
{
2224
public function __construct(
2325
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
2426
) {
2527
}
2628

29+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
30+
{
31+
return new ComposerPackageConstraint('phpunit/phpunit', '>=11.0');
32+
}
33+
2734
public function getRuleDefinition(): RuleDefinition
2835
{
2936
return new RuleDefinition(

‎rules/PHPUnit120/Rector/Class_/AllowMockObjectsForDataProviderRector.php‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@
1616
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
1717
use Rector\Rector\AbstractRector;
1818
use Rector\ValueObject\PhpVersionFeature;
19+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
1920
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
21+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
2022
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2123
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2224

2325
/**
26+
* The AllowMockObjectsWithoutExpectations attribute was added in PHPUnit 12.5.2
27+
*
2428
* @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsForDataProviderRector\AllowMockObjectsForDataProviderRectorTest
29+
*
30+
* @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43
2531
*/
26-
final class AllowMockObjectsForDataProviderRector extends AbstractRector implements MinPhpVersionInterface
32+
final class AllowMockObjectsForDataProviderRector extends AbstractRector implements MinPhpVersionInterface, ComposerPackageConstraintInterface
2733
{
2834
public function __construct(
2935
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
@@ -33,6 +39,11 @@ public function __construct(
3339
) {
3440
}
3541

42+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
43+
{
44+
return new ComposerPackageConstraint('phpunit/phpunit', '>=12.5.2');
45+
}
46+
3647
public function getNodeTypes(): array
3748
{
3849
return [Class_::class];

‎rules/PHPUnit120/Rector/Class_/AllowMockObjectsWhereParentClassRector.php‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@
1818
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
1919
use Rector\Rector\AbstractRector;
2020
use Rector\ValueObject\PhpVersionFeature;
21+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
2122
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
23+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
2224
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2325
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2426

2527
/**
28+
* The AllowMockObjectsWithoutExpectations attribute was added in PHPUnit 12.5.2
29+
*
2630
* @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsWhereParentClassRector\AllowMockObjectsWhereParentClassRectorTest
2731
*
2832
* @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43
2933
*/
30-
final class AllowMockObjectsWhereParentClassRector extends AbstractRector implements MinPhpVersionInterface
34+
final class AllowMockObjectsWhereParentClassRector extends AbstractRector implements MinPhpVersionInterface, ComposerPackageConstraintInterface
3135
{
3236
/**
3337
* @var string[]
@@ -41,6 +45,11 @@ public function __construct(
4145
) {
4246
}
4347

48+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
49+
{
50+
return new ComposerPackageConstraint('phpunit/phpunit', '>=12.5.2');
51+
}
52+
4453
public function getNodeTypes(): array
4554
{
4655
return [Class_::class];

‎rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,20 @@
2525
use Rector\Rector\AbstractRector;
2626
use Rector\ValueObject\MethodName;
2727
use Rector\ValueObject\PhpVersionFeature;
28+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
2829
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
30+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
2931
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
3032
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
3133

3234
/**
35+
* The AllowMockObjectsWithoutExpectations attribute was added in PHPUnit 12.5.2
36+
*
3337
* @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsWithoutExpectationsAttributeRector\AllowMockObjectsWithoutExpectationsAttributeRectorTest
3438
*
3539
* @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43
3640
*/
37-
final class AllowMockObjectsWithoutExpectationsAttributeRector extends AbstractRector implements MinPhpVersionInterface
41+
final class AllowMockObjectsWithoutExpectationsAttributeRector extends AbstractRector implements MinPhpVersionInterface, ComposerPackageConstraintInterface
3842
{
3943
public function __construct(
4044
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
@@ -44,6 +48,11 @@ public function __construct(
4448
) {
4549
}
4650

51+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
52+
{
53+
return new ComposerPackageConstraint('phpunit/phpunit', '>=12.5.2');
54+
}
55+
4756
public function getNodeTypes(): array
4857
{
4958
return [Class_::class];

‎rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,30 @@
1010
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
1111
use Rector\Rector\AbstractRector;
1212
use Rector\ValueObject\MethodName;
13+
use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface;
14+
use Rector\VersionBonding\ValueObject\ComposerPackageConstraint;
1315
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
1416
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
1517

1618
/**
19+
* The TestCase::__construct() was declared final in PHPUnit 12.0.3, overriding it is a fatal error since then
20+
*
1721
* @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\RemoveOverrideFinalConstructTestCaseRector\RemoveOverrideFinalConstructTestCaseRectorTest
22+
*
23+
* @see https://github.com/sebastianbergmann/phpunit/commit/3263f4c62d4af44777ff1c81d093ee88eafccdad
1824
*/
19-
final class RemoveOverrideFinalConstructTestCaseRector extends AbstractRector
25+
final class RemoveOverrideFinalConstructTestCaseRector extends AbstractRector implements ComposerPackageConstraintInterface
2026
{
2127
public function __construct(
2228
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
2329
) {
2430
}
2531

32+
public function provideComposerPackageConstraint(): ComposerPackageConstraint
33+
{
34+
return new ComposerPackageConstraint('phpunit/phpunit', '>=12.0.3');
35+
}
36+
2637
public function getRuleDefinition(): RuleDefinition
2738
{
2839
return new RuleDefinition(
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
5+
final class RemoveOverrideFinalConstructTest extends TestCase
6+
{
7+
public function __construct()
8+
{
9+
parent::__construct(static::class);
10+
}
11+
}
12+
13+
?>
14+
-----
15+
<?php
16+
17+
use PHPUnit\Framework\TestCase;
18+
19+
final class RemoveOverrideFinalConstructTest extends TestCase
20+
{
21+
}
22+
23+
?>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
5+
final class VersionBoundMethodRenamesTest extends TestCase
6+
{
7+
public function testSomething()
8+
{
9+
$this->assertObjectHasAttribute('someProperty', new stdClass());
10+
$this->expectExceptionMessage('some message');
11+
}
12+
}
13+
14+
?>
15+
-----
16+
<?php
17+
18+
use PHPUnit\Framework\TestCase;
19+
20+
final class VersionBoundMethodRenamesTest extends TestCase
21+
{
22+
public function testSomething()
23+
{
24+
$this->assertObjectHasProperty('someProperty', new stdClass());
25+
$this->expectExceptionMessageIsOrContains('some message');
26+
}
27+
}
28+
29+
?>

0 commit comments

Comments
 (0)