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