Skip to content

Commit

Permalink
Merge pull request #21 from hotmeteor/better-error-reporting
Browse files Browse the repository at this point in the history
Better error reporting
  • Loading branch information
hotmeteor authored Dec 18, 2020
2 parents 98808d4 + 7a261e5 commit aff19af
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 54 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"opis/json-schema": "^1.0"
},
"require-dev": {
"nunomaduro/collision": "^5.1",
"orchestra/testbench": "^4.0|^5.0|^6.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0"
},
Expand Down
16 changes: 10 additions & 6 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
bootstrap="vendor/autoload.php"
forceCoversAnnotation="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true">
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
Expand Down
123 changes: 75 additions & 48 deletions src/Assertions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,110 +2,124 @@

namespace Spectator;

use Closure;
use Illuminate\Support\Arr;
use PHPUnit\Framework\Assert as PHPUnit;
use Spectator\Exceptions\RequestValidationException;
use Spectator\Exceptions\ResponseValidationException;
use cebe\openapi\exceptions\UnresolvableReferenceException;

/** @mixin \Illuminate\Testing\TestResponse|Illuminate\Foundation\Testing\TestResponse */
class Assertions
{
public function assertValidRequest()
{
return function () {
$contents = $this->getContent() ? $contents = (array) $this->json() : [];
return $this->runAssertion(function () {
$contents = $this->getContent() ? $contents = (array) $this->json() : [];

PHPUnit::assertFalse(
in_array(Arr::get($contents, 'exception'), [RequestValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);
PHPUnit::assertFalse(
in_array(Arr::get($contents, 'exception'), [RequestValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);

return $this;
return $this;
});
};
}

public function assertInvalidRequest()
{
return function () {
$contents = (array) $this->json();
return $this->runAssertion(function () {
$contents = (array) $this->json();

PHPUnit::assertTrue(
!in_array(Arr::get($contents, 'exception'), [RequestValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);
PHPUnit::assertTrue(
!in_array(Arr::get($contents, 'exception'), [RequestValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);

return $this;
return $this;
});
};
}

public function assertValidResponse()
{
return function ($status = null) {
$contents = $this->getContent() ? (array) $this->json() : [];
return $this->runAssertion(function () use ($status) {
$contents = $this->getContent() ? (array) $this->json() : [];

PHPUnit::assertFalse(
in_array(Arr::get($contents, 'exception'), [ResponseValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);
PHPUnit::assertFalse(
in_array(Arr::get($contents, 'exception'), [ResponseValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);

if ($status) {
$actual = $this->getStatusCode();
if ($status) {
$actual = $this->getStatusCode();

PHPUnit::assertTrue(
$actual === $status,
"Expected status code {$status} but received {$actual}."
);
}
PHPUnit::assertTrue(
$actual === $status,
"Expected status code {$status} but received {$actual}."
);
}

return $this;
return $this;
});
};
}

public function assertInvalidResponse()
{
return function ($status = null) {
$contents = (array) $this->json();

PHPUnit::assertTrue(
in_array(Arr::get($contents, 'exception'), [ResponseValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);

if ($status) {
$actual = $this->getStatusCode();
return $this->runAssertion(function () use ($status) {
$contents = (array) $this->json();

PHPUnit::assertTrue(
$actual === $status,
"Expected status code {$status} but received {$actual}."
in_array(Arr::get($contents, 'exception'), [ResponseValidationException::class, UnresolvableReferenceException::class]),
$this->decodeExceptionMessage($contents)
);
}

return $this;
if ($status) {
$actual = $this->getStatusCode();

PHPUnit::assertTrue(
$actual === $status,
"Expected status code {$status} but received {$actual}."
);
}

return $this;
});
};
}

public function assertValidationMessage()
{
return function ($expected) {
$actual = $this->getData()->message;
return $this->runAssertion(function () use ($expected) {
$actual = $this->getData()->message;

PHPUnit::assertSame(
$expected, $actual,
'The expected error did not match the actual error.'
);
PHPUnit::assertSame(
$expected, $actual,
'The expected error did not match the actual error.'
);

return $this;
return $this;
});
};
}

public function assertErrorsContain()
{
return function ($errors) {
self::assertJson([
'errors' => Arr::wrap($errors),
]);
return $this->runAssertion(function () use ($errors) {
self::assertJson([
'errors' => Arr::wrap($errors),
]);

return $this;
return $this;
});
};
}

Expand All @@ -115,4 +129,17 @@ protected function decodeExceptionMessage()
return Arr::get($contents, 'message', '');
};
}

protected function runAssertion()
{
return function (Closure $closure) {
$original = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 6)[5];

try {
return $closure();
} catch (\Exception $exception) {
throw new \ErrorException($exception->getMessage(), $exception->getCode(), E_WARNING, $original['file'], $original['line']);
}
};
}
}
36 changes: 36 additions & 0 deletions tests/AssertionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Spectator\Tests;

use Spectator\Spectator;
use Spectator\Middleware;
use Illuminate\Support\Facades\Route;
use Spectator\SpectatorServiceProvider;

class AssertionsTest extends TestCase
{
public function setUp(): void
{
parent::setUp();

$this->app->register(SpectatorServiceProvider::class);

Spectator::using('Test.v1.json');
}

public function testExceptionPointsToMixinMethod()
{
$this->expectException(\ErrorException::class);
$this->expectExceptionCode(0);
$this->expectExceptionMessage('No response object matching returned status code [500].
Failed asserting that true is false.');

Route::get('/users', function () {
throw new \Exception('Explosion');
})->middleware(Middleware::class);

$this->getJson('/users')
->assertValidRequest()
->assertValidResponse(200);
}
}

0 comments on commit aff19af

Please sign in to comment.