Browse Source

Starting to fix NamedNodeMap, test fails

master
Dustin Wilson 2 years ago
parent
commit
3d0e21edaf
  1. 5
      lib/Attr.php
  2. 4
      lib/HTMLCollection.php
  3. 55
      lib/NamedNodeMap.php
  4. 2
      tests/cases/TestAttr.php
  5. 94
      tests/cases/TestCollection.php
  6. 31
      tests/cases/TestNamedNodeMap.php
  7. 2
      tests/cases/TestNonDocumentTypeChildNode.php
  8. 2
      tests/phpunit.dist.xml

5
lib/Attr.php

@ -18,9 +18,10 @@ class Attr extends Node {
}
protected function __get_name(): string {
// PHP's DOM does this correctly already.
// PHP's DOM incorrectly returns the local name instead of the qualified name
// per the specification.
// Need to uncoerce string if necessary.
$name = $this->innerNode->name;
$name = $this->innerNode->nodeName;
return (!str_contains(needle: 'U', haystack: $name)) ? $name : $this->uncoerceName($name);
}

4
lib/HTMLCollection.php

@ -45,4 +45,8 @@ class HTMLCollection extends Collection {
public function offsetGet($offset): ?Element {
return (is_int($offset)) ? $this->item($offset) : $this->namedItem($offset);
}
public function offsetExists($offset): bool {
return (((is_int($offset)) ? $this->item($offset) : $this->namedItem($offset)) !== null);
}
}

55
lib/NamedNodeMap.php

@ -7,10 +7,16 @@
declare(strict_types=1);
namespace MensBeam\HTML\DOM;
use MensBeam\HTML\DOM\Inner\Document as InnerDocument;
use MensBeam\HTML\DOM\Inner\{
Document as InnerDocument,
Reflection
};
use MensBeam\HTML\Parser\NameCoercion;
class NamedNodeMap extends Collection {
use NameCoercion;
# A NamedNodeMap has an associated element (an element).
protected Element $element;
@ -43,6 +49,53 @@ class NamedNodeMap extends Collection {
return parent::item($index);
}
public function offsetGet($offset): ?Attr {
if (is_int($offset)) {
return $this->item($offset);
}
# A NamedNodeMap object’s supported property names are the return value of running
# these steps:
# 1. Let names be the qualified names of the attributes in this NamedNodeMap object’s
# attribute list, with duplicates omitted, in order.
// The spec is extremely vague as to what to do here, but it seems to expect
// this to be some sort of live private property that the class will poll to
// check for valid property names when trying to access them. This is
// inefficient. Going to do basically the same thing but not return a list of
// every one. It will just search the element's attribute list instead using the
// same process.
# 2. If this NamedNodeMap object’s element is in the HTML namespace and its node
# document is an HTML document, then for each name in names:
# 1. Let lowercaseName be name, in ASCII lowercase.
# 2. If lowercaseName is not equal to name, remove name from names.
# 3. Return names.
$innerElement = Reflection::getProtectedProperty($this->element, 'innerNode');
$innerDocument = $innerElement->ownerDocument;
$attributes = $innerElement->attributes;
if ($attributes->length > 0) {
$coercedOffset = $this->coerceName($offset);
foreach ($attributes as $attr) {
$name = $attr->nodeName;
if ($this->element->namespaceURI === Node::HTML_NAMESPACE && $name !== strtolower($name)) {
continue;
}
if ($name === $offset || $name === $coercedOffset) {
return $innerDocument->getWrapperNode($attr);
}
}
}
return null;
}
public function offsetExists($offset): bool {
return (((is_int($offset)) ? $this->item($offset) : $this->getNamedItem($offset)) !== null);
}
public function removeNamedItem(string $qualifiedName): ?Attr {
return $this->removeNamedItemNS(null, $qualifiedName);
}

2
tests/cases/TestAttr.php

@ -27,7 +27,7 @@ class TestAttr extends \PHPUnit\Framework\TestCase {
// Coerced name
$this->assertSame('poop💩', $body->getAttributeNode('poop💩')->name);
// Foreign attribute name
$this->assertSame('xlink', $svg->getAttributeNodeNS(Node::XMLNS_NAMESPACE, 'xlink')->name);
$this->assertSame('xmlns:xlink', $svg->getAttributeNodeNS(Node::XMLNS_NAMESPACE, 'xlink')->name);
}
public function testProperty_prefix(): void {

94
tests/cases/TestCollection.php

@ -0,0 +1,94 @@
<?php
/**
* @license MIT
* Copyright 2017 Dustin Wilson, J. King, et al.
* See LICENSE and AUTHORS files for details
*/
declare(strict_types=1);
namespace MensBeam\HTML\DOM\TestCase;
use MensBeam\HTML\DOM\{
Attr,
Document,
HTMLElement
};
/** @covers \MensBeam\HTML\DOM\Collection */
class TestCollection extends \PHPUnit\Framework\TestCase {
/**
* @covers \MensBeam\HTML\DOM\Collection::current
* @covers \MensBeam\HTML\DOM\Collection::item
* @covers \MensBeam\HTML\DOM\Collection::key
* @covers \MensBeam\HTML\DOM\Collection::next
* @covers \MensBeam\HTML\DOM\Collection::offsetExists
* @covers \MensBeam\HTML\DOM\Collection::rewind
* @covers \MensBeam\HTML\DOM\Collection::valid
*
* @covers \MensBeam\HTML\DOM\Collection::__construct
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_body
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_childNodes
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::hasChildNodes
* @covers \MensBeam\HTML\DOM\Node::postParsingTemplatesFix
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_xpath
* @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::get
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::has
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::key
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::set
* @covers \MensBeam\HTML\DOM\Inner\Reflection::createFromProtectedConstructor
*/
public function testIteration(): void {
$d = new Document('<!DOCTYPE html><html><body><br><br><br><br><br></body></html>');
$body = $d->body;
$children = $body->childNodes;
foreach ($children as $key => $child) {
$this->assertTrue($child instanceof HTMLElement);
}
}
/**
* @covers \MensBeam\HTML\DOM\Collection::offsetGet
* @covers \MensBeam\HTML\DOM\Collection::offsetUnset
*
* @covers \MensBeam\HTML\DOM\Attr::__get_value
* @covers \MensBeam\HTML\DOM\Collection::item
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_body
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_attributes
* @covers \MensBeam\HTML\DOM\NamedNodeMap::__construct
* @covers \MensBeam\HTML\DOM\NamedNodeMap::item
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::hasChildNodes
* @covers \MensBeam\HTML\DOM\Node::postParsingTemplatesFix
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_xpath
* @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::get
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::has
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::key
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::set
* @covers \MensBeam\HTML\DOM\Inner\Reflection::createFromProtectedConstructor
*/
public function testMethod_offsetSet_offsetUnset(): void {
$d = new Document('<!DOCTYPE html><html><body a="ook" b="eek" c="ook" d="eek" e="ook"></body></html>');
$body = $d->body;
$attributes = $body->attributes;
$attributes[0] = 'eek';
$this->assertSame('ook', $attributes[0]->value);
unset($attributes[2]);
$this->assertSame('ook', $attributes[2]->value);
}
}

31
tests/cases/TestNamedNodeMap.php

@ -0,0 +1,31 @@
<?php
/**
* @license MIT
* Copyright 2017 Dustin Wilson, J. King, et al.
* See LICENSE and AUTHORS files for details
*/
declare(strict_types=1);
namespace MensBeam\HTML\DOM\TestCase;
use MensBeam\HTML\DOM\{
Attr,
Document,
Node
};
/** @covers \MensBeam\HTML\DOM\NamedNodeMap */
class TestNamedNodeMap extends \PHPUnit\Framework\TestCase {
public function testMethod_getOffset(): void {
$d = new Document('<!DOCTYPE html><html><body a="ook" b="eek" c="ook" d="eek" e="ook"></body></html>', 'UTF-8');
$body = $d->body;
$body->setAttributeNS(Node::XMLNS_NAMESPACE, 'xmlns:href', Node::HTML_NAMESPACE);
$body->setAttributeNS('https://poop💩.poop', 'poop💩:poop💩', 'poop💩');
$attributes = $body->attributes;
$this->assertSame('ook', $attributes['a']->value);
$this->assertSame(Node::HTML_NAMESPACE, $attributes['xmlns:href']->value);
$this->assertSame('poop💩', $attributes['poop💩:poop💩']->value);
}
}

2
tests/cases/TestNonDocumentTypeChildNode.php

@ -27,6 +27,8 @@ class TestNonDocumentTypeChildNode extends \PHPUnit\Framework\TestCase {
$br2 = $body->appendChild($d->createElement('br'));
$this->assertSame($br2, $br->nextElementSibling);
$this->assertNull($br2->nextElementSibling);
$this->assertSame($br, $ook->previousElementSibling);
$this->assertNull($br->previousElementSibling);
}
}

2
tests/phpunit.dist.xml

@ -19,12 +19,14 @@
<file>cases/TestAttr.php</file>
<file>cases/TestCharacterData.php</file>
<file>cases/TestChildNode.php</file>
<file>cases/TestCollection.php</file>
<file>cases/TestDocument.php</file>
<file>cases/TestDocumentOrElement.php</file>
<file>cases/TestDOMImplementation.php</file>
<file>cases/TestDOMTokenList.php</file>
<file>cases/TestElement.php</file>
<file>cases/TestInnerDocument.php</file>
<file>cases/TestNamedNodeMap.php</file>
<file>cases/TestNode.php</file>
<file>cases/TestNonDocumentTypeChildNode.php</file>
<file>cases/TestParentNode.php</file>

Loading…
Cancel
Save