diff --git a/src/DOMNodeComparator.php b/src/DOMNodeComparator.php
index 5b8629ca..fa642abe 100644
--- a/src/DOMNodeComparator.php
+++ b/src/DOMNodeComparator.php
@@ -70,8 +70,15 @@ public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = f
private function nodeToText(DOMNode $node, bool $canonicalize, bool $ignoreCase): string
{
if ($canonicalize) {
+ /** @psalm-var string|false $c14n */
+ $c14n = @$node->C14N();
+
+ if ($c14n === false || $c14n === '') { // try node-to-text without canonicalize
+ return $this->nodeToText($node, false, $ignoreCase);
+ }
+
$document = new DOMDocument;
- @$document->loadXML($node->C14N());
+ $document->loadXML($c14n);
$node = $document;
}
diff --git a/tests/DOMNodeComparatorTest.php b/tests/DOMNodeComparatorTest.php
index 8d52fc2b..6a30e0c0 100644
--- a/tests/DOMNodeComparatorTest.php
+++ b/tests/DOMNodeComparatorTest.php
@@ -121,6 +121,50 @@ public function assertEqualsFailsProvider()
];
}
+ public function assertEqualsSucceedsWithNonCanonicalizableNodesProvider()
+ {
+ $document = new DOMDocument;
+
+ return [
+ [$document, new DOMDocument],
+ [$document->createElement('foo'), $document->createElement('foo')],
+ [
+ $this->createDOMDocument(
+ ']>'
+ ),
+ $this->createDOMDocument(
+ ']>'
+ ),
+ ],
+ ];
+ }
+
+ public function assertEqualsFailsWithNonCanonicalizableNodesProvider()
+ {
+ // empty document makes C14N return empty string
+ $document = new DOMDocument;
+
+ // nodes created but not appended to the document makes C14N return empty string
+ $nodeFoo = $document->createElement('foo');
+ $nodeBar = $document->createElement('bar');
+
+ // documents with xmlns definitions to xml entities makes C14N return false
+ $documentNsUriIsEntityFoo = $this->createDOMDocument( // root element is i:foo
+ ']>'
+ );
+ $documentNsUriIsEntityBar = $this->createDOMDocument( // root element is i:bar
+ ']>'
+ );
+
+ return [
+ [$document, $nodeFoo],
+ [$document, $documentNsUriIsEntityFoo],
+ [$nodeFoo, $nodeBar],
+ [$nodeFoo, $documentNsUriIsEntityFoo],
+ [$documentNsUriIsEntityFoo, $documentNsUriIsEntityBar],
+ ];
+ }
+
/**
* @dataProvider acceptsSucceedsProvider
*/
@@ -169,6 +213,22 @@ public function testAssertEqualsFails($expected, $actual): void
$this->comparator->assertEquals($expected, $actual);
}
+ /**
+ * @dataProvider assertEqualsSucceedsWithNonCanonicalizableNodesProvider
+ */
+ public function testAssertEqualsSucceedsWithNonCanonicalizableNodes($expected, $actual): void
+ {
+ $this->testAssertEqualsSucceeds($expected, $actual);
+ }
+
+ /**
+ * @dataProvider assertEqualsFailsWithNonCanonicalizableNodesProvider
+ */
+ public function testAssertEqualsFailsWithNonCanonicalizableNodes($expected, $actual): void
+ {
+ $this->testAssertEqualsFails($expected, $actual);
+ }
+
private function createDOMDocument($content)
{
$document = new DOMDocument;