From 1080c7e8760e22b8fe1dbce44b2e6e926613a70b Mon Sep 17 00:00:00 2001 From: Dustin Wilson Date: Sat, 16 Oct 2021 14:23:10 -0500 Subject: [PATCH] Added NodeTrait::isEqualNode --- lib/traits/NodeTrait.php | 86 +++++++++++++++++++ .../{TestBaseNode.php => TestNodeTrait.php} | 53 +++++++++++- tests/phpunit.dist.xml | 2 +- vendor-bin/phpunit/composer.lock | 1 + 4 files changed, 139 insertions(+), 3 deletions(-) rename tests/cases/{TestBaseNode.php => TestNodeTrait.php} (67%) diff --git a/lib/traits/NodeTrait.php b/lib/traits/NodeTrait.php index 9db2f2a..21999bb 100644 --- a/lib/traits/NodeTrait.php +++ b/lib/traits/NodeTrait.php @@ -114,6 +114,92 @@ trait NodeTrait { return Node::DOCUMENT_POSITION_FOLLOWING; } + public function isEqualNode(\DOMDocumentType|Node $otherNode): bool { + # The isEqualNode(otherNode) method steps are to return true if otherNode is + # non-null and this equals otherNode; otherwise false. + + # A node A equals a node B if all of the following conditions are true: + # + # • A and B implement the same interfaces. + if ($this::class !== $otherNode::class) { + return false; + } + + # • The following are equal, switching on the interface A implements: + $thisClass = substr($this::class, strrpos($this::class, '\\') + 1); + switch ($thisClass) { + # - DocumentType + # Its name, public ID, and system ID. + // DEVIATION: $this can never be a \DOMDocumentType seeing as we we cannot extend + // \DOMDocumentType, so there is no need to check for it. + + # - Element + # Its namespace, namespace prefix, local name, and its attribute list’s size. + // PCOV is stupid + // @codeCoverageIgnoreStart + case 'Element': + // @codeCoverageIgnoreEnd + if ($this->namespaceURI !== $otherNode->namespaceURI || $this->prefix !== $otherNode->prefix || $this->localName !== $otherNode->localName || $this->attributes->length !== $otherNode->attributes->length) { + return false; + } + + # • If A is an element, each attribute in its attribute list has an attribute that + # equals an attribute in B’s attribute list. + foreach ($this->attributes as $key => $attr) { + if (!$attr->isEqualNode($otherNode->attributes[$key])) { + return false; + } + } + break; + # - Attr + # Its namespace, local name, and value. + // PCOV is stupid + // @codeCoverageIgnoreStart + case 'Attr': + // @codeCoverageIgnoreEnd + if ($this->namespaceURI !== $otherNode->namespaceURI || $this->localName !== $otherNode->localName || $this->value !== $otherNode->value) { + return false; + } + break; + # - Text + # - Comment + # Its data. + // PCOV is stupid + // @codeCoverageIgnoreStart + case 'Text': + case 'Comment': + // @codeCoverageIgnoreEnd + if ($this->data !== $otherNode->data) { + return false; + } + break; + } + + if ($this instanceof Document || $this instanceof DocumentFragment || $this instanceof Element) { + # • A and B have the same number of children. + if ($this->childNodes->length !== $otherNode->childNodes->length) { + return false; + } + + # • Each child of A equals the child of B at the identical index. + foreach ($this->childNodes as $key => $child) { + // Have to work around the fact we cannot extend \DOMDocumentType + if (!$child instanceof \DOMDocumentType) { + if (!$child->isEqualNode($otherNode->childNodes[$key])) { + return false; + } + } else { + $other = $otherNode->childNodes[$key]; + if ($child->name !== $other->name || $child->publicId !== $other->publicId || $child->systemId !== $other->systemId) { + return false; + } + } + } + } + + return true; + } + // Disable getLineNo public function getLineNo(): int { throw new DOMException(DOMException::NOT_SUPPORTED, __METHOD__ . ' is not in the standard, is buggy, and useless'); diff --git a/tests/cases/TestBaseNode.php b/tests/cases/TestNodeTrait.php similarity index 67% rename from tests/cases/TestBaseNode.php rename to tests/cases/TestNodeTrait.php index 3202415..3d71da2 100644 --- a/tests/cases/TestBaseNode.php +++ b/tests/cases/TestNodeTrait.php @@ -15,8 +15,8 @@ use MensBeam\HTML\DOM\{ }; -/** @covers \MensBeam\HTML\DOM\Node */ -class TestBaseNode extends \PHPUnit\Framework\TestCase { +/** @covers \MensBeam\HTML\DOM\NodeTrait */ +class TestNodeTrait extends \PHPUnit\Framework\TestCase { /** @covers \MensBeam\HTML\DOM\NodeTrait::compareDocumentPosition */ public function testCompareDocumentPosition(): void { $d = new Document(); @@ -99,4 +99,53 @@ class TestBaseNode extends \PHPUnit\Framework\TestCase { $div = $t->content->appendChild($d->createElement('div')); $this->assertTrue($t->content->isSameNode($div->getRootNode())); } + + /** @covers \MensBeam\HTML\DOM\NodeTrait::isEqualNode */ + public function testIsEqualNode(): void { + $d = new Document(); + $d->appendChild($d->createElement('html')); + $d->documentElement->appendChild($d->createElement('body')); + $d->body->innerHTML = '

Ook

Eek

'; + + $d2 = new Document(); + $d2->appendChild($d2->createElement('html')); + $d2->documentElement->appendChild($d2->createElement('body')); + $d2->body->innerHTML = '

Ook

Eek

'; + + $this->assertTrue($d->isEqualNode($d2)); + + $d = new Document(); + $de = $d->createElement('html'); + $this->assertFalse($d->isEqualNode($de)); + + $d = new Document(); + $d->appendChild($d->implementation->createDocumentType('html', '', '')); + + $d2 = new Document(); + $d2->appendChild($d2->implementation->createDocumentType('ook', 'eek', 'ack')); + $this->assertFalse($d->isEqualNode($d2)); + + $d = new Document('Ook!

Eek

'); + $d2 = new Document('Eek!

Eek

'); + $this->assertFalse($d->isEqualNode($d2)); + + $d = new Document(); + $f = $d->createDocumentFragment(); + $f->appendChild($d->createElement('span')); + $f->appendChild($d->createTextNode('Ook')); + + $f2 = $d->createDocumentFragment(); + $f2->appendChild($d->createElement('span')); + $this->assertFalse($f->isEqualNode($f2)); + + $s = $d->createElement('span'); + $s->setAttribute('id', 'ook'); + $s2 = $d->createElement('span'); + $s2->setAttribute('class', 'ook'); + $this->assertFalse($s->isEqualNode($s2)); + + $s = $d->createElement('span'); + $br = $d->createElement('br'); + $this->assertFalse($s->isEqualNode($br)); + } } \ No newline at end of file diff --git a/tests/phpunit.dist.xml b/tests/phpunit.dist.xml index 1482324..123f805 100644 --- a/tests/phpunit.dist.xml +++ b/tests/phpunit.dist.xml @@ -16,7 +16,6 @@ - cases/TestBaseNode.php cases/TestChildNode.php cases/TestDocument.php cases/TestDocumentFragment.php @@ -24,6 +23,7 @@ cases/TestElement.php cases/TestElementMap.php cases/TestLeafNode.php + cases/TestNodeTrait.php cases/TestParentNode.php cases/TestTokenList.php diff --git a/vendor-bin/phpunit/composer.lock b/vendor-bin/phpunit/composer.lock index d6d4c14..d1691ea 100644 --- a/vendor-bin/phpunit/composer.lock +++ b/vendor-bin/phpunit/composer.lock @@ -1800,6 +1800,7 @@ "type": "github" } ], + "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, {