From 83ab59322a92c64a9298742a2eb6db839be0fda0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 11 Nov 2025 07:26:10 +0100 Subject: [PATCH 1/2] Make AssertSameWithCountRule auto-fixable --- src/Rules/PHPUnit/AssertSameWithCountRule.php | 49 +++++++++++++++++++ .../PHPUnit/AssertSameWithCountRuleTest.php | 5 ++ .../data/assert-same-count-fixable.php | 42 ++++++++++++++++ .../data/assert-same-count-fixable.php.fixed | 42 ++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 tests/Rules/PHPUnit/data/assert-same-count-fixable.php create mode 100644 tests/Rules/PHPUnit/data/assert-same-count-fixable.php.fixed diff --git a/src/Rules/PHPUnit/AssertSameWithCountRule.php b/src/Rules/PHPUnit/AssertSameWithCountRule.php index 2a5a765..1d1939e 100644 --- a/src/Rules/PHPUnit/AssertSameWithCountRule.php +++ b/src/Rules/PHPUnit/AssertSameWithCountRule.php @@ -50,6 +50,17 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('You should use assertCount($expectedCount, $variable) instead of assertSame($expectedCount, count($variable)).') ->identifier('phpunit.assertCount') + ->fixNode($node, static function (CallLike $node) use ($scope) { + $newArgs = self::rewriteArgs($node->args, $scope); + if ($newArgs === null) { + return $node; + } + + $node->name = new Node\Identifier('assertCount'); + $node->args = $newArgs; + + return $node; + }) ->build(), ]; } @@ -58,6 +69,12 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('You should use assertCount($expectedCount, $variable) instead of assertSame($expectedCount, $variable->count()).') ->identifier('phpunit.assertCount') + ->fixNode($node, static function (CallLike $node) use ($scope) { + $node->name = new Node\Identifier('assertCount'); + $node->args = self::rewriteArgs($node->args, $scope); + + return $node; + }) ->build(), ]; } @@ -109,4 +126,36 @@ private static function isNormalCount(Node\Expr\FuncCall $countFuncCall, Type $c return $isNormalCount; } + /** + * @param array $args + * @return list + */ + private static function rewriteArgs(array $args, Scope $scope): ?array + { + $newArgs = []; + for ($i = 0; $i < count($args); $i++) { + + if ( + $args[$i] instanceof Node\Arg + && $args[$i]->value instanceof CallLike + ) { + $value = $args[$i]->value; + if (self::isCountFunctionCall($value, $scope)) { + if (count($value->getArgs()) !== 1) { + return null; + } + + $newArgs[] = new Node\Arg($value->getArgs()[0]->value); + continue; + } elseif (self::isCountableMethodCall($value, $scope)) { + $newArgs[] = new Node\Arg($value->var); + continue; + } + } + + $newArgs[] = $args[$i]; + } + return $newArgs; + } + } diff --git a/tests/Rules/PHPUnit/AssertSameWithCountRuleTest.php b/tests/Rules/PHPUnit/AssertSameWithCountRuleTest.php index dfb940c..c90b2d6 100644 --- a/tests/Rules/PHPUnit/AssertSameWithCountRuleTest.php +++ b/tests/Rules/PHPUnit/AssertSameWithCountRuleTest.php @@ -42,6 +42,11 @@ public function testRule(): void ]); } + public function testFix(): void + { + $this->fix(__DIR__ . '/data/assert-same-count-fixable.php', __DIR__ . '/data/assert-same-count-fixable.php.fixed'); + } + /** * @return string[] */ diff --git a/tests/Rules/PHPUnit/data/assert-same-count-fixable.php b/tests/Rules/PHPUnit/data/assert-same-count-fixable.php new file mode 100644 index 0000000..a15c16d --- /dev/null +++ b/tests/Rules/PHPUnit/data/assert-same-count-fixable.php @@ -0,0 +1,42 @@ +assertSame(5, count([1, 2, 3])); + } + + public function testAssertSameWithCountRecursive($x) + { + $this->assertSame(5, count([1, 2, 3, $x], COUNT_RECURSIVE)); + } + + public function testAssertSameWithCountMethodForCountableVariableIsNotOK() + { + $bar = new \ExampleTestCaseFix\Bar (); + + $this->assertSame(5, $bar->count()); + } + + public function testAssertSameWithCountMethodForCountablePropertyFetchIsNotOK() + { + $foo = new \stdClass(); + $foo->bar = new Bar (); + + $this->assertSame(5, $foo->bar->count()); + } + +} + +class Bar implements \Countable { + public function count(): int + { + return 1; + } +} diff --git a/tests/Rules/PHPUnit/data/assert-same-count-fixable.php.fixed b/tests/Rules/PHPUnit/data/assert-same-count-fixable.php.fixed new file mode 100644 index 0000000..c2e9f96 --- /dev/null +++ b/tests/Rules/PHPUnit/data/assert-same-count-fixable.php.fixed @@ -0,0 +1,42 @@ +assertCount(5, [1, 2, 3]); + } + + public function testAssertSameWithCountRecursive($x) + { + $this->assertSame(5, count([1, 2, 3, $x], COUNT_RECURSIVE)); + } + + public function testAssertSameWithCountMethodForCountableVariableIsNotOK() + { + $bar = new \ExampleTestCaseFix\Bar (); + + $this->assertCount(5, $bar); + } + + public function testAssertSameWithCountMethodForCountablePropertyFetchIsNotOK() + { + $foo = new \stdClass(); + $foo->bar = new Bar (); + + $this->assertCount(5, $foo->bar); + } + +} + +class Bar implements \Countable { + public function count(): int + { + return 1; + } +} From 8def34158bef0c33738670c1ee900a4289cbd428 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 11 Nov 2025 10:51:48 +0100 Subject: [PATCH 2/2] Update AssertSameWithCountRule.php --- src/Rules/PHPUnit/AssertSameWithCountRule.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Rules/PHPUnit/AssertSameWithCountRule.php b/src/Rules/PHPUnit/AssertSameWithCountRule.php index 1d1939e..744641a 100644 --- a/src/Rules/PHPUnit/AssertSameWithCountRule.php +++ b/src/Rules/PHPUnit/AssertSameWithCountRule.php @@ -70,8 +70,13 @@ public function processNode(Node $node, Scope $scope): array RuleErrorBuilder::message('You should use assertCount($expectedCount, $variable) instead of assertSame($expectedCount, $variable->count()).') ->identifier('phpunit.assertCount') ->fixNode($node, static function (CallLike $node) use ($scope) { + $newArgs = self::rewriteArgs($node->args, $scope); + if ($newArgs === null) { + return $node; + } + $node->name = new Node\Identifier('assertCount'); - $node->args = self::rewriteArgs($node->args, $scope); + $node->args = $newArgs; return $node; })