diff --git a/src/FluentDOM/Loader/JSONx.php b/src/FluentDOM/Loader/JSONx.php index 3bd0eaec..2b48f3dd 100644 --- a/src/FluentDOM/Loader/JSONx.php +++ b/src/FluentDOM/Loader/JSONx.php @@ -15,6 +15,7 @@ use FluentDOM\DOM\DocumentFragment; use FluentDOM\DOM\Element; use FluentDOM\Loadable; + use FluentDOM\Utility\Constraints; use FluentDOM\Utility\QualifiedName; /** @@ -89,22 +90,12 @@ public function loadFragment($source, string $contentType, $options = []) { * @throws \LogicException */ private function transferNode(\DOMNode $node, \DOMNode $target) { - if (!($node instanceof Element)) { - throw new \LogicException( - sprintf('Unexpected node type: %s', get_class($node)) - ); - } - if ( - !( - $target instanceOf Element || - $target instanceof DocumentFragment || - $target instanceof Document - ) - ) { - throw new \LogicException( - sprintf('Unexpected node type: %s', get_class($node)) - ); - } + Constraints::assertNodeClass( + $node, Element::class + ); + Constraints::assertNodeClass( + $node, [Element::class, DocumentFragment::class, Document::class] + ); if ($node->namespaceURI === self::XMLNS_JSONX) { if ($target instanceof Document) { $normalizedName = $name = 'json:json'; diff --git a/src/FluentDOM/Utility/Constraints.php b/src/FluentDOM/Utility/Constraints.php index 71dc7e89..5956aab5 100644 --- a/src/FluentDOM/Utility/Constraints.php +++ b/src/FluentDOM/Utility/Constraints.php @@ -11,6 +11,8 @@ namespace FluentDOM\Utility { + use FluentDOM\DOM\Element; + /** * Abstract utility class that provides several constraints/validations */ @@ -62,6 +64,26 @@ public static function assertNode($node, $message = 'DOMNode expected, got: %s.' return TRUE; } + /** + * @param \DOMNode $node + * @param string|string[] $classes + * @param string $message + * @return boolean + */ + public static function assertNodeClass(\DOMNode $node, $classes, $message = 'Unexpected node type: %s') { + if (!is_array($classes)) { + $classes = [$classes]; + } + foreach ($classes as $className) { + if ($node instanceof $className) { + return TRUE; + } + } + throw new \LogicException( + sprintf($message, get_class($node)) + ); + } + /** * Check if $elements is a traversable node list. It returns * the $elements or NULL diff --git a/tests/FluentDOM/Utility/ConstraintsTest.php b/tests/FluentDOM/Utility/ConstraintsTest.php index 7685c0ec..633b9015 100644 --- a/tests/FluentDOM/Utility/ConstraintsTest.php +++ b/tests/FluentDOM/Utility/ConstraintsTest.php @@ -1,8 +1,18 @@ assertTrue( + Constraints::assertNodeClass($document, [\DOMElement::class, \DOMDocument::class]) + ); + } + + /** + * @group Utility + * @group Constraints + * @covers \FluentDOM\Utility\Constraints::assertNodeClass + */ + public function testAssertNodeClassExpectingException() { + $document = new \DOMDocument(); + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Unexpected node type: DOMDocument'); + Constraints::assertNodeClass($document, \DOMElement::class); + } + + /** + * @group Utility + * @group Constraints + * @covers \FluentDOM\Utility\Constraints::assertNodeClass + */ + public function testAssertNodeClassExpectingExceptionWithProvidedMessage() { + $document = new \DOMDocument(); + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Expect DOMElement not DOMDocument'); + Constraints::assertNodeClass($document, \DOMElement::class, 'Expect DOMElement not %s'); + } + + /** + * @group Utility + * @group Constraints + * @covers \FluentDOM\Utility\Constraints::assertNodeClass + */ + public function testAssertNodeClassWithMultipleClassesExpectingException() { + $document = new \DOMDocument(); + $this->expectException(\LogicException::class); + Constraints::assertNodeClass($document, [\DOMElement::class, \DOMAttr::class]); + } + /** * @group Utility @@ -213,4 +270,4 @@ public function testHasOptionExpectingFalse() { ); } } -} \ No newline at end of file +}