From 5c5530abf565842c610e18100752932828da8d32 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 19 Oct 2023 18:32:06 +0200 Subject: [PATCH] Add AssertSameResponseCodeWithDebugContentsRector (#536) --- config/sets/symfony/symfony-code-quality.php | 4 + docs/rector_rules_overview.md | 26 +++- ...esponseCodeWithDebugContentsRectorTest.php | 28 ++++ .../Fixture/skip_custom_message.php.inc | 16 +++ .../Fixture/some_class.php.inc | 37 +++++ .../config/configured_rule.php | 11 ++ ...ameResponseCodeWithDebugContentsRector.php | 134 ++++++++++++++++++ 7 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/AssertSameResponseCodeWithDebugContentsRectorTest.php create mode 100644 rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/skip_custom_message.php.inc create mode 100644 rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/some_class.php.inc create mode 100644 rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/config/configured_rule.php create mode 100644 rules/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector.php diff --git a/config/sets/symfony/symfony-code-quality.php b/config/sets/symfony/symfony-code-quality.php index 4ddc5c76..f2ee87d3 100644 --- a/config/sets/symfony/symfony-code-quality.php +++ b/config/sets/symfony/symfony-code-quality.php @@ -11,6 +11,7 @@ use Rector\Symfony\CodeQuality\Rector\ClassMethod\ParamTypeFromRouteRequiredRegexRector; use Rector\Symfony\CodeQuality\Rector\ClassMethod\RemoveUnusedRequestParamRector; use Rector\Symfony\CodeQuality\Rector\ClassMethod\ResponseReturnTypeControllerActionRector; +use Rector\Symfony\CodeQuality\Rector\MethodCall\AssertSameResponseCodeWithDebugContentsRector; use Rector\Symfony\CodeQuality\Rector\MethodCall\LiteralGetToRequestClassConstantRector; return static function (RectorConfig $rectorConfig): void { @@ -26,5 +27,8 @@ ParamTypeFromRouteRequiredRegexRector::class, ActionSuffixRemoverRector::class, LoadValidatorMetadataToAnnotationRector::class, + + // tests + AssertSameResponseCodeWithDebugContentsRector::class, ]); }; diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md index e74f3f9f..78df6779 100644 --- a/docs/rector_rules_overview.md +++ b/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# 82 Rules Overview +# 83 Rules Overview ## ActionSuffixRemoverRector @@ -84,6 +84,30 @@ Replaces ArgumentValueResolverInterface by ValueResolverInterface
+## AssertSameResponseCodeWithDebugContentsRector + +Make assertSame(200, `$response->getStatusCode())` in tests comparing response code to include response contents for faster feedback + +- class: [`Rector\Symfony\CodeQuality\Rector\MethodCall\AssertSameResponseCodeWithDebugContentsRector`](../rules/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector.php) + +```diff + use PHPUnit\Framework\TestCase; + + class SomeClass extends TestCase + { + public function run() + { + /** @var \Symfony\Component\HttpFoundation\Response $response */ + $response = $this->processResult(); + +- $this->assertSame(200, $response->getStatusCode()); ++ $this->assertSame(200, $response->getStatusCode(), $response->getContents()); + } + } +``` + +
+ ## AuthorizationCheckerIsGrantedExtractorRector Change `$this->authorizationChecker->isGranted([$a, $b])` to `$this->authorizationChecker->isGranted($a) || $this->authorizationChecker->isGranted($b)` diff --git a/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/AssertSameResponseCodeWithDebugContentsRectorTest.php b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/AssertSameResponseCodeWithDebugContentsRectorTest.php new file mode 100644 index 00000000..0f7d1454 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/AssertSameResponseCodeWithDebugContentsRectorTest.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/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/skip_custom_message.php.inc b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/skip_custom_message.php.inc new file mode 100644 index 00000000..fbb23469 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/skip_custom_message.php.inc @@ -0,0 +1,16 @@ +processResult(); + + $this->assertSame(200, $response->getStatusCode(), 'custom message'); + } +} diff --git a/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/some_class.php.inc b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/some_class.php.inc new file mode 100644 index 00000000..7f281d98 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/Fixture/some_class.php.inc @@ -0,0 +1,37 @@ +processResult(); + + $this->assertSame(200, $response->getStatusCode()); + } +} + +?> +----- +processResult(); + + $this->assertSame(200, $response->getStatusCode(), $response->getContents()); + } +} + +?> diff --git a/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/config/configured_rule.php b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/config/configured_rule.php new file mode 100644 index 00000000..4b8f6cc9 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector/config/configured_rule.php @@ -0,0 +1,11 @@ +rule(AssertSameResponseCodeWithDebugContentsRector::class); +}; diff --git a/rules/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector.php b/rules/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector.php new file mode 100644 index 00000000..edd43820 --- /dev/null +++ b/rules/CodeQuality/Rector/MethodCall/AssertSameResponseCodeWithDebugContentsRector.php @@ -0,0 +1,134 @@ +getStatusCode()) in tests comparing response code to include response contents for faster feedback', + [ + new CodeSample( + <<<'CODE_SAMPLE' +use PHPUnit\Framework\TestCase; + +class SomeClass extends TestCase +{ + public function run() + { + /** @var \Symfony\Component\HttpFoundation\Response $response */ + $response = $this->processResult(); + + $this->assertSame(200, $response->getStatusCode()); + } +} +CODE_SAMPLE + + , + <<<'CODE_SAMPLE' +use PHPUnit\Framework\TestCase; + +class SomeClass extends TestCase +{ + public function run() + { + /** @var \Symfony\Component\HttpFoundation\Response $response */ + $response = $this->processResult(); + + $this->assertSame(200, $response->getStatusCode(), $response->getContents()); + } +} +CODE_SAMPLE + ), + + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** + * @param MethodCall $node + */ + public function refactor(Node $node): ?Node + { + if (! $this->testsNodeAnalyzer->isInTestClass($node)) { + return null; + } + + if (! $this->isName($node->name, 'assertSame')) { + return null; + } + + // there cannot be any custom message + $args = $node->getArgs(); + if (count($args) !== 2) { + return null; + } + + $firstArg = $args[0]; + $comparedValueType = $this->getType($firstArg->value); + + // must be number + if (! $comparedValueType instanceof ConstantIntegerType) { + return null; + } + + $responseExpr = $this->matchResponseExpr($args[1]->value); + if (! $responseExpr instanceof Expr) { + return null; + } + + $getContentsMethodCall = new MethodCall($responseExpr, 'getContents'); + $node->args[2] = new Arg($getContentsMethodCall); + + return $node; + } + + /** + * We look for $response->getStatusCode() + * $client->getResponse()->getStatusCode() + * + * etc. + */ + private function matchResponseExpr(Expr $expr): ?Expr + { + if (! $expr instanceof MethodCall) { + return null; + } + + // must be status method call + if (! $this->isName($expr->name, 'getStatusCode')) { + return null; + } + + return $expr->var; + } +}