Skip to content

Commit

Permalink
fix: keep nested errors when superfluous keys are detected
Browse files Browse the repository at this point in the history
  • Loading branch information
romm committed Dec 20, 2022
1 parent 3fac3e5 commit 813b3b4
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 27 deletions.
12 changes: 7 additions & 5 deletions src/Mapper/Tree/Builder/ClassNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ public function build(ObjectBuilder $builder, Shell $shell, RootNodeBuilder $roo
{
$arguments = ArgumentsValues::forClass($builder->describeArguments(), $shell->value());

if (! $this->allowSuperfluousKeys && count($arguments->superfluousKeys()) > 0) {
return TreeNode::error($shell, new UnexpectedArrayKeysForClass($arguments));
}

$children = $this->children($shell, $arguments, $rootBuilder);

$object = $this->buildObject($builder, $children);

return count($children) === 1
$node = count($children) === 1
? TreeNode::flattenedBranch($shell, $object, $children[0])
: TreeNode::branch($shell, $object, $children);

if (! $this->allowSuperfluousKeys && count($arguments->superfluousKeys()) > 0) {
$node = $node->withMessage(new UnexpectedArrayKeysForClass($arguments));
}

return $node;
}

/**
Expand Down
14 changes: 8 additions & 6 deletions src/Mapper/Tree/Builder/ShapedArrayNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use CuyZ\Valinor\Type\Types\ShapedArrayType;

use function array_key_exists;
use function array_keys;
use function assert;
use function count;
use function is_array;
Expand All @@ -34,9 +33,16 @@ public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
}

$children = $this->children($type, $shell, $rootBuilder);

$array = $this->buildArray($children);

return TreeNode::branch($shell, $array, $children);
$node = TreeNode::branch($shell, $array, $children);

if (! $this->allowSuperfluousKeys && count($value) > count($children)) {
$node = $node->withMessage(new UnexpectedShapedArrayKeys($value, $children));
}

return $node;
}

/**
Expand Down Expand Up @@ -65,10 +71,6 @@ private function children(ShapedArrayType $type, Shell $shell, RootNodeBuilder $
unset($value[$key]);
}

if (! $this->allowSuperfluousKeys && count($value) > 0) {
throw new UnexpectedShapedArrayKeys(array_keys($value), $elements);
}

return $children;
}

Expand Down
19 changes: 13 additions & 6 deletions src/Mapper/Tree/Exception/UnexpectedShapedArrayKeys.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

namespace CuyZ\Valinor\Mapper\Tree\Exception;

use CuyZ\Valinor\Mapper\Tree\Builder\TreeNode;
use CuyZ\Valinor\Mapper\Tree\Message\ErrorMessage;
use CuyZ\Valinor\Mapper\Tree\Message\HasParameters;
use CuyZ\Valinor\Type\Types\ShapedArrayElement;
use CuyZ\Valinor\Utility\String\StringFormatter;
use RuntimeException;

use function array_filter;
use function array_keys;
use function array_map;
use function implode;
use function in_array;

/** @internal */
final class UnexpectedShapedArrayKeys extends RuntimeException implements ErrorMessage, HasParameters
Expand All @@ -22,15 +25,19 @@ final class UnexpectedShapedArrayKeys extends RuntimeException implements ErrorM
private array $parameters;

/**
* @param array<string> $keys
* @param array<ShapedArrayElement> $elements
* @param array<mixed> $value
* @param array<TreeNode> $children
*/
public function __construct(array $keys, array $elements)
public function __construct(array $value, array $children)
{
$expected = array_map(fn (ShapedArrayElement $element) => $element->key()->toString(), $elements);
$expected = array_map(fn (TreeNode $child) => $child->name(), $children);
$superfluous = array_filter(
array_keys($value),
fn (string $key) => ! in_array($key, $expected, true)
);

$this->parameters = [
'keys' => '`' . implode('`, `', $keys) . '`',
'keys' => '`' . implode('`, `', $superfluous) . '`',
'expected_keys' => '`' . implode('`, `', $expected) . '`',
];

Expand Down
12 changes: 7 additions & 5 deletions tests/Integration/Mapping/Object/ObjectValuesMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,23 @@ public function test_invalid_iterable_source_throws_exception(): void
}
}

public function test_superfluous_values_throws_exception(): void
public function test_superfluous_values_throws_exception_and_keeps_nested_errors(): void
{
try {
(new MapperBuilder())->mapper()->map(ObjectWithTwoProperties::class, [
'stringA' => 'fooA',
'stringA' => 42,
'stringB' => 'fooB',
'unexpectedValueA' => 'foo',
'unexpectedValueB' => 'bar',
42 => 'baz',
]);
} catch (MappingError $exception) {
$error = $exception->node()->messages()[0];
$rootError = $exception->node()->messages()[0];
$nestedError = $exception->node()->children()['stringA']->messages()[0];

self::assertSame('1655149208', $error->code());
self::assertSame('Unexpected key(s) `unexpectedValueA`, `unexpectedValueB`, `42`, expected `stringA`, `stringB`.', (string)$error);
self::assertSame('1655149208', $rootError->code());
self::assertSame('Unexpected key(s) `unexpectedValueA`, `unexpectedValueB`, `42`, expected `stringA`, `stringB`.', (string)$rootError);
self::assertSame('Value 42 is not a valid string.', (string)$nestedError);
}
}

Expand Down
12 changes: 7 additions & 5 deletions tests/Integration/Mapping/Other/ShapedArrayMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,23 @@ public function test_missing_element_throws_exception(): void
}
}

public function test_superfluous_values_throws_exception(): void
public function test_superfluous_values_throws_exception_and_keeps_nested_errors(): void
{
$source = [
'foo' => 'foo',
'foo' => 404,
'bar' => 42,
'fiz' => 1337.404,
];

try {
(new MapperBuilder())->mapper()->map('array{foo: string, bar: int}', $source);
} catch (MappingError $exception) {
$error = $exception->node()->messages()[0];
$rootError = $exception->node()->messages()[0];
$nestedError = $exception->node()->children()['foo']->messages()[0];

self::assertSame('1655117782', $error->code());
self::assertSame('Unexpected key(s) `fiz`, expected `foo`, `bar`.', (string)$error);
self::assertSame('1655117782', $rootError->code());
self::assertSame('Unexpected key(s) `fiz`, expected `foo`, `bar`.', (string)$rootError);
self::assertSame('Value 404 is not a valid string.', (string)$nestedError);
}
}
}

0 comments on commit 813b3b4

Please sign in to comment.