Skip to content

Commit

Permalink
Improvements to the AssertStatusToAssertMethodRector (#255)
Browse files Browse the repository at this point in the history
* Major improvements

* Fix up docs
  • Loading branch information
peterfox authored Oct 1, 2024
1 parent 833504e commit 62598cb
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 247 deletions.
96 changes: 10 additions & 86 deletions docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,103 +273,27 @@ Replace `(new \Illuminate\Testing\TestResponse)->assertStatus(200)` with `(new \
```diff
class ExampleTest extends \Illuminate\Foundation\Testing\TestCase
{
public function testOk()
public function testFoo()
{
- $this->get('/')->assertStatus(200);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_OK);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_OK);
+ $this->get('/')->assertOk();
+ $this->get('/')->assertOk();
+ $this->get('/')->assertOk();
}

public function testNoContent()
{
- $this->get('/')->assertStatus(204);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_NO_CONTENT);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_NO_CONTENT);
+ $this->get('/')->assertNoContent();
+ $this->get('/')->assertNoContent();
+ $this->get('/')->assertNoContent();
}

public function testUnauthorized()
{
- $this->get('/')->assertStatus(401);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_UNAUTHORIZED);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_UNAUTHORIZED);
+ $this->get('/')->assertUnauthorized();
+ $this->get('/')->assertUnauthorized();
+ $this->get('/')->assertUnauthorized();
}

public function testForbidden()
{
- $this->get('/')->assertStatus(403);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_FORBIDDEN);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_FORBIDDEN);
+ $this->get('/')->assertForbidden();
+ $this->get('/')->assertForbidden();
+ $this->get('/')->assertForbidden();
}

public function testNotFound()
{
- $this->get('/')->assertStatus(404);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_NOT_FOUND);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_NOT_FOUND);
+ $this->get('/')->assertNotFound();
+ $this->get('/')->assertNotFound();
+ $this->get('/')->assertNotFound();
}

public function testMethodNotAllowed()
{
- $this->get('/')->assertStatus(405);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_METHOD_NOT_ALLOWED);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_METHOD_NOT_ALLOWED);
+ $this->get('/')->assertMethodNotAllowed();
+ $this->get('/')->assertMethodNotAllowed();
+ $this->get('/')->assertMethodNotAllowed();
}

public function testUnprocessableEntity()
{
- $this->get('/')->assertStatus(422);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_UNPROCESSABLE_ENTITY);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_UNPROCESSABLE_ENTITY);
+ $this->get('/')->assertUnprocessable();
+ $this->get('/')->assertUnprocessable();
+ $this->get('/')->assertUnprocessable();
}

public function testGone()
{
- $this->get('/')->assertStatus(410);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_GONE);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_GONE);
+ $this->get('/')->assertGone();
+ $this->get('/')->assertGone();
+ $this->get('/')->assertGone();
}

public function testInternalServerError()
{
- $this->get('/')->assertStatus(500);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_INTERNAL_SERVER_ERROR);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_INTERNAL_SERVER_ERROR);
+ $this->get('/')->assertInternalServerError();
+ $this->get('/')->assertInternalServerError();
+ $this->get('/')->assertInternalServerError();
}

public function testServiceUnavailable()
{
- $this->get('/')->assertStatus(503);
- $this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_SERVICE_UNAVAILABLE);
- $this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_SERVICE_UNAVAILABLE);
+ $this->get('/')->assertServiceUnavailable();
+ $this->get('/')->assertServiceUnavailable();
+ $this->get('/')->assertOk();
+ $this->get('/')->assertNoContent();
+ $this->get('/')->assertUnauthorized();
+ $this->get('/')->assertForbidden();
+ $this->get('/')->assertNotFound();
+ $this->get('/')->assertMethodNotAllowed();
+ $this->get('/')->assertUnprocessable();
+ $this->get('/')->assertGone();
+ $this->get('/')->assertInternalServerError();
+ $this->get('/')->assertServiceUnavailable();
}
}
Expand Down
175 changes: 24 additions & 151 deletions src/Rector/MethodCall/AssertStatusToAssertMethodRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
namespace RectorLaravel\Rector\MethodCall;

use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\LNumber;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
Expand All @@ -28,148 +26,36 @@ public function getRuleDefinition(): RuleDefinition
<<<'CODE_SAMPLE'
class ExampleTest extends \Illuminate\Foundation\Testing\TestCase
{
public function testOk()
public function testFoo()
{
$this->get('/')->assertStatus(200);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_OK);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_OK);
}
public function testNoContent()
{
$this->get('/')->assertStatus(204);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_NO_CONTENT);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_NO_CONTENT);
}
public function testUnauthorized()
{
$this->get('/')->assertStatus(401);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_UNAUTHORIZED);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_UNAUTHORIZED);
}
public function testForbidden()
{
$this->get('/')->assertStatus(403);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_FORBIDDEN);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_FORBIDDEN);
}
public function testNotFound()
{
$this->get('/')->assertStatus(404);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_NOT_FOUND);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_NOT_FOUND);
}
public function testMethodNotAllowed()
{
$this->get('/')->assertStatus(405);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_METHOD_NOT_ALLOWED);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_METHOD_NOT_ALLOWED);
}
public function testUnprocessableEntity()
{
$this->get('/')->assertStatus(422);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_UNPROCESSABLE_ENTITY);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_UNPROCESSABLE_ENTITY);
}
public function testGone()
{
$this->get('/')->assertStatus(410);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_GONE);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_GONE);
}
public function testInternalServerError()
{
$this->get('/')->assertStatus(500);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_INTERNAL_SERVER_ERROR);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_INTERNAL_SERVER_ERROR);
}
public function testServiceUnavailable()
{
$this->get('/')->assertStatus(503);
$this->get('/')->assertStatus(\Illuminate\Http\Response::HTTP_SERVICE_UNAVAILABLE);
$this->get('/')->assertStatus(\Symfony\Component\HttpFoundation\Response::HTTP_SERVICE_UNAVAILABLE);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class ExampleTest extends \Illuminate\Foundation\Testing\TestCase
{
public function testOk()
public function testFoo()
{
$this->get('/')->assertOk();
$this->get('/')->assertOk();
$this->get('/')->assertOk();
}
public function testNoContent()
{
$this->get('/')->assertNoContent();
$this->get('/')->assertNoContent();
$this->get('/')->assertNoContent();
}
public function testUnauthorized()
{
$this->get('/')->assertUnauthorized();
$this->get('/')->assertUnauthorized();
$this->get('/')->assertUnauthorized();
}
public function testForbidden()
{
$this->get('/')->assertForbidden();
$this->get('/')->assertForbidden();
$this->get('/')->assertForbidden();
}
public function testNotFound()
{
$this->get('/')->assertNotFound();
$this->get('/')->assertNotFound();
$this->get('/')->assertNotFound();
}
public function testMethodNotAllowed()
{
$this->get('/')->assertMethodNotAllowed();
$this->get('/')->assertMethodNotAllowed();
$this->get('/')->assertMethodNotAllowed();
}
public function testUnprocessableEntity()
{
$this->get('/')->assertUnprocessable();
$this->get('/')->assertUnprocessable();
$this->get('/')->assertUnprocessable();
}
public function testGone()
{
$this->get('/')->assertGone();
$this->get('/')->assertGone();
$this->get('/')->assertGone();
}
public function testInternalServerError()
{
$this->get('/')->assertInternalServerError();
$this->get('/')->assertInternalServerError();
$this->get('/')->assertInternalServerError();
}
public function testServiceUnavailable()
{
$this->get('/')->assertServiceUnavailable();
$this->get('/')->assertServiceUnavailable();
$this->get('/')->assertServiceUnavailable();
}
}
Expand Down Expand Up @@ -212,47 +98,34 @@ private function updateAssertStatusCall(MethodCall $methodCall): ?MethodCall
$arg = $methodCall->getArgs()[0];
$argValue = $arg->value;

if (! $argValue instanceof LNumber && ! $argValue instanceof ClassConstFetch) {
// we can check if the arg is an integer even if it comes from a constant
$type = $this->getType($argValue);

if (! $type->isInteger()->yes()) {
return null;
}

if ($argValue instanceof LNumber) {
$replacementMethod = match ($argValue->value) {
200 => 'assertOk',
204 => 'assertNoContent',
401 => 'assertUnauthorized',
403 => 'assertForbidden',
404 => 'assertNotFound',
405 => 'assertMethodNotAllowed',
410 => 'assertGone',
422 => 'assertUnprocessable',
500 => 'assertInternalServerError',
503 => 'assertServiceUnavailable',
default => null
};
} else {
if (! in_array($this->getName($argValue->class), [
'Illuminate\Http\Response',
'Symfony\Component\HttpFoundation\Response',
], true)) {
return null;
}
// we want the value of the integer if it's known
$value = ($type->getConstantScalarValues()[0] ?? null);

$replacementMethod = match ($this->getName($argValue->name)) {
'HTTP_OK' => 'assertOk',
'HTTP_NO_CONTENT' => 'assertNoContent',
'HTTP_UNAUTHORIZED' => 'assertUnauthorized',
'HTTP_FORBIDDEN' => 'assertForbidden',
'HTTP_NOT_FOUND' => 'assertNotFound',
'HTTP_METHOD_NOT_ALLOWED' => 'assertMethodNotAllowed',
'HTTP_GONE' => 'assertGone',
'HTTP_UNPROCESSABLE_ENTITY' => 'assertUnprocessable',
'HTTP_INTERNAL_SERVER_ERROR' => 'assertInternalServerError',
'HTTP_SERVICE_UNAVAILABLE' => 'assertServiceUnavailable',
default => null
};
if ($value === null) {
return null;
}

$replacementMethod = match ($value) {
200 => 'assertOk',
204 => 'assertNoContent',
401 => 'assertUnauthorized',
403 => 'assertForbidden',
404 => 'assertNotFound',
405 => 'assertMethodNotAllowed',
410 => 'assertGone',
422 => 'assertUnprocessable',
500 => 'assertInternalServerError',
503 => 'assertServiceUnavailable',
default => null
};

if ($replacementMethod === null) {
return null;
}
Expand Down
13 changes: 13 additions & 0 deletions stubs/Illuminate/Http/Response.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Illuminate\Http;

use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

if (class_exists('Illuminate\Http\Response')) {
return;
}

class Response extends SymfonyResponse
{
}
Loading

0 comments on commit 62598cb

Please sign in to comment.