Added as much additional data as possible to exceptions

This commit is contained in:
Alejandro Celaya 2019-11-27 20:18:36 +01:00
parent fffb2872ef
commit 5266743a0c
9 changed files with 26 additions and 84 deletions

View file

@ -83,7 +83,7 @@ class DeleteShortUrlCommandTest extends TestCase
$ignoreThreshold = array_pop($args);
if (!$ignoreThreshold) {
throw new Exception\DeleteShortUrlException(10);
throw Exception\DeleteShortUrlException::fromVisitsThreshold(10, '');
}
}
);
@ -112,7 +112,7 @@ class DeleteShortUrlCommandTest extends TestCase
{
$shortCode = 'abc123';
$deleteByShortCode = $this->service->deleteByShortCode($shortCode, false)->willThrow(
new Exception\DeleteShortUrlException(10)
Exception\DeleteShortUrlException::fromVisitsThreshold(10, '')
);
$this->commandTester->setInputs(['no']);

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Exception;
use Fig\Http\Message\StatusCodeInterface;
use Throwable;
use Zend\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Zend\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
@ -18,18 +17,9 @@ class DeleteShortUrlException extends DomainException implements ProblemDetailsE
private const TITLE = 'Cannot delete short URL';
private const TYPE = 'INVALID_SHORTCODE_DELETION'; // FIXME Should be INVALID_SHORT_URL_DELETION
/** @var int */
private $visitsThreshold;
public function __construct(int $visitsThreshold, string $message = '', int $code = 0, ?Throwable $previous = null)
{
$this->visitsThreshold = $visitsThreshold;
parent::__construct($message, $code, $previous);
}
public static function fromVisitsThreshold(int $threshold, string $shortCode): self
{
$e = new self($threshold, sprintf(
$e = new self(sprintf(
'Impossible to delete short URL with short code "%s" since it has more than "%s" visits.',
$shortCode,
$threshold
@ -39,13 +29,16 @@ class DeleteShortUrlException extends DomainException implements ProblemDetailsE
$e->title = self::TITLE;
$e->type = self::TYPE;
$e->status = StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY;
$e->additional = ['threshold' => $threshold];
$e->additional = [
'shortCode' => $shortCode,
'threshold' => $threshold,
];
return $e;
}
public function getVisitsThreshold(): int
{
return $this->visitsThreshold;
return $this->additional['threshold'];
}
}

View file

@ -27,6 +27,7 @@ class InvalidUrlException extends DomainException implements ProblemDetailsExcep
$e->title = self::TITLE;
$e->type = self::TYPE;
$e->status = $status;
$e->additional = ['url' => $url];
return $e;
}

View file

@ -26,6 +26,11 @@ class NonUniqueSlugException extends InvalidArgumentException implements Problem
$e->title = self::TITLE;
$e->type = self::TYPE;
$e->status = StatusCodeInterface::STATUS_BAD_REQUEST;
$e->additional = ['customSlug' => $slug];
if ($domain !== null) {
$e->additional['domain'] = $domain;
}
return $e;
}

View file

@ -26,6 +26,11 @@ class ShortUrlNotFoundException extends DomainException implements ProblemDetail
$e->title = self::TITLE;
$e->type = self::TYPE;
$e->status = StatusCodeInterface::STATUS_NOT_FOUND;
$e->additional = ['shortCode' => $shortCode];
if ($domain !== null) {
$e->additional['domain'] = $domain;
}
return $e;
}

View file

@ -25,6 +25,7 @@ class TagNotFoundException extends DomainException implements ProblemDetailsExce
$e->title = self::TITLE;
$e->type = self::TYPE;
$e->status = StatusCodeInterface::STATUS_NOT_FOUND;
$e->additional = ['tag' => $tag];
return $e;
}

View file

@ -24,19 +24,6 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
private const TITLE = 'Invalid data';
private const TYPE = 'INVALID_ARGUMENT';
/** @var array */
private $invalidElements;
public function __construct(
string $message = '',
array $invalidElements = [],
int $code = 0,
?Throwable $previous = null
) {
$this->invalidElements = $invalidElements;
parent::__construct($message, $code, $previous);
}
public static function fromInputFilter(InputFilterInterface $inputFilter, ?Throwable $prev = null): self
{
return static::fromArray($inputFilter->getMessages(), $prev);
@ -45,22 +32,20 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
public static function fromArray(array $invalidData, ?Throwable $prev = null): self
{
$status = StatusCodeInterface::STATUS_BAD_REQUEST;
$e = new self('Provided data is not valid', $invalidData, $status, $prev);
$e = new self('Provided data is not valid', $status, $prev);
$e->detail = $e->getMessage();
$e->title = self::TITLE;
$e->type = self::TYPE;
$e->status = StatusCodeInterface::STATUS_BAD_REQUEST;
$e->additional = [
'invalidElements' => $invalidData,
];
$e->additional = ['invalidElements' => $invalidData];
return $e;
}
public function getInvalidElements(): array
{
return $this->invalidElements;
return $this->additional['invalidElements'];
}
public function __toString(): string
@ -80,7 +65,7 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
private function invalidElementsToString(): string
{
return reduce_left($this->invalidElements, function ($messageSet, string $name, $_, string $acc) {
return reduce_left($this->getInvalidElements(), function ($messageSet, string $name, $_, string $acc) {
return $acc . sprintf(
"\n '%s' => %s",
$name,

View file

@ -5,17 +5,15 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Exception;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Common\Util\StringUtilsTrait;
use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException;
use function Functional\map;
use function range;
use function Shlinkio\Shlink\Core\generateRandomShortCode;
use function sprintf;
class DeleteShortUrlExceptionTest extends TestCase
{
use StringUtilsTrait;
/**
* @test
* @dataProvider provideThresholds
@ -29,29 +27,12 @@ class DeleteShortUrlExceptionTest extends TestCase
$this->assertEquals($threshold, $e->getVisitsThreshold());
$this->assertEquals($expectedMessage, $e->getMessage());
$this->assertEquals(0, $e->getCode());
$this->assertNull($e->getPrevious());
}
/**
* @test
* @dataProvider provideThresholds
*/
public function visitsThresholdIsProperlyReturned(int $threshold): void
{
$e = new DeleteShortUrlException($threshold);
$this->assertEquals($threshold, $e->getVisitsThreshold());
$this->assertEquals('', $e->getMessage());
$this->assertEquals(0, $e->getCode());
$this->assertNull($e->getPrevious());
}
public function provideThresholds(): array
{
return map(range(5, 50, 5), function (int $number) {
$shortCode = $this->generateRandomString(6);
return [$number, $shortCode, sprintf(
return [$number, $shortCode = generateRandomShortCode(6), sprintf(
'Impossible to delete short URL with short code "%s" since it has more than "%s" visits.',
$shortCode,
$number

View file

@ -13,38 +13,9 @@ use Throwable;
use Zend\InputFilter\InputFilterInterface;
use function print_r;
use function random_int;
class ValidationExceptionTest extends TestCase
{
/**
* @test
* @dataProvider provideExceptionData
*/
public function createsExceptionWrappingExpectedData(
array $args,
string $expectedMessage,
array $expectedInvalidElements,
int $expectedCode,
?Throwable $expectedPrev
): void {
$e = new ValidationException(...$args);
$this->assertEquals($expectedMessage, $e->getMessage());
$this->assertEquals($expectedInvalidElements, $e->getInvalidElements());
$this->assertEquals($expectedCode, $e->getCode());
$this->assertEquals($expectedPrev, $e->getPrevious());
}
public function provideExceptionData(): iterable
{
yield 'empty args' => [[], '', [], 0, null];
yield 'with message' => [['something'], 'something', [], 0, null];
yield 'with elements' => [['something_else', [1, 2, 3]], 'something_else', [1, 2, 3], 0, null];
yield 'with code' => [['foo', [], $foo = random_int(-100, 100)], 'foo', [], $foo, null];
yield 'with prev' => [['bar', [], 8, $e = new RuntimeException()], 'bar', [], 8, $e];
}
/**
* @test
* @dataProvider provideExceptions