Merge pull request #2144 from rectorphp/phpunit-provider

[PHPUnit] Add RemoveDataProviderTestPrefixRector
This commit is contained in:
Tomáš Votruba 2019-10-12 13:51:52 +02:00 committed by GitHub
commit 4fd1cde4b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 333 additions and 0 deletions

View File

@ -5,3 +5,4 @@ services:
Rector\Renaming\Rector\Annotation\RenameAnnotationRector: Rector\Renaming\Rector\Annotation\RenameAnnotationRector:
PHPUnit\Framework\TestCase: PHPUnit\Framework\TestCase:
scenario: 'test' scenario: 'test'
Rector\PHPUnit\Rector\Class_\RemoveDataProviderTestPrefixRector: ~

View File

@ -0,0 +1,147 @@
<?php declare(strict_types=1);
namespace Rector\PHPUnit\Rector\Class_;
use Nette\Utils\Strings;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Rector\AbstractPHPUnitRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see https://stackoverflow.com/a/46693675/1348344
*
* @see \Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\RemoveDataProviderTestPrefixRectorTest
*/
final class RemoveDataProviderTestPrefixRector extends AbstractPHPUnitRector
{
/**
* @var string
*/
private const DATA_PROVIDER_ANNOTATION_PATTERN = '#(@dataProvider\s+)(?<providerMethodName>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);
}
}
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\Fixture;
class SomeClass extends \PHPUnit\Framework\TestCase
{
/**
* @dataProvider testProvideData()
*/
public function test()
{
$nothing = 5;
}
public function testProvideData()
{
return ['123'];
}
}
?>
-----
<?php
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\Fixture;
class SomeClass extends \PHPUnit\Framework\TestCase
{
/**
* @dataProvider provideData()
*/
public function test()
{
$nothing = 5;
}
public function provideData()
{
return ['123'];
}
}
?>

View File

@ -0,0 +1,67 @@
<?php
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\Fixture;
class MultipleDataProviders extends \PHPUnit\Framework\TestCase
{
/**
* @dataProvider testProvideData()
* @dataProvider testNextProvideData2()
* @dataProvider testNextProvideData()
*/
public function test()
{
$nothing = 5;
}
public function testProvideData()
{
return ['123'];
}
public function testNextProvideData2()
{
return ['123'];
}
public function testNextProvideData()
{
return ['123'];
}
}
?>
-----
<?php
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\Fixture;
class MultipleDataProviders extends \PHPUnit\Framework\TestCase
{
/**
* @dataProvider provideData()
* @dataProvider nextProvideData2()
* @dataProvider nextProvideData()
*/
public function test()
{
$nothing = 5;
}
public function provideData()
{
return ['123'];
}
public function nextProvideData2()
{
return ['123'];
}
public function nextProvideData()
{
return ['123'];
}
}
?>

View File

@ -0,0 +1,45 @@
<?php
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\Fixture;
class WithTestAnnotation extends \PHPUnit\Framework\TestCase
{
/**
* @test
* @dataProvider testProvideDataForWithATestAnnotation()
*/
public function test()
{
$nothing = 5;
}
public function testProvideDataForWithATestAnnotation()
{
return ['123'];
}
}
?>
-----
<?php
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector\Fixture;
class WithTestAnnotation extends \PHPUnit\Framework\TestCase
{
/**
* @test
* @dataProvider provideDataForWithATestAnnotation()
*/
public function test()
{
$nothing = 5;
}
public function provideDataForWithATestAnnotation()
{
return ['123'];
}
}
?>

View File

@ -0,0 +1,30 @@
<?php declare(strict_types=1);
namespace Rector\PHPUnit\Tests\Rector\Class_\RemoveDataProviderTestPrefixRector;
use Iterator;
use Rector\PHPUnit\Rector\Class_\RemoveDataProviderTestPrefixRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class RemoveDataProviderTestPrefixRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->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;
}
}