Skip to content

Commit d864c2a

Browse files
authored
[CodeQuality] Add AssertClassToThisAssertRector (#707)
* [CodeQuality] Add AssertClassToThisAssertRector * remove rule from code-quality set
1 parent 3591920 commit d864c2a

9 files changed

Lines changed: 272 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class AssertClassToThisAssertRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
4+
5+
use PHPUnit\Framework\Assert;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class BasicTest extends TestCase
9+
{
10+
public function testMe()
11+
{
12+
Assert::assertSame(1, 1);
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
21+
22+
use PHPUnit\Framework\Assert;
23+
use PHPUnit\Framework\TestCase;
24+
25+
final class BasicTest extends TestCase
26+
{
27+
public function testMe()
28+
{
29+
$this->assertSame(1, 1);
30+
}
31+
}
32+
33+
?>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class FullyQualifiedTest extends TestCase
8+
{
9+
public function testMe()
10+
{
11+
\PHPUnit\Framework\Assert::assertEquals('expected', $result);
12+
}
13+
}
14+
15+
?>
16+
-----
17+
<?php
18+
19+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
20+
21+
use PHPUnit\Framework\TestCase;
22+
23+
final class FullyQualifiedTest extends TestCase
24+
{
25+
public function testMe()
26+
{
27+
$this->assertEquals('expected', $result);
28+
}
29+
}
30+
31+
?>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
4+
5+
use PHPUnit\Framework\Assert;
6+
7+
final class SkipNonTestClass
8+
{
9+
public function run()
10+
{
11+
Assert::assertSame(1, 1);
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class SkipSelfCall extends TestCase
8+
{
9+
public function testMe()
10+
{
11+
self::assertSame(1, 1);
12+
}
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
4+
5+
use PHPUnit\Framework\Assert;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class SkipStaticClosure extends TestCase
9+
{
10+
public function testMe()
11+
{
12+
static fn() => Assert::assertSame(1, 1);
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\Fixture;
4+
5+
use PHPUnit\Framework\Assert;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class SkipStaticMethod extends TestCase
9+
{
10+
public static function testMe()
11+
{
12+
Assert::assertSame(1, 1);
13+
}
14+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\PHPUnit\CodeQuality\Rector\Class_\AssertClassToThisAssertRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(AssertClassToThisAssertRector::class);
10+
};
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\CodeQuality\Rector\Class_;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\ArrowFunction;
9+
use PhpParser\Node\Expr\Closure;
10+
use PhpParser\Node\Expr\MethodCall;
11+
use PhpParser\Node\Expr\StaticCall;
12+
use PhpParser\Node\Stmt\Class_;
13+
use PhpParser\Node\Stmt\ClassMethod;
14+
use PhpParser\NodeVisitor;
15+
use Rector\PHPUnit\Enum\PHPUnitClassName;
16+
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
17+
use Rector\Rector\AbstractRector;
18+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
19+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
20+
21+
/**
22+
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\AssertClassToThisAssertRector\AssertClassToThisAssertRectorTest
23+
*/
24+
final class AssertClassToThisAssertRector extends AbstractRector
25+
{
26+
public function __construct(
27+
private readonly TestsNodeAnalyzer $testsNodeAnalyzer
28+
) {
29+
}
30+
31+
public function getRuleDefinition(): RuleDefinition
32+
{
33+
return new RuleDefinition('Changes PHPUnit calls from Assert::assert*() to $this->assert*()', [
34+
new CodeSample(
35+
<<<'CODE_SAMPLE'
36+
use PHPUnit\Framework\Assert;
37+
use PHPUnit\Framework\TestCase;
38+
39+
final class SomeClass extends TestCase
40+
{
41+
public function run()
42+
{
43+
Assert::assertEquals('expected', $result);
44+
}
45+
}
46+
CODE_SAMPLE
47+
,
48+
<<<'CODE_SAMPLE'
49+
use PHPUnit\Framework\Assert;
50+
use PHPUnit\Framework\TestCase;
51+
52+
final class SomeClass extends TestCase
53+
{
54+
public function run()
55+
{
56+
$this->assertEquals('expected', $result);
57+
}
58+
}
59+
CODE_SAMPLE
60+
),
61+
]);
62+
}
63+
64+
/**
65+
* @return array<class-string<Node>>
66+
*/
67+
public function getNodeTypes(): array
68+
{
69+
return [Class_::class];
70+
}
71+
72+
/**
73+
* @param Class_ $node
74+
*/
75+
public function refactor(Node $node): ?Node
76+
{
77+
if (! $this->testsNodeAnalyzer->isInTestClass($node)) {
78+
return null;
79+
}
80+
81+
$hasChanged = false;
82+
83+
$this->traverseNodesWithCallable($node, function (Node $node) use (&$hasChanged): int|null|MethodCall {
84+
$isInsideStaticFunctionLike = ($node instanceof ClassMethod && $node->isStatic()) || (($node instanceof Closure || $node instanceof ArrowFunction) && $node->static);
85+
if ($isInsideStaticFunctionLike) {
86+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
87+
}
88+
89+
if (! $node instanceof StaticCall) {
90+
return null;
91+
}
92+
93+
if ($node->isFirstClassCallable()) {
94+
return null;
95+
}
96+
97+
if (! $this->isName($node->class, PHPUnitClassName::ASSERT)) {
98+
return null;
99+
}
100+
101+
$methodName = $this->getName($node->name);
102+
if ($methodName === null) {
103+
return null;
104+
}
105+
106+
$hasChanged = true;
107+
return $this->nodeFactory->createMethodCall('this', $methodName, $node->getArgs());
108+
});
109+
110+
if ($hasChanged) {
111+
return $node;
112+
}
113+
114+
return null;
115+
}
116+
}

0 commit comments

Comments
 (0)