fix: handle invalid nodes recursively

This commit is contained in:
Romain Canon 2022-08-05 11:57:25 +02:00
parent 2540741171
commit a401c2a2d6
4 changed files with 46 additions and 19 deletions

View File

@ -145,7 +145,8 @@ final class TreeNode
} }
if ($this->valid && ! $this->shell->type()->accepts($this->value)) { if ($this->valid && ! $this->shell->type()->accepts($this->value)) {
throw new InvalidNodeValue($this->value, $this->shell->type()); $this->valid = false;
$this->messages[] = new InvalidNodeValue($this->value, $this->shell->type());
} }
} }

View File

@ -68,6 +68,10 @@ final class Node
$this->messages[] = $message; $this->messages[] = $message;
$this->isValid = $this->isValid && ! $message->isError(); $this->isValid = $this->isValid && ! $message->isError();
} }
foreach ($this->children as $child) {
$this->isValid = $this->isValid && $child->isValid();
}
} }
public function isRoot(): bool public function isRoot(): bool

View File

@ -7,7 +7,6 @@ namespace CuyZ\Valinor\Tests\Unit\Mapper\Tree\Builder;
use AssertionError; use AssertionError;
use CuyZ\Valinor\Mapper\Tree\Builder\TreeNode; use CuyZ\Valinor\Mapper\Tree\Builder\TreeNode;
use CuyZ\Valinor\Mapper\Tree\Exception\DuplicatedNodeChild; use CuyZ\Valinor\Mapper\Tree\Exception\DuplicatedNodeChild;
use CuyZ\Valinor\Mapper\Tree\Exception\InvalidNodeValue;
use CuyZ\Valinor\Mapper\Tree\Shell; use CuyZ\Valinor\Mapper\Tree\Shell;
use CuyZ\Valinor\Tests\Fake\Definition\FakeAttributes; use CuyZ\Valinor\Tests\Fake\Definition\FakeAttributes;
use CuyZ\Valinor\Tests\Fake\Mapper\Tree\Builder\FakeTreeNode; use CuyZ\Valinor\Tests\Fake\Mapper\Tree\Builder\FakeTreeNode;
@ -37,15 +36,13 @@ final class TreeNodeTest extends TestCase
self::assertSame('some value', $node->mappedValue()); self::assertSame('some value', $node->mappedValue());
} }
public function test_node_leaf_with_incorrect_value_throws_exception(): void public function test_node_leaf_with_incorrect_value_is_invalid(): void
{ {
$type = new FakeType(); $type = new FakeType();
$this->expectException(InvalidNodeValue::class); $node = FakeTreeNode::leaf($type, 'foo');
$this->expectExceptionCode(1630678334);
$this->expectExceptionMessage("Value 'foo' does not match type `{$type->toString()}`.");
FakeTreeNode::leaf($type, 'foo'); self::assertFalse($node->isValid());
} }
public function test_node_branch_values_can_be_retrieved(): void public function test_node_branch_values_can_be_retrieved(): void
@ -84,11 +81,9 @@ final class TreeNodeTest extends TestCase
{ {
$type = new FakeType(); $type = new FakeType();
$this->expectException(InvalidNodeValue::class); $node = FakeTreeNode::branch([], $type, 'foo');
$this->expectExceptionCode(1630678334);
$this->expectExceptionMessage("Value 'foo' does not match type `{$type->toString()}`.");
FakeTreeNode::branch([], $type, 'foo'); self::assertFalse($node->isValid());
} }
public function test_node_error_values_can_be_retrieved(): void public function test_node_error_values_can_be_retrieved(): void
@ -133,11 +128,9 @@ final class TreeNodeTest extends TestCase
{ {
$type = FakeType::accepting('foo'); $type = FakeType::accepting('foo');
$this->expectException(InvalidNodeValue::class); $node = FakeTreeNode::leaf($type, 'foo')->withValue(1337);
$this->expectExceptionCode(1630678334);
$this->expectExceptionMessage("Value 1337 does not match type `{$type->toString()}`.");
FakeTreeNode::leaf($type, 'foo')->withValue(1337); self::assertFalse($node->isValid());
} }
public function test_node_with_invalid_value_for_object_type_returns_invalid_node(): void public function test_node_with_invalid_value_for_object_type_returns_invalid_node(): void
@ -145,11 +138,9 @@ final class TreeNodeTest extends TestCase
$object = new stdClass(); $object = new stdClass();
$type = FakeObjectType::accepting($object); $type = FakeObjectType::accepting($object);
$this->expectException(InvalidNodeValue::class); $node = FakeTreeNode::leaf($type, $object)->withValue(1337);
$this->expectExceptionCode(1630678334);
$this->expectExceptionMessage('Invalid value 1337.');
FakeTreeNode::leaf($type, $object)->withValue(1337); self::assertFalse($node->isValid());
} }
public function test_node_with_messages_returns_node_with_messages(): void public function test_node_with_messages_returns_node_with_messages(): void

View File

@ -62,6 +62,37 @@ final class NodeTest extends TestCase
self::assertSame(false, $node->isValid()); self::assertSame(false, $node->isValid());
} }
public function test_invalid_child_makes_root_node_not_valid(): void
{
$message = new FakeErrorMessage();
$node = new Node(
true,
'',
'*root*',
'string',
true,
'some source value',
'some value',
[],
[
new Node(
false,
'nodeName',
'some.node.path',
'string',
true,
'some source value',
'some value',
[$message],
[]
)
]
);
self::assertSame(false, $node->isValid());
}
public function test_get_source_value_not_filled_throws_exception(): void public function test_get_source_value_not_filled_throws_exception(): void
{ {
$this->expectException(SourceValueWasNotFilled::class); $this->expectException(SourceValueWasNotFilled::class);