diff --git a/config/set/phpunit/phpunit70.yaml b/config/set/phpunit/phpunit70.yaml index 9602144a207..b99b6139ee6 100644 --- a/config/set/phpunit/phpunit70.yaml +++ b/config/set/phpunit/phpunit70.yaml @@ -5,3 +5,4 @@ services: Rector\Renaming\Rector\Annotation\RenameAnnotationRector: PHPUnit\Framework\TestCase: scenario: 'test' + Rector\PHPUnit\Rector\Class_\RemoveDataProviderTestPrefixRector: ~ diff --git a/packages/PHPUnit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php b/packages/PHPUnit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php new file mode 100644 index 00000000000..f953fe1a03b --- /dev/null +++ b/packages/PHPUnit/src/Rector/Class_/RemoveDataProviderTestPrefixRector.php @@ -0,0 +1,147 @@ +test\w+)#'; + + /** + * @var string + */ + private const DATA_PROVIDER_EXACT_NAME_PATTERN = '#(@dataProvider\s+)(%s)#'; + + /** + * @var string[] + */ + private $providerMethodNamesToNewNames = []; + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Data provider methods cannot start with "test" prefix', [ + new CodeSample( + <<<'PHP' +class SomeClass extends PHPUnit\Framework\TestCase +{ + /** + * @dataProvider testProvideData() + */ + public function test() + { + $nothing = 5; + } + + public function testProvideData() + { + return ['123']; + } +} +PHP + , + <<<'PHP' +class SomeClass extends PHPUnit\Framework\TestCase +{ + /** + * @dataProvider provideData() + */ + public function test() + { + $nothing = 5; + } + + public function provideData() + { + return ['123']; + } +} +PHP + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + if (! $this->isInTestClass($node)) { + return null; + } + + $this->providerMethodNamesToNewNames = []; + + $this->renameDataProviderAnnotationsAndCollectRenamedMethods($node); + + $this->renameProviderMethods($node); + + return $node; + } + + private function renameDataProviderAnnotationsAndCollectRenamedMethods(Class_ $class): void + { + foreach ($class->getMethods() as $classMethod) { + if ($classMethod->getDocComment() === null) { + continue; + } + + $docCommentText = $classMethod->getDocComment()->getText(); + if (! Strings::match($docCommentText, self::DATA_PROVIDER_ANNOTATION_PATTERN)) { + continue; + } + + // replace the name in the doc + $matches = Strings::matchAll($docCommentText, self::DATA_PROVIDER_ANNOTATION_PATTERN); + foreach ($matches as $match) { + $currentProviderMethodName = $match['providerMethodName']; + + $newMethodName = Strings::substring($currentProviderMethodName, strlen('test')); + $newMethodName = lcfirst($newMethodName); + + $currentMethodPattern = sprintf(self::DATA_PROVIDER_EXACT_NAME_PATTERN, $currentProviderMethodName); + + $docCommentText = Strings::replace($docCommentText, $currentMethodPattern, '$1' . $newMethodName); + + $this->providerMethodNamesToNewNames[$currentProviderMethodName] = $newMethodName; + } + + $classMethod->setDocComment(new Doc($docCommentText)); + } + } + + private function renameProviderMethods(Class_ $class): void + { + foreach ($class->getMethods() as $classMethod) { + foreach ($this->providerMethodNamesToNewNames as $oldName => $newName) { + if (! $this->isName($classMethod, $oldName)) { + continue; + } + + $classMethod->name = new Node\Identifier($newName); + } + } + } +} diff --git a/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/fixture.php.inc b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..20375b1f439 --- /dev/null +++ b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/fixture.php.inc @@ -0,0 +1,43 @@ + +----- + diff --git a/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/multiple_data_providers.php.inc b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/multiple_data_providers.php.inc new file mode 100644 index 00000000000..8285e25633a --- /dev/null +++ b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/multiple_data_providers.php.inc @@ -0,0 +1,67 @@ + +----- + diff --git a/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/with_test_annotation.php.inc b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/with_test_annotation.php.inc new file mode 100644 index 00000000000..a311f56b862 --- /dev/null +++ b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/Fixture/with_test_annotation.php.inc @@ -0,0 +1,45 @@ + +----- + diff --git a/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/RemoveDataProviderTestPrefixRectorTest.php b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/RemoveDataProviderTestPrefixRectorTest.php new file mode 100644 index 00000000000..3aa796835c1 --- /dev/null +++ b/packages/PHPUnit/tests/Rector/Class_/RemoveDataProviderTestPrefixRector/RemoveDataProviderTestPrefixRectorTest.php @@ -0,0 +1,30 @@ +doTestFile($file); + } + + public function provideDataForTest(): Iterator + { + yield [__DIR__ . '/Fixture/fixture.php.inc']; + yield [__DIR__ . '/Fixture/with_test_annotation.php.inc']; + yield [__DIR__ . '/Fixture/multiple_data_providers.php.inc']; + } + + protected function getRectorClass(): string + { + return RemoveDataProviderTestPrefixRector::class; + } +}