From 8e9e3f82ed8919fed895c371766db2bc37a085dc Mon Sep 17 00:00:00 2001 From: Dominik Zogg Date: Sat, 4 Oct 2025 14:09:54 +0200 Subject: [PATCH] prototype-better-error-handling --- README.md | 18 +- composer.json | 2 +- doc/Migration/1.x-2.x.md | 60 ++ phpstan.neon | 3 - src/Error.php | 19 +- src/Errors.php | 122 ++++ src/ErrorsException.php | 18 + src/ParserErrorException.php | 116 ---- src/ParserErrorExceptionToString.php | 25 - src/Result.php | 2 +- src/Schema/AbstractSchema.php | 10 +- src/Schema/ArraySchema.php | 29 +- src/Schema/BackedEnumSchema.php | 12 +- src/Schema/BoolSchema.php | 10 +- src/Schema/DateTimeSchema.php | 14 +- src/Schema/DiscriminatedUnionSchema.php | 21 +- src/Schema/FloatSchema.php | 20 +- src/Schema/IntSchema.php | 18 +- src/Schema/LazySchema.php | 4 +- src/Schema/LiteralSchema.php | 12 +- src/Schema/ObjectSchema.php | 31 +- src/Schema/RecordSchema.php | 21 +- src/Schema/RespectValidationSchema.php | 29 +- src/Schema/SchemaInterface.php | 4 +- src/Schema/StringSchema.php | 42 +- src/Schema/TupleSchema.php | 29 +- src/Schema/UnionSchema.php | 17 +- tests/Integration/ParserTest.php | 76 ++- tests/Unit/AbstractTestCase.php | 15 - tests/Unit/ErrorTest.php | 16 +- tests/Unit/ErrorsExceptionTest.php | 36 ++ tests/Unit/ErrorsTest.php | 394 ++++++++++++ tests/Unit/ParserErrorExceptionTest.php | 574 ------------------ .../Unit/ParserErrorExceptionToStringTest.php | 51 -- tests/Unit/ResultTest.php | 5 +- tests/Unit/Schema/ArraySchemaTest.php | 161 +++-- tests/Unit/Schema/BackedEnumSchemaTest.php | 98 +-- tests/Unit/Schema/BoolSchemaTest.php | 51 +- tests/Unit/Schema/DateTimeSchemaTest.php | 90 +-- .../Schema/DiscriminatedUnionSchemaTest.php | 98 +-- tests/Unit/Schema/FloatSchemaTest.php | 246 +++++--- tests/Unit/Schema/IntSchemaTest.php | 221 ++++--- tests/Unit/Schema/LazySchemaTest.php | 4 +- tests/Unit/Schema/LiteralSchemaTest.php | 119 ++-- tests/Unit/Schema/ObjectSchemaTest.php | 83 +-- tests/Unit/Schema/RecordSchemaTest.php | 61 +- .../Schema/RespectValidationSchemaTest.php | 84 ++- tests/Unit/Schema/StringSchemaTest.php | 358 ++++++----- tests/Unit/Schema/TupleSchemaTest.php | 83 +-- tests/Unit/Schema/UnionSchemaTest.php | 87 ++- 50 files changed, 1987 insertions(+), 1732 deletions(-) create mode 100644 doc/Migration/1.x-2.x.md create mode 100644 src/Errors.php create mode 100644 src/ErrorsException.php delete mode 100644 src/ParserErrorException.php delete mode 100644 src/ParserErrorExceptionToString.php delete mode 100644 tests/Unit/AbstractTestCase.php create mode 100644 tests/Unit/ErrorsExceptionTest.php create mode 100644 tests/Unit/ErrorsTest.php delete mode 100644 tests/Unit/ParserErrorExceptionTest.php delete mode 100644 tests/Unit/ParserErrorExceptionToStringTest.php diff --git a/README.md b/README.md index d26d798..02dc459 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,13 @@ Heavily inspired by the well-known TypeScript library [zod](https://github.com/c Through [Composer](http://getcomposer.org) as [chubbyphp/chubbyphp-parsing][1]. ```sh -composer require chubbyphp/chubbyphp-parsing "^1.4" +composer require chubbyphp/chubbyphp-parsing "^2.0" ``` ## Usage ```php +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\SchemaInterface; /** @var SchemaInterface $schema */ @@ -51,7 +52,13 @@ $schema->preParse(static fn ($input) => $input); $schema->postParse(static fn (string $output) => $output); $schema->parse('test'); $schema->safeParse('test'); -$schema->catch(static fn (string $output, ParserErrorException $e) => $output); +$schema->catch(static fn (string $output, ErrorsException $e) => $output); + +try { + $schema->parse('test'); +} catch (ErrorsException $e) { + var_dump($e->errors->toApiProblems()); +} ``` ### array @@ -391,8 +398,15 @@ $schema = $p->union([$p->string(), $p->int()]); $data = $schema->parse('42'); ``` +## Migration + + * [1.x to 2.x][10] + ## Copyright 2025 Dominik Zogg [1]: https://packagist.org/packages/chubbyphp/chubbyphp-parsing + + +[10]: doc/Migration/1.x-2.x.md diff --git a/composer.json b/composer.json index 6e57958..781c3a5 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "2.0-dev" } }, "scripts": { diff --git a/doc/Migration/1.x-2.x.md b/doc/Migration/1.x-2.x.md new file mode 100644 index 0000000..a3c1921 --- /dev/null +++ b/doc/Migration/1.x-2.x.md @@ -0,0 +1,60 @@ +# 1.x to 2.x + +Adapted error handling. + +Added: + +- `Chubbyphp\Parsing\Errors` +- `Chubbyphp\Parsing\ErrorsException` + +Removed: + +- `Chubbyphp\Parsing\ParserErrorException` +- `Chubbyphp\Parsing\ParserErrorExceptionToString` + + +old: + +```php +string(); + +try { + $schema->parse('test'); +} catch (ParserErrorException $e) { + var_dump($e->getApiProblemErrorMessages()); +} +``` + +new + +```php +string(); + +try { + $schema->parse('test'); +} catch (ErrorsException $e) { + var_dump($e->errors->toApiProblems()); +} +``` diff --git a/phpstan.neon b/phpstan.neon index 13e0a0f..58b70f1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,5 @@ parameters: ignoreErrors: - - - message: '/type specified in iterable type array/' - path: %currentWorkingDirectory%/src/ParserErrorException.php - message: '/Instanceof between Chubbyphp\\Parsing\\Schema\\ObjectSchemaInterface and Chubbyphp\\Parsing\\Schema\\ObjectSchemaInterface will always evaluate to true./' path: %currentWorkingDirectory%/src/Schema/DiscriminatedUnionSchema.php diff --git a/src/Error.php b/src/Error.php index 5895d11..796fbd2 100644 --- a/src/Error.php +++ b/src/Error.php @@ -4,12 +4,15 @@ namespace Chubbyphp\Parsing; -final class Error +/** + * @phpstan-type ErrorAsJson array{code: string, template: string, variables: array} + */ +final class Error implements \JsonSerializable { /** * @param array $variables */ - public function __construct(public string $code, public string $template, public array $variables) {} + public function __construct(public readonly string $code, public readonly string $template, public readonly array $variables) {} public function __toString() { @@ -25,4 +28,16 @@ public function __toString() return $message; } + + /** + * @return ErrorAsJson + */ + public function jsonSerialize(): array + { + return [ + 'code' => $this->code, + 'template' => $this->template, + 'variables' => json_decode(json_encode($this->variables, JSON_THROW_ON_ERROR), true), + ]; + } } diff --git a/src/Errors.php b/src/Errors.php new file mode 100644 index 0000000..2a257c3 --- /dev/null +++ b/src/Errors.php @@ -0,0 +1,122 @@ + + * @phpstan-type ErrorAsJson array{code: string, template: string, variables: array} + * @phpstan-type ErrorWithPathJson array{path: string, error: ErrorAsJson} + * @phpstan-type ErrorsWithPathJson array + * @phpstan-type ApiProblem array{name: string, reason: string, details: non-empty-array} + */ +final class Errors implements \JsonSerializable +{ + /** + * @var ErrorsWithPath + */ + private array $errorsWithPath = []; + + public function __toString() + { + return implode(PHP_EOL, array_map(static fn ($error) => ('' !== $error['path'] ? $error['path'].': ' : '').$error['error'], $this->errorsWithPath)); + } + + public function add(Error|self $errors, string $path = ''): self + { + if ($errors instanceof self) { + foreach ($errors->errorsWithPath as $errorWithPath) { + $this->errorsWithPath[] = ['path' => $this->mergePath($path, $errorWithPath['path']), 'error' => $errorWithPath['error']]; + } + + return $this; + } + + $this->errorsWithPath[] = ['path' => $path, 'error' => $errors]; + + return $this; + } + + public function has(): bool + { + return 0 !== \count($this->errorsWithPath); + } + + /** + * @return ErrorsWithPathJson + */ + public function jsonSerialize(): array + { + return array_map(static fn ($errorWithPath) => [ + 'path' => $errorWithPath['path'], + 'error' => $errorWithPath['error']->jsonSerialize(), + ], $this->errorsWithPath); + } + + /** + * @return array + */ + public function toApiProblems(): array + { + return array_map( + fn ($errorWithPath) => [ + 'name' => $this->pathToName($errorWithPath['path']), + 'reason' => (string) $errorWithPath['error'], + 'details' => [ + '_template' => $errorWithPath['error']->template, + ...$errorWithPath['error']->variables, + ], + ], + $this->errorsWithPath + ); + } + + /** + * @return array + */ + public function toTree(): array + { + // @var array $tree + return array_reduce( + $this->errorsWithPath, + static function (array $tree, $errorWithPath): array { + $pathParts = explode('.', $errorWithPath['path']); + + $current = &$tree; + $lastIndex = \count($pathParts) - 1; + + foreach ($pathParts as $i => $pathPart) { + if ($i < $lastIndex) { + $current[$pathPart] ??= []; + $current = &$current[$pathPart]; + + continue; + } + + $current[$pathPart] = array_merge($current[$pathPart] ?? [], [(string) $errorWithPath['error']]); + } + + return $tree; + }, + [] + ); + } + + private function mergePath(string $path, string $existingPath): string + { + return implode('.', array_filter([$path, $existingPath], static fn ($part) => '' !== $part)); + } + + private function pathToName(string $path): string + { + $pathParts = explode('.', $path); + + return implode('', array_map( + static fn (string $pathPart, $i) => 0 === $i ? $pathPart : '['.$pathPart.']', + $pathParts, + array_keys($pathParts) + )); + } +} diff --git a/src/ErrorsException.php b/src/ErrorsException.php new file mode 100644 index 0000000..655d767 --- /dev/null +++ b/src/ErrorsException.php @@ -0,0 +1,18 @@ +add($errorsOrError); + + $this->errors = $errors; + parent::__construct((string) $errors); + } +} diff --git a/src/ParserErrorException.php b/src/ParserErrorException.php deleted file mode 100644 index d12eb7a..0000000 --- a/src/ParserErrorException.php +++ /dev/null @@ -1,116 +0,0 @@ -} - */ -final class ParserErrorException extends \RuntimeException -{ - private array $errors = []; - - public function __construct(?Error $error = null, int|string|null $key = null) - { - $this->message = new ParserErrorExceptionToString($this); - - if ($error) { - $this->addError($error, $key); - } - } - - public function __toString(): string - { - return self::class; - } - - public function addParserErrorException(self $parserErrorException, int|string|null $key = null): self - { - if (null !== $key) { - $this->errors = $this->mergeErrors([$key => $parserErrorException->getErrors()], $this->errors); - - return $this; - } - - $this->errors = $this->mergeErrors($parserErrorException->getErrors(), $this->errors); - - return $this; - } - - public function addError(Error $error, int|string|null $key = null): self - { - if (null !== $key) { - $this->errors = $this->mergeErrors([$key => [$error]], $this->errors); - - return $this; - } - - $this->errors = $this->mergeErrors([$error], $this->errors); - - return $this; - } - - public function getErrors(): array - { - return $this->errors; - } - - public function hasError(): bool - { - return 0 !== \count($this->errors); - } - - /** - * @return array - */ - public function getApiProblemErrorMessages(): array - { - return $this->flatErrorsToApiProblemMessages($this->errors); - } - - private function mergeErrors(array $errors, array $mergedErrors): array - { - foreach ($errors as $key => $error) { - if ($error instanceof Error) { - $mergedErrors[] = $error; - } else { - $mergedErrors[$key] = $this->mergeErrors($error, $mergedErrors[$key] ?? []); - } - } - - return $mergedErrors; - } - - /** - * @return array - */ - private function flatErrorsToApiProblemMessages(array $errors, string $path = ''): array - { - /** @var array */ - $errorsToApiProblemMessages = []; - - foreach ($errors as $key => $error) { - if ($error instanceof Error) { - $errorsToApiProblemMessages[] = [ - 'name' => $path, - 'reason' => (string) $error, - 'details' => [ - '_template' => $error->template, - ...$error->variables, - ], - ]; - } else { - $errorsToApiProblemMessages = array_merge( - $errorsToApiProblemMessages, - $this->flatErrorsToApiProblemMessages( - $error, - '' === $path ? $key : $path.'['.$key.']' - ) - ); - } - } - - return $errorsToApiProblemMessages; - } -} diff --git a/src/ParserErrorExceptionToString.php b/src/ParserErrorExceptionToString.php deleted file mode 100644 index c97174d..0000000 --- a/src/ParserErrorExceptionToString.php +++ /dev/null @@ -1,25 +0,0 @@ - */ - $lines = []; - - foreach ($this->e->getApiProblemErrorMessages() as $apiProblemErrorMessage) { - $lines[] = "{$apiProblemErrorMessage['name']}: {$apiProblemErrorMessage['reason']}"; - } - - return implode(PHP_EOL, $lines); - } -} diff --git a/src/Result.php b/src/Result.php index 9de3630..d883244 100644 --- a/src/Result.php +++ b/src/Result.php @@ -8,7 +8,7 @@ final class Result { public bool $success; - public function __construct(public mixed $data, public ?ParserErrorException $exception) + public function __construct(public mixed $data, public ?ErrorsException $exception) { $this->success = null === $exception; } diff --git a/src/Schema/AbstractSchema.php b/src/Schema/AbstractSchema.php index e7b4dea..ed1ce6f 100644 --- a/src/Schema/AbstractSchema.php +++ b/src/Schema/AbstractSchema.php @@ -4,7 +4,7 @@ namespace Chubbyphp\Parsing\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Result; abstract class AbstractSchema implements SchemaInterface @@ -22,7 +22,7 @@ abstract class AbstractSchema implements SchemaInterface protected array $postParses = []; /** - * @var \Closure(mixed, ParserErrorException): mixed + * @var \Closure(mixed, ErrorsException): mixed */ protected ?\Closure $catch = null; @@ -63,13 +63,13 @@ final public function safeParse(mixed $input): Result { try { return new Result($this->parse($input), null); - } catch (ParserErrorException $parserErrorException) { - return new Result(null, $parserErrorException); + } catch (ErrorsException $e) { + return new Result(null, $e); } } /** - * @param \Closure(mixed $input, ParserErrorException $parserErrorException): mixed $catch + * @param \Closure(mixed $input, ErrorsException $e): mixed $catch */ final public function catch(\Closure $catch): static { diff --git a/src/Schema/ArraySchema.php b/src/Schema/ArraySchema.php index 11aa8ad..5e09c3d 100644 --- a/src/Schema/ArraySchema.php +++ b/src/Schema/ArraySchema.php @@ -5,7 +5,8 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; final class ArraySchema extends AbstractSchema implements SchemaInterface { @@ -36,7 +37,7 @@ public function parse(mixed $input): mixed } if (!\is_array($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -47,27 +48,27 @@ public function parse(mixed $input): mixed $array = []; - $childrenParserErrorException = new ParserErrorException(); + $childrenErrors = new Errors(); foreach ($input as $i => $item) { try { $array[$i] = $this->itemSchema->parse($item); - } catch (ParserErrorException $childParserErrorException) { - $childrenParserErrorException->addParserErrorException($childParserErrorException, $i); + } catch (ErrorsException $e) { + $childrenErrors->add($e->errors, (string) $i); } } - if ($childrenParserErrorException->hasError()) { - throw $childrenParserErrorException; + if ($childrenErrors->has()) { + throw new ErrorsException($childrenErrors); } return $this->dispatchPostParses($array); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } @@ -77,7 +78,7 @@ public function length(int $length): static $arrayLength = \count($array); if ($arrayLength !== $length) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_LENGTH_CODE, self::ERROR_LENGTH_TEMPLATE, @@ -96,7 +97,7 @@ public function minLength(int $minLength): static $arrayLength = \count($array); if ($arrayLength < $minLength) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_MIN_LENGTH_CODE, self::ERROR_MIN_LENGTH_TEMPLATE, @@ -115,7 +116,7 @@ public function maxLength(int $maxLength): static $arrayLength = \count($array); if ($arrayLength > $maxLength) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_MAX_LENGTH_CODE, self::ERROR_MAX_LENGTH_TEMPLATE, @@ -132,7 +133,7 @@ public function includes(mixed $includes, bool $strict = true): static { return $this->postParse(static function (array $array) use ($includes, $strict) { if (!\in_array($includes, $array, $strict)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_INCLUDES_CODE, self::ERROR_INCLUDES_TEMPLATE, diff --git a/src/Schema/BackedEnumSchema.php b/src/Schema/BackedEnumSchema.php index 4135f65..52d0402 100644 --- a/src/Schema/BackedEnumSchema.php +++ b/src/Schema/BackedEnumSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class BackedEnumSchema extends AbstractSchema implements SchemaInterface { @@ -57,7 +57,7 @@ public function parse(mixed $input): mixed } if (!\is_int($input) && !\is_string($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -69,7 +69,7 @@ public function parse(mixed $input): mixed $output = ($this->backedEnum)::tryFrom($input); if (null === $output) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_VALUE_CODE, self::ERROR_VALUE_TEMPLATE, @@ -82,12 +82,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($output); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } diff --git a/src/Schema/BoolSchema.php b/src/Schema/BoolSchema.php index 9844f6b..c0a76c3 100644 --- a/src/Schema/BoolSchema.php +++ b/src/Schema/BoolSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class BoolSchema extends AbstractSchema implements SchemaInterface { @@ -22,7 +22,7 @@ public function parse(mixed $input): mixed } if (!\is_bool($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -32,12 +32,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($input); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } diff --git a/src/Schema/DateTimeSchema.php b/src/Schema/DateTimeSchema.php index c40de69..8adcbb5 100644 --- a/src/Schema/DateTimeSchema.php +++ b/src/Schema/DateTimeSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class DateTimeSchema extends AbstractSchema implements SchemaInterface { @@ -28,7 +28,7 @@ public function parse(mixed $input): mixed } if (!$input instanceof \DateTimeInterface) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -38,12 +38,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($input); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } @@ -51,7 +51,7 @@ public function from(\DateTimeImmutable $from): static { return $this->postParse(static function (\DateTimeImmutable $datetime) use ($from) { if ($datetime < $from) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_FROM_CODE, self::ERROR_FROM_TEMPLATE, @@ -68,7 +68,7 @@ public function to(\DateTimeImmutable $to): static { return $this->postParse(static function (\DateTimeImmutable $datetime) use ($to) { if ($datetime > $to) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TO_CODE, self::ERROR_TO_TEMPLATE, diff --git a/src/Schema/DiscriminatedUnionSchema.php b/src/Schema/DiscriminatedUnionSchema.php index d00c71a..f07a27c 100644 --- a/src/Schema/DiscriminatedUnionSchema.php +++ b/src/Schema/DiscriminatedUnionSchema.php @@ -5,7 +5,8 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; final class DiscriminatedUnionSchema extends AbstractSchema implements SchemaInterface { @@ -73,7 +74,7 @@ public function parse(mixed $input): mixed } if (!\is_array($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -83,7 +84,7 @@ public function parse(mixed $input): mixed } if (!isset($input[$this->discriminatorFieldName])) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_DISCRIMINATOR_FIELD_CODE, self::ERROR_DISCRIMINATOR_FIELD_TEMPLATE, @@ -95,18 +96,18 @@ public function parse(mixed $input): mixed $output = $this->parseObjectSchemas($input, $input[$this->discriminatorFieldName]); return $this->dispatchPostParses($output); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } private function parseObjectSchemas(mixed $input, mixed $discriminator): mixed { - $parserErrorException = new ParserErrorException(); + $errors = new Errors(); foreach ($this->objectSchemas as $objectSchema) { /** @var SchemaInterface $discriminatorFieldSchema */ @@ -114,8 +115,8 @@ private function parseObjectSchemas(mixed $input, mixed $discriminator): mixed try { $discriminatorFieldSchema->parse($discriminator); - } catch (ParserErrorException $childParserErrorException) { - $parserErrorException->addParserErrorException($childParserErrorException); + } catch (ErrorsException $e) { + $errors->add($e->errors); continue; } @@ -123,6 +124,6 @@ private function parseObjectSchemas(mixed $input, mixed $discriminator): mixed return $objectSchema->parse($input); } - throw $parserErrorException; + throw new ErrorsException($errors); } } diff --git a/src/Schema/FloatSchema.php b/src/Schema/FloatSchema.php index 69cfa04..e8fb7f6 100644 --- a/src/Schema/FloatSchema.php +++ b/src/Schema/FloatSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class FloatSchema extends AbstractSchema implements SchemaInterface { @@ -37,7 +37,7 @@ public function parse(mixed $input): mixed } if (!\is_float($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -47,12 +47,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($input); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } @@ -60,7 +60,7 @@ public function gt(float $gt): static { return $this->postParse(static function (float $float) use ($gt) { if ($float <= $gt) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_GT_CODE, self::ERROR_GT_TEMPLATE, @@ -77,7 +77,7 @@ public function gte(float $gte): static { return $this->postParse(static function (float $float) use ($gte) { if ($float < $gte) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_GTE_CODE, self::ERROR_GTE_TEMPLATE, @@ -94,7 +94,7 @@ public function lt(float $lt): static { return $this->postParse(static function (float $float) use ($lt) { if ($float >= $lt) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_LT_CODE, self::ERROR_LT_TEMPLATE, @@ -111,7 +111,7 @@ public function lte(float $lte): static { return $this->postParse(static function (float $float) use ($lte) { if ($float > $lte) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_LTE_CODE, self::ERROR_LTE_TEMPLATE, @@ -157,7 +157,7 @@ public function toInt(): IntSchema $intInput = (int) $input; if ((float) $intInput !== $input) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_INT_CODE, self::ERROR_INT_TEMPLATE, diff --git a/src/Schema/IntSchema.php b/src/Schema/IntSchema.php index b7dfed9..6b0f868 100644 --- a/src/Schema/IntSchema.php +++ b/src/Schema/IntSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class IntSchema extends AbstractSchema implements SchemaInterface { @@ -34,7 +34,7 @@ public function parse(mixed $input): mixed } if (!\is_int($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -44,12 +44,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($input); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } @@ -57,7 +57,7 @@ public function gt(int $gt): static { return $this->postParse(static function (int $int) use ($gt) { if ($int <= $gt) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_GT_CODE, self::ERROR_GT_TEMPLATE, @@ -74,7 +74,7 @@ public function gte(int $gte): static { return $this->postParse(static function (int $int) use ($gte) { if ($int < $gte) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_GTE_CODE, self::ERROR_GTE_TEMPLATE, @@ -91,7 +91,7 @@ public function lt(int $lt): static { return $this->postParse(static function (int $int) use ($lt) { if ($int >= $lt) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_LT_CODE, self::ERROR_LT_TEMPLATE, @@ -108,7 +108,7 @@ public function lte(int $lte): static { return $this->postParse(static function (int $int) use ($lte) { if ($int > $lte) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_LTE_CODE, self::ERROR_LTE_TEMPLATE, diff --git a/src/Schema/LazySchema.php b/src/Schema/LazySchema.php index 96e73d3..8b6de2b 100644 --- a/src/Schema/LazySchema.php +++ b/src/Schema/LazySchema.php @@ -4,7 +4,7 @@ namespace Chubbyphp\Parsing\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Result; /** @@ -46,7 +46,7 @@ public function postParse(\Closure $postParse): static } /** - * @param \Closure(mixed $input, ParserErrorException $parserErrorException): mixed $catch + * @param \Closure(mixed $input, ErrorsException $e): mixed $catch */ public function catch(\Closure $catch): static { diff --git a/src/Schema/LiteralSchema.php b/src/Schema/LiteralSchema.php index e5d43cf..23957f4 100644 --- a/src/Schema/LiteralSchema.php +++ b/src/Schema/LiteralSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class LiteralSchema extends AbstractSchema { @@ -27,7 +27,7 @@ public function parse(mixed $input): mixed } if (!\is_bool($input) && !\is_float($input) && !\is_int($input) && !\is_string($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -37,7 +37,7 @@ public function parse(mixed $input): mixed } if ($input !== $this->literal) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_EQUALS_CODE, self::ERROR_EQUALS_TEMPLATE, @@ -47,12 +47,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($input); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } } diff --git a/src/Schema/ObjectSchema.php b/src/Schema/ObjectSchema.php index d2f6db3..7640d9f 100644 --- a/src/Schema/ObjectSchema.php +++ b/src/Schema/ObjectSchema.php @@ -5,7 +5,8 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; final class ObjectSchema extends AbstractSchema implements ObjectSchemaInterface { @@ -80,7 +81,7 @@ public function parse(mixed $input): mixed } if (!\is_array($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -91,23 +92,23 @@ public function parse(mixed $input): mixed $output = new $this->classname(); - $childrenParserErrorException = new ParserErrorException(); + $childrenErrors = new Errors(); - $this->unknownFields($input, $childrenParserErrorException); + $this->unknownFields($input, $childrenErrors); - $this->parseFields($input, $output, $childrenParserErrorException); + $this->parseFields($input, $output, $childrenErrors); - if ($childrenParserErrorException->hasError()) { - throw $childrenParserErrorException; + if ($childrenErrors->has()) { + throw new ErrorsException($childrenErrors); } return $this->dispatchPostParses($output); - } catch (ParserErrorException $childrenParserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $childrenParserErrorException); + return ($this->catch)($input, $e); } - throw $childrenParserErrorException; + throw $e; } } @@ -151,7 +152,7 @@ public function strict(array $strict = []): static /** * @param array $input */ - private function unknownFields(array $input, ParserErrorException $childrenParserErrorException): void + private function unknownFields(array $input, Errors $childrenErrors): void { if (null === $this->strict) { return; @@ -159,7 +160,7 @@ private function unknownFields(array $input, ParserErrorException $childrenParse foreach (array_keys($input) as $fieldName) { if (!\in_array($fieldName, $this->strict, true) && !isset($this->fieldToSchema[$fieldName])) { - $childrenParserErrorException->addError(new Error( + $childrenErrors->add(new Error( self::ERROR_UNKNOWN_FIELD_CODE, self::ERROR_UNKNOWN_FIELD_TEMPLATE, ['fieldName' => $fieldName] @@ -171,7 +172,7 @@ private function unknownFields(array $input, ParserErrorException $childrenParse /** * @param array $input */ - private function parseFields(array $input, object $object, ParserErrorException $childrenParserErrorException): void + private function parseFields(array $input, object $object, Errors $childrenErrors): void { foreach ($this->fieldToSchema as $fieldName => $fieldSchema) { try { @@ -184,8 +185,8 @@ private function parseFields(array $input, object $object, ParserErrorException } $object->{$fieldName} = $fieldSchema->parse($input[$fieldName] ?? null); - } catch (ParserErrorException $childParserErrorException) { - $childrenParserErrorException->addParserErrorException($childParserErrorException, $fieldName); + } catch (ErrorsException $e) { + $childrenErrors->add($e->errors, $fieldName); } } } diff --git a/src/Schema/RecordSchema.php b/src/Schema/RecordSchema.php index a2c9fa8..7a599a0 100644 --- a/src/Schema/RecordSchema.php +++ b/src/Schema/RecordSchema.php @@ -5,7 +5,8 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; final class RecordSchema extends AbstractSchema implements SchemaInterface { @@ -32,7 +33,7 @@ public function parse(mixed $input): mixed } if (!\is_array($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -43,27 +44,27 @@ public function parse(mixed $input): mixed $output = []; - $childrenParserErrorException = new ParserErrorException(); + $childrenErrors = new Errors(); foreach ($input as $fieldName => $fieldValue) { try { $output[$fieldName] = $this->fieldSchema->parse($fieldValue); - } catch (ParserErrorException $childParserErrorException) { - $childrenParserErrorException->addParserErrorException($childParserErrorException, $fieldName); + } catch (ErrorsException $e) { + $childrenErrors->add($e->errors, $fieldName); } } - if ($childrenParserErrorException->hasError()) { - throw $childrenParserErrorException; + if ($childrenErrors->has()) { + throw new ErrorsException($childrenErrors); } return $this->dispatchPostParses($output); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } } diff --git a/src/Schema/RespectValidationSchema.php b/src/Schema/RespectValidationSchema.php index de1acdf..6cb4895 100644 --- a/src/Schema/RespectValidationSchema.php +++ b/src/Schema/RespectValidationSchema.php @@ -5,7 +5,8 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; use Respect\Validation\Exceptions\NestedValidationException; use Respect\Validation\Exceptions\ValidationException; use Respect\Validation\Validatable; @@ -30,31 +31,31 @@ public function parse(mixed $input): mixed } catch (ValidationException $e) { throw $this->convertException($e); } - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } - private function convertException(NestedValidationException|ValidationException $validationException): ParserErrorException + private function convertException(NestedValidationException|ValidationException $e): ErrorsException { - if ($validationException instanceof NestedValidationException) { - $parserErrorException = new ParserErrorException(); - foreach ($validationException->getChildren() as $childValidationException) { - $parserErrorException->addParserErrorException($this->convertException($childValidationException)); + if ($e instanceof NestedValidationException) { + $errors = new Errors(); + foreach ($e->getChildren() as $child) { + $errors->add($this->convertException($child)->errors); } - return $parserErrorException; + return new ErrorsException($errors); } - return new ParserErrorException( + return new ErrorsException( new Error( - $validationException->getId(), - $validationException->getMessage(), - $validationException->getParams(), + $e->getId(), + $e->getMessage(), + $e->getParams(), ) ); } diff --git a/src/Schema/SchemaInterface.php b/src/Schema/SchemaInterface.php index f0ddebf..0c7ccec 100644 --- a/src/Schema/SchemaInterface.php +++ b/src/Schema/SchemaInterface.php @@ -4,7 +4,7 @@ namespace Chubbyphp\Parsing\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Result; interface SchemaInterface @@ -26,7 +26,7 @@ public function parse(mixed $input): mixed; public function safeParse(mixed $input): Result; /** - * @param \Closure(mixed $input, ParserErrorException $parserErrorException): mixed $catch + * @param \Closure(mixed $input, ErrorsException $e): mixed $catch */ public function catch(\Closure $catch): static; } diff --git a/src/Schema/StringSchema.php b/src/Schema/StringSchema.php index 66524fc..62b695e 100644 --- a/src/Schema/StringSchema.php +++ b/src/Schema/StringSchema.php @@ -5,7 +5,7 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; final class StringSchema extends AbstractSchema implements SchemaInterface { @@ -67,7 +67,7 @@ public function parse(mixed $input): mixed } if (!\is_string($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -77,12 +77,12 @@ public function parse(mixed $input): mixed } return $this->dispatchPostParses($input); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } @@ -92,7 +92,7 @@ public function length(int $length): static $stringLength = \strlen($string); if ($stringLength !== $length) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_LENGTH_CODE, self::ERROR_LENGTH_TEMPLATE, @@ -111,7 +111,7 @@ public function minLength(int $minLength): static $stringLength = \strlen($string); if ($stringLength < $minLength) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_MIN_LENGTH_CODE, self::ERROR_MIN_LENGTH_TEMPLATE, @@ -130,7 +130,7 @@ public function maxLength(int $maxLength): static $stringLength = \strlen($string); if ($stringLength > $maxLength) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_MAX_LENGTH_CODE, self::ERROR_MAX_LENGTH_TEMPLATE, @@ -147,7 +147,7 @@ public function includes(string $includes): static { return $this->postParse(static function (string $string) use ($includes) { if (!str_contains($string, $includes)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_INCLUDES_CODE, self::ERROR_INCLUDES_TEMPLATE, @@ -164,7 +164,7 @@ public function startsWith(string $startsWith): static { return $this->postParse(static function (string $string) use ($startsWith) { if (!str_starts_with($string, $startsWith)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_STARTSWITH_CODE, self::ERROR_STARTSWITH_TEMPLATE, @@ -181,7 +181,7 @@ public function endsWith(string $endsWith): static { return $this->postParse(static function (string $string) use ($endsWith) { if (!str_ends_with($string, $endsWith)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_ENDSWITH_CODE, self::ERROR_ENDSWITH_TEMPLATE, @@ -202,7 +202,7 @@ public function match(string $match): static return $this->postParse(static function (string $string) use ($match) { if (0 === preg_match($match, $string)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_MATCH_CODE, self::ERROR_MATCH_TEMPLATE, @@ -219,7 +219,7 @@ public function email(): static { return $this->postParse(static function (string $string) { if (!filter_var($string, FILTER_VALIDATE_EMAIL)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_EMAIL_CODE, self::ERROR_EMAIL_TEMPLATE, @@ -236,7 +236,7 @@ public function ipV4(): static { return $this->postParse(static function (string $string) { if (!filter_var($string, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_IP_CODE, self::ERROR_IP_TEMPLATE, @@ -253,7 +253,7 @@ public function ipV6(): static { return $this->postParse(static function (string $string) { if (!filter_var($string, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_IP_CODE, self::ERROR_IP_TEMPLATE, @@ -270,7 +270,7 @@ public function url(): static { return $this->postParse(static function (string $string) { if (!filter_var($string, FILTER_VALIDATE_URL)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_URL_CODE, self::ERROR_URL_TEMPLATE, @@ -287,7 +287,7 @@ public function uuidV4(): static { return $this->postParse(static function (string $string) { if (0 === preg_match(self::UUID_V4_PATTERN, $string)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_UUID_CODE, self::ERROR_UUID_TEMPLATE, @@ -304,7 +304,7 @@ public function uuidV5(): static { return $this->postParse(static function (string $string) { if (0 === preg_match(self::UUID_V5_PATTERN, $string)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_UUID_CODE, self::ERROR_UUID_TEMPLATE, @@ -364,7 +364,7 @@ public function toDateTime(): DateTimeSchema } catch (\Exception) { // NOSONAR: supress the exception to throw a more specific one } - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_DATETIME_CODE, self::ERROR_DATETIME_TEMPLATE, @@ -387,7 +387,7 @@ public function toFloat(): FloatSchema $floatInput = (float) $input; if ((string) $floatInput !== $input) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_FLOAT_CODE, self::ERROR_FLOAT_TEMPLATE, @@ -413,7 +413,7 @@ public function toInt(): IntSchema $intInput = (int) $input; if ((string) $intInput !== $input) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_INT_CODE, self::ERROR_INT_TEMPLATE, diff --git a/src/Schema/TupleSchema.php b/src/Schema/TupleSchema.php index 578bd85..3f1ddab 100644 --- a/src/Schema/TupleSchema.php +++ b/src/Schema/TupleSchema.php @@ -5,7 +5,8 @@ namespace Chubbyphp\Parsing\Schema; use Chubbyphp\Parsing\Error; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; final class TupleSchema extends AbstractSchema implements SchemaInterface { @@ -57,7 +58,7 @@ public function parse(mixed $input): mixed } if (!\is_array($input)) { - throw new ParserErrorException( + throw new ErrorsException( new Error( self::ERROR_TYPE_CODE, self::ERROR_TYPE_TEMPLATE, @@ -66,25 +67,25 @@ public function parse(mixed $input): mixed ); } - $childrenParserErrorException = new ParserErrorException(); + $childrenErrors = new Errors(); $output = []; foreach ($this->schemas as $i => $schema) { if (!isset($input[$i])) { - $childrenParserErrorException->addError(new Error( + $childrenErrors->add(new Error( self::ERROR_MISSING_INDEX_CODE, self::ERROR_MISSING_INDEX_TEMPLATE, ['index' => $i] - ), $i); + ), (string) $i); continue; } try { $output[$i] = $schema->parse($input[$i]); - } catch (ParserErrorException $childParserErrorException) { - $childrenParserErrorException->addParserErrorException($childParserErrorException, $i); + } catch (ErrorsException $e) { + $childrenErrors->add($e->errors, (string) $i); } } @@ -92,24 +93,24 @@ public function parse(mixed $input): mixed $schemaCount = \count($this->schemas); for ($i = $schemaCount; $i < $inputCount; ++$i) { - $childrenParserErrorException->addError(new Error( + $childrenErrors->add(new Error( self::ERROR_ADDITIONAL_INDEX_CODE, self::ERROR_ADDITIONAL_INDEX_TEMPLATE, ['index' => $i] - ), $i); + ), (string) $i); } - if ($childrenParserErrorException->hasError()) { - throw $childrenParserErrorException; + if ($childrenErrors->has()) { + throw new ErrorsException($childrenErrors); } return $this->dispatchPostParses($output); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } } diff --git a/src/Schema/UnionSchema.php b/src/Schema/UnionSchema.php index 52928a9..fc4b546 100644 --- a/src/Schema/UnionSchema.php +++ b/src/Schema/UnionSchema.php @@ -4,7 +4,8 @@ namespace Chubbyphp\Parsing\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Errors; +use Chubbyphp\Parsing\ErrorsException; final class UnionSchema extends AbstractSchema implements SchemaInterface { @@ -46,27 +47,27 @@ public function parse(mixed $input): mixed $output = $this->parseSchemas($input); return $this->dispatchPostParses($output); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $e) { if ($this->catch) { - return ($this->catch)($input, $parserErrorException); + return ($this->catch)($input, $e); } - throw $parserErrorException; + throw $e; } } private function parseSchemas(mixed $input): mixed { - $parserErrorException = new ParserErrorException(); + $errors = new Errors(); foreach ($this->schemas as $schema) { try { return $schema->parse($input); - } catch (ParserErrorException $childParserErrorException) { - $parserErrorException->addParserErrorException($childParserErrorException); + } catch (ErrorsException $e) { + $errors->add($e->errors); } } - throw $parserErrorException; + throw new ErrorsException($errors); } } diff --git a/tests/Integration/ParserTest.php b/tests/Integration/ParserTest.php index e6ee93b..acf3857 100644 --- a/tests/Integration/ParserTest.php +++ b/tests/Integration/ParserTest.php @@ -4,8 +4,8 @@ namespace Chubbyphp\Tests\Parsing\Integration; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Parser; -use Chubbyphp\Parsing\ParserErrorException; use Chubbyphp\Parsing\Schema\SchemaInterface; use PHPUnit\Framework\TestCase; @@ -90,10 +90,11 @@ public function testFailureWithEmptyArray(): void $schema->parse([]); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 'array' => [ - [ + [ + 'path' => 'array', + 'error' => [ 'code' => 'array.type', 'template' => 'Type should be "array", {{given}} given', 'variables' => [ @@ -101,8 +102,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'backedEnum' => [ - [ + [ + 'path' => 'backedEnum', + 'error' => [ 'code' => 'backedEnum.type', 'template' => 'Type should be "int|string", {{given}} given', 'variables' => [ @@ -110,8 +112,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'bool' => [ - [ + [ + 'path' => 'bool', + 'error' => [ 'code' => 'bool.type', 'template' => 'Type should be "bool", {{given}} given', 'variables' => [ @@ -119,8 +122,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'dateTime' => [ - [ + [ + 'path' => 'dateTime', + 'error' => [ 'code' => 'datetime.type', 'template' => 'Type should be "\DateTimeInterface", {{given}} given', 'variables' => [ @@ -128,8 +132,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'discriminatedUnion' => [ - [ + [ + 'path' => 'discriminatedUnion', + 'error' => [ 'code' => 'discriminatedUnion.type', 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', 'variables' => [ @@ -137,8 +142,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'float' => [ - [ + [ + 'path' => 'float', + 'error' => [ 'code' => 'float.type', 'template' => 'Type should be "float", {{given}} given', 'variables' => [ @@ -146,8 +152,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'int' => [ - [ + [ + 'path' => 'int', + 'error' => [ 'code' => 'int.type', 'template' => 'Type should be "int", {{given}} given', 'variables' => [ @@ -155,8 +162,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'literal' => [ - [ + [ + 'path' => 'literal', + 'error' => [ 'code' => 'literal.type', 'template' => 'Type should be "bool|float|int|string", {{given}} given', 'variables' => [ @@ -164,8 +172,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'object' => [ - [ + [ + 'path' => 'object', + 'error' => [ 'code' => 'object.type', 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', 'variables' => [ @@ -173,8 +182,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'record' => [ - [ + [ + 'path' => 'record', + 'error' => [ 'code' => 'record.type', 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', 'variables' => [ @@ -182,8 +192,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'string' => [ - [ + [ + 'path' => 'string', + 'error' => [ 'code' => 'string.type', 'template' => 'Type should be "string", {{given}} given', 'variables' => [ @@ -191,8 +202,9 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'tuple' => [ - [ + [ + 'path' => 'tuple', + 'error' => [ 'code' => 'tuple.type', 'template' => 'Type should be "array", {{given}} given', 'variables' => [ @@ -200,15 +212,19 @@ public function testFailureWithEmptyArray(): void ], ], ], - 'union' => [ - [ + [ + 'path' => 'union', + 'error' => [ 'code' => 'string.type', 'template' => 'Type should be "string", {{given}} given', 'variables' => [ 'given' => 'NULL', ], ], - [ + ], + [ + 'path' => 'union', + 'error' => [ 'code' => 'int.type', 'template' => 'Type should be "int", {{given}} given', 'variables' => [ @@ -216,7 +232,7 @@ public function testFailureWithEmptyArray(): void ], ], ], - ], json_decode(json_encode($parserErrorException->getErrors()), true)); + ], $errorsException->errors->jsonSerialize()); } } diff --git a/tests/Unit/AbstractTestCase.php b/tests/Unit/AbstractTestCase.php deleted file mode 100644 index 5d35e27..0000000 --- a/tests/Unit/AbstractTestCase.php +++ /dev/null @@ -1,15 +0,0 @@ - true, 'int' => 1337, 'float' => 4.2, 'string' => 'test', 'array' => ['bool' => true, 'int' => 1337, 'float' => 4.2, 'string' => 'test'], + 'date' => new \DateTimeImmutable('2025-10-07T00:00:00Z'), ]; $error = new Error($code, $template, $variables); @@ -32,7 +33,16 @@ public function testToString(): void self::assertSame($template, $error->template); self::assertSame($variables, $error->variables); - self::assertSame('true,1337,4.2,"test",{"bool":true,"int":1337,"float":4.2,"string":"test"}', (string) $error); + self::assertSame( + 'true,1337,4.2,"test",{"bool":true,"int":1337,"float":4.2,"string":"test"},{"date":"2025-10-07 00:00:00.000000","timezone_type":2,"timezone":"Z"}', + (string) $error + ); + + self::assertSame([ + 'code' => 'some.error', + 'template' => '{{bool}},{{int}},{{float}},{{string}},{{array}},{{date}}', + 'variables' => json_decode(json_encode($variables), true), + ], $error->jsonSerialize()); } public function testToStringWithError(): void diff --git a/tests/Unit/ErrorsExceptionTest.php b/tests/Unit/ErrorsExceptionTest.php new file mode 100644 index 0000000..30a8583 --- /dev/null +++ b/tests/Unit/ErrorsExceptionTest.php @@ -0,0 +1,36 @@ +add($error, 'path'); + $exception = new ErrorsException($errors); + + self::assertSame($errors, $exception->errors); + self::assertSame('path: template', $exception->getMessage()); + } + + public function testWithError(): void + { + $error = new Error('code', 'template', []); + $exception = new ErrorsException($error); + + self::assertSame('template', $exception->getMessage()); + } +} diff --git a/tests/Unit/ErrorsTest.php b/tests/Unit/ErrorsTest.php new file mode 100644 index 0000000..bd9188d --- /dev/null +++ b/tests/Unit/ErrorsTest.php @@ -0,0 +1,394 @@ +add(new Error('code1', 'template1', []))); + self::assertSame('path: template2', (string) (new Errors())->add(new Error('code2', 'template2', []), 'path')); + + self::assertSame(<<<'EOD' + offset: Type should be "int", "float" given + offset: Type should be "string", "float" given + limit: Type should be "int", "float" given + limit: Type should be "string", "float" given + sort.name: Type should be "bool|float|int|string", "null" given + items.0.id: Type should be "string", "float" given + items.0.createdAt: Type should be "\DateTimeInterface", "float" given + items.0.updatedAt: Type should be "\DateTimeInterface", "float" given + items.0.name: Type should be "string", "float" given + items.0.tag: Type should be "string", "float" given + items.0.vaccinations.0.name: Type should be "string", "float" given + items.0.vaccinations.3.name: Type should be "string", "float" given + _type: Type should be "bool|float|int|string", "null" given + EOD, (string) $this->provideErrors()); + } + + public function testHas(): void + { + self::assertTrue($this->provideErrors()->has()); + } + + public function testJsonSerialize(): void + { + self::assertSame([ + 0 => [ + 'path' => 'offset', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 1 => [ + 'path' => 'offset', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 2 => [ + 'path' => 'limit', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 3 => [ + 'path' => 'limit', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 4 => [ + 'path' => 'sort.name', + 'error' => [ + 'code' => 'literal.type', + 'template' => 'Type should be "bool|float|int|string", {{given}} given', + 'variables' => [ + 'given' => 'null', + ], + ], + ], + 5 => [ + 'path' => 'items.0.id', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 6 => [ + 'path' => 'items.0.createdAt', + 'error' => [ + 'code' => 'datetime.type', + 'template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 7 => [ + 'path' => 'items.0.updatedAt', + 'error' => [ + 'code' => 'datetime.type', + 'template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 8 => [ + 'path' => 'items.0.name', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 9 => [ + 'path' => 'items.0.tag', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 10 => [ + 'path' => 'items.0.vaccinations.0.name', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 11 => [ + 'path' => 'items.0.vaccinations.3.name', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'float', + ], + ], + ], + 12 => [ + 'path' => '_type', + 'error' => [ + 'code' => 'literal.type', + 'template' => 'Type should be "bool|float|int|string", {{given}} given', + 'variables' => [ + 'given' => 'null', + ], + ], + ], + ], $this->provideErrors()->jsonSerialize()); + } + + public function testToApiProblems(): void + { + self::assertSame([ + 0 => [ + 'name' => 'offset', + 'reason' => 'Type should be "int", "float" given', + 'details' => [ + '_template' => 'Type should be "int", {{given}} given', + 'given' => 'float', + ], + ], + 1 => [ + 'name' => 'offset', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 2 => [ + 'name' => 'limit', + 'reason' => 'Type should be "int", "float" given', + 'details' => [ + '_template' => 'Type should be "int", {{given}} given', + 'given' => 'float', + ], + ], + 3 => [ + 'name' => 'limit', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 4 => [ + 'name' => 'sort[name]', + 'reason' => 'Type should be "bool|float|int|string", "null" given', + 'details' => [ + '_template' => 'Type should be "bool|float|int|string", {{given}} given', + 'given' => 'null', + ], + ], + 5 => [ + 'name' => 'items[0][id]', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 6 => [ + 'name' => 'items[0][createdAt]', + 'reason' => 'Type should be "\DateTimeInterface", "float" given', + 'details' => [ + '_template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'given' => 'float', + ], + ], + 7 => [ + 'name' => 'items[0][updatedAt]', + 'reason' => 'Type should be "\DateTimeInterface", "float" given', + 'details' => [ + '_template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'given' => 'float', + ], + ], + 8 => [ + 'name' => 'items[0][name]', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 9 => [ + 'name' => 'items[0][tag]', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 10 => [ + 'name' => 'items[0][vaccinations][0][name]', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 11 => [ + 'name' => 'items[0][vaccinations][3][name]', + 'reason' => 'Type should be "string", "float" given', + 'details' => [ + '_template' => 'Type should be "string", {{given}} given', + 'given' => 'float', + ], + ], + 12 => [ + 'name' => '_type', + 'reason' => 'Type should be "bool|float|int|string", "null" given', + 'details' => [ + '_template' => 'Type should be "bool|float|int|string", {{given}} given', + 'given' => 'null', + ], + ], + ], $this->provideErrors()->toApiProblems()); + } + + public function testToTree(): void + { + self::assertSame([ + 'offset' => [ + 0 => 'Type should be "int", "float" given', + 1 => 'Type should be "string", "float" given', + ], + 'limit' => [ + 0 => 'Type should be "int", "float" given', + 1 => 'Type should be "string", "float" given', + ], + 'sort' => [ + 'name' => [ + 0 => 'Type should be "bool|float|int|string", "null" given', + ], + ], + 'items' => [ + 0 => [ + 'id' => [ + 0 => 'Type should be "string", "float" given', + ], + 'createdAt' => [ + 0 => 'Type should be "\DateTimeInterface", "float" given', + ], + 'updatedAt' => [ + 0 => 'Type should be "\DateTimeInterface", "float" given', + ], + 'name' => [ + 0 => 'Type should be "string", "float" given', + ], + 'tag' => [ + 0 => 'Type should be "string", "float" given', + ], + 'vaccinations' => [ + 0 => [ + 'name' => [ + 0 => 'Type should be "string", "float" given', + ], + ], + 3 => [ + 'name' => [ + 0 => 'Type should be "string", "float" given', + ], + ], + ], + ], + ], + '_type' => [ + 0 => 'Type should be "bool|float|int|string", "null" given', + ], + ], $this->provideErrors()->toTree()); + } + + private function provideErrors(): Errors + { + return (new Errors()) + ->add( + (new Errors()) + ->add(new Error('int.type', 'Type should be "int", {{given}} given', ['given' => 'float'])) + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), + 'offset' + ) + ->add( + (new Errors()) + ->add(new Error('int.type', 'Type should be "int", {{given}} given', ['given' => 'float'])) + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), + 'limit' + ) + ->add( + (new Errors()) + ->add(new Error('literal.type', 'Type should be "bool|float|int|string", {{given}} given', ['given' => 'null']), 'name'), + 'sort' + ) + ->add( + (new Errors()) + ->add( + (new Errors()) + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float']), 'id') + ->add(new Error('datetime.type', 'Type should be "\DateTimeInterface", {{given}} given', ['given' => 'float']), 'createdAt') + ->add(new Error('datetime.type', 'Type should be "\DateTimeInterface", {{given}} given', ['given' => 'float']), 'updatedAt') + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float']), 'name') + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float']), 'tag') + ->add( + (new Errors()) + ->add( + (new Errors()) + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float']), 'name'), + '0' + ) + ->add( + (new Errors()) + ->add(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float']), 'name'), + '3' + ), + 'vaccinations' + ), + '0' + ), + 'items' + ) + ->add(new Error('literal.type', 'Type should be "bool|float|int|string", {{given}} given', ['given' => 'null']), '_type') + ; + } +} diff --git a/tests/Unit/ParserErrorExceptionTest.php b/tests/Unit/ParserErrorExceptionTest.php deleted file mode 100644 index 8de7044..0000000 --- a/tests/Unit/ParserErrorExceptionTest.php +++ /dev/null @@ -1,574 +0,0 @@ -getErrors()); - self::assertFalse($exception->hasError()); - } - - public function testConstructWithError(): void - { - $error = new Error('code', 'template', ['key' => 'value']); - - $exception = new ParserErrorException($error); - - self::assertSame([$error], $exception->getErrors()); - self::assertTrue($exception->hasError()); - } - - public function testConstructWithErrorAndKey(): void - { - $error = new Error('code', 'template', ['key' => 'value']); - - $exception = new ParserErrorException($error, 'field'); - - self::assertSame(['field' => [$error]], $exception->getErrors()); - self::assertTrue($exception->hasError()); - } - - public function testToString(): void - { - self::assertSame(ParserErrorException::class, (string) new ParserErrorException()); - } - - public function testAddParserErrorException(): void - { - $error = new Error('code', 'template', ['key' => 'value']); - - $exception = new ParserErrorException(); - $exception->addParserErrorException(new ParserErrorException($error)); - - self::assertSame([$error], $exception->getErrors()); - self::assertTrue($exception->hasError()); - } - - public function testAddParserErrorExceptionAndKey(): void - { - $error = new Error('code', 'template', ['key' => 'value']); - - $exception = new ParserErrorException(); - $exception->addParserErrorException(new ParserErrorException($error), 'field'); - - self::assertSame(['field' => [$error]], $exception->getErrors()); - self::assertTrue($exception->hasError()); - } - - public function testAddError(): void - { - $error = new Error('code', 'template', ['key' => 'value']); - - $exception = new ParserErrorException(); - $exception->addError($error); - - self::assertSame([$error], $exception->getErrors()); - self::assertTrue($exception->hasError()); - } - - public function testAddErrorAndKey(): void - { - $error = new Error('code', 'template', ['key' => 'value']); - - $exception = new ParserErrorException(); - $exception->addError($error, 'field'); - - self::assertSame(['field' => [$error]], $exception->getErrors()); - self::assertTrue($exception->hasError()); - } - - public function testNestedGetErrors(): void - { - $exception = self::getNestedParserErrorException(); - - self::assertSame([ - 'offset' => [ - [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'limit' => [ - [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'filters' => [ - 'name' => [ - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - ], - 'sort' => [ - 'name' => [ - [ - 'code' => 'literal.type', - 'template' => 'Type should be "bool|float|int|string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - [ - 'code' => 'literal.type', - 'template' => 'Type should be "bool|float|int|string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - ], - 'items' => [ - [ - 'id' => [ - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'createdAt' => [ - [ - 'code' => 'datetime.type', - 'template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'updatedAt' => [ - [ - 'code' => 'datetime.type', - 'template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'name' => [ - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'tag' => [ - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - 'vaccinations' => [ - 0 => [ - 'name' => [ - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - ], - 3 => [ - 'name' => [ - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - ], - ], - '_type' => [ - [ - 'code' => 'literal.type', - 'template' => 'Type should be "bool|float|int|string", {{given}} given', - 'variables' => [ - 'given' => 'float', - ], - ], - ], - ], - ], - ], $this->errorsToSimpleArray($exception->getErrors())); - - self::assertTrue($exception->hasError()); - } - - public function testNestedGetApiProblemErrorMessages(): void - { - $exception = self::getNestedParserErrorException(); - - self::assertSame([ - [ - 'name' => 'offset', - 'reason' => 'Type should be "int", "float" given', - 'details' => [ - '_template' => 'Type should be "int", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'offset', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'limit', - 'reason' => 'Type should be "int", "float" given', - 'details' => [ - '_template' => 'Type should be "int", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'limit', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'filters[name]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'sort[name]', - 'reason' => 'Type should be "bool|float|int|string", "float" given', - 'details' => [ - '_template' => 'Type should be "bool|float|int|string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'sort[name]', - 'reason' => 'Type should be "bool|float|int|string", "float" given', - 'details' => [ - '_template' => 'Type should be "bool|float|int|string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][id]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][createdAt]', - 'reason' => 'Type should be "\DateTimeInterface", "float" given', - 'details' => [ - '_template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][updatedAt]', - 'reason' => 'Type should be "\DateTimeInterface", "float" given', - 'details' => [ - '_template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][name]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][tag]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][vaccinations][0][name]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][vaccinations][0][name]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][vaccinations][3][name]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][vaccinations][3][name]', - 'reason' => 'Type should be "string", "float" given', - 'details' => [ - '_template' => 'Type should be "string", {{given}} given', - 'given' => 'float', - ], - ], - [ - 'name' => 'items[0][_type]', - 'reason' => 'Type should be "bool|float|int|string", "float" given', - 'details' => [ - '_template' => 'Type should be "bool|float|int|string", {{given}} given', - 'given' => 'float', - ], - ], - ], $this->errorsToSimpleArray($exception->getApiProblemErrorMessages())); - - self::assertTrue($exception->hasError()); - } - - public function testGetMessage(): void - { - $exception = self::getNestedParserErrorException(); - - $message = <<<'EOD' - offset: Type should be "int", "float" given - offset: Type should be "string", "float" given - limit: Type should be "int", "float" given - limit: Type should be "string", "float" given - filters[name]: Type should be "string", "float" given - sort[name]: Type should be "bool|float|int|string", "float" given - sort[name]: Type should be "bool|float|int|string", "float" given - items[0][id]: Type should be "string", "float" given - items[0][createdAt]: Type should be "\DateTimeInterface", "float" given - items[0][updatedAt]: Type should be "\DateTimeInterface", "float" given - items[0][name]: Type should be "string", "float" given - items[0][tag]: Type should be "string", "float" given - items[0][vaccinations][0][name]: Type should be "string", "float" given - items[0][vaccinations][0][name]: Type should be "string", "float" given - items[0][vaccinations][3][name]: Type should be "string", "float" given - items[0][vaccinations][3][name]: Type should be "string", "float" given - items[0][_type]: Type should be "bool|float|int|string", "float" given - EOD; - - self::assertSame($message, $exception->getMessage()); - - $exception->addError(new Error('random', 'Make sure this error gets added as well', []), 'anotherField'); - - $messageWithOneErrorMore = $message .= PHP_EOL.'anotherField: Make sure this error gets added as well'; - - self::assertSame($messageWithOneErrorMore, $exception->getMessage()); - } - - public static function getNestedParserErrorException(): ParserErrorException - { - return (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('int.type', 'Type should be "int", {{given}} given', ['given' => 'float'])) - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])) - ), - 'offset' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('int.type', 'Type should be "int", {{given}} given', ['given' => 'float'])) - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])) - ), - 'limit' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'name' - ), - 'filters' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('literal.type', 'Type should be "bool|float|int|string", {{given}} given', ['given' => 'float'])) - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('literal.type', 'Type should be "bool|float|int|string", {{given}} given', ['given' => 'float'])) - ), - 'name' - ), - 'sort' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'id' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('datetime.type', 'Type should be "\DateTimeInterface", {{given}} given', ['given' => 'float'])), - 'createdAt' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('datetime.type', 'Type should be "\DateTimeInterface", {{given}} given', ['given' => 'float'])), - 'updatedAt' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'name' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'tag' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'name' - ), - 0 - ) - // does make sense, but to make sure the nesting works as expected - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'name' - ), - 0 - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'name' - ), - 3 - ) - // does make sense, but to make sure the nesting works as expected - ->addParserErrorException( - (new ParserErrorException()) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('string.type', 'Type should be "string", {{given}} given', ['given' => 'float'])), - 'name' - ), - 3 - ), - 'vaccinations' - ) - ->addParserErrorException( - (new ParserErrorException()) - ->addError(new Error('literal.type', 'Type should be "bool|float|int|string", {{given}} given', ['given' => 'float'])), - '_type' - ), - 0 - ), - 'items' - ) - ; - } -} diff --git a/tests/Unit/ParserErrorExceptionToStringTest.php b/tests/Unit/ParserErrorExceptionToStringTest.php deleted file mode 100644 index ec4341d..0000000 --- a/tests/Unit/ParserErrorExceptionToStringTest.php +++ /dev/null @@ -1,51 +0,0 @@ -addError(new Error('random', 'Make sure this error gets added as well', []), 'anotherField'); - - $messageWithOneErrorMore = $message .= PHP_EOL.'anotherField: Make sure this error gets added as well'; - - self::assertSame($messageWithOneErrorMore, (string) $stringableException); - } -} diff --git a/tests/Unit/ResultTest.php b/tests/Unit/ResultTest.php index b168ae2..667eca7 100644 --- a/tests/Unit/ResultTest.php +++ b/tests/Unit/ResultTest.php @@ -4,7 +4,8 @@ namespace Chubbyphp\Tests\Parsing\Unit; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\Error; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Result; use PHPUnit\Framework\TestCase; @@ -28,7 +29,7 @@ public function testData(): void public function testException(): void { - $exception = new ParserErrorException(); + $exception = new ErrorsException(new Error('code', 'template', ['key' => 'value'])); $result = new Result(null, $exception); diff --git a/tests/Unit/Schema/ArraySchemaTest.php b/tests/Unit/Schema/ArraySchemaTest.php index 4d26e52..7794fb5 100644 --- a/tests/Unit/Schema/ArraySchemaTest.php +++ b/tests/Unit/Schema/ArraySchemaTest.php @@ -4,12 +4,12 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\ArraySchema; use Chubbyphp\Parsing\Schema\DateTimeSchema; use Chubbyphp\Parsing\Schema\IntSchema; use Chubbyphp\Parsing\Schema\StringSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -17,7 +17,7 @@ * * @internal */ -final class ArraySchemaTest extends AbstractTestCase +final class ArraySchemaTest extends TestCase { public function testImmutability(): void { @@ -28,7 +28,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(['test'])); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (array $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (array $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (array $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -66,18 +66,21 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame( [ [ - 'code' => 'array.type', - 'template' => 'Type should be "array", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'array.type', + 'template' => 'Type should be "array", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], ], - $this->errorsToSimpleArray($parserErrorException->getErrors()) + $errorsException->errors->jsonSerialize() ); } } @@ -92,10 +95,11 @@ public function testParseFailedWithoutStringInArray(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 1 => [ - [ + [ + 'path' => '1', + 'error' => [ 'code' => 'string.type', 'template' => 'Type should be "string", {{given}} given', 'variables' => [ @@ -103,8 +107,10 @@ public function testParseFailedWithoutStringInArray(): void ], ], ], - 2 => [ - [ + + [ + 'path' => '2', + 'error' => [ 'code' => 'string.type', 'template' => 'Type should be "string", {{given}} given', 'variables' => [ @@ -112,7 +118,7 @@ public function testParseFailedWithoutStringInArray(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -139,20 +145,23 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new ArraySchema(new StringSchema())) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame( [ [ - 'code' => 'array.type', - 'template' => 'Type should be "array", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'array.type', + 'template' => 'Type should be "array", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], ], - $this->errorsToSimpleArray($parserErrorException->getErrors()) + $errorsException->errors->jsonSerialize() ); return 'catched'; @@ -178,14 +187,17 @@ public function testSafeParseFailed(): void self::assertSame( [ [ - 'code' => 'array.type', - 'template' => 'Type should be "array", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'array.type', + 'template' => 'Type should be "array", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], ], - $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors()) + $schema->safeParse(null)->exception->errors->jsonSerialize() ); } @@ -208,17 +220,20 @@ public function testParseWithInvalidLength(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'array.length', - 'template' => 'Length {{length}}, {{given}} given', - 'variables' => [ - 'length' => 5, - 'given' => \count($input), + 'path' => '', + 'error' => [ + 'code' => 'array.length', + 'template' => 'Length {{length}}, {{given}} given', + 'variables' => [ + 'length' => 5, + 'given' => \count($input), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -241,17 +256,20 @@ public function testParseWithInvalidMinLength(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'array.minLength', - 'template' => 'Min length {{min}}, {{given}} given', - 'variables' => [ - 'minLength' => 5, - 'given' => \count($input), + 'path' => '', + 'error' => [ + 'code' => 'array.minLength', + 'template' => 'Min length {{min}}, {{given}} given', + 'variables' => [ + 'minLength' => 5, + 'given' => \count($input), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -274,17 +292,20 @@ public function testParseWithInvalidMaxLength(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'array.maxLength', - 'template' => 'Max length {{max}}, {{given}} given', - 'variables' => [ - 'maxLength' => 3, - 'given' => \count($input), + 'path' => '', + 'error' => [ + 'code' => 'array.maxLength', + 'template' => 'Max length {{max}}, {{given}} given', + 'variables' => [ + 'maxLength' => 3, + 'given' => \count($input), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -329,17 +350,23 @@ public function testParseWithInvalidIncludesWithEqualButNotSame(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { - self::assertSame([ + } catch (ErrorsException $errorsException) { + self::assertSame( [ - 'code' => 'array.includes', - 'template' => '{{given}} does not include {{includes}}', - 'variables' => [ - 'includes' => json_decode(json_encode($dateTime2Equal), true), - 'given' => json_decode(json_encode($input), true), + [ + 'path' => '', + 'error' => [ + 'code' => 'array.includes', + 'template' => '{{given}} does not include {{includes}}', + 'variables' => [ + 'includes' => json_decode(json_encode($dateTime2Equal), true), + 'given' => json_decode(json_encode($input), true), + ], + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + $errorsException->errors->jsonSerialize() + ); } } @@ -357,17 +384,23 @@ public function testParseWithInvalidIncludes(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { - self::assertSame([ + } catch (ErrorsException $errorsException) { + self::assertSame( [ - 'code' => 'array.includes', - 'template' => '{{given}} does not include {{includes}}', - 'variables' => [ - 'includes' => json_decode(json_encode($dateTime3), true), - 'given' => json_decode(json_encode($input), true), + [ + 'path' => '', + 'error' => [ + 'code' => 'array.includes', + 'template' => '{{given}} does not include {{includes}}', + 'variables' => [ + 'includes' => json_decode(json_encode($dateTime3), true), + 'given' => json_decode(json_encode($input), true), + ], + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + $errorsException->errors->jsonSerialize() + ); } } diff --git a/tests/Unit/Schema/BackedEnumSchemaTest.php b/tests/Unit/Schema/BackedEnumSchemaTest.php index d265c0f..c9d4e86 100644 --- a/tests/Unit/Schema/BackedEnumSchemaTest.php +++ b/tests/Unit/Schema/BackedEnumSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\BackedEnumSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; enum Suit { @@ -40,7 +40,7 @@ enum BackedEmpty: string {} * * @internal */ -final class BackedEnumSchemaTest extends AbstractTestCase +final class BackedEnumSchemaTest extends TestCase { public function testImmutability(): void { @@ -51,7 +51,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(true)); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (BackedSuit $output) => $output->value)); - self::assertNotSame($schema, $schema->catch(static fn (BackedSuit $output, ParserErrorException $e) => $output->value)); + self::assertNotSame($schema, $schema->catch(static fn (BackedSuit $output, ErrorsException $e) => $output->value)); } public function testConstructWithoutEnumClass(): void @@ -135,16 +135,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'backedEnum.type', - 'template' => 'Type should be "int|string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'backedEnum.type', + 'template' => 'Type should be "int|string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -156,17 +159,20 @@ public function testParseFailedWithUnknownValue(): void $schema->parse('Z'); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'backedEnum.value', - 'template' => 'Value should be one of {{cases}}, {{given}} given', - 'variables' => [ - 'cases' => ['H', 'D', 'C', 'S'], - 'given' => 'Z', + 'path' => '', + 'error' => [ + 'code' => 'backedEnum.value', + 'template' => 'Value should be one of {{cases}}, {{given}} given', + 'variables' => [ + 'cases' => ['H', 'D', 'C', 'S'], + 'given' => 'Z', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -193,17 +199,20 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new BackedEnumSchema(BackedSuit::class)) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'backedEnum.type', - 'template' => 'Type should be "int|string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'backedEnum.type', + 'template' => 'Type should be "int|string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -228,13 +237,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'backedEnum.type', - 'template' => 'Type should be "int|string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'backedEnum.type', + 'template' => 'Type should be "int|string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testParseWithValidtoInt(): void @@ -265,16 +277,19 @@ public function testParseWithInvalidToInt(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'string', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'string', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -306,16 +321,19 @@ public function testParseWithInvalidToString(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'integer', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'integer', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } } diff --git a/tests/Unit/Schema/BoolSchemaTest.php b/tests/Unit/Schema/BoolSchemaTest.php index a1532a1..415d523 100644 --- a/tests/Unit/Schema/BoolSchemaTest.php +++ b/tests/Unit/Schema/BoolSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\BoolSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -14,7 +14,7 @@ * * @internal */ -final class BoolSchemaTest extends AbstractTestCase +final class BoolSchemaTest extends TestCase { public function testImmutability(): void { @@ -25,7 +25,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(true)); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (bool $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (bool $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (bool $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -63,16 +63,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'bool.type', - 'template' => 'Type should be "bool", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'bool.type', + 'template' => 'Type should be "bool", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -98,17 +101,20 @@ public function testParseFailedWithCatch(): void { $schema = (new BoolSchema()) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'bool.type', - 'template' => 'Type should be "bool", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'bool.type', + 'template' => 'Type should be "bool", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -132,13 +138,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'bool.type', - 'template' => 'Type should be "bool", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'bool.type', + 'template' => 'Type should be "bool", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testParseWithToFloat(): void diff --git a/tests/Unit/Schema/DateTimeSchemaTest.php b/tests/Unit/Schema/DateTimeSchemaTest.php index 5afeefd..d4e2a5f 100644 --- a/tests/Unit/Schema/DateTimeSchemaTest.php +++ b/tests/Unit/Schema/DateTimeSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\DateTimeSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -14,7 +14,7 @@ * * @internal */ -final class DateTimeSchemaTest extends AbstractTestCase +final class DateTimeSchemaTest extends TestCase { public function testImmutability(): void { @@ -25,7 +25,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(new \DateTimeImmutable('2024-01-20T09:15:00+00:00'))); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (\DateTimeInterface $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (\DateTimeInterface $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (\DateTimeInterface $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -63,16 +63,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'datetime.type', - 'template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'datetime.type', + 'template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -97,17 +100,20 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new DateTimeSchema()) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'datetime.type', - 'template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'datetime.type', + 'template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -131,13 +137,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'datetime.type', - 'template' => 'Type should be "\DateTimeInterface", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'datetime.type', + 'template' => 'Type should be "\DateTimeInterface", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testParseWithValidFrom(): void @@ -161,17 +170,20 @@ public function testParseWithInvalidFrom(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'datetime.from', - 'template' => 'From datetime {{from}}, {{given}} given', - 'variables' => [ - 'from' => $min->format('c'), - 'given' => $input->format('c'), + 'path' => '', + 'error' => [ + 'code' => 'datetime.from', + 'template' => 'From datetime {{from}}, {{given}} given', + 'variables' => [ + 'from' => $min->format('c'), + 'given' => $input->format('c'), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -196,17 +208,23 @@ public function testParseWithInvalidTo(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { - self::assertSame([ + } catch (ErrorsException $errorsException) { + self::assertSame( [ - 'code' => 'datetime.to', - 'template' => 'To datetime {{to}}, {{given}} given', - 'variables' => [ - 'to' => $max->format('c'), - 'given' => $input->format('c'), + [ + 'path' => '', + 'error' => [ + 'code' => 'datetime.to', + 'template' => 'To datetime {{to}}, {{given}} given', + 'variables' => [ + 'to' => $max->format('c'), + 'given' => $input->format('c'), + ], + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + $errorsException->errors->jsonSerialize() + ); } } diff --git a/tests/Unit/Schema/DiscriminatedUnionSchemaTest.php b/tests/Unit/Schema/DiscriminatedUnionSchemaTest.php index 5a34c7c..e4d1e35 100644 --- a/tests/Unit/Schema/DiscriminatedUnionSchemaTest.php +++ b/tests/Unit/Schema/DiscriminatedUnionSchemaTest.php @@ -4,14 +4,14 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\ArraySchema; use Chubbyphp\Parsing\Schema\DiscriminatedUnionSchema; use Chubbyphp\Parsing\Schema\IntSchema; use Chubbyphp\Parsing\Schema\LiteralSchema; use Chubbyphp\Parsing\Schema\ObjectSchema; use Chubbyphp\Parsing\Schema\StringSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; final class DiscriminatedUnionDemo implements \JsonSerializable { @@ -33,7 +33,7 @@ public function jsonSerialize(): array * * @internal */ -final class DiscriminatedUnionSchemaTest extends AbstractTestCase +final class DiscriminatedUnionSchemaTest extends TestCase { public function testImmutability(): void { @@ -47,7 +47,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default([])); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (\stdClass $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (\stdClass $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (\stdClass $output, ErrorsException $e) => $output)); } public function testConstructWithoutObjectSchema(): void @@ -197,16 +197,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'discriminatedUnion.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'discriminatedUnion.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -223,16 +226,19 @@ public function testParseFailedWithMissingDiscriminatorField(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'discriminatedUnion.discriminatorField', - 'template' => 'Input does not contain the discriminator field {{discriminatorFieldName}}', - 'variables' => [ - 'discriminatorFieldName' => 'field1', + 'path' => '', + 'error' => [ + 'code' => 'discriminatedUnion.discriminatorField', + 'template' => 'Input does not contain the discriminator field {{discriminatorFieldName}}', + 'variables' => [ + 'discriminatorFieldName' => 'field1', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -249,25 +255,31 @@ public function testParseFailedWithNoMatchingDiscriminator(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'literal.equals', - 'template' => 'Input should be {{expected}}, {{given}} given', - 'variables' => [ - 'expected' => 'type1', - 'given' => 'type3', + 'path' => '', + 'error' => [ + 'code' => 'literal.equals', + 'template' => 'Input should be {{expected}}, {{given}} given', + 'variables' => [ + 'expected' => 'type1', + 'given' => 'type3', + ], ], ], - 1 => [ - 'code' => 'literal.equals', - 'template' => 'Input should be {{expected}}, {{given}} given', - 'variables' => [ - 'expected' => 'type2', - 'given' => 'type3', + [ + 'path' => '', + 'error' => [ + 'code' => 'literal.equals', + 'template' => 'Input should be {{expected}}, {{given}} given', + 'variables' => [ + 'expected' => 'type2', + 'given' => 'type3', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -305,17 +317,20 @@ public function testParseFailedWithCatch(): void new ObjectSchema(['field1' => new LiteralSchema('type1')]), new ObjectSchema(['field1' => new LiteralSchema('type2'), 'field2' => new StringSchema()]), ], 'field1')) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'discriminatedUnion.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'discriminatedUnion.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -345,12 +360,15 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'discriminatedUnion.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'discriminatedUnion.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/FloatSchemaTest.php b/tests/Unit/Schema/FloatSchemaTest.php index d52a79d..ac98046 100644 --- a/tests/Unit/Schema/FloatSchemaTest.php +++ b/tests/Unit/Schema/FloatSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\FloatSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -14,7 +14,7 @@ * * @internal */ -final class FloatSchemaTest extends AbstractTestCase +final class FloatSchemaTest extends TestCase { public function testImmutability(): void { @@ -25,7 +25,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(4.2)); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (float $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (float $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (float $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -63,16 +63,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.type', - 'template' => 'Type should be "float", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'float.type', + 'template' => 'Type should be "float", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -98,17 +101,20 @@ public function testParseFailedWithCatch(): void { $schema = (new FloatSchema()) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'float.type', - 'template' => 'Type should be "float", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'float.type', + 'template' => 'Type should be "float", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -132,13 +138,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'float.type', - 'template' => 'Type should be "float", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'float.type', + 'template' => 'Type should be "float", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testParseWithValidGt(): void @@ -162,17 +171,23 @@ public function testParseWithInvalidGtEqual(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { - self::assertSame([ + } catch (ErrorsException $errorsException) { + self::assertSame( [ - 'code' => 'float.gt', - 'template' => 'Value should be greater than {{gt}}, {{given}} given', - 'variables' => [ - 'gt' => $gt, - 'given' => $input, + [ + 'path' => '', + 'error' => [ + 'code' => 'float.gt', + 'template' => 'Value should be greater than {{gt}}, {{given}} given', + 'variables' => [ + 'gt' => $gt, + 'given' => $input, + ], + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + $errorsException->errors->jsonSerialize() + ); } } @@ -187,17 +202,23 @@ public function testParseWithInvalidGtLesser(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { - self::assertSame([ + } catch (ErrorsException $errorsException) { + self::assertSame( [ - 'code' => 'float.gt', - 'template' => 'Value should be greater than {{gt}}, {{given}} given', - 'variables' => [ - 'gt' => $gt, - 'given' => $input, + [ + 'path' => '', + 'error' => [ + 'code' => 'float.gt', + 'template' => 'Value should be greater than {{gt}}, {{given}} given', + 'variables' => [ + 'gt' => $gt, + 'given' => $input, + ], + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + $errorsException->errors->jsonSerialize() + ); } } @@ -222,17 +243,20 @@ public function testParseWithInvalidGte(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.gte', - 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', - 'variables' => [ - 'gte' => $gte, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.gte', + 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', + 'variables' => [ + 'gte' => $gte, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -257,17 +281,20 @@ public function testParseWithInvalidLtEqual(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.lt', - 'template' => 'Value should be lesser than {{lt}}, {{given}} given', - 'variables' => [ - 'lt' => $lt, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.lt', + 'template' => 'Value should be lesser than {{lt}}, {{given}} given', + 'variables' => [ + 'lt' => $lt, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -282,17 +309,20 @@ public function testParseWithInvalidLtLesser(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.lt', - 'template' => 'Value should be lesser than {{lt}}, {{given}} given', - 'variables' => [ - 'lt' => $lt, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.lt', + 'template' => 'Value should be lesser than {{lt}}, {{given}} given', + 'variables' => [ + 'lt' => $lt, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -317,17 +347,20 @@ public function testParseWithInvalidLte(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.lte', - 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', - 'variables' => [ - 'lte' => $lte, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.lte', + 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', + 'variables' => [ + 'lte' => $lte, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -350,17 +383,20 @@ public function testParseWithInvalidPositive(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.gt', - 'template' => 'Value should be greater than {{gt}}, {{given}} given', - 'variables' => [ - 'gt' => 0, - 'given' => 0, + 'path' => '', + 'error' => [ + 'code' => 'float.gt', + 'template' => 'Value should be greater than {{gt}}, {{given}} given', + 'variables' => [ + 'gt' => 0, + 'given' => 0, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -383,17 +419,20 @@ public function testParseWithInvalidNonNegative(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.gte', - 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', - 'variables' => [ - 'gte' => 0, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.gte', + 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', + 'variables' => [ + 'gte' => 0, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -416,17 +455,20 @@ public function testParseWithInvalidNegative(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.lt', - 'template' => 'Value should be lesser than {{lt}}, {{given}} given', - 'variables' => [ - 'lt' => 0, - 'given' => 0, + 'path' => '', + 'error' => [ + 'code' => 'float.lt', + 'template' => 'Value should be lesser than {{lt}}, {{given}} given', + 'variables' => [ + 'lt' => 0, + 'given' => 0, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -449,17 +491,20 @@ public function testParseWithInvalidNonPositive(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.lte', - 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', - 'variables' => [ - 'lte' => 0, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.lte', + 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', + 'variables' => [ + 'lte' => 0, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -489,16 +534,19 @@ public function testParseWithInvalidToInt(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'float.int', - 'template' => 'Cannot convert {{given}} to int', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'float.int', + 'template' => 'Cannot convert {{given}} to int', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/IntSchemaTest.php b/tests/Unit/Schema/IntSchemaTest.php index c7fc520..102ca41 100644 --- a/tests/Unit/Schema/IntSchemaTest.php +++ b/tests/Unit/Schema/IntSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\IntSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -14,7 +14,7 @@ * * @internal */ -final class IntSchemaTest extends AbstractTestCase +final class IntSchemaTest extends TestCase { public function testImmutability(): void { @@ -25,7 +25,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(42)); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (int $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (int $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (int $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -63,16 +63,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -97,17 +100,20 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new IntSchema()) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -131,13 +137,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testParseWithValidGt(): void @@ -161,17 +170,20 @@ public function testParseWithInvalidGtEqual(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.gt', - 'template' => 'Value should be greater than {{gt}}, {{given}} given', - 'variables' => [ - 'gt' => $gt, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.gt', + 'template' => 'Value should be greater than {{gt}}, {{given}} given', + 'variables' => [ + 'gt' => $gt, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -186,17 +198,20 @@ public function testParseWithInvalidGtLesser(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.gt', - 'template' => 'Value should be greater than {{gt}}, {{given}} given', - 'variables' => [ - 'gt' => $gt, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.gt', + 'template' => 'Value should be greater than {{gt}}, {{given}} given', + 'variables' => [ + 'gt' => $gt, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -221,17 +236,20 @@ public function testParseWithInvalidGte(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.gte', - 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', - 'variables' => [ - 'gte' => $gte, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.gte', + 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', + 'variables' => [ + 'gte' => $gte, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -256,17 +274,20 @@ public function testParseWithInvalidLtEqual(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.lt', - 'template' => 'Value should be lesser than {{lt}}, {{given}} given', - 'variables' => [ - 'lt' => $lt, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.lt', + 'template' => 'Value should be lesser than {{lt}}, {{given}} given', + 'variables' => [ + 'lt' => $lt, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -281,17 +302,20 @@ public function testParseWithInvalidLtLesser(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.lt', - 'template' => 'Value should be lesser than {{lt}}, {{given}} given', - 'variables' => [ - 'lt' => $lt, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.lt', + 'template' => 'Value should be lesser than {{lt}}, {{given}} given', + 'variables' => [ + 'lt' => $lt, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -316,17 +340,20 @@ public function testParseWithInvalidLte(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.lte', - 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', - 'variables' => [ - 'lte' => $lte, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.lte', + 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', + 'variables' => [ + 'lte' => $lte, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -349,17 +376,20 @@ public function testParseWithInvalidPositive(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.gt', - 'template' => 'Value should be greater than {{gt}}, {{given}} given', - 'variables' => [ - 'gt' => 0, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.gt', + 'template' => 'Value should be greater than {{gt}}, {{given}} given', + 'variables' => [ + 'gt' => 0, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -382,17 +412,20 @@ public function testParseWithInvalidNonNegative(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.gte', - 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', - 'variables' => [ - 'gte' => 0, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.gte', + 'template' => 'Value should be greater than or equal {{gte}}, {{given}} given', + 'variables' => [ + 'gte' => 0, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -415,17 +448,20 @@ public function testParseWithInvalidNegative(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.lt', - 'template' => 'Value should be lesser than {{lt}}, {{given}} given', - 'variables' => [ - 'lt' => 0, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.lt', + 'template' => 'Value should be lesser than {{lt}}, {{given}} given', + 'variables' => [ + 'lt' => 0, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -448,17 +484,20 @@ public function testParseWithInvalidNonPositive(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'int.lte', - 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', - 'variables' => [ - 'lte' => 0, - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'int.lte', + 'template' => 'Value should be lesser than or equal {{lte}}, {{given}} given', + 'variables' => [ + 'lte' => 0, + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/LazySchemaTest.php b/tests/Unit/Schema/LazySchemaTest.php index b7dffc5..0e2bbdb 100644 --- a/tests/Unit/Schema/LazySchemaTest.php +++ b/tests/Unit/Schema/LazySchemaTest.php @@ -7,7 +7,7 @@ use Chubbyphp\Parsing\Schema\LazySchema; use Chubbyphp\Parsing\Schema\ObjectSchema; use Chubbyphp\Parsing\Schema\StringSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -15,7 +15,7 @@ * * @internal */ -final class LazySchemaTest extends AbstractTestCase +final class LazySchemaTest extends TestCase { public function testParseSuccess(): void { diff --git a/tests/Unit/Schema/LiteralSchemaTest.php b/tests/Unit/Schema/LiteralSchemaTest.php index 5e74b3f..618ecd0 100644 --- a/tests/Unit/Schema/LiteralSchemaTest.php +++ b/tests/Unit/Schema/LiteralSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\LiteralSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -14,7 +14,7 @@ * * @internal */ -final class LiteralSchemaTest extends AbstractTestCase +final class LiteralSchemaTest extends TestCase { public function testImmutability(): void { @@ -25,7 +25,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default('test')); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (string $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (string $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (string $output, ErrorsException $e) => $output)); } public function testParseSuccessWithBool(): void @@ -88,16 +88,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'literal.type', - 'template' => 'Type should be "bool|float|int|string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'literal.type', + 'template' => 'Type should be "bool|float|int|string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -109,17 +112,20 @@ public function testParseFailedWithDifferentStringLiteralValue(): void $schema->parse('test2'); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'literal.equals', - 'template' => 'Input should be {{expected}}, {{given}} given', - 'variables' => [ - 'expected' => 'test1', - 'given' => 'test2', + 'path' => '', + 'error' => [ + 'code' => 'literal.equals', + 'template' => 'Input should be {{expected}}, {{given}} given', + 'variables' => [ + 'expected' => 'test1', + 'given' => 'test2', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -131,17 +137,20 @@ public function testParseFailedWithDifferentFloatLiteralValue(): void $schema->parse(4.1); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'literal.equals', - 'template' => 'Input should be {{expected}}, {{given}} given', - 'variables' => [ - 'expected' => 4.2, - 'given' => 4.1, + 'path' => '', + 'error' => [ + 'code' => 'literal.equals', + 'template' => 'Input should be {{expected}}, {{given}} given', + 'variables' => [ + 'expected' => 4.2, + 'given' => 4.1, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -153,17 +162,20 @@ public function testParseFailedWithDifferentIntLiteralValue(): void $schema->parse(1336); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'literal.equals', - 'template' => 'Input should be {{expected}}, {{given}} given', - 'variables' => [ - 'expected' => 1337, - 'given' => 1336, + 'path' => '', + 'error' => [ + 'code' => 'literal.equals', + 'template' => 'Input should be {{expected}}, {{given}} given', + 'variables' => [ + 'expected' => 1337, + 'given' => 1336, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -175,17 +187,20 @@ public function testParseFailedWithDifferentBoolLiteralValue(): void $schema->parse(false); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'literal.equals', - 'template' => 'Input should be {{expected}}, {{given}} given', - 'variables' => [ - 'expected' => true, - 'given' => false, + 'path' => '', + 'error' => [ + 'code' => 'literal.equals', + 'template' => 'Input should be {{expected}}, {{given}} given', + 'variables' => [ + 'expected' => true, + 'given' => false, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -210,17 +225,20 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new LiteralSchema('test')) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'literal.type', - 'template' => 'Type should be "bool|float|int|string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'literal.type', + 'template' => 'Type should be "bool|float|int|string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -244,12 +262,15 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'literal.type', - 'template' => 'Type should be "bool|float|int|string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'literal.type', + 'template' => 'Type should be "bool|float|int|string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/ObjectSchemaTest.php b/tests/Unit/Schema/ObjectSchemaTest.php index 78e0ca9..486eef8 100644 --- a/tests/Unit/Schema/ObjectSchemaTest.php +++ b/tests/Unit/Schema/ObjectSchemaTest.php @@ -4,13 +4,13 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\BoolSchema; use Chubbyphp\Parsing\Schema\FloatSchema; use Chubbyphp\Parsing\Schema\IntSchema; use Chubbyphp\Parsing\Schema\ObjectSchema; use Chubbyphp\Parsing\Schema\StringSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; final class ObjectDemo implements \JsonSerializable { @@ -32,7 +32,7 @@ public function jsonSerialize(): array * * @internal */ -final class ObjectSchemaTest extends AbstractTestCase +final class ObjectSchemaTest extends TestCase { public function testImmutability(): void { @@ -43,7 +43,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default([])); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (\stdClass $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (\stdClass $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (\stdClass $output, ErrorsException $e) => $output)); self::assertNotSame($schema, $schema->strict()); self::assertNotSame($schema, $schema->optional([])); @@ -202,16 +202,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'object.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'object.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -225,10 +228,11 @@ public function testParseFailedWithAdditionalFields(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 'field2' => [ - [ + [ + 'path' => 'field2', + 'error' => [ 'code' => 'object.unknownField', 'template' => 'Unknown field {{fieldName}}', 'variables' => [ @@ -236,8 +240,9 @@ public function testParseFailedWithAdditionalFields(): void ], ], ], - 'field3' => [ - [ + [ + 'path' => 'field3', + 'error' => [ 'code' => 'object.unknownField', 'template' => 'Unknown field {{fieldName}}', 'variables' => [ @@ -245,7 +250,7 @@ public function testParseFailedWithAdditionalFields(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -259,10 +264,11 @@ public function testParseFailedWithFailedFields(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 'field2' => [ - [ + [ + 'path' => 'field2', + 'error' => [ 'code' => 'float.type', 'template' => 'Type should be "float", {{given}} given', 'variables' => [ @@ -270,8 +276,9 @@ public function testParseFailedWithFailedFields(): void ], ], ], - 'field3' => [ - [ + [ + 'path' => 'field3', + 'error' => [ 'code' => 'int.type', 'template' => 'Type should be "int", {{given}} given', 'variables' => [ @@ -279,7 +286,7 @@ public function testParseFailedWithFailedFields(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -295,10 +302,10 @@ public function testParseFailedWithOptionalButStillNotProvidedEnoughFields(): vo $schema->parse(['field2' => 'test']); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame( 'field3: Type should be "string", "NULL" given', - $parserErrorException->getMessage() + $errorsException->getMessage() ); } } @@ -328,17 +335,20 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new ObjectSchema(['field1' => new StringSchema()])) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'object.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'object.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -362,13 +372,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'object.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'object.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testGetFieldToSchema(): void diff --git a/tests/Unit/Schema/RecordSchemaTest.php b/tests/Unit/Schema/RecordSchemaTest.php index 1257dfa..969e8ce 100644 --- a/tests/Unit/Schema/RecordSchemaTest.php +++ b/tests/Unit/Schema/RecordSchemaTest.php @@ -4,10 +4,10 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\RecordSchema; use Chubbyphp\Parsing\Schema\StringSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; final class RecordDemo implements \JsonSerializable { @@ -29,7 +29,7 @@ public function jsonSerialize(): array * * @internal */ -final class RecordSchemaTest extends AbstractTestCase +final class RecordSchemaTest extends TestCase { public function testImmutability(): void { @@ -40,7 +40,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default([])); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (array $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (array $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (array $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -117,16 +117,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'record.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'record.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -140,10 +143,11 @@ public function testParseFailedWithFailedFields(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 'field2' => [ - [ + [ + 'path' => 'field2', + 'error' => [ 'code' => 'string.type', 'template' => 'Type should be "string", {{given}} given', 'variables' => [ @@ -151,7 +155,7 @@ public function testParseFailedWithFailedFields(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -180,17 +184,21 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new RecordSchema(new StringSchema())) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); + self::assertSame([ [ - 'code' => 'record.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'record.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -214,12 +222,15 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'record.type', - 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'record.type', + 'template' => 'Type should be "array|\stdClass|\Traversable", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/RespectValidationSchemaTest.php b/tests/Unit/Schema/RespectValidationSchemaTest.php index 3855284..2565ad0 100644 --- a/tests/Unit/Schema/RespectValidationSchemaTest.php +++ b/tests/Unit/Schema/RespectValidationSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\RespectValidationSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; use Respect\Validation\Validator as v; /** @@ -15,7 +15,7 @@ * * @internal */ -final class RespectValidationSchemaTest extends AbstractTestCase +final class RespectValidationSchemaTest extends TestCase { public function testImmutability(): void { @@ -26,7 +26,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(42)); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (float|int $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (float|int $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (float|int $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -66,23 +66,29 @@ public function testParseFailed(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'numericVal', - 'template' => '`NULL` must be numeric', - 'variables' => [ - 'input' => null, + 'path' => '', + 'error' => [ + 'code' => 'numericVal', + 'template' => '`NULL` must be numeric', + 'variables' => [ + 'input' => null, + ], ], ], [ - 'code' => 'positive', - 'template' => '`NULL` must be positive', - 'variables' => [ - 'input' => null, + 'path' => '', + 'error' => [ + 'code' => 'positive', + 'template' => '`NULL` must be positive', + 'variables' => [ + 'input' => null, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -111,24 +117,30 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new RespectValidationSchema(v::numericVal()->positive()->between(1, 255))) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'numericVal', - 'template' => '`NULL` must be numeric', - 'variables' => [ - 'input' => null, + 'path' => '', + 'error' => [ + 'code' => 'numericVal', + 'template' => '`NULL` must be numeric', + 'variables' => [ + 'input' => null, + ], ], ], [ - 'code' => 'positive', - 'template' => '`NULL` must be positive', - 'variables' => [ - 'input' => null, + 'path' => '', + 'error' => [ + 'code' => 'positive', + 'template' => '`NULL` must be positive', + 'variables' => [ + 'input' => null, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -154,19 +166,25 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'numericVal', - 'template' => '`NULL` must be numeric', - 'variables' => [ - 'input' => null, + 'path' => '', + 'error' => [ + 'code' => 'numericVal', + 'template' => '`NULL` must be numeric', + 'variables' => [ + 'input' => null, + ], ], ], [ - 'code' => 'positive', - 'template' => '`NULL` must be positive', - 'variables' => [ - 'input' => null, + 'path' => '', + 'error' => [ + 'code' => 'positive', + 'template' => '`NULL` must be positive', + 'variables' => [ + 'input' => null, + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse($input)->exception->getErrors())); + ], $schema->safeParse($input)->exception->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/StringSchemaTest.php b/tests/Unit/Schema/StringSchemaTest.php index 21ad0b7..3334246 100644 --- a/tests/Unit/Schema/StringSchemaTest.php +++ b/tests/Unit/Schema/StringSchemaTest.php @@ -4,9 +4,9 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\StringSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -14,7 +14,7 @@ * * @internal */ -final class StringSchemaTest extends AbstractTestCase +final class StringSchemaTest extends TestCase { public function testImmutability(): void { @@ -25,7 +25,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(42)); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (string $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (string $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (string $output, ErrorsException $e) => $output)); } public function testParseSuccess(): void @@ -63,16 +63,19 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -97,17 +100,20 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new StringSchema()) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -131,13 +137,16 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } public function testParseWithValidLength(): void @@ -159,17 +168,20 @@ public function testParseWithInvalidLength(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.length', - 'template' => 'Length {{length}}, {{given}} given', - 'variables' => [ - 'length' => 5, - 'given' => \strlen($input), + 'path' => '', + 'error' => [ + 'code' => 'string.length', + 'template' => 'Length {{length}}, {{given}} given', + 'variables' => [ + 'length' => 5, + 'given' => \strlen($input), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -192,17 +204,20 @@ public function testParseWithInvalidMinLength(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.minLength', - 'template' => 'Min length {{min}}, {{given}} given', - 'variables' => [ - 'minLength' => 5, - 'given' => \strlen($input), + 'path' => '', + 'error' => [ + 'code' => 'string.minLength', + 'template' => 'Min length {{min}}, {{given}} given', + 'variables' => [ + 'minLength' => 5, + 'given' => \strlen($input), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -225,17 +240,20 @@ public function testParseWithInvalidMaxLength(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.maxLength', - 'template' => 'Max length {{max}}, {{given}} given', - 'variables' => [ - 'maxLength' => 3, - 'given' => \strlen($input), + 'path' => '', + 'error' => [ + 'code' => 'string.maxLength', + 'template' => 'Max length {{max}}, {{given}} given', + 'variables' => [ + 'maxLength' => 3, + 'given' => \strlen($input), + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -258,17 +276,20 @@ public function testParseWithInvalidIncludes(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.includes', - 'template' => '{{given}} does not include {{includes}}', - 'variables' => [ - 'includes' => 'lee', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.includes', + 'template' => '{{given}} does not include {{includes}}', + 'variables' => [ + 'includes' => 'lee', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -291,17 +312,20 @@ public function testParseWithInvalidStartsWith(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.startsWith', - 'template' => '{{given}} does not starts with {{startsWith}}', - 'variables' => [ - 'startsWith' => 'xam', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.startsWith', + 'template' => '{{given}} does not starts with {{startsWith}}', + 'variables' => [ + 'startsWith' => 'xam', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -324,17 +348,20 @@ public function testParseWithInvalidEndsWith(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.endsWith', - 'template' => '{{given}} does not ends with {{endsWith}}', - 'variables' => [ - 'endsWith' => 'mpl', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.endsWith', + 'template' => '{{given}} does not ends with {{endsWith}}', + 'variables' => [ + 'endsWith' => 'mpl', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -368,17 +395,20 @@ public function testParseWithInvalidMatch(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.match', - 'template' => '{{given}} does not match {{match}}', - 'variables' => [ - 'match' => '/^[a-z]+$/i', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.match', + 'template' => '{{given}} does not match {{match}}', + 'variables' => [ + 'match' => '/^[a-z]+$/i', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -401,16 +431,19 @@ public function testParseWithInvalidEmail(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.email', - 'template' => 'Invalid email {{given}}', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.email', + 'template' => 'Invalid email {{given}}', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -433,17 +466,20 @@ public function testParseWithInvalidIpV4(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.ip', - 'template' => 'Invalid ip {{version}} {{given}}', - 'variables' => [ - 'version' => 'v4', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.ip', + 'template' => 'Invalid ip {{version}} {{given}}', + 'variables' => [ + 'version' => 'v4', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -466,17 +502,20 @@ public function testParseWithInvalidIpV6(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.ip', - 'template' => 'Invalid ip {{version}} {{given}}', - 'variables' => [ - 'version' => 'v6', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.ip', + 'template' => 'Invalid ip {{version}} {{given}}', + 'variables' => [ + 'version' => 'v6', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -499,16 +538,19 @@ public function testParseWithInvalidUrl(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.url', - 'template' => 'Invalid url {{given}}', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.url', + 'template' => 'Invalid url {{given}}', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -531,17 +573,20 @@ public function testParseWithInvalidUuidV4(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.uuid', - 'template' => 'Invalid uuid {{version}} {{given}}', - 'variables' => [ - 'version' => 'v4', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.uuid', + 'template' => 'Invalid uuid {{version}} {{given}}', + 'variables' => [ + 'version' => 'v4', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -564,17 +609,20 @@ public function testParseWithInvalidUuidV5(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.uuid', - 'template' => 'Invalid uuid {{version}} {{given}}', - 'variables' => [ - 'version' => 'v5', - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.uuid', + 'template' => 'Invalid uuid {{version}} {{given}}', + 'variables' => [ + 'version' => 'v5', + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -642,16 +690,19 @@ public function testParseWithInvalidToDateTimeWithInvalidMonth(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.datetime', - 'template' => 'Cannot convert {{given}} to datetime', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.datetime', + 'template' => 'Cannot convert {{given}} to datetime', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -665,16 +716,19 @@ public function testParseWithInvalidToDateTimeWithInvalidDay(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.datetime', - 'template' => 'Cannot convert {{given}} to datetime', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.datetime', + 'template' => 'Cannot convert {{given}} to datetime', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -688,16 +742,19 @@ public function testParseWithInvalidToDateTimeWithAllZero(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.datetime', - 'template' => 'Cannot convert {{given}} to datetime', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.datetime', + 'template' => 'Cannot convert {{given}} to datetime', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -711,16 +768,19 @@ public function testParseWithInvalidToDateTimeWithText(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.datetime', - 'template' => 'Cannot convert {{given}} to datetime', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.datetime', + 'template' => 'Cannot convert {{given}} to datetime', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -750,16 +810,19 @@ public function testParseWithInvalidToFloat(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.float', - 'template' => 'Cannot convert {{given}} to float', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.float', + 'template' => 'Cannot convert {{given}} to float', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -789,16 +852,19 @@ public function testParseWithInvalidToInt(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.int', - 'template' => 'Cannot convert {{given}} to int', - 'variables' => [ - 'given' => $input, + 'path' => '', + 'error' => [ + 'code' => 'string.int', + 'template' => 'Cannot convert {{given}} to int', + 'variables' => [ + 'given' => $input, + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } diff --git a/tests/Unit/Schema/TupleSchemaTest.php b/tests/Unit/Schema/TupleSchemaTest.php index f4b1315..7bd3eae 100644 --- a/tests/Unit/Schema/TupleSchemaTest.php +++ b/tests/Unit/Schema/TupleSchemaTest.php @@ -4,10 +4,10 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\StringSchema; use Chubbyphp\Parsing\Schema\TupleSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -15,7 +15,7 @@ * * @internal */ -final class TupleSchemaTest extends AbstractTestCase +final class TupleSchemaTest extends TestCase { public function testImmutability(): void { @@ -26,7 +26,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default(['test'])); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (array $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (array $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (array $output, ErrorsException $e) => $output)); } public function testConstructWithoutSchema(): void @@ -78,18 +78,21 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame( [ [ - 'code' => 'tuple.type', - 'template' => 'Type should be "array", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'tuple.type', + 'template' => 'Type should be "array", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], ], - $this->errorsToSimpleArray($parserErrorException->getErrors()) + $errorsException->errors->jsonSerialize() ); } } @@ -104,10 +107,11 @@ public function testParseFailedWithoutStringInArray(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 1 => [ - [ + [ + 'path' => '1', + 'error' => [ 'code' => 'string.type', 'template' => 'Type should be "string", {{given}} given', 'variables' => [ @@ -115,7 +119,7 @@ public function testParseFailedWithoutStringInArray(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -129,10 +133,11 @@ public function testParseFailedCauseMissingIndex(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 1 => [ - [ + [ + 'path' => '1', + 'error' => [ 'code' => 'tuple.missingIndex', 'template' => 'Missing input at index {{index}}', 'variables' => [ @@ -140,8 +145,9 @@ public function testParseFailedCauseMissingIndex(): void ], ], ], - 2 => [ - [ + [ + 'path' => '2', + 'error' => [ 'code' => 'tuple.missingIndex', 'template' => 'Missing input at index {{index}}', 'variables' => [ @@ -149,7 +155,7 @@ public function testParseFailedCauseMissingIndex(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -163,10 +169,11 @@ public function testParseFailedCauseAdditionalIndex(): void $schema->parse($input); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ - 2 => [ - [ + [ + 'path' => '2', + 'error' => [ 'code' => 'tuple.additionalIndex', 'template' => 'Additional input at index {{index}}', 'variables' => [ @@ -174,7 +181,7 @@ public function testParseFailedCauseAdditionalIndex(): void ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -201,20 +208,23 @@ public function testParseSuccessWithPostParse(): void public function testParseFailedWithCatch(): void { $schema = (new TupleSchema([new StringSchema(), new StringSchema()])) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); self::assertSame( [ [ - 'code' => 'tuple.type', - 'template' => 'Type should be "array", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'tuple.type', + 'template' => 'Type should be "array", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], ], - $this->errorsToSimpleArray($parserErrorException->getErrors()) + $errorsException->errors->jsonSerialize() ); return 'catched'; @@ -240,14 +250,17 @@ public function testSafeParseFailed(): void self::assertSame( [ [ - 'code' => 'tuple.type', - 'template' => 'Type should be "array", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'tuple.type', + 'template' => 'Type should be "array", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], ], - $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors()) + $schema->safeParse(null)->exception->errors->jsonSerialize() ); } } diff --git a/tests/Unit/Schema/UnionSchemaTest.php b/tests/Unit/Schema/UnionSchemaTest.php index 49b7955..9caaaf5 100644 --- a/tests/Unit/Schema/UnionSchemaTest.php +++ b/tests/Unit/Schema/UnionSchemaTest.php @@ -4,11 +4,11 @@ namespace Chubbyphp\Tests\Parsing\Unit\Schema; -use Chubbyphp\Parsing\ParserErrorException; +use Chubbyphp\Parsing\ErrorsException; use Chubbyphp\Parsing\Schema\IntSchema; use Chubbyphp\Parsing\Schema\StringSchema; use Chubbyphp\Parsing\Schema\UnionSchema; -use Chubbyphp\Tests\Parsing\Unit\AbstractTestCase; +use PHPUnit\Framework\TestCase; /** * @covers \Chubbyphp\Parsing\Schema\AbstractSchema @@ -16,7 +16,7 @@ * * @internal */ -final class UnionSchemaTest extends AbstractTestCase +final class UnionSchemaTest extends TestCase { public function testImmutability(): void { @@ -27,7 +27,7 @@ public function testImmutability(): void self::assertNotSame($schema, $schema->default('test')); self::assertNotSame($schema, $schema->preParse(static fn (mixed $input) => $input)); self::assertNotSame($schema, $schema->postParse(static fn (int|string $output) => $output)); - self::assertNotSame($schema, $schema->catch(static fn (int|string $output, ParserErrorException $e) => $output)); + self::assertNotSame($schema, $schema->catch(static fn (int|string $output, ErrorsException $e) => $output)); } public function testConstructWithWrongArgument(): void @@ -97,23 +97,30 @@ public function testParseFailedWithNull(): void $schema->parse(null); throw new \Exception('code should not be reached'); - } catch (ParserErrorException $parserErrorException) { + } catch (ErrorsException $errorsException) { self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], + [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); } } @@ -138,24 +145,32 @@ public function testParseSuccessWithIntAndparse(): void public function testParseFailedWithCatch(): void { $schema = (new UnionSchema([new StringSchema(), new IntSchema()])) - ->catch(function (mixed $input, ParserErrorException $parserErrorException) { + ->catch(static function (mixed $input, ErrorsException $errorsException) { self::assertNull($input); + self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], + [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($parserErrorException->getErrors())); + ], $errorsException->errors->jsonSerialize()); return 'catched'; }) @@ -188,19 +203,25 @@ public function testSafeParseFailed(): void self::assertSame([ [ - 'code' => 'string.type', - 'template' => 'Type should be "string", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'string.type', + 'template' => 'Type should be "string", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], [ - 'code' => 'int.type', - 'template' => 'Type should be "int", {{given}} given', - 'variables' => [ - 'given' => 'NULL', + 'path' => '', + 'error' => [ + 'code' => 'int.type', + 'template' => 'Type should be "int", {{given}} given', + 'variables' => [ + 'given' => 'NULL', + ], ], ], - ], $this->errorsToSimpleArray($schema->safeParse(null)->exception->getErrors())); + ], $schema->safeParse(null)->exception->errors->jsonSerialize()); } }