Skip to content

Commit 45b0f6b

Browse files
authored
Adds AssertCountWithZeroToAssertEmptyRector rule (#456)
* Adds AssertCountWithZeroToAssertEmptyRector rule * Added test * correct test * Adds rule to code quality set
1 parent 03e2418 commit 45b0f6b

File tree

9 files changed

+226
-0
lines changed

9 files changed

+226
-0
lines changed

config/sets/phpunit-code-quality.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Rector\PHPUnit\CodeQuality\Rector\Foreach_\SimplifyForeachInstanceOfRector;
1616
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertCompareOnCountableWithMethodToAssertCountRector;
1717
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertComparisonToSpecificMethodRector;
18+
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector;
1819
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertEmptyNullableObjectToAssertInstanceofRector;
1920
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertEqualsOrAssertSameFloatParameterToSpecificMethodsTypeRector;
2021
use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertEqualsToSameRector;
@@ -72,6 +73,7 @@
7273
UseSpecificWillMethodRector::class,
7374
UseSpecificWithMethodRector::class,
7475
AssertEmptyNullableObjectToAssertInstanceofRector::class,
76+
AssertCountWithZeroToAssertEmptyRector::class,
7577

7678
/**
7779
* Improve direct testing of your code, without mock creep. Make it simple, clear and easy to maintain:
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\MethodCall\AssertCountWithZeroToAssertEmptyRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class AssertCountWithZeroToAssertEmptyRectorTest 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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Fixture;
4+
5+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Source\Collection;
6+
7+
final class CountToEmpty extends \PHPUnit\Framework\TestCase
8+
{
9+
public function test()
10+
{
11+
$collection = new Collection();
12+
$this->assertCount(0, $collection);
13+
$this->assertCount(0, $collection, 'message here!');
14+
$this->assertNotCount(0, $collection);
15+
$this->assertNotCount(0, $collection, 'message here!');
16+
}
17+
}
18+
19+
?>
20+
-----
21+
<?php
22+
23+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Fixture;
24+
25+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Source\Collection;
26+
27+
final class CountToEmpty extends \PHPUnit\Framework\TestCase
28+
{
29+
public function test()
30+
{
31+
$collection = new Collection();
32+
$this->assertEmpty($collection);
33+
$this->assertEmpty($collection, 'message here!');
34+
$this->assertNotEmpty($collection);
35+
$this->assertNotEmpty($collection, 'message here!');
36+
}
37+
}
38+
39+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Fixture;
4+
5+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Source\Collection;
6+
7+
final class SkipOnFirstClassCallable extends \PHPUnit\Framework\TestCase
8+
{
9+
public function test()
10+
{
11+
$collection = new Collection();
12+
$this->assertCount(...);
13+
}
14+
}
15+
16+
?>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Fixture;
4+
5+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Source\Collection;
6+
7+
final class SkipOnNonTestClass
8+
{
9+
public function test()
10+
{
11+
$collection = new Collection();
12+
$this->assertCount(0, $collection);
13+
}
14+
}
15+
16+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Fixture;
4+
5+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Source\Collection;
6+
7+
final class SkipOnNonZeroArgument extends \PHPUnit\Framework\TestCase
8+
{
9+
public function test()
10+
{
11+
$collection = new Collection();
12+
$this->assertCount(5, $collection);
13+
}
14+
}
15+
16+
?>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\Source;
4+
5+
class Collection implements \Countable
6+
{
7+
public function count(): int
8+
{
9+
return 0;
10+
}
11+
}
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\MethodCall\AssertCountWithZeroToAssertEmptyRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(AssertCountWithZeroToAssertEmptyRector::class);
10+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\CodeQuality\Rector\MethodCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Expr\StaticCall;
10+
use PhpParser\Node\Name;
11+
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
12+
use Rector\Rector\AbstractRector;
13+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
14+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
15+
16+
/**
17+
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector\AssertCountWithZeroToAssertEmptyRectorTest
18+
*/
19+
final class AssertCountWithZeroToAssertEmptyRector extends AbstractRector
20+
{
21+
public function __construct(
22+
private readonly TestsNodeAnalyzer $testsNodeAnalyzer
23+
) {
24+
}
25+
26+
public function getRuleDefinition(): RuleDefinition
27+
{
28+
return new RuleDefinition(
29+
'Change $this->assertCount(0, ...) to $this->assertEmpty(...)',
30+
[
31+
new CodeSample(
32+
<<<'CODE_SAMPLE'
33+
$this->assertCount(0, $countable);
34+
$this->assertNotCount(0, $countable);
35+
CODE_SAMPLE
36+
,
37+
<<<'CODE_SAMPLE'
38+
$this->assertEmpty($countable);
39+
$this->assertNotEmpty($countable);
40+
CODE_SAMPLE
41+
),
42+
],
43+
);
44+
}
45+
46+
/**
47+
* @return array<class-string<MethodCall|StaticCall>>
48+
*/
49+
public function getNodeTypes(): array
50+
{
51+
return [MethodCall::class, StaticCall::class];
52+
}
53+
54+
/**
55+
* @param MethodCall|StaticCall $node
56+
*/
57+
public function refactor(Node $node): MethodCall|StaticCall|null
58+
{
59+
if (! $this->testsNodeAnalyzer->isPHPUnitMethodCallNames($node, ['assertCount', 'assertNotCount'])) {
60+
return null;
61+
}
62+
63+
if ($node->isFirstClassCallable()) {
64+
return null;
65+
}
66+
67+
if (count($node->getArgs()) < 2) {
68+
return null;
69+
}
70+
71+
$type = $this->getType($node->getArgs()[0]->value);
72+
$value = ($type->getConstantScalarValues()[0] ?? null);
73+
if ($value === 0) {
74+
$args = $node->getArgs();
75+
if ($this->isName($node->name, 'assertNotCount')) {
76+
$node->name = new Name('assertNotEmpty');
77+
} else {
78+
$node->name = new Name('assertEmpty');
79+
}
80+
81+
array_shift($args);
82+
$node->args = $args;
83+
return $node;
84+
}
85+
86+
return null;
87+
}
88+
}

0 commit comments

Comments
 (0)