mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-29 06:03:30 +00:00
add links to each rule and test fixture in docs
This commit is contained in:
parent
1127400a06
commit
d0afc945e0
File diff suppressed because it is too large
Load Diff
|
@ -4,8 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\PHPUnit\Rector\Class_;
|
||||
|
||||
use Nette\Loaders\RobotLoader;
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
||||
|
@ -17,7 +15,7 @@ use Rector\Core\Rector\AbstractRector;
|
|||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PHPUnit\Composer\ComposerAutoloadedDirectoryProvider;
|
||||
use Rector\PHPUnit\TestClassResolver\TestClassResolver;
|
||||
|
||||
/**
|
||||
* @see \Rector\PHPUnit\Tests\Rector\Class_\AddSeeTestAnnotationRector\AddSeeTestAnnotationRectorTest
|
||||
|
@ -25,18 +23,13 @@ use Rector\PHPUnit\Composer\ComposerAutoloadedDirectoryProvider;
|
|||
final class AddSeeTestAnnotationRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
* @var TestClassResolver
|
||||
*/
|
||||
private $phpUnitTestCaseClasses = [];
|
||||
private $testClassResolver;
|
||||
|
||||
/**
|
||||
* @var ComposerAutoloadedDirectoryProvider
|
||||
*/
|
||||
private $composerAutoloadedDirectoryProvider;
|
||||
|
||||
public function __construct(ComposerAutoloadedDirectoryProvider $composerAutoloadedDirectoryProvider)
|
||||
public function __construct(TestClassResolver $testClassResolver)
|
||||
{
|
||||
$this->composerAutoloadedDirectoryProvider = $composerAutoloadedDirectoryProvider;
|
||||
$this->testClassResolver = $testClassResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
|
@ -89,7 +82,7 @@ PHP
|
|||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$testCaseClassName = $this->resolveTestCaseClassName($node);
|
||||
$testCaseClassName = $this->testClassResolver->resolveFromClass($node);
|
||||
if ($testCaseClassName === null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -134,71 +127,8 @@ PHP
|
|||
return false;
|
||||
}
|
||||
|
||||
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')) {
|
||||
return $className . 'Test';
|
||||
}
|
||||
|
||||
$shortClassName = Strings::after($className, '\\', -1);
|
||||
$testShortClassName = $shortClassName . 'Test';
|
||||
|
||||
$phpUnitTestCaseClasses = $this->getPhpUnitTestCaseClasses();
|
||||
foreach ($phpUnitTestCaseClasses as $declaredClass) {
|
||||
if (Strings::endsWith($declaredClass, '\\' . $testShortClassName)) {
|
||||
return $declaredClass;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function createSeePhpDocTagNode(string $className): PhpDocTagNode
|
||||
{
|
||||
return new AttributeAwarePhpDocTagNode('@see', new AttributeAwareGenericTagValueNode('\\' . $className));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getPhpUnitTestCaseClasses(): array
|
||||
{
|
||||
if ($this->phpUnitTestCaseClasses !== []) {
|
||||
return $this->phpUnitTestCaseClasses;
|
||||
}
|
||||
|
||||
$robotLoader = $this->createRobotLoadForDirectories();
|
||||
$robotLoader->rebuild();
|
||||
|
||||
$this->phpUnitTestCaseClasses = array_keys($robotLoader->getIndexedClasses());
|
||||
|
||||
return $this->phpUnitTestCaseClasses;
|
||||
}
|
||||
|
||||
private function createRobotLoadForDirectories(): RobotLoader
|
||||
{
|
||||
$robotLoader = new RobotLoader();
|
||||
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/tests_add_see_rector_tests');
|
||||
|
||||
$directories = $this->composerAutoloadedDirectoryProvider->provide();
|
||||
foreach ($directories as $directory) {
|
||||
$robotLoader->addDirectory($directory);
|
||||
}
|
||||
|
||||
$robotLoader->acceptFiles = ['*Test.php'];
|
||||
$robotLoader->ignoreDirs[] = '*Expected*';
|
||||
$robotLoader->ignoreDirs[] = '*Fixture*';
|
||||
|
||||
return $robotLoader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\TestClassResolver;
|
||||
|
||||
use Nette\Loaders\RobotLoader;
|
||||
use Rector\PHPUnit\Composer\ComposerAutoloadedDirectoryProvider;
|
||||
|
||||
final class PHPUnitTestCaseClassesProvider
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $phpUnitTestCaseClasses = [];
|
||||
|
||||
/**
|
||||
* @var ComposerAutoloadedDirectoryProvider
|
||||
*/
|
||||
private $composerAutoloadedDirectoryProvider;
|
||||
|
||||
public function __construct(ComposerAutoloadedDirectoryProvider $composerAutoloadedDirectoryProvider)
|
||||
{
|
||||
$this->composerAutoloadedDirectoryProvider = $composerAutoloadedDirectoryProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function provide(): array
|
||||
{
|
||||
if ($this->phpUnitTestCaseClasses !== []) {
|
||||
return $this->phpUnitTestCaseClasses;
|
||||
}
|
||||
|
||||
$robotLoader = $this->createRobotLoadForDirectories();
|
||||
$robotLoader->rebuild();
|
||||
|
||||
$this->phpUnitTestCaseClasses = array_keys($robotLoader->getIndexedClasses());
|
||||
|
||||
return $this->phpUnitTestCaseClasses;
|
||||
}
|
||||
|
||||
private function createRobotLoadForDirectories(): RobotLoader
|
||||
{
|
||||
$robotLoader = new RobotLoader();
|
||||
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/tests_add_see_rector_tests');
|
||||
|
||||
$directories = $this->composerAutoloadedDirectoryProvider->provide();
|
||||
foreach ($directories as $directory) {
|
||||
$robotLoader->addDirectory($directory);
|
||||
}
|
||||
|
||||
$robotLoader->acceptFiles = ['*Test.php'];
|
||||
$robotLoader->ignoreDirs[] = '*Expected*';
|
||||
$robotLoader->ignoreDirs[] = '*Fixture*';
|
||||
|
||||
return $robotLoader;
|
||||
}
|
||||
}
|
60
rules/phpunit/src/TestClassResolver/TestClassResolver.php
Normal file
60
rules/phpunit/src/TestClassResolver/TestClassResolver.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\TestClassResolver;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
|
||||
final class TestClassResolver
|
||||
{
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
/**
|
||||
* @var PHPUnitTestCaseClassesProvider
|
||||
*/
|
||||
private $phpUnitTestCaseClassesProvider;
|
||||
|
||||
public function __construct(
|
||||
NodeNameResolver $nodeNameResolver,
|
||||
PHPUnitTestCaseClassesProvider $phpUnitTestCaseClassesProvider
|
||||
) {
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->phpUnitTestCaseClassesProvider = $phpUnitTestCaseClassesProvider;
|
||||
}
|
||||
|
||||
public function resolveFromClassName(string $className): ?string
|
||||
{
|
||||
// fallback for unit tests that only have extra "Test" suffix
|
||||
if (class_exists($className . 'Test')) {
|
||||
return $className . 'Test';
|
||||
}
|
||||
|
||||
$shortClassName = Strings::after($className, '\\', -1);
|
||||
$testShortClassName = $shortClassName . 'Test';
|
||||
|
||||
$phpUnitTestCaseClasses = $this->phpUnitTestCaseClassesProvider->provide();
|
||||
foreach ($phpUnitTestCaseClasses as $declaredClass) {
|
||||
if (Strings::endsWith($declaredClass, '\\' . $testShortClassName)) {
|
||||
return $declaredClass;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function resolveFromClass(Class_ $class): ?string
|
||||
{
|
||||
$className = $this->nodeNameResolver->getName($class);
|
||||
if ($className === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->resolveFromClassName($className);
|
||||
}
|
||||
}
|
|
@ -9,10 +9,13 @@ use Rector\ConsoleDiffer\MarkdownDifferAndFormatter;
|
|||
use Rector\Core\Contract\Rector\RectorInterface;
|
||||
use Rector\Core\Contract\RectorDefinition\CodeSampleInterface;
|
||||
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
|
||||
use Rector\PHPUnit\TestClassResolver\TestClassResolver;
|
||||
use Rector\Utils\DocumentationGenerator\Contract\OutputFormatter\DumpRectorsOutputFormatterInterface;
|
||||
use Rector\Utils\DocumentationGenerator\RectorMetadataResolver;
|
||||
use ReflectionClass;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class MarkdownDumpRectorsOutputFormatter implements DumpRectorsOutputFormatterInterface
|
||||
{
|
||||
|
@ -31,14 +34,21 @@ final class MarkdownDumpRectorsOutputFormatter implements DumpRectorsOutputForma
|
|||
*/
|
||||
private $rectorMetadataResolver;
|
||||
|
||||
/**
|
||||
* @var TestClassResolver
|
||||
*/
|
||||
private $testClassResolver;
|
||||
|
||||
public function __construct(
|
||||
SymfonyStyle $symfonyStyle,
|
||||
MarkdownDifferAndFormatter $markdownDifferAndFormatter,
|
||||
RectorMetadataResolver $rectorMetadataResolver
|
||||
RectorMetadataResolver $rectorMetadataResolver,
|
||||
TestClassResolver $testClassResolver
|
||||
) {
|
||||
$this->symfonyStyle = $symfonyStyle;
|
||||
$this->markdownDifferAndFormatter = $markdownDifferAndFormatter;
|
||||
$this->rectorMetadataResolver = $rectorMetadataResolver;
|
||||
$this->testClassResolver = $testClassResolver;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
|
@ -130,8 +140,22 @@ final class MarkdownDumpRectorsOutputFormatter implements DumpRectorsOutputForma
|
|||
$headline = $this->getRectorClassWithoutNamespace($rector);
|
||||
$this->symfonyStyle->writeln(sprintf('### `%s`', $headline));
|
||||
|
||||
$rectorClass = get_class($rector);
|
||||
|
||||
$this->symfonyStyle->newLine();
|
||||
$this->symfonyStyle->writeln(sprintf('- class: `%s`', get_class($rector)));
|
||||
$this->symfonyStyle->writeln(sprintf(
|
||||
'- class: [`%s`](%s)',
|
||||
get_class($rector),
|
||||
$this->resolveClassFilePathOnGitHub($rectorClass)
|
||||
));
|
||||
|
||||
$rectorTestClass = $this->testClassResolver->resolveFromClassName($rectorClass);
|
||||
if ($rectorTestClass !== null) {
|
||||
$fixtureDirectoryPath = $this->resolveFixtureDirectoryPathOnGitHub($rectorTestClass);
|
||||
if ($fixtureDirectoryPath !== null) {
|
||||
$this->symfonyStyle->writeln(sprintf('- [test fixtures](%s)', $fixtureDirectoryPath));
|
||||
}
|
||||
}
|
||||
|
||||
$rectorDefinition = $rector->getDefinition();
|
||||
if ($rectorDefinition->getDescription() !== '') {
|
||||
|
@ -193,4 +217,30 @@ final class MarkdownDumpRectorsOutputFormatter implements DumpRectorsOutputForma
|
|||
{
|
||||
$this->symfonyStyle->writeln(sprintf('```%s%s%s%s```', $format, PHP_EOL, rtrim($content), PHP_EOL));
|
||||
}
|
||||
|
||||
private function resolveClassFilePathOnGitHub(string $className): string
|
||||
{
|
||||
$classRelativePath = $this->getClassRelativePath($className);
|
||||
return '/../master/' . $classRelativePath;
|
||||
}
|
||||
|
||||
private function resolveFixtureDirectoryPathOnGitHub(string $className): ?string
|
||||
{
|
||||
$classRelativePath = $this->getClassRelativePath($className);
|
||||
|
||||
$fixtureDirectory = dirname($classRelativePath) . '/Fixture';
|
||||
if (is_dir($fixtureDirectory)) {
|
||||
return '/../master/' . $fixtureDirectory;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getClassRelativePath(string $className): string
|
||||
{
|
||||
$rectorReflectionClass = new ReflectionClass($className);
|
||||
$rectorSmartFileInfo = new SmartFileInfo($rectorReflectionClass->getFileName());
|
||||
|
||||
return $rectorSmartFileInfo->getRelativeFilePathFromCwd();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user