Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ Better use a one definition with single pattern, to make your tests more precise

<br>

### 2. Find duplicated masks (`duplicated-masks`)
### 2. Find duplicated patterns (`duplicated-patterns`)

Same as services, there should be unique definition masks:
Same as services, there should be unique definition patterns:

```php
use Behat\Step\When;
Expand Down
46 changes: 23 additions & 23 deletions src/DefinitionPatternsExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ public function __construct(
*/
public function extract(array $contextFiles): PatternCollection
{
$masks = [];
$patterns = [];

$classMethodContextDefinitions = $this->resolveMasksFromFiles($contextFiles);
$classMethodContextDefinitions = $this->resolvePatternsFromFiles($contextFiles);

foreach ($classMethodContextDefinitions as $classMethodContextDefinition) {
$rawMask = $classMethodContextDefinition->getMask();
$rawPattern = $classMethodContextDefinition->getPattern();

// @todo edge case - handle next
if (str_contains($rawMask, ' [:')) {
$masks[] = new SkippedPattern(
$rawMask,
if (str_contains($rawPattern, ' [:')) {
$patterns[] = new SkippedPattern(
$rawPattern,
$classMethodContextDefinition->getFilePath(),
$classMethodContextDefinition->getMethodLine(),
$classMethodContextDefinition->getClass(),
Expand All @@ -55,9 +55,9 @@ public function extract(array $contextFiles): PatternCollection
}

// regex pattern, handled else-where
if (PatternAnalyzer::isRegex($rawMask)) {
$masks[] = new RegexPattern(
$rawMask,
if (PatternAnalyzer::isRegex($rawPattern)) {
$patterns[] = new RegexPattern(
$rawPattern,
$classMethodContextDefinition->getFilePath(),
$classMethodContextDefinition->getMethodLine(),
$classMethodContextDefinition->getClass(),
Expand All @@ -66,11 +66,11 @@ public function extract(array $contextFiles): PatternCollection
continue;
}

// handled in mask one
if (PatternAnalyzer::isValuePattern($rawMask)) {
// if (str_contains($rawMask, ':')) {
$masks[] = new NamedPattern(
$rawMask,
// handled in pattern one
if (PatternAnalyzer::isValuePattern($rawPattern)) {
// if (str_contains($rawPattern, ':')) {
$patterns[] = new NamedPattern(
$rawPattern,
$classMethodContextDefinition->getFilePath(),
$classMethodContextDefinition->getMethodLine(),
$classMethodContextDefinition->getClass(),
Expand All @@ -79,26 +79,26 @@ public function extract(array $contextFiles): PatternCollection
continue;
}

// remove \/ escape from mask
$rawMask = str_replace('\/', '/', $rawMask);
// remove \/ escape from pattern
$rawPattern = str_replace('\/', '/', $rawPattern);

$masks[] = new ExactPattern(
$rawMask,
$patterns[] = new ExactPattern(
$rawPattern,
$classMethodContextDefinition->getFilePath(),
$classMethodContextDefinition->getMethodLine(),
$classMethodContextDefinition->getClass(),
$classMethodContextDefinition->getMethodName()
);
}

return new PatternCollection($masks);
return new PatternCollection($patterns);
}

/**
* @param SplFileInfo[] $fileInfos
* @return ContextDefinition[]
*/
private function resolveMasksFromFiles(array $fileInfos): array
private function resolvePatternsFromFiles(array $fileInfos): array
{
$classMethodContextDefinitions = [];

Expand All @@ -123,14 +123,14 @@ private function resolveMasksFromFiles(array $fileInfos): array
$className = $class->namespacedName->toString();

foreach ($class->getMethods() as $classMethod) {
$rawMasks = $this->classMethodPatternResolver->resolve($classMethod);
$rawPatterns = $this->classMethodPatternResolver->resolve($classMethod);

foreach ($rawMasks as $rawMask) {
foreach ($rawPatterns as $rawPattern) {
$classMethodContextDefinitions[] = new ContextDefinition(
$fileInfo->getRealPath(),
$className,
$classMethod->name->toString(),
$rawMask,
$rawPattern,
$classMethod->getStartLine()
);
}
Expand Down
18 changes: 9 additions & 9 deletions src/Reporting/PatternCollectionStatsPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,27 @@ public function print(PatternCollection $patternCollection): void
$this->outputPrinter->writeln(sprintf(' * %d /regex/', $patternCollection->countByType(RegexPattern::class)));
$this->outputPrinter->writeln(sprintf(' * %d :named', $patternCollection->countByType(NamedPattern::class)));

$this->printSkippedMasks($patternCollection);
$this->printSkippedPatterns($patternCollection);
}

private function printSkippedMasks(PatternCollection $patternCollection): void
private function printSkippedPatterns(PatternCollection $patternCollection): void
{
$skippedMasks = $patternCollection->byType(SkippedPattern::class);
if ($skippedMasks === []) {
$skippedPatterns = $patternCollection->byType(SkippedPattern::class);
if ($skippedPatterns === []) {
return;
}

$skippedMasksValues = [];
foreach ($skippedMasks as $skippedMask) {
$skippedMasksValues[] = $skippedMask->pattern;
$skippedPatternsValues = [];
foreach ($skippedPatterns as $skippedPattern) {
$skippedPatternsValues[] = $skippedPattern->pattern;
}

$skippedMasksString = implode('", "', $skippedMasksValues);
$skippedPatternsString = implode('", "', $skippedPatternsValues);

$this->outputPrinter->writeln(sprintf(
' * %d skipped ("%s")',
$patternCollection->countByType(SkippedPattern::class),
$skippedMasksString
$skippedPatternsString
));
}
}
12 changes: 6 additions & 6 deletions src/Resolver/ClassMethodPatternResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function resolve(ClassMethod $classMethod): array
preg_match_all(self::INSTRUCTION_DOCBLOCK_REGEX, $classMethod->getDocComment()->getText(), $match);

foreach ($match['instruction'] as $instruction) {
$rawPatterns[] = $this->clearMask($instruction);
$rawPatterns[] = $this->clearPattern($instruction);
}
}

Expand All @@ -53,12 +53,12 @@ public function resolve(ClassMethod $classMethod): array
return $rawPatterns;
}

private function clearMask(string $mask): string
private function clearPattern(string $pattern): string
{
$mask = trim($mask);
$pattern = trim($pattern);

// clear extra quote escaping that would cause miss-match with feature masks
$mask = str_replace('\\\'', "'", $mask);
return str_replace('\\/', '/', $mask);
// clear extra quote escaping that would cause miss-match with feature patterns
$pattern = str_replace('\\\'', "'", $pattern);
return str_replace('\\/', '/', $pattern);
}
}
8 changes: 4 additions & 4 deletions src/Rule/DuplicatedContextDefinitionContentsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ public function process(
$duplicatedContextDefinitionByContentsHash = $this->filterOutNotDuplicated($contextDefinitionByContentHash);

foreach ($duplicatedContextDefinitionByContentsHash as $duplicatedContextDefinition) {
$maskStrings = '';
$patternStrings = '';
$lineFilePaths = [];
foreach ($duplicatedContextDefinition as $contextDefinition) {
$maskStrings .= ' * ' . $contextDefinition->getMask() . "\n";
$patternStrings .= ' * ' . $contextDefinition->getPattern() . "\n";
$lineFilePaths[] = $contextDefinition->getFilePath() . ':' . $contextDefinition->getMethodLine();
}

// standardize order
sort($lineFilePaths);

$errorMessage = sprintf(
'These %d definitions have different masks, but same method body: %s%s',
'These %d definitions have different patterns, but same method body: %s%s',
count($duplicatedContextDefinition),
PHP_EOL,
$maskStrings
$patternStrings
);

$ruleErrors[] = new RuleError($errorMessage, $lineFilePaths, $this->getIdentifier());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use Rector\Behastan\ValueObject\RuleError;
use Symfony\Component\Finder\SplFileInfo;

final readonly class DuplicatedMaskRule implements RuleInterface
final readonly class DuplicatedPatternRule implements RuleInterface
{
public function __construct(
private ContextDefinitionsAnalyzer $classMethodContextDefinitionsAnalyzer
Expand All @@ -30,17 +30,17 @@ public function process(
PatternCollection $patternCollection,
string $projectDirectory
): array {
// 1. find duplicated masks, e.g. if 2 methods have the same mask, its a race condition problem
// 1. find duplicated patterns, e.g. if 2 methods have the same pattern, its a race condition problem
$classMethodContextDefinitions = $this->classMethodContextDefinitionsAnalyzer->resolve($contextFiles);

$groupedByMask = [];
$groupedByPattern = [];
foreach ($classMethodContextDefinitions as $classMethodContextDefinition) {
$groupedByMask[$classMethodContextDefinition->getMask()][] = $classMethodContextDefinition;
$groupedByPattern[$classMethodContextDefinition->getPattern()][] = $classMethodContextDefinition;
}

$ruleErrors = [];

foreach ($groupedByMask as $mask => $sameMaksClassMethodContextDefinitions) {
foreach ($groupedByPattern as $pattern => $sameMaksClassMethodContextDefinitions) {
/** @var ContextDefinition[] $sameMaksClassMethodContextDefinitions */
if (count($sameMaksClassMethodContextDefinitions) === 1) {
continue;
Expand All @@ -52,8 +52,8 @@ public function process(
}

$ruleErrors[] = new RuleError(sprintf(
'Duplicated mask "%s"',
$mask
'Duplicated pattern "%s"',
$pattern
), $lineFilePaths, $this->getIdentifier());
}

Expand Down
14 changes: 7 additions & 7 deletions src/Rule/UnusedContextDefinitionsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ public function process(
PatternCollection $patternCollection,
string $projectDirectory
): array {
$unusedMasks = $this->unusedDefinitionsAnalyzer->analyse($contextFiles, $featureFiles, $patternCollection);
$unusedPatterns = $this->unusedDefinitionsAnalyzer->analyse($contextFiles, $featureFiles, $patternCollection);

$ruleErrors = [];

foreach ($unusedMasks as $unusedMask) {
foreach ($unusedPatterns as $unusedPattern) {
$errorMessage = sprintf(
'The mask "%s" and its definition %s::%s() is never used',
$unusedMask->pattern,
$unusedMask->className,
$unusedMask->methodName
'The pattern "%s" and its definition %s::%s() is never used',
$unusedPattern->pattern,
$unusedPattern->className,
$unusedPattern->methodName
);

$ruleErrors[] = new RuleError(
$errorMessage,
[$unusedMask->filePath . ':' . $unusedMask->line],
[$unusedPattern->filePath . ':' . $unusedPattern->line],
$this->getIdentifier()
);
}
Expand Down
8 changes: 4 additions & 4 deletions src/ValueObject/ContextDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public function __construct(
private readonly string $filePath,
private readonly string $class,
private readonly string $methodName,
private readonly string $mask,
private readonly string $pattern,
private readonly int $methodLine
) {
}
Expand All @@ -32,9 +32,9 @@ public function getMethodName(): string
return $this->methodName;
}

public function getMask(): string
public function getPattern(): string
{
return $this->mask;
return $this->pattern;
}

public function getMethodLine(): int
Expand All @@ -49,7 +49,7 @@ public function recordUsage(array $featureInstructions): void
{
$usageCount = 0;
foreach ($featureInstructions as $featureInstruction) {
if ($this->mask === $featureInstruction) {
if ($this->pattern === $featureInstruction) {
++$usageCount;
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/ValueObject/PatternCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
final readonly class PatternCollection
{
/**
* @param AbstractPattern[] $masks
* @param AbstractPattern[] $patterns
*/
public function __construct(
private array $masks
private array $patterns
) {
}

Expand All @@ -21,31 +21,31 @@ public function __construct(
*/
public function countByType(string $type): int
{
$masksByType = $this->byType($type);
return count($masksByType);
$patternsByType = $this->byType($type);
return count($patternsByType);
}

public function count(): int
{
return count($this->masks);
return count($this->patterns);
}

/**
* @return AbstractPattern[]
*/
public function all(): array
{
return $this->masks;
return $this->patterns;
}

/**
* @template TMask as AbstractPattern
* @template TPattern as AbstractPattern
*
* @param class-string<TMask> $type
* @return TMask[]
* @param class-string<TPattern> $type
* @return TPattern[]
*/
public function byType(string $type): array
{
return array_filter($this->masks, fn (AbstractPattern $pattern): bool => $pattern instanceof $type);
return array_filter($this->patterns, fn (AbstractPattern $pattern): bool => $pattern instanceof $type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\Behastan\Tests\Analyzer\UnusedDefinitionsAnalyzer\Fixture\UnusedMasks;
namespace Rector\Behastan\Tests\Analyzer\UnusedDefinitionsAnalyzer\Fixture\UnusedPattern;

final class BehatContext
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ public function testFoundPattern(): void

$patternCollection = $this->definitionPatternsExtractor->extract($contextFiles);

$unusedMasks = $this->unusedDefinitionsAnalyzer->analyse($contextFiles, $featureFiles, $patternCollection);
$unusedPatterns = $this->unusedDefinitionsAnalyzer->analyse($contextFiles, $featureFiles, $patternCollection);

$this->assertCount(1, $unusedMasks);
$this->assertContainsOnlyInstancesOf(AbstractPattern::class, $unusedMasks);
$this->assertCount(1, $unusedPatterns);
$this->assertContainsOnlyInstancesOf(AbstractPattern::class, $unusedPatterns);

/** @var AbstractPattern $unusedMask */
$unusedMask = $unusedMasks[0];
$this->assertSame(__DIR__ . '/Fixture/UnusedPattern/BehatContext.php', $unusedMask->filePath);
$this->assertSame('never used', $unusedMask->pattern);
/** @var AbstractPattern $unusedPattern */
$unusedPattern = $unusedPatterns[0];
$this->assertSame(__DIR__ . '/Fixture/UnusedPattern/BehatContext.php', $unusedPattern->filePath);
$this->assertSame('never used', $unusedPattern->pattern);
}
}
Loading