improve AddSeeTestAnnotationRector

This commit is contained in:
TomasVotruba 2020-02-11 14:40:59 +01:00
parent 4aac338d20
commit bc5eefdb76
7 changed files with 56 additions and 40 deletions

View File

@ -124,7 +124,7 @@ parameters:
- 'rules/cakephp-to-symfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/CakePHPModelToDoctrineRepositoryRectorTest.php' - 'rules/cakephp-to-symfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/CakePHPModelToDoctrineRepositoryRectorTest.php'
PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer: PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer:
- 'rules/better-php-doc-parser/tests/PhpDocInfo/PhpDocInfo/PhpDocInfoTest.php' - 'packages/better-php-doc-parser/tests/PhpDocInfo/PhpDocInfo/PhpDocInfoTest.php'
# intentional "assertEquals()" # intentional "assertEquals()"
- 'tests/PhpParser/Node/NodeFactoryTest.php' - 'tests/PhpParser/Node/NodeFactoryTest.php'
- '*TypeResolverTest.php' - '*TypeResolverTest.php'

View File

@ -73,19 +73,19 @@ final class PhpDocInfoTest extends AbstractKernelTestCase
new PreSlashStringType(), new PreSlashStringType(),
]); ]);
$this->assertSame($expectedUnionType, $paramType); $this->assertEquals($expectedUnionType, $paramType);
} }
public function testGetVarType(): void public function testGetVarType(): void
{ {
$expectedObjectType = new ObjectType('SomeType'); $expectedObjectType = new ObjectType('SomeType');
$this->assertSame($expectedObjectType, $this->phpDocInfo->getVarType()); $this->assertEquals($expectedObjectType, $this->phpDocInfo->getVarType());
} }
public function testGetReturnType(): void public function testGetReturnType(): void
{ {
$expectedObjectType = new ObjectType('SomeType'); $expectedObjectType = new ObjectType('SomeType');
$this->assertSame($expectedObjectType, $this->phpDocInfo->getReturnType()); $this->assertEquals($expectedObjectType, $this->phpDocInfo->getReturnType());
} }
public function testReplaceTagByAnother(): void public function testReplaceTagByAnother(): void

View File

@ -31,7 +31,7 @@ final class ComposerAutoloadedDirectoryProvider
public function provide(): array public function provide(): array
{ {
if (PHPUnitEnvironment::isPHPUnitRun()) { if (PHPUnitEnvironment::isPHPUnitRun()) {
return [getcwd() . '/src', getcwd() . '/tests', getcwd() . '/packages']; return [getcwd() . '/src', getcwd() . '/tests', getcwd() . '/packages', getcwd() . '/rules'];
} }
$composerJson = $this->loadComposerJsonArray(); $composerJson = $this->loadComposerJsonArray();

View File

@ -8,6 +8,7 @@ use Nette\Loaders\RobotLoader;
use Nette\Utils\Strings; use Nette\Utils\Strings;
use PhpParser\Node; use PhpParser\Node;
use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Class_;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareGenericTagValueNode; use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareGenericTagValueNode;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocTagNode; use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocTagNode;
@ -49,7 +50,9 @@ class SomeService
{ {
} }
class SomeServiceTest extends \PHPUnit\Framework\TestCase use PHPUnit\Framework\TestCase;
class SomeServiceTest extends TestCase
{ {
} }
PHP PHP
@ -62,7 +65,9 @@ class SomeService
{ {
} }
class SomeServiceTest extends \PHPUnit\Framework\TestCase use PHPUnit\Framework\TestCase;
class SomeServiceTest extends TestCase
{ {
} }
PHP PHP
@ -84,53 +89,44 @@ PHP
*/ */
public function refactor(Node $node): ?Node public function refactor(Node $node): ?Node
{ {
if ($this->shouldSkipClass($node)) { $testCaseClassName = $this->resolveTestCaseClassName($node);
if ($testCaseClassName === null) {
return null;
}
if ($this->shouldSkipClass($node, $testCaseClassName)) {
return null; return null;
} }
/** @var PhpDocInfo $phpDocInfo */ /** @var PhpDocInfo $phpDocInfo */
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO); $phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
/** @var string $className */
$className = $this->getName($node);
$testCaseClassName = $this->resolveTestCaseClassName($className);
if ($testCaseClassName === null) {
return null;
}
$seeTagNode = $this->createSeePhpDocTagNode($testCaseClassName); $seeTagNode = $this->createSeePhpDocTagNode($testCaseClassName);
$phpDocInfo->addPhpDocTagNode($seeTagNode); $phpDocInfo->addPhpDocTagNode($seeTagNode);
return $node; return $node;
} }
private function shouldSkipClass(Class_ $class): bool private function shouldSkipClass(Class_ $class, string $testCaseClassName): bool
{ {
if ($class->isAnonymous()) { // we are in the test case
if ($this->isName($class, '*Test')) {
return true; return true;
} }
$className = $this->getName($class); /** @var PhpDocInfo $phpDocInfo */
if ($className === null) { $phpDocInfo = $class->getAttribute(AttributeKey::PHP_DOC_INFO);
return true;
}
// is a test case $seeTags = $phpDocInfo->getTagsByName('see');
if (Strings::endsWith($className, 'Test')) {
return true;
}
// is the @see annotation already added // is the @see annotation already added
if ($class->getDocComment() !== null) { foreach ($seeTags as $seeTag) {
/** @var string $docCommentText */ if (! $seeTag->value instanceof GenericTagValueNode) {
$docCommentText = $class->getDocComment()->getText(); continue;
}
/** @var string $shortClassName */ $seeTagClass = ltrim($seeTag->value->value, '\\');
$shortClassName = Strings::after($className, '\\', -1); if ($seeTagClass === $testCaseClassName) {
$seeClassPattern = '#@see (.*?)' . preg_quote($shortClassName, '#') . 'Test#m';
if (Strings::match($docCommentText, $seeClassPattern)) {
return true; return true;
} }
} }
@ -138,8 +134,18 @@ PHP
return false; return false;
} }
private function resolveTestCaseClassName(string $className): ?string private function resolveTestCaseClassName(Class_ $class): ?string
{ {
if ($this->isAnonymousClass($class)) {
return null;
}
$className = $this->getName($class);
if ($className === null) {
return null;
}
// fallback for unit tests that only have extra "Test" suffix
if (class_exists($className . 'Test')) { if (class_exists($className . 'Test')) {
return $className . 'Test'; return $className . 'Test';
} }
@ -182,6 +188,7 @@ PHP
private function createRobotLoadForDirectories(): RobotLoader private function createRobotLoadForDirectories(): RobotLoader
{ {
$robotLoader = new RobotLoader(); $robotLoader = new RobotLoader();
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/tests_add_see_rector_tests');
$directories = $this->composerAutoloadedDirectoryProvider->provide(); $directories = $this->composerAutoloadedDirectoryProvider->provide();
foreach ($directories as $directory) { foreach ($directories as $directory) {

View File

@ -47,7 +47,7 @@ final class FileRelocationResolverTest extends AbstractKernelTestCase
__DIR__ . '/Source/SomeFile.php', __DIR__ . '/Source/SomeFile.php',
SomeFile::class, SomeFile::class,
'Rector\PSR10\Tests\Source\SomeFile', 'Rector\PSR10\Tests\Source\SomeFile',
'packages/psr4/tests/Source/SomeFile.php', 'rules/psr4/tests/Source/SomeFile.php',
]; ];
} }
} }

View File

@ -4,9 +4,9 @@ sonar.projectKey=rectorphp_rector
# relative paths to source # relative paths to source
# wildcards don't work :( # wildcards don't work :(
sonar.sources=compiler/src,src,packages/architecture/src,packages/attribute-aware-php-doc/src,packages/autodiscovery/src,packages/better-php-doc-parser/src,packages/cakephp/src,packages/cakephp-to-symfony/src,packages/celebrity/src,packages/code-quality/src,packages/coding-style/src,packages/console-differ/src,packages/dead-code/src,packages/doctrine/src,packages/doctrine-code-quality/src,packages/doctrine-gedmo-to-knplabs/src,packages/dynamic-type-analysis/src,packages/elastic-search-dsl/src,packages/file-system-rector/src,packages/framework-migration/src,packages/guzzle/src,packages/laravel/src,packages/legacy/src,packages/minimal-scope/src,packages/mysql-to-mysqli/src,packages/nette/src,packages/nette-tester-to-phpunit/src,packages/nette-to-symfony/src,packages/node-type-resolver/src,packages/phalcon/src,packages/php-52/src,packages/php-53/src,packages/php-54/src,packages/php-55/src,packages/php-56/src,packages/php-70/src,packages/php-71/src,packages/php-72/src,packages/php-73/src,packages/php-74/src,packages/php-80/src,packages/php-deglobalize/src,packages/php-spec-to-phpunit/src,packages/phpstan/src,packages/phpstan-static-type-mapper/src,packages/phpunit/src,packages/phpunit-symfony/src,packages/polyfill/src,packages/psr4/src,packages/rector-generator/src,packages/refactoring/src,packages/removing-static/src,packages/renaming/src,packages/restoration/src,packages/sensio/src,packages/shopware/src,packages/silverstripe/src,packages/solid/src,packages/strict-code-quality/src,packages/sylius/src,packages/symfony/src,packages/symfony-code-quality/src,packages/symfony-phpunit/src,packages/twig/src,packages/type-declaration/src,packages/zend-to-symfony/src sonar.sources=compiler/src,src,rules/autodiscovery/src,rules/architecture/src,packages/attribute-aware-php-doc/src,packages/better-php-doc-parser/src,rules/cakephp/src,rules/celebrity/src,rules/code-quality/src,rules/coding-style/src,packages/console-differ/src,rules/dead-code/src,rules/doctrine/src,rules/doctrine-code-quality/src,rules/framework-migration/src,packages/file-system-rector/src,rules/elastic-search-dsl/src,rules/guzzle/src,rules/laravel/src,packages/legacy/src,rules/mysql-to-mysqli/src,rules/nette-tester-to-phpunit/src,rules/nette-to-symfony/src,packages/nette/src,packages/node-collector/src,packages/node-type-resolver/src,packages/node-name-resolver/src,rules/phpstan/src,packages/phpstan-static-type-mapper/src,rules/phpunit-symfony/src,rules/phpunit/src,rules/psr4/src,rules/php-spec-to-phpunit/src,rules/php-52/src,rules/php-53/src,rules/php-54/src,rules/php-55/src,rules/php-56/src,rules/php-70/src,rules/php-71/src,rules/php-72/src,rules/php-73/src,rules/php-74/src,rules/php-80/src,rules/removing-static/src,rules/renaming/src,rules/restoration/src,packages/refactoring/src,rules/solid/src,rules/sensio/src,rules/shopware/src,rules/silverstripe/src,packages/static-type-mapper/src,rules/sylius/src,rules/symfony-code-quality/src,rules/symfony-phpunit/src,rules/symfony/src,rules/twig/src,rules/type-declaration/src,packages/vendor-locker/src,rules/zend-to-symfony/src,packages/rector-generator/src,rules/strict-code-quality/src,packages/dynamic-type-analysis/src,rules/php-deglobalize/src,rules/phalcon/src,rules/doctrine-gedmo-to-knplabs/src,rules/minimal-scope/src,packages/polyfill/src,rules/cakephp-to-symfony/src
sonar.tests=tests,packages/architecture/tests,packages/autodiscovery/tests,packages/better-php-doc-parser/tests,packages/cakephp/tests,packages/cakephp-to-symfony/tests,packages/celebrity/tests,packages/code-quality/tests,packages/coding-style/tests,packages/dead-code/tests,packages/doctrine/tests,packages/doctrine-code-quality/tests,packages/doctrine-gedmo-to-knplabs/tests,packages/dynamic-type-analysis/tests,packages/elastic-search-dsl/tests,packages/guzzle/tests,packages/laravel/tests,packages/legacy/tests,packages/minimal-scope/tests,packages/mysql-to-mysqli/tests,packages/nette/tests,packages/nette-tester-to-phpunit/tests,packages/nette-to-symfony/tests,packages/node-type-resolver/tests,packages/phalcon/tests,packages/php-52/tests,packages/php-53/tests,packages/php-54/tests,packages/php-55/tests,packages/php-56/tests,packages/php-70/tests,packages/php-71/tests,packages/php-72/tests,packages/php-73/tests,packages/php-74/tests,packages/php-80/tests,packages/php-deglobalize/tests,packages/php-spec-to-phpunit/tests,packages/phpstan/tests,packages/phpunit/tests,packages/phpunit-symfony/tests,packages/polyfill/tests,packages/psr4/tests,packages/removing-static/tests,packages/renaming/tests,packages/restoration/tests,packages/sensio/tests,packages/shopware/tests,packages/silverstripe/tests,packages/solid/tests,packages/strict-code-quality/tests,packages/sylius/tests,packages/symfony/tests,packages/symfony-code-quality/tests,packages/symfony-phpunit/tests,packages/twig/tests,packages/type-declaration/tests,packages/zend-to-symfony/tests sonar.tests=tests,rules/architecture/tests,packages/autodiscovery/tests,packages/better-php-doc-parser/tests,packages/cakephp/tests,packages/cakephp-to-symfony/tests,packages/celebrity/tests,packages/code-quality/tests,packages/coding-style/tests,packages/dead-code/tests,packages/doctrine/tests,packages/doctrine-code-quality/tests,packages/doctrine-gedmo-to-knplabs/tests,packages/dynamic-type-analysis/tests,packages/elastic-search-dsl/tests,packages/guzzle/tests,packages/laravel/tests,packages/legacy/tests,packages/minimal-scope/tests,packages/mysql-to-mysqli/tests,packages/nette/tests,packages/nette-tester-to-phpunit/tests,packages/nette-to-symfony/tests,packages/node-type-resolver/tests,packages/phalcon/tests,packages/php-52/tests,packages/php-53/tests,packages/php-54/tests,packages/php-55/tests,packages/php-56/tests,packages/php-70/tests,packages/php-71/tests,packages/php-72/tests,packages/php-73/tests,packages/php-74/tests,packages/php-80/tests,packages/php-deglobalize/tests,packages/php-spec-to-phpunit/tests,packages/phpstan/tests,packages/phpunit/tests,packages/phpunit-symfony/tests,packages/polyfill/tests,packages/psr4/tests,packages/removing-static/tests,packages/renaming/tests,packages/restoration/tests,packages/sensio/tests,packages/shopware/tests,packages/silverstripe/tests,packages/solid/tests,packages/strict-code-quality/tests,packages/sylius/tests,packages/symfony/tests,packages/symfony-code-quality/tests,packages/symfony-phpunit/tests,packages/twig/tests,packages/type-declaration/tests,packages/zend-to-symfony/tests
# see https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus/#NarrowingtheFocus-patterns # see https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus/#NarrowingtheFocus-patterns
sonar.exclusions=src/**/*.php.inc,packages/**/*.php.inc,packages/**/Fixture/**/*,tests/**/Source/**/* sonar.exclusions=src/**/*.php.inc,rules/**/*.php.inc,packages/**/*.php.inc,packages/**/Fixture/**/*,rules/**/Fixture/**/*,tests/**/Source/**/*

View File

@ -13,12 +13,21 @@ use ReflectionClass;
final class RectorsFinder final class RectorsFinder
{ {
/**
* @var string[]
*/
private const RECTOR_PATHS = [
__DIR__ . '/../../../rules',
__DIR__ . '/../../../packages',
__DIR__ . '/../../../src',
];
/** /**
* @return string[] * @return string[]
*/ */
public function findCoreRectorClasses(): array public function findCoreRectorClasses(): array
{ {
$allRectors = $this->findInDirectories([__DIR__ . '/../../../packages', __DIR__ . '/../../../src']); $allRectors = $this->findInDirectories(self::RECTOR_PATHS);
return array_map(function (RectorInterface $rector): string { return array_map(function (RectorInterface $rector): string {
return get_class($rector); return get_class($rector);