diff --git a/config/sets/phpunit-code-quality.php b/config/sets/phpunit-code-quality.php index 55ff7785..73f4acb6 100644 --- a/config/sets/phpunit-code-quality.php +++ b/config/sets/phpunit-code-quality.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use Rector\PHPUnit\CodeQuality\Rector\Expression\DecorateWillReturnMapWithExpectsMockRector; use Rector\Config\RectorConfig; use Rector\PHPUnit\CodeQuality\Rector\CallLike\DirectInstanceOverMockArgRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\AddParamTypeFromDependsRector; @@ -26,6 +25,7 @@ use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\RemoveStandaloneCreateMockRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\ReplaceTestAnnotationWithPrefixedFunctionRector; use Rector\PHPUnit\CodeQuality\Rector\Expression\AssertArrayCastedObjectToAssertSameRector; +use Rector\PHPUnit\CodeQuality\Rector\Expression\DecorateWillReturnMapWithExpectsMockRector; use Rector\PHPUnit\CodeQuality\Rector\Foreach_\SimplifyForeachInstanceOfRector; use Rector\PHPUnit\CodeQuality\Rector\FuncCall\AssertFuncCallToPHPUnitAssertRector; use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertCompareOnCountableWithMethodToAssertCountRector; diff --git a/config/sets/phpunit120.php b/config/sets/phpunit120.php index ff9dc64a..11982aa9 100644 --- a/config/sets/phpunit120.php +++ b/config/sets/phpunit120.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +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; @@ -19,6 +20,7 @@ // stubs over mocks CreateStubOverCreateMockArgRector::class, + CreateStubInCoalesceArgRector::class, ExpressionCreateMockToCreateStubRector::class, PropertyCreateMockToCreateStubRector::class, AllowMockObjectsWhereParentClassRector::class, diff --git a/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/CreateStubInCoalesceArgRectorTest.php b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/CreateStubInCoalesceArgRectorTest.php new file mode 100644 index 00000000..f277e00e --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/CreateStubInCoalesceArgRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/handle_array_item.php.inc b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/handle_array_item.php.inc new file mode 100644 index 00000000..1bbea872 --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/handle_array_item.php.inc @@ -0,0 +1,41 @@ +createMock(\stdClass::class), + $value ?? $this->createMock(\stdClass::class), + ]; + } +} + +?> +----- +createStub(\stdClass::class), + $value ?? $this->createStub(\stdClass::class), + ]; + } +} + +?> diff --git a/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/skip_in_assign.php.inc b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/skip_in_assign.php.inc new file mode 100644 index 00000000..4c444868 --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/skip_in_assign.php.inc @@ -0,0 +1,15 @@ +createMock(\stdClass::class); + } +} diff --git a/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/some_file_with_mocks.php.inc b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/some_file_with_mocks.php.inc new file mode 100644 index 00000000..29b8706e --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/Fixture/some_file_with_mocks.php.inc @@ -0,0 +1,43 @@ +run( + $value ?? $this->createMock(\stdClass::class), + $value ?? $this->createMock(\stdClass::class), + ); + } +} + +?> +----- +run( + $value ?? $this->createStub(\stdClass::class), + $value ?? $this->createStub(\stdClass::class), + ); + } +} + +?> diff --git a/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/config/configured_rule.php b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/config/configured_rule.php new file mode 100644 index 00000000..10c63ae8 --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([CreateStubInCoalesceArgRector::class]); diff --git a/rules/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector.php b/rules/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector.php new file mode 100644 index 00000000..8f875b88 --- /dev/null +++ b/rules/PHPUnit120/Rector/CallLike/CreateStubInCoalesceArgRector.php @@ -0,0 +1,147 @@ +>get('service'); + $this->someMethod($mockObject ?? $this->createMock(SomeClass::class)); + } + + private function someMethod($someClass) + { + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +use PHPUnit\Framework\TestCase; + +final class SomeTest extends TestCase +{ + public function test() + { + $mockObject = $this->>get('service'); + $this->someMethod($mockObject ?? $this->createStub(SomeClass::class)); + } + + private function someMethod($someClass) + { +} +CODE_SAMPLE + ), + + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [StaticCall::class, MethodCall::class, New_::class, ArrayItem::class]; + } + + /** + * @param MethodCall|StaticCall|New_|ArrayItem $node + */ + public function refactor(Node $node): MethodCall|StaticCall|New_|ArrayItem|null + { + if (! $this->testsNodeAnalyzer->isInTestClass($node)) { + return null; + } + + if ($node instanceof ArrayItem) { + return $this->refactorArrayItem($node); + } + + $hasChanges = false; + if ($node->isFirstClassCallable()) { + return null; + } + + foreach ($node->getArgs() as $arg) { + if (! $arg->value instanceof Coalesce) { + continue; + } + + $coalesce = $arg->value; + if (! $coalesce->right instanceof MethodCall) { + continue; + } + + $methodCall = $coalesce->right; + if (! $this->isName($methodCall->name, 'createMock')) { + continue; + } + + $methodCall->name = new Identifier('createStub'); + $hasChanges = true; + } + + if ($hasChanges) { + return $node; + } + + return null; + } + + private function refactorArrayItem(ArrayItem $arrayItem): ?ArrayItem + { + if (! $arrayItem->value instanceof Coalesce) { + return null; + } + + $coalesce = $arrayItem->value; + if (! $coalesce->right instanceof MethodCall) { + return null; + } + + $methodCall = $coalesce->right; + if (! $this->isName($methodCall->name, 'createMock')) { + return null; + } + + $methodCall->name = new Identifier('createStub'); + + return $arrayItem; + } +}