Skip to content

Commit 3c433f9

Browse files
[dx] add test to check that a rule is not applied if it does not change the code
1 parent f5edbf5 commit 3c433f9

File tree

10 files changed

+125
-8
lines changed

10 files changed

+125
-8
lines changed

src/Application/FileProcessor.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ public function processFile(File $file, Configuration $configuration): FileProce
8585
// when changed, set final status changed to true
8686
// to ensure it make sense to verify in next process when needed
8787
$file->changeHasChanged(true);
88+
}
8889

90+
$rectorWithLineChanges = $file->getRectorWithLineChanges();
91+
if ($file->hasChanged() || $rectorWithLineChanges !== []) {
8992
$currentFileDiff = $this->fileDiffFactory->createFileDiffWithLineChanges(
9093
$configuration->shouldShowDiffs(),
9194
$file,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Exception\Configuration;
6+
7+
use Exception;
8+
9+
final class RectorRuleShouldNotBeAppliedException extends Exception
10+
{
11+
}

src/Testing/PHPUnit/AbstractRectorTestCase.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Rector\Contract\DependencyInjection\ResetableInterface;
1919
use Rector\Contract\Rector\RectorInterface;
2020
use Rector\DependencyInjection\Laravel\ContainerMemento;
21+
use Rector\Exception\Configuration\RectorRuleShouldNotBeAppliedException;
2122
use Rector\Exception\ShouldNotHappenException;
2223
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
2324
use Rector\PhpParser\NodeTraverser\RectorNodeTraverser;
@@ -207,18 +208,22 @@ private function doTestFileMatchesExpectedContent(
207208
$changedContents = $rectorTestResult->getChangedContents();
208209

209210
$fixtureFilename = basename($fixtureFilePath);
210-
$failureMessage = sprintf('Failed on fixture file "%s"', $fixtureFilename);
211+
$fixtureNameMessage = sprintf('Failed on fixture file "%s"', $fixtureFilename);
211212

213+
$failureMessage = $fixtureNameMessage;
214+
$numAppliedRectorClasses = count($rectorTestResult->getAppliedRectorClasses());
212215
// give more context about used rules in case of set testing
213-
if (count($rectorTestResult->getAppliedRectorClasses()) > 1) {
214-
$failureMessage .= PHP_EOL . PHP_EOL;
215-
$failureMessage .= 'Applied Rector rules:' . PHP_EOL;
216-
216+
$appliedRulesList = '';
217+
if ($numAppliedRectorClasses > 0) {
217218
foreach ($rectorTestResult->getAppliedRectorClasses() as $appliedRectorClass) {
218-
$failureMessage .= ' * ' . $appliedRectorClass . PHP_EOL;
219+
$appliedRulesList .= ' * ' . $appliedRectorClass . PHP_EOL;
219220
}
220221
}
221222

223+
if ($numAppliedRectorClasses > 1) {
224+
$failureMessage .= PHP_EOL . PHP_EOL . 'Applied Rector rules:' . PHP_EOL . $appliedRulesList;
225+
}
226+
222227
try {
223228
$this->assertSame($expectedFileContents, $changedContents, $failureMessage);
224229
} catch (ExpectationFailedException) {
@@ -227,6 +232,12 @@ private function doTestFileMatchesExpectedContent(
227232
// if not exact match, check the regex version (useful for generated hashes/uuids in the code)
228233
$this->assertStringMatchesFormat($expectedFileContents, $changedContents, $failureMessage);
229234
}
235+
236+
if ($inputFileContents === $expectedFileContents && $numAppliedRectorClasses > 0) {
237+
$failureMessage = $fixtureNameMessage . PHP_EOL . PHP_EOL
238+
. 'File not changed but some Rector rules applied:' . PHP_EOL . $appliedRulesList;
239+
throw new RectorRuleShouldNotBeAppliedException($failureMessage);
240+
}
230241
}
231242

232243
private function processFilePath(string $filePath): RectorTestResult

src/Testing/PHPUnit/ValueObject/RectorTestResult.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function getAppliedRectorClasses(): array
3030
{
3131
$rectorClasses = [];
3232

33-
foreach ($this->processResult->getFileDiffs() as $fileDiff) {
33+
foreach ($this->processResult->getFileDiffs(false) as $fileDiff) {
3434
$rectorClasses = array_merge($rectorClasses, $fileDiff->getRectorClasses());
3535
}
3636

src/ValueObject/ProcessResult.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ public function getSystemErrors(): array
3333
/**
3434
* @return FileDiff[]
3535
*/
36-
public function getFileDiffs(): array
36+
public function getFileDiffs(bool $onlyWithChanges = true): array
3737
{
38+
if ($onlyWithChanges) {
39+
return array_filter($this->fileDiffs, fn (FileDiff $fileDiff): bool => $fileDiff->getDiff() !== '');
40+
}
41+
3842
return $this->fileDiffs;
3943
}
4044

tests/Issues/ScopeNotAvailable/ForeachValueScopeTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66

77
use Iterator;
88
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Exception\Configuration\RectorRuleShouldNotBeAppliedException;
910
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
1011

1112
final class ForeachValueScopeTest extends AbstractRectorTestCase
1213
{
1314
#[DataProvider('provideData')]
1415
public function test(string $filePath): void
1516
{
17+
$this->expectException(RectorRuleShouldNotBeAppliedException::class);
1618
$this->doTestFile($filePath);
1719
}
1820

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Testing\RectorRuleShouldNotBeApplied;
6+
7+
class NoChange
8+
{
9+
}
10+
11+
?>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Testing\RectorRuleShouldNotBeApplied;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Exception\Configuration\RectorRuleShouldNotBeAppliedException;
10+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
11+
12+
final class RectorRuleShouldNotBeAppliedTest extends AbstractRectorTestCase
13+
{
14+
#[DataProvider('provideData')]
15+
public function test(string $filePath): void
16+
{
17+
$this->expectException(RectorRuleShouldNotBeAppliedException::class);
18+
$this->expectExceptionMessage(
19+
'Failed on fixture file "no_change.php.inc"' . PHP_EOL . PHP_EOL
20+
. 'File not changed but some Rector rules applied:' . PHP_EOL
21+
. ' * Rector\Tests\Testing\RectorRuleShouldNotBeApplied\Source\NoChangeRector'
22+
);
23+
24+
$this->doTestFile($filePath);
25+
}
26+
27+
public static function provideData(): Iterator
28+
{
29+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
30+
}
31+
32+
public function provideConfigFilePath(): string
33+
{
34+
return __DIR__ . '/config/configured_rule.php';
35+
}
36+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Testing\RectorRuleShouldNotBeApplied\Source;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Stmt\Class_;
9+
use Rector\Rector\AbstractRector;
10+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
11+
12+
final class NoChangeRector extends AbstractRector
13+
{
14+
public function getRuleDefinition(): RuleDefinition
15+
{
16+
return new RuleDefinition('no change', []);
17+
}
18+
19+
public function getNodeTypes(): array
20+
{
21+
return [
22+
Class_::class,
23+
];
24+
}
25+
26+
public function refactor(Node $node)
27+
{
28+
return $node;
29+
}
30+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Tests\Testing\RectorRuleShouldNotBeApplied\Source\NoChangeRector;
7+
8+
return RectorConfig::configure()
9+
->withRules([NoChangeRector::class]);

0 commit comments

Comments
 (0)