[CI] Drop fixture checks, that are now covered by static reflection (#5831)

This commit is contained in:
Tomas Votruba 2021-03-13 11:47:11 +01:00 committed by GitHub
parent 5677e7caef
commit ab1154f6c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 4 additions and 652 deletions

View File

@ -17,18 +17,6 @@ jobs:
name: Validate Fixtures
run: bin/rector validate-fixture-suffix --ansi
-
name: Validate Fixtures Namespace
run: bin/rector validate-fixture-namespace --ansi
-
name: Validate Fixtures class name
run: bin/rector validate-fixture-classname --ansi
-
name: Validate Fixtures file name
run: bin/rector validate-fixture-filename --ansi
# make sure skipped files have "skip_" prefix
-
name: Validate Fixtures skip file prefix

View File

@ -6,7 +6,7 @@ use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Stmt\Nop;
final class ImproveNullable
final class DoubleCallArray
{
public function getName(?Node $node)
{
@ -16,7 +16,7 @@ final class ImproveNullable
final class CallGetName
{
public function run(ImproveNullable $improveNullable)
public function run(DoubleCallArray $improveNullable)
{
$nop = new Nop();
$improveNullable->getName($nop);
@ -36,7 +36,7 @@ use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Stmt\Nop;
final class ImproveNullable
final class DoubleCallArray
{
public function getName(\PhpParser\Node $node)
{
@ -46,7 +46,7 @@ final class ImproveNullable
final class CallGetName
{
public function run(ImproveNullable $improveNullable)
public function run(DoubleCallArray $improveNullable)
{
$nop = new Nop();
$improveNullable->getName($nop);

View File

@ -1,260 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\ProjectValidator\Command;
use Nette\Utils\Strings;
use Rector\Core\Configuration\Option;
use Rector\Core\Util\StaticRectorStrings;
use Rector\Utils\ProjectValidator\Finder\FixtureFinder;
use Rector\Utils\ProjectValidator\Naming\ExpectedNameResolver;
use Rector\Utils\ProjectValidator\Naming\NamespaceMatcher;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\SmartFileSystem\SmartFileInfo;
use Symplify\SmartFileSystem\SmartFileSystem;
final class ValidateFixtureClassnameCommand extends Command
{
/**
* @var string
* @see https://regex101.com/r/5KtBi8/2
*/
private const NAMESPACE_REGEX = '#^namespace (.*);$#msU';
/**
* @var string
* @see https://regex101.com/r/IDSGdI/6
*/
private const CLASS_REGEX = '#(class) (\w+)\s+{$#msU';
/**
* @var string
* @see https://regex101.com/r/yv2Rul/4
*/
private const CLASS_WITH_EXTENDS_IMPLEMENTS_REGEX = '#(class) (\w+)\s+(extends|implements)\s+(.*)\s+\{$#msU';
/**
* @var string
* @see https://regex101.com/r/T5LUbA/6
*/
private const CLASS_USE_TRAIT_REGEX = '#^\s{0,}use\s+(.*);$#msU';
/**
* @var string[]
*/
private const EXCLUDE_NAMES = [
'string',
'false',
'resource',
'mixed',
'git_wrapper',
'this',
'object',
'array_item',
'array',
'callable',
'scalar',
'throw',
'boolean',
'elseif',
'exit',
'function',
'substr',
'abstract',
'exception',
'concat',
'const',
'variable',
'property',
];
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
/**
* @var string
*/
private $currentDirectory;
/**
* @var SmartFileSystem
*/
private $smartFileSystem;
/**
* @var FixtureFinder
*/
private $fixtureFinder;
/**
* @var NamespaceMatcher
*/
private $namespaceMatcher;
/**
* @var ExpectedNameResolver
*/
private $expectedNameResolver;
public function __construct(
SymfonyStyle $symfonyStyle,
ExpectedNameResolver $expectedNameResolver,
SmartFileSystem $smartFileSystem,
FixtureFinder $fixtureFinder,
NamespaceMatcher $namespaceMatcher
) {
parent::__construct();
$this->symfonyStyle = $symfonyStyle;
$this->currentDirectory = getcwd();
$this->smartFileSystem = $smartFileSystem;
$this->fixtureFinder = $fixtureFinder;
$this->namespaceMatcher = $namespaceMatcher;
$this->expectedNameResolver = $expectedNameResolver;
}
protected function configure(): void
{
$this->addOption(Option::FIX, null, null, 'Fix found violations.');
$this->setDescription('[CI] Validate tests fixtures class name');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$optionFix = (bool) $input->getOption(Option::FIX);
$fixtureFileInfos = $this->fixtureFinder->findFixtureFileInfos();
$incorrectClassNameFiles = [];
foreach ($fixtureFileInfos as $fixtureFileInfo) {
// 1. geting expected namespace ...
$paths = explode('/tests/', (string) $fixtureFileInfo);
if (count($paths) > 2) {
continue;
}
$path = ltrim(Strings::substring($paths[0], strlen($this->currentDirectory)) . '/tests', '/');
$expectedNamespace = $this->expectedNameResolver->resolve($path, $paths[1]);
if ($expectedNamespace === null) {
continue;
}
// 2. reading file contents
$fileContent = $this->smartFileSystem->readFile((string) $fixtureFileInfo);
$matchAll = Strings::matchAll($fileContent, self::NAMESPACE_REGEX);
$namespaceMatcherIsFoundCorrectNamespace = $this->namespaceMatcher->isFoundCorrectNamespace(
$matchAll,
$expectedNamespace
);
if (! $namespaceMatcherIsFoundCorrectNamespace) {
continue;
}
$incorrectClassNameFiles = $this->checkAndFixClassName(
$fileContent,
$fixtureFileInfo,
$incorrectClassNameFiles,
$optionFix
);
}
if ($incorrectClassNameFiles !== []) {
$this->symfonyStyle->listing($incorrectClassNameFiles);
$message = sprintf(
'Found %d fixture files with invalid class name which not follow psr-4 defined in composer.json',
count($incorrectClassNameFiles)
);
if (! $optionFix) {
$message .= '. Just add "--fix" to console command and rerun to apply.';
$this->symfonyStyle->error($message);
return ShellCode::ERROR;
}
$this->symfonyStyle->success($message . ' and all fixtures are corrected', );
return ShellCode::SUCCESS;
}
$this->symfonyStyle->success('All fixtures are correct');
return ShellCode::SUCCESS;
}
/**
* @param string[] $incorrectClassNameFiles
* @return string[]
*/
private function checkAndFixClassName(
string $fileContent,
SmartFileInfo $fixtureFile,
array $incorrectClassNameFiles,
bool $optionFix
): array {
$matchAll = Strings::matchAll($fileContent, self::CLASS_REGEX);
if ($matchAll === []) {
return $incorrectClassNameFiles;
}
if (count($matchAll) > 2) {
return $incorrectClassNameFiles;
}
$fileName = Strings::substring($fixtureFile->getFileName(), 0, -8);
if (in_array($fileName, self::EXCLUDE_NAMES, true)) {
return $incorrectClassNameFiles;
}
$hasTrait = (bool) Strings::match($fileContent, self::CLASS_USE_TRAIT_REGEX);
if ($hasTrait) {
return $incorrectClassNameFiles;
}
$fileName = str_replace('-', '_', $fileName);
$expectedClassName = ucfirst(StaticRectorStrings::uppercaseUnderscoreToCamelCase($fileName));
$incorrectClassName = $this->getClassName($matchAll);
if ($expectedClassName === $incorrectClassName) {
return $incorrectClassNameFiles;
}
$hasExtendsImplements = (bool) Strings::match($fileContent, self::CLASS_WITH_EXTENDS_IMPLEMENTS_REGEX);
if ($hasExtendsImplements) {
return $incorrectClassNameFiles;
}
$incorrectClassNameFiles[] = (string) $fixtureFile;
if ($optionFix) {
$this->fixClassName((string) $fixtureFile, $incorrectClassName, $fileContent, $expectedClassName);
}
return $incorrectClassNameFiles;
}
/**
* @param array<int, array<int, string>> $matchAll
*/
private function getClassName(array $matchAll): string
{
return $matchAll[0][2];
}
private function fixClassName(
string $incorrectClassNameFile,
string $incorrectClassName,
string $incorrectFileContent,
string $expectedClassName
): void {
$newContent = str_replace('class ' . $incorrectClassName, 'class ' . $expectedClassName, $incorrectFileContent);
$this->smartFileSystem->dumpFile($incorrectClassNameFile, $newContent);
}
}

View File

@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\ProjectValidator\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Finder;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\SmartFileSystem\Finder\FinderSanitizer;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ValidateFixtureFilenameCommand extends Command
{
/**
* @var FinderSanitizer
*/
private $finderSanitizer;
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
public function __construct(FinderSanitizer $finderSanitizer, SymfonyStyle $symfonyStyle)
{
$this->finderSanitizer = $finderSanitizer;
$this->symfonyStyle = $symfonyStyle;
parent::__construct();
}
protected function configure(): void
{
$this->setDescription('[CI] Validate tests fixtures file name');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$invalidFilePaths = [];
foreach ($this->getInvalidFixtureFileInfos() as $invalidFixtureFileInfo) {
$invalidFilePaths[] = $invalidFixtureFileInfo->getRelativeFilePathFromCwd();
}
if ($invalidFilePaths !== []) {
$this->symfonyStyle->listing($invalidFilePaths);
$message = sprintf('Found %d files with - character. Must use _', count($invalidFilePaths));
$this->symfonyStyle->error($message);
return ShellCode::ERROR;
}
$this->symfonyStyle->success('All fixtures are correct');
return ShellCode::SUCCESS;
}
/**
* @return SmartFileInfo[]
*/
private function getInvalidFixtureFileInfos(): array
{
$finder = new Finder();
$finder = $finder->files()
->name('#(?<=-)[^\/]*\.php\.inc$#')
->path('#/Fixture/#')
->in(__DIR__ . '/../../../../tests')
->in(__DIR__ . '/../../../../packages-tests')
->in(__DIR__ . '/../../../../rules-tests');
return $this->finderSanitizer->sanitize($finder);
}
}

View File

@ -1,169 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\ProjectValidator\Command;
use Nette\Utils\Strings;
use Rector\Core\Configuration\Option;
use Rector\Utils\ProjectValidator\Finder\FixtureFinder;
use Rector\Utils\ProjectValidator\Naming\ExpectedNameResolver;
use Rector\Utils\ProjectValidator\Naming\NamespaceMatcher;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\SmartFileSystem\SmartFileSystem;
final class ValidateFixtureNamespaceCommand extends Command
{
/**
* @var string
* @see https://regex101.com/r/5KtBi8/2
*/
private const NAMESPACE_REGEX = '#^namespace (.*);$#msU';
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
/**
* @var string
*/
private $currentDirectory;
/**
* @var SmartFileSystem
*/
private $smartFileSystem;
/**
* @var FixtureFinder
*/
private $fixtureFinder;
/**
* @var NamespaceMatcher
*/
private $namespaceMatcher;
/**
* @var ExpectedNameResolver
*/
private $expectedNameResolver;
public function __construct(
SymfonyStyle $symfonyStyle,
SmartFileSystem $smartFileSystem,
FixtureFinder $fixtureFinder,
NamespaceMatcher $namespaceMatcher,
ExpectedNameResolver $expectedNameResolver
) {
parent::__construct();
$this->symfonyStyle = $symfonyStyle;
$this->currentDirectory = getcwd();
$this->smartFileSystem = $smartFileSystem;
$this->fixtureFinder = $fixtureFinder;
$this->namespaceMatcher = $namespaceMatcher;
$this->expectedNameResolver = $expectedNameResolver;
}
protected function configure(): void
{
$this->addOption(Option::FIX, null, null, 'Fix found violations.');
$this->setDescription('[CI] Validate tests fixtures namespace');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$optionFix = $input->getOption(Option::FIX);
$fixtureFileInfos = $this->fixtureFinder->findFixtureFileInfos();
$incorrectNamespaceFiles = [];
foreach ($fixtureFileInfos as $fixtureFile) {
// 1. geting expected namespace ...
$paths = explode('/tests/', (string) $fixtureFile);
if (count($paths) > 2) {
continue;
}
$path = ltrim(Strings::substring($paths[0], strlen($this->currentDirectory)) . '/tests', '/');
$expectedNamespace = $this->expectedNameResolver->resolve($path, $paths[1]);
if ($expectedNamespace === null) {
continue;
}
// 2. reading file contents
$fileContent = $this->smartFileSystem->readFile((string) $fixtureFile);
$matchAll = Strings::matchAll($fileContent, self::NAMESPACE_REGEX);
if ($this->namespaceMatcher->isFoundCorrectNamespace($matchAll, $expectedNamespace)) {
continue;
}
// 3. collect files with incorrect namespace
$incorrectNamespaceFiles[] = (string) $fixtureFile;
$incorrectNamespace = $this->getIncorrectNamespace($matchAll, $expectedNamespace);
if ($optionFix) {
$this->fixNamespace((string) $fixtureFile, $incorrectNamespace, $fileContent, $expectedNamespace);
}
}
if ($incorrectNamespaceFiles !== []) {
$this->symfonyStyle->listing($incorrectNamespaceFiles);
$message = sprintf(
'Found %d fixture files with invalid namespace which not follow psr-4 defined in composer.json',
count($incorrectNamespaceFiles)
);
if (! $optionFix) {
$message .= '. Just add "--fix" to console command and rerun to apply.';
$this->symfonyStyle->error($message);
return ShellCode::ERROR;
}
$this->symfonyStyle->success($message . ' and all fixtures are corrected', );
return ShellCode::SUCCESS;
}
$this->symfonyStyle->success('All fixtures are correct');
return ShellCode::SUCCESS;
}
/**
* @param array<int, array<int, string>> $matchAll
*/
private function getIncorrectNamespace(array $matchAll, string $expectedNamespace): string
{
$countMatchAll = count($matchAll);
if ($countMatchAll === 1) {
return $matchAll[0][1];
}
return $matchAll[0][1] !== $expectedNamespace
? $matchAll[0][1]
: $matchAll[1][1];
}
private function fixNamespace(
string $incorrectNamespaceFile,
string $incorrectNamespace,
string $incorrectFileContent,
string $expectedNamespace
): void {
$newContent = str_replace(
'namespace ' . $incorrectNamespace,
'namespace ' . $expectedNamespace,
$incorrectFileContent
);
$this->smartFileSystem->dumpFile($incorrectNamespaceFile, $newContent);
}
}

View File

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\ProjectValidator\Finder;
use Symfony\Component\Finder\Finder;
use Symplify\SmartFileSystem\Finder\FinderSanitizer;
use Symplify\SmartFileSystem\SmartFileInfo;
final class FixtureFinder
{
/**
* @var FinderSanitizer
*/
private $finderSanitizer;
public function __construct(FinderSanitizer $finderSanitizer)
{
$this->finderSanitizer = $finderSanitizer;
}
/**
* @return SmartFileInfo[]
*/
public function findFixtureFileInfos(): array
{
$finder = new Finder();
$finder = $finder->files()
->name('#\.php\.inc$#')
->notName('#empty_file\.php\.inc$#')
->path('#/Fixture(Php\d+)?/#')
->notPath('#/blade-template/#')
->notPath('#/Name/RenameClassRector/#')
->notPath('#/Namespace_/RenameNamespaceRector/#')
->notPath('#/TemplateAnnotationToThisRenderRector/#')
->notPath('#/ParamTypeDeclarationRector/#')
->notPath('#/ReturnTypeDeclarationRector/#')
->notPath('#/PhpSpecToPHPUnitRector/#')
->notPath('#/FileWithoutNamespace/PseudoNamespaceToNamespaceRector/Fixture/fixture3\.php\.inc$#')
->notPath('#/SwapClassMethodArgumentsRector/Fixture/fixture\.php\.inc$#')
->notPath('#bootstrap_names\.php\.inc$#')
->notPath('#keep_anonymous_classes\.php\.inc$#')
->notPath('#skip_different_order\.php\.inc$#')
->notPath('#extended_parent\.php\.inc$#')
->notPath('#trait_name\.php\.inc$#')
->notPath('#normalize_file\.php\.inc$#')
->notPath('#wrong_namespace\.php\.inc$#')
->notPath('#stringy_calls\.php\.inc$#')
->notPath('#delegating(_\d)?\.php\.inc$#')
->notPath('#keep_annotated\.php\.inc$#')
->notPath('#double_same_variable\.php\.inc$#')
->notName('#_\.php\.inc$#')
->notName('#Fixture/without_namespace.php.inc$#')
->in(__DIR__ . '/../../../../tests')
->in(__DIR__ . '/../../../../packages')
->in(__DIR__ . '/../../../../rules');
return $this->finderSanitizer->sanitize($finder);
}
}

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\ProjectValidator\Naming;
use Rector\PSR4\Composer\PSR4AutoloadPathsProvider;
final class ExpectedNameResolver
{
/**
* @var array<string, string|string[]>
*/
private $psr4autoloadPaths = [];
public function __construct(PSR4AutoloadPathsProvider $psr4AutoloadPathsProvider)
{
$this->psr4autoloadPaths = $psr4AutoloadPathsProvider->provide();
}
public function resolve(string $path, string $relativePath): ?string
{
$directory = dirname($relativePath, PATHINFO_DIRNAME);
$relativePath = str_replace('/', '\\', $directory);
foreach ($this->psr4autoloadPaths as $prefix => $psr4autoloadPath) {
if (! is_string($psr4autoloadPath)) {
continue;
}
if ($psr4autoloadPath === $path) {
return $prefix . $relativePath;
}
}
return null;
}
}

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\ProjectValidator\Naming;
final class NamespaceMatcher
{
/**
* @param array<int, array<int, string>> $matchAll
*/
public function isFoundCorrectNamespace(array $matchAll, string $expectedNamespace): bool
{
if ($matchAll === []) {
return true;
}
$countMatchAll = count($matchAll);
if ($countMatchAll === 1 && $matchAll[0][1] === $expectedNamespace) {
return true;
}
if ($countMatchAll !== 2) {
return false;
}
if ($matchAll[0][1] !== $expectedNamespace) {
return false;
}
return $matchAll[1][1] === $expectedNamespace;
}
}