diff --git a/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithOneCount.php.inc b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithOneCount.php.inc new file mode 100644 index 00000000..048f0ce3 --- /dev/null +++ b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithOneCount.php.inc @@ -0,0 +1,33 @@ +expects($this->at(1)) + ->method('foo') + ->willReturn('1'); + } +} +?> +----- +expects($this->once()) + ->method('foo') + ->willReturn('1'); + } +} +?> diff --git a/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithTwoOrMoreCount.php.inc b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithTwoOrMoreCount.php.inc new file mode 100644 index 00000000..685c7f67 --- /dev/null +++ b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithTwoOrMoreCount.php.inc @@ -0,0 +1,33 @@ +expects($this->at(2)) + ->method('foo') + ->willReturn('1'); + } +} +?> +----- +expects($this->exactly(2)) + ->method('foo') + ->willReturn('1'); + } +} +?> diff --git a/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithZeroCount.php.inc b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithZeroCount.php.inc new file mode 100644 index 00000000..d585c6d2 --- /dev/null +++ b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/AtWithZeroCount.php.inc @@ -0,0 +1,33 @@ +expects($this->at(0)) + ->method('foo') + ->willReturn('1'); + } +} +?> +----- +expects($this->never()) + ->method('foo') + ->willReturn('1'); + } +} +?> diff --git a/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/MultipleAtWithDifferentCount.php.inc b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/MultipleAtWithDifferentCount.php.inc new file mode 100644 index 00000000..84fde23e --- /dev/null +++ b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/Fixture/MultipleAtWithDifferentCount.php.inc @@ -0,0 +1,55 @@ +expects($this->at(0)) + ->method('foo') + ->willReturn('1'); + + $mock->expects($this->at(1)) + ->method('foo') + ->willReturn('1'); + + $mock->expects($this->at(2)) + ->method('foo') + ->willReturn('1'); + $mock->expects($this->at(3)) + ->method('foo') + ->willReturn('1'); + } +} +?> +----- +expects($this->never()) + ->method('foo') + ->willReturn('1'); + + $mock->expects($this->once()) + ->method('foo') + ->willReturn('1'); + + $mock->expects($this->exactly(2)) + ->method('foo') + ->willReturn('1'); + $mock->expects($this->exactly(3)) + ->method('foo') + ->willReturn('1'); + } +} +?> diff --git a/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/ReplaceAtMethodWithDesiredMatcherRectorTest.php b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/ReplaceAtMethodWithDesiredMatcherRectorTest.php new file mode 100644 index 00000000..0a944fbe --- /dev/null +++ b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/ReplaceAtMethodWithDesiredMatcherRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/config/configured_rule.php b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/config/configured_rule.php new file mode 100644 index 00000000..ff9ed64b --- /dev/null +++ b/rules-tests/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(ReplaceAtMethodWithDesiredMatcherRector::class); +}; diff --git a/rules/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector.php b/rules/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector.php new file mode 100644 index 00000000..39f74c1a --- /dev/null +++ b/rules/PHPUnit90/Rector/MethodCall/ReplaceAtMethodWithDesiredMatcherRector.php @@ -0,0 +1,115 @@ +expects($this->at(0)) + ->method('foo') + ->willReturn('1'); +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +$mock->expects($this->never()) + ->method('foo') + ->willReturn('1'); +CODE_SAMPLE + ), + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** + * @param MethodCall $node + */ + public function refactor(Node $node): null|MethodCall + { + if (! $this->testsNodeAnalyzer->isInTestClass($node)) { + return null; + } + + if ($node->var instanceof MethodCall && $arg = $this->findAtMethodCall($node->var)) { + $this->replaceWithDesiredMatcher($arg); + } + + return null; + } + + private function findAtMethodCall(MethodCall $methodCall): ?Arg + { + foreach ($methodCall->getArgs() as $arg) { + if ($arg->value instanceof MethodCall && + $arg->value->name instanceof Identifier && + $arg->value->name->toString() === 'at' + ) { + return $arg; + } + } + + if ($methodCall->var instanceof MethodCall) { + $this->findAtMethodCall($methodCall->var); + } + + return null; + } + + private function replaceWithDesiredMatcher(Arg $arg): void + { + if (! $arg->value instanceof MethodCall) { + return; + } + + foreach ($arg->value->getArgs() as $item) { + if ($item->value instanceof Int_) { + $count = $item->value->value; + } + } + + if (! isset($count)) { + return; + } + + if ($count === 0) { + $arg->value = new MethodCall($arg->value->var, 'never'); + } elseif ($count === 1) { + $arg->value = new MethodCall($arg->value->var, 'once'); + } elseif ($count > 1) { + $arg->value = new MethodCall($arg->value->var, 'exactly', [new Arg(new Int_($count))]); + } + } +}