diff --git a/src/XmlTemplateReader.php b/src/XmlTemplateReader.php index fd0cff7..e4d59cf 100644 --- a/src/XmlTemplateReader.php +++ b/src/XmlTemplateReader.php @@ -516,12 +516,19 @@ private function addListenersFromTemplate(SimpleXMLElement $simpleXMLElement, ar $this->namespace, )); - Assertion::true(class_exists($configuration['castTo']), sprintf( + Assertion::classExists($configuration['castTo'], sprintf( 'The "%s" node\'s %s:castTo attribute value "%s" refers to non-existent class FQN', $currentPathString, $this->namespace, $configurationAttributes['castTo'], )); + Assertion::subclassOf($configuration['castTo'], NodeInterface::class, sprintf( + 'The "%s" node\'s %s:castTo attribute value "%s" refers to a class that does not implement "%s" interface', + $currentPathString, + $this->namespace, + $configurationAttributes['castTo'], + NodeInterface::class, + )); // Attributes rules foreach ($child->attributes() as $name => $rulesDefinition) { diff --git a/tests/Feature/XmlTemplateReader/BasicTemplateReaderTest.php b/tests/Feature/XmlTemplateReader/BasicTemplateReaderTest.php index ad73bca..7da0554 100644 --- a/tests/Feature/XmlTemplateReader/BasicTemplateReaderTest.php +++ b/tests/Feature/XmlTemplateReader/BasicTemplateReaderTest.php @@ -176,7 +176,7 @@ public function invalidChunkSizeDataProvider(): array } /** - * @depends testCanBeConstructedWithDefaultDispatcher + * @depends testCanBeConstructedWithDefaultDispatcher * @dataProvider invalidChunkSizeDataProvider */ public function testFailToParseFromResourceWithInvalidChunkSize(int $chunkSize, XmlTemplateReader $xmlTemplateReader): void diff --git a/tests/Feature/XmlTemplateReader/CastToModeTest.php b/tests/Feature/XmlTemplateReader/CastToModeTest.php new file mode 100644 index 0000000..27f81e5 --- /dev/null +++ b/tests/Feature/XmlTemplateReader/CastToModeTest.php @@ -0,0 +1,89 @@ +read( + <<<'XML' + + + + + + + + +XML + ); + + self::assertInstanceOf(Node::class, $node); + + $rootNodeRelationsMap = $node->getRelations(); + + self::assertTrue($rootNodeRelationsMap->has('casted')); + self::assertInstanceOf(CastedRelationNode::class, $rootNodeRelationsMap->get('casted')); + + self::assertTrue($rootNodeRelationsMap->has('uncasted')); + self::assertInstanceOf(Node::class, $rootNodeRelationsMap->get('casted')); + + $rootNodeChildrenMap = $node->getChildren(); + + self::assertTrue($rootNodeChildrenMap->has('children')); + + $children = $rootNodeChildrenMap->get('children'); + self::assertCount(3, $children); + + foreach ($children as $child) { + self::assertInstanceOf(CastedChildNode::class, $child); + } + } + + public function testFailToCastToNonExistentClass(): void + { + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_INVALID_NON_EXISTENT_CLASS)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "root/nonExistentClass" node\'s tpl:castTo attribute value "\Donatorsky\XmlTemplate\Reader\Tests\Feature\XmlTemplateReader\NonExistentNodeClass" refers to non-existent class FQN'); + + $xmlTemplateReader->preloadTemplate(); + } + + public function testFailToCastToUnsupportedClass(): void + { + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_INVALID_UNSUPPORTED_CLASS)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(sprintf('The "root/unsupportedClass" node\'s tpl:castTo attribute value "\stdClass" refers to a class that does not implement "%s" interface', NodeInterface::class)); + + $xmlTemplateReader->preloadTemplate(); + } +} + +class CastedRelationNode extends Node +{ +} + +class CastedChildNode extends Node +{ +} diff --git a/tests/Feature/XmlTemplateReader/CollectAttributesModeTest.php b/tests/Feature/XmlTemplateReader/CollectAttributesModeTest.php index a8856b9..5d1cb7c 100644 --- a/tests/Feature/XmlTemplateReader/CollectAttributesModeTest.php +++ b/tests/Feature/XmlTemplateReader/CollectAttributesModeTest.php @@ -3,6 +3,7 @@ namespace Donatorsky\XmlTemplate\Reader\Tests\Feature\XmlTemplateReader; +use Assert\InvalidArgumentException; use Donatorsky\XmlTemplate\Reader\Models\Map; use Donatorsky\XmlTemplate\Reader\XmlTemplateReader; @@ -12,13 +13,15 @@ */ class CollectAttributesModeTest extends AbstractXmlTemplateReaderTest { - private const XML = 'configuration-collect-attributes'; + private const XML_VALID = 'configuration-collect-attributes-valid'; + + private const XML_INVALID = 'configuration-collect-attributes-invalid'; public function testRelationsWereRead(): Map { - $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML)); + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_VALID)); - $node = $xmlTemplateReader->read(self::getDataXml(self::XML)); + $node = $xmlTemplateReader->read(self::getDataXml(self::XML_VALID)); $relationsMap = $node->getRelations(); self::assertTrue($relationsMap->has('all')); @@ -57,4 +60,14 @@ public function testCollectValidated(Map $relationsMap): void self::assertSame('value 2', $attributesMap['validatedAttribute']); self::assertArrayNotHasKey('otherAttribute', $attributesMap); } + + public function testFailsForInvalidValue(): void + { + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_INVALID)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "root/invalid" node\'s tpl:collectAttributes attribute value "invalid value" is invalid, expecting one of: all, validated'); + + $xmlTemplateReader->preloadTemplate(); + } } diff --git a/tests/Feature/XmlTemplateReader/ContentsModeTest.php b/tests/Feature/XmlTemplateReader/ContentsModeTest.php index b263bb1..807a957 100644 --- a/tests/Feature/XmlTemplateReader/ContentsModeTest.php +++ b/tests/Feature/XmlTemplateReader/ContentsModeTest.php @@ -3,6 +3,7 @@ namespace Donatorsky\XmlTemplate\Reader\Tests\Feature\XmlTemplateReader; +use Assert\InvalidArgumentException; use Donatorsky\XmlTemplate\Reader\Models\Map; use Donatorsky\XmlTemplate\Reader\XmlTemplateReader; @@ -12,13 +13,15 @@ */ class ContentsModeTest extends AbstractXmlTemplateReaderTest { - private const XML = 'configuration-contents'; + private const XML_VALID = 'configuration-contents-valid'; + + private const XML_INVALID = 'configuration-contents-invalid'; public function testRelationsWereRead(): Map { - $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML)); + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_VALID)); - $node = $xmlTemplateReader->read(self::getDataXml(self::XML)); + $node = $xmlTemplateReader->read(self::getDataXml(self::XML_VALID)); $relationsMap = $node->getRelations(); self::assertTrue($relationsMap->has('none')); @@ -77,4 +80,14 @@ public function testContentsTrimmed(Map $relationsMap): void self::assertSame('Contents of: trimmed', $trimmedNode->getContents()); self::assertSame('Contents "of" & ', $trimmedWithCDataNode->getContents()); } + + public function testFailsForInvalidValue(): void + { + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_INVALID)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "root/invalid" node\'s tpl:contents attribute value "invalid value" is invalid, expecting one of: none, raw, trimmed'); + + ($xmlTemplateReader)->preloadTemplate(); + } } diff --git a/tests/Feature/XmlTemplateReader/TypeModeTest.php b/tests/Feature/XmlTemplateReader/TypeModeTest.php index 3f592e5..1000522 100644 --- a/tests/Feature/XmlTemplateReader/TypeModeTest.php +++ b/tests/Feature/XmlTemplateReader/TypeModeTest.php @@ -3,6 +3,7 @@ namespace Donatorsky\XmlTemplate\Reader\Tests\Feature\XmlTemplateReader; +use Assert\InvalidArgumentException; use Donatorsky\XmlTemplate\Reader\Exceptions\UnexpectedMultipleNodeReadException; use Donatorsky\XmlTemplate\Reader\XmlTemplateReader; @@ -12,19 +13,18 @@ */ class TypeModeTest extends AbstractXmlTemplateReaderTest { - private XmlTemplateReader $xmlTemplateReader; + private const XML_VALID = 'configuration-type-valid'; - protected function setUp(): void - { - $this->xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml('configuration-type')); - } + private const XML_INVALID = 'configuration-type-invalid'; public function testSingleNodeAsCollection(): void { + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_VALID)); + $this->expectException(UnexpectedMultipleNodeReadException::class); $this->expectExceptionMessage('The node "root/singleNode" is expected to be a single node, but another was read'); - $this->xmlTemplateReader->read( + $xmlTemplateReader->read( <<<'XML' 1 @@ -37,7 +37,9 @@ public function testSingleNodeAsCollection(): void public function testFiltersPass(): void { - $node = $this->xmlTemplateReader->read( + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_VALID)); + + $node = $xmlTemplateReader->read( <<<'XML' 1 @@ -54,4 +56,14 @@ public function testFiltersPass(): void self::assertTrue($childrenMap->has('multipleNode')); self::assertCount(2, $childrenMap->get('multipleNode')); } + + public function testFailsForInvalidMode(): void + { + $xmlTemplateReader = new XmlTemplateReader(self::getTemplateXml(self::XML_INVALID)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "root/invalid" node\'s tpl:type attribute value "invalid value" is invalid, expecting one of: single, collection'); + + $xmlTemplateReader->preloadTemplate(); + } } diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-invalid-non-existent-class-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-invalid-non-existent-class-template.xml new file mode 100644 index 0000000..734073d --- /dev/null +++ b/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-invalid-non-existent-class-template.xml @@ -0,0 +1,7 @@ + + diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-invalid-unsupported-class-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-invalid-unsupported-class-template.xml new file mode 100644 index 0000000..6a18331 --- /dev/null +++ b/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-invalid-unsupported-class-template.xml @@ -0,0 +1,7 @@ + + diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-valid-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-valid-template.xml new file mode 100644 index 0000000..c21dc3f --- /dev/null +++ b/tests/Feature/XmlTemplateReader/resources/configuration-cast-to-valid-template.xml @@ -0,0 +1,10 @@ + + diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-invalid-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-invalid-template.xml new file mode 100644 index 0000000..2627174 --- /dev/null +++ b/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-invalid-template.xml @@ -0,0 +1,7 @@ + + diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-data.xml b/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-valid-data.xml similarity index 100% rename from tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-data.xml rename to tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-valid-data.xml diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-valid-template.xml similarity index 100% rename from tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-template.xml rename to tests/Feature/XmlTemplateReader/resources/configuration-collect-attributes-valid-template.xml diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-contents-invalid-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-contents-invalid-template.xml new file mode 100644 index 0000000..1a05c93 --- /dev/null +++ b/tests/Feature/XmlTemplateReader/resources/configuration-contents-invalid-template.xml @@ -0,0 +1,7 @@ + + diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-contents-data.xml b/tests/Feature/XmlTemplateReader/resources/configuration-contents-valid-data.xml similarity index 100% rename from tests/Feature/XmlTemplateReader/resources/configuration-contents-data.xml rename to tests/Feature/XmlTemplateReader/resources/configuration-contents-valid-data.xml diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-contents-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-contents-valid-template.xml similarity index 100% rename from tests/Feature/XmlTemplateReader/resources/configuration-contents-template.xml rename to tests/Feature/XmlTemplateReader/resources/configuration-contents-valid-template.xml diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-type-invalid-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-type-invalid-template.xml new file mode 100644 index 0000000..fe21299 --- /dev/null +++ b/tests/Feature/XmlTemplateReader/resources/configuration-type-invalid-template.xml @@ -0,0 +1,7 @@ + + diff --git a/tests/Feature/XmlTemplateReader/resources/configuration-type-template.xml b/tests/Feature/XmlTemplateReader/resources/configuration-type-valid-template.xml similarity index 100% rename from tests/Feature/XmlTemplateReader/resources/configuration-type-template.xml rename to tests/Feature/XmlTemplateReader/resources/configuration-type-valid-template.xml