More tests on Element

This commit is contained in:
Dustin Wilson 2021-11-21 22:39:29 -06:00
parent bb8850064c
commit b5f56b31a6
6 changed files with 577 additions and 98 deletions

4
composer.lock generated
View file

@ -63,7 +63,7 @@
"source": {
"type": "git",
"url": "mensbeam-gitea:MensBeam/HTML-Parser.git",
"reference": "5495e7c81e36409bebb998962f8624b5744a1b30"
"reference": "afaf10d602ee04d7eba437d3a08ef10ebef4f5b0"
},
"require": {
"ext-dom": "*",
@ -130,7 +130,7 @@
"parsing",
"whatwg"
],
"time": "2021-11-18T17:39:20+00:00"
"time": "2021-11-22T01:55:09+00:00"
},
{
"name": "mensbeam/intl",

View file

@ -25,14 +25,18 @@ class Attr extends Node {
}
protected function __get_namespaceURI(): ?string {
$namespace = $this->innerNode->namespaceURI;
return (!$this->ownerDocument instanceof XMLDocument && $namespace === null) ? Node::HTML_NAMESPACE : $namespace;
return $this->innerNode->namespaceURI;
}
protected function __get_ownerElement(): Element {
protected function __get_ownerElement(): ?Element {
// PHP's DOM does this correctly already.
$wrapperNode = $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->ownerElement);
return $wrapperNode;
$innerOwnerElement = $this->innerNode->ownerElement;
if ($innerOwnerElement === null) {
return null;
}
return $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->ownerElement);
}
protected function __get_prefix(): string {

View file

@ -18,6 +18,7 @@ class DOMException extends Exception {
public const NO_MODIFICATION_ALLOWED = 7;
public const NOT_FOUND = 8;
public const NOT_SUPPORTED = 9;
public const IN_USE_ATTRIBUTE = 10;
public const SYNTAX_ERROR = 12;
public const INVALID_MODIFICATION = 13;
public const NAMESPACE_ERROR = 14;
@ -35,6 +36,7 @@ class DOMException extends Exception {
7 => 'Modification not allowed here',
8 => 'Not found error',
9 => 'Feature is not supported',
10 => 'The attribute is in use',
12 => 'Syntax error',
13 => 'Invalid modification error',
14 => 'Namespace error',

View file

@ -22,16 +22,28 @@ class Element extends Node {
return Reflection::createFromProtectedConstructor(__NAMESPACE__ . '\\NamedNodeMap', $this, ($this instanceof Document) ? $this->innerNode : $this->innerNode->ownerDocument, $this->innerNode->attributes);
}
protected function __get_className(): string {
# The className attribute must reflect the "class" content attribute.
# Return the result of running get an attribute value given this and name.
return $this->getAttribute('class') ?? '';
}
protected function __set_className(string $value): void {
# The className attribute must reflect the "class" content attribute.
# Set an attribute value for this using name and the given value.
$this->setAttribute('class', $value);
}
protected function __get_id(): string {
# The id attribute must reflect the "id" content attribute.
# Return the result of running get an attribute value given this and name.
return $this->getAttribute('id') ?? '';
}
protected function __set_id(string $value): string {
protected function __set_id(string $value): void {
# The id attribute must reflect the "id" content attribute.
# Set an attribute value for this using name and the given value.
return $this->setAttribute('id', $value);
$this->setAttribute('id', $value);
}
protected function __get_localName(): ?string {
@ -39,14 +51,13 @@ class Element extends Node {
return $this->innerNode->localName;
}
protected function __get_namespaceURI(): string {
protected function __get_namespaceURI(): ?string {
// PHP's DOM uses null incorrectly for the HTML namespace, and if you attempt to
// use the HTML namespace anyway it has additional bugs we don't have to work
// around because of the wrapper classes; So, use the null namespace internally
// but print out the HTML namespace instead.
$namespace = $this->innerNode->namespaceURI;
$doc = $this->ownerDocument;
return (!$doc instanceof XMLDocument && $namespace === null) ? self::HTML_NAMESPACE : $namespace;
return (!$this->ownerDocument instanceof XMLDocument && $namespace === null) ? self::HTML_NAMESPACE : $namespace;
}
protected function __get_prefix(): ?string {
@ -94,7 +105,39 @@ class Element extends Node {
return $list;
}
public function getAttributeNode(string $qualifiedName): ?Attr {
# The getAttributeNode(qualifiedName) method steps are to return the result of
# getting an attribute given qualifiedName and this.
#
# To get an attribute by name given a qualifiedName and element element, run
# these steps:
#
# 1. If element is in the HTML namespace and its node document is an HTML document,
# then set qualifiedName to qualifiedName in ASCII lowercase.
if (!$this instanceof XMLDocument && $this->namespaceURI === self::HTML_NAMESPACE) {
$qualifiedName = strtolower($qualifiedName);
}
$qualifiedName = $this->coerceName($qualifiedName);
# 2. Return the first attribute in elements attribute list whose qualified name is
# qualifiedName; otherwise null.
// Manually going through the attributes because PHP DOM has issues, returning
// odd "DOMNamespaceNode" objects sometimes instead of the actual attributes...
// yeah...
$attributes = $this->innerNode->attributes;
foreach ($attributes as $attr) {
if ($attr->nodeName === $qualifiedName) {
return $this->innerNode->ownerDocument->getWrapperNode($attr);
}
}
return null;
}
public function getAttributeNodeNS(?string $namespace, string $localName): ?Attr {
static $count = 0;
$count++;
# The getAttributeNodeNS(namespace, localName) method steps are to return the
# result of getting an attribute given namespace, localName, and this.
#
@ -106,64 +149,21 @@ class Element extends Node {
$namespace = null;
}
$localName = $this->coerceName($localName);
# 2. Return the attribute in elements attribute list whose namespace is namespace
# and local name is localName, if any; otherwise null.
// Going to try to handle this by getting the PHP DOM to do the heavy lifting
// when we can because it's faster.
$value = $this->innerNode->getAttributeNodeNS($namespace, $localName);
if (!$value) {
// Replace any offending characters with "UHHHHHH" where H are the uppercase
// hexadecimal digits of the character's code point
$localName = $this->coerceName($localName);
// The PHP DOM does not acknowledge the presence of XMLNS-namespace attributes
// sometimes, too... so this will get those as well in those circumstances.
$attributes = $this->innerNode->attributes;
foreach ($attributes as $a) {
if ($a->namespaceURI === $namespace && $a->localName === $localName) {
return $this->innerNode->ownerDocument->getWrapperNode($a);
}
// Manually going through the attributes because PHP DOM has issues, returning
// odd "DOMNamespaceNode" objects sometimes instead of the actual attributes...
// yeah...
$attributes = $this->innerNode->attributes;
foreach ($attributes as $attr) {
if ($attr->namespaceURI === $namespace && $attr->localName === $localName) {
return $this->innerNode->ownerDocument->getWrapperNode($attr);
}
return null;
}
return ($value !== false) ? $this->innerNode->ownerDocument->getWrapperNode($value) : null;
}
public function getAttributeNode(string $qualifiedName): ?Attr {
# The getAttributeNode(qualifiedName) method steps are to return the result of
# getting an attribute given qualifiedName and this.
#
# To get an attribute by name given a qualifiedName and element element, run
# these steps:
#
# 1. If element is in the HTML namespace and its node document is an HTML document,
# then set qualifiedName to qualifiedName in ASCII lowercase.
// Document will always be an HTML document
if (!$this instanceof XMLDocument && $this->namespaceURI === self::HTML_NAMESPACE) {
$qualifiedName = strtolower($qualifiedName);
}
# 2. Return the first attribute in elements attribute list whose qualified name is
# qualifiedName; otherwise null.
// Going to try to handle this by getting the PHP DOM to do the heavy lifting
// when we can because it's faster.
$attr = $this->innerNode->getAttributeNode($qualifiedName);
if ($attr === false) {
// Replace any offending characters with "UHHHHHH" where H are the uppercase
// hexadecimal digits of the character's code point
$qualifiedName = $this->coerceName($qualifiedName);
$attributes = $this->innerNode->attributes;
foreach ($attributes as $a) {
if ($a->nodeName === $qualifiedName) {
return $this->innerNode->ownerDocument->getWrapperNode($a);
}
}
return null;
}
return ($attr !== false) ? $this->innerNode->ownerDocument->getWrapperNode($attr) : null;
return null;
}
public function getAttributeNS(?string $namespace, string $localName): ?string {
@ -183,13 +183,6 @@ class Element extends Node {
return $attr->value;
}
public function hasAttributes(): bool {
# The hasAttributes() method steps are to return false if thiss attribute list
# is empty; otherwise true.
// PHP's DOM does this correctly already.
return $this->innerNode->hasAttributes();
}
public function hasAttribute(string $qualifiedName): bool {
# The hasAttribute(qualifiedName) method steps are:
#
@ -215,16 +208,47 @@ class Element extends Node {
return $value;
}
public function hasAttributeNS(?string $namespace, string $localName): bool {
# The hasAttributeNS(namespace, localName) method steps are:
#
# 1. If namespace is the empty string, then set it to null.
if ($namespace === '') {
$namespace = null;
}
# 2. Return true if this has an attribute whose namespace is namespace and local
# name is localName; otherwise false.
# An element has an attribute A if its attribute list contains A.
// Going to try to handle this by getting the PHP DOM to do the heavy lifting
// when we can because it's faster.
$value = $this->innerNode->hasAttributeNS($namespace, $localName);
if (!$value) {
// PHP DOM does not acknowledge the presence of XMLNS-namespace attributes,
// so try it again just in case; getAttributeNode will coerce names if
// necessary, too.
$value = ($this->getAttributeNodeNS($namespace, $localName) !== null);
}
return $value;
}
public function hasAttributes(): bool {
# The hasAttributes() method steps are to return false if thiss attribute list
# is empty; otherwise true.
// PHP's DOM does this correctly already.
return $this->innerNode->hasAttributes();
}
public function setAttribute(string $qualifiedName, string $value): void {
# 1. If qualifiedName does not match the Name production in XML, then throw an
# "InvalidCharacterError" DOMException.
if (preg_match(InnerDocument::NAME_PRODUCTION_REGEX, $qualifiedName) !== 1) {
if (!preg_match(InnerDocument::NAME_PRODUCTION_REGEX, $qualifiedName)) {
throw new DOMException(DOMException::INVALID_CHARACTER);
}
# 2. If this is in the HTML namespace and its node document is an HTML document,
# then set qualifiedName to qualifiedName in ASCII lowercase.
if (!$this instanceof XMLDocument) {
if (!$this->ownerDocument instanceof XMLDocument && $this->namespaceURI === Node::HTML_NAMESPACE) {
$qualifiedName = strtolower($qualifiedName);
}
@ -253,20 +277,41 @@ class Element extends Node {
}
public function setAttributeNode(Attr $attr): ?Attr {
$innerNode = $this->innerNode;
$innerAttr = $this->getInnerNode($attr);
# The setAttributeNode(attr) and setAttributeNodeNS(attr) methods steps are to
# return the result of setting an attribute given attr and this.
$this->innerNode->setAttributeNode($innerAttr);
// If you create an id attribute it won't be used by PHP in getElementById, so
// let's fix that.
if ($innerAttr->namespaceURI === null && $innerAttr->localName === 'id') {
$innerNode->setIdAttributeNode($attr, true);
#
# To set an attribute given an attr and element, run these steps:
#
# 1. If attrs element is neither null nor element, throw an
# "InUseAttributeError" DOMException.
$ownerElement = $attr->ownerElement;
if ($ownerElement !== null && $ownerElement !== $this) {
throw new DOMException(DOMException::IN_USE_ATTRIBUTE);
}
return $attr;
// PHP's DOM doesn't do this method correctly. It returns the old node if it is
// replaced and null otherwise. It's always supposed to return a node.
$oldAttr = $this->getAttributeNodeNS($attr->namespaceURI, $attr->localName);
# 3. If oldAttr is attr, return attr.
if ($oldAttr === $attr) {
return $attr;
}
# 4. If oldAttr is non-null, then replace oldAttr with attr.
if ($oldAttr !== null) {
$this->innerNode->setAttributeNode($this->getInnerNode($attr));
return $attr;
}
# 5. Otherwise, append attr to element.
else {
$this->innerNode->appendChild($this->getInnerNode($attr));
return $attr;
}
# 6. Return oldAttr.
return $oldAttr;
}
public function setAttributeNodeNS(Attr $attr): ?Attr {
@ -277,10 +322,25 @@ class Element extends Node {
# 1. Let namespace, prefix, and localName be the result of passing namespace and
# qualifiedName to validate and extract.
[ 'namespace' => $namespace, 'prefix' => $prefix, 'localName' => $localName ] = $this->validateAndExtract($qualifiedName, $namespace);
$prefix = ($prefix === null) ? null : $this->coerceName($prefix);
$localName = $this->coerceName($localName);
$qualifiedName = ($prefix === null || $prefix === '') ? $localName : "{$prefix}:{$localName}";
# 2. Set an attribute value for this using localName, value, and also prefix and
# namespace.
// NOTE: We create attribute nodes so that xmlns attributes don't get lost;
// otherwise they cannot be serialized
if ($namespace === self::XMLNS_NAMESPACE) {
$attr = $this->ownerDocument->createAttributeNS($namespace, $qualifiedName);
$attr->value = $this->escapeString($value, true);
$this->setAttributeNodeNS($attr);
} else {
$this->innerNode->setAttributeNS($namespace, $qualifiedName, $value);
}
/*# 2. Set an attribute value for this using localName, value, and also prefix and
# namespace.
// Going to try to handle this by getting the PHP DOM to do the heavy lifting
// when we can because it's faster.
// NOTE: We create attribute nodes so that xmlns attributes don't get lost;
@ -310,14 +370,12 @@ class Element extends Node {
$this->innerNode->setAttributeNS($namespace, $qualifiedName, $value);
}
}
}*/
if ($namespace === null) {
// If you create an id attribute this way it won't be used by PHP in
// getElementById, so let's fix that.
if ($qualifiedName === 'id') {
$this->innerNode->setIdAttribute($qualifiedName, true);
}
// If you create an id attribute this way it won't be used by PHP in
// getElementById, so let's fix that.
if ($namespace === null && $qualifiedName === 'id') {
$this->innerNode->setIdAttribute($qualifiedName, true);
}
}
}

View file

@ -121,7 +121,7 @@ class TestElement extends \PHPUnit\Framework\TestCase {
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_getAttributeNS() {
$d = new Document('<!DOCTYPE html><html><head></head><body><svg xmlns="' . Node::SVG_NAMESPACE . '" xmlns:xlink="' . Node::XLINK_NAMESPACE . '" viewBox="0 0 42 42"></svg></body></html>');
$d = new Document('<!DOCTYPE html><html><head></head><body><svg xmlns="' . Node::SVG_NAMESPACE . '" xmlns:xlink="' . Node::XLINK_NAMESPACE . '" viewBox="0 0 42 42"></svg></body></html>', 'UTF-8');
$svg = $d->getElementsByTagNameNS(Node::SVG_NAMESPACE, 'svg')[0];
// Parser per the spec doesn't parse xmlns prefixed attributes except xlink, so let's add one manually instead to test coercion.
$svg->setAttributeNS(Node::XMLNS_NAMESPACE, 'xmlns:poop💩', 'https://poop💩.poop');
@ -137,4 +137,419 @@ class TestElement extends \PHPUnit\Framework\TestCase {
// empty string namespace
$this->assertSame('0 0 42 42', $svg->getAttributeNS('', 'viewBox'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::hasAttribute
*
* @covers \MensBeam\HTML\DOM\Collection::__construct
* @covers \MensBeam\HTML\DOM\Collection::item
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\DocumentOrElement::getElementsByTagNameNS
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_namespaceURI
* @covers \MensBeam\HTML\DOM\Element::getAttributeNode
* @covers \MensBeam\HTML\DOM\HTMLCollection::item
* @covers \MensBeam\HTML\DOM\HTMLCollection::offsetGet
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::hasChildNodes
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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_hasAttribute() {
$d = new Document('<!DOCTYPE html><html id="ook" poop💩="jeff"></html>', 'UTF-8');
$documentElement = $d->documentElement;
$svg = $d->getElementsByTagNameNS(Node::SVG_NAMESPACE, 'svg')[0];
$this->assertTrue($documentElement->hasAttribute('id'));
$this->assertTrue($documentElement->hasAttribute('poop💩'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::hasAttributeNS
*
* @covers \MensBeam\HTML\DOM\Attr::__set_value
* @covers \MensBeam\HTML\DOM\Collection::__construct
* @covers \MensBeam\HTML\DOM\Collection::item
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::createAttributeNS
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\DocumentOrElement::getElementsByTagNameNS
* @covers \MensBeam\HTML\DOM\DocumentOrElement::validateAndExtract
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::getAttributeNodeNS
* @covers \MensBeam\HTML\DOM\Element::setAttributeNode
* @covers \MensBeam\HTML\DOM\Element::setAttributeNodeNS
* @covers \MensBeam\HTML\DOM\Element::setAttributeNS
* @covers \MensBeam\HTML\DOM\HTMLCollection::item
* @covers \MensBeam\HTML\DOM\HTMLCollection::offsetGet
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::hasChildNodes
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_hasAttributeNS() {
$d = new Document('<!DOCTYPE html><html><head></head><body><svg xmlns="' . Node::SVG_NAMESPACE . '" xmlns:xlink="' . Node::XLINK_NAMESPACE . '" viewBox="0 0 42 42"></svg></body></html>', 'UTF-8');
$svg = $d->getElementsByTagNameNS(Node::SVG_NAMESPACE, 'svg')[0];
// Parser per the spec doesn't parse xmlns prefixed attributes except xlink, so let's add one manually instead to test coercion.
$svg->setAttributeNS(Node::XMLNS_NAMESPACE, 'xmlns:poop💩', 'https://poop💩.poop');
// xmlns attribute
$this->assertTrue($svg->hasAttributeNS(Node::XMLNS_NAMESPACE, 'xmlns'));
// xmlns xlink attribute
$this->assertTrue($svg->hasAttributeNS(Node::XMLNS_NAMESPACE, 'xlink'));
// coerced namespaced attribute
$this->assertTrue($svg->hasAttributeNS(Node::XMLNS_NAMESPACE, 'poop💩'));
// nonexistent namespaced attribute
$this->assertFalse($svg->hasAttributeNS(Node::XMLNS_NAMESPACE, 'ook'));
// empty string namespace
$this->assertTrue($svg->hasAttributeNS('', 'viewBox'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::hasAttributes
*
* @covers \MensBeam\HTML\DOM\Collection::__construct
* @covers \MensBeam\HTML\DOM\Collection::item
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\DocumentOrElement::getElementsByTagNameNS
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\HTMLCollection::item
* @covers \MensBeam\HTML\DOM\HTMLCollection::offsetGet
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::hasChildNodes
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @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_hasAttributes() {
$d = new Document('<!DOCTYPE html><html><body><svg xmlns="' . Node::SVG_NAMESPACE . '" xmlns:xlink="' . Node::XLINK_NAMESPACE . '"></svg></body></html>', 'UTF-8');
$svg = $d->getElementsByTagNameNS(Node::SVG_NAMESPACE, 'svg')[0];
$this->assertTrue($svg->hasAttributes());
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttribute
*
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::createElement
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_namespaceURI
* @covers \MensBeam\HTML\DOM\Element::getAttributeNode
* @covers \MensBeam\HTML\DOM\Element::hasAttribute
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::appendChild
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::getRootNode
* @covers \MensBeam\HTML\DOM\Node::postInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionValidity
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_setAttribute() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$documentElement = $d->documentElement;
// Just need to test coerced attributes; everything else has been covered
// elsewhere
$documentElement->setAttribute('poop💩', 'jeff');
$this->assertTrue($documentElement->hasAttribute('poop💩'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttribute
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::createElement
* @covers \MensBeam\HTML\DOM\DOMException::__construct
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::appendChild
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::getRootNode
* @covers \MensBeam\HTML\DOM\Node::postInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionValidity
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_setAttribute_errors() {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::INVALID_CHARACTER);
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->setAttribute('this will fail', 'fail');
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttributeNode
* @covers \MensBeam\HTML\DOM\Attr::__get_localName
* @covers \MensBeam\HTML\DOM\Attr::__get_ownerElement
* @covers \MensBeam\HTML\DOM\Attr::__get_value
* @covers \MensBeam\HTML\DOM\Attr::__set_value
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::createAttribute
* @covers \MensBeam\HTML\DOM\Document::createElement
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_namespaceURI
* @covers \MensBeam\HTML\DOM\Element::getAttribute
* @covers \MensBeam\HTML\DOM\Element::getAttributeNode
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::appendChild
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::getRootNode
* @covers \MensBeam\HTML\DOM\Node::postInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionValidity
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_setAttributeNode() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$documentElement = $d->documentElement;
$attr = $d->createAttribute('poop💩');
$attr->value = 'jeff';
$documentElement->setAttributeNode($attr);
// Almost everything is covered. Just need to test same attributes and
// replacements.
$documentElement->setAttributeNode($attr);
$this->assertSame('jeff', $documentElement->getAttribute('poop💩'));
$attr = $d->createAttribute('poop💩');
$attr->value = 'jeff';
$documentElement->setAttributeNode($attr);
$this->assertSame('jeff', $documentElement->getAttribute('poop💩'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttributeNode
*
* @covers \MensBeam\HTML\DOM\Attr::__get_localName
* @covers \MensBeam\HTML\DOM\Attr::__get_ownerElement
* @covers \MensBeam\HTML\DOM\Attr::__set_value
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::createAttribute
* @covers \MensBeam\HTML\DOM\Document::createElement
* @covers \MensBeam\HTML\DOM\DOMException::__construct
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_namespaceURI
* @covers \MensBeam\HTML\DOM\Element::getAttributeNode
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::appendChild
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::getRootNode
* @covers \MensBeam\HTML\DOM\Node::postInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionValidity
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_setAttributeNode_errors() {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::IN_USE_ATTRIBUTE);
$d = new Document();
$documentElement = $d->appendChild($d->createElement('html'));
$body = $documentElement->appendChild($d->createElement('body'));
$attr = $d->createAttribute('ook');
$attr->value = 'eek';
$body->setAttributeNode($attr);
$documentElement->setAttributeNode($attr);
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttributeNS
*
* @covers \MensBeam\HTML\DOM\Attr::__get_value
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::createElement
* @covers \MensBeam\HTML\DOM\DocumentOrElement::validateAndExtract
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::getAttributeNodeNS
* @covers \MensBeam\HTML\DOM\Element::getAttributeNS
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::appendChild
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::getRootNode
* @covers \MensBeam\HTML\DOM\Node::postInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionValidity
* @covers \MensBeam\HTML\DOM\NonElementParentNode::getElementById
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testMethod_setAttributeNS() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$documentElement = $d->documentElement;
// Just need to test setting of a bullshit namespaced attribute and id
// attribute; everything else is covered already.
$documentElement->setAttributeNS('https://poop💩.poop💩', 'poop💩:poop💩', 'jeff');
$this->assertSame('jeff', $documentElement->getAttributeNS('https://poop💩.poop💩', 'poop💩'));
$documentElement->setAttributeNS(null, 'id', 'ook');
$this->assertSame($documentElement, $d->getElementById('ook'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::__get_attributes
*
* @covers \MensBeam\HTML\DOM\Attr::__get_value
* @covers \MensBeam\HTML\DOM\Collection::__get_length
* @covers \MensBeam\HTML\DOM\Collection::count
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::__get_documentElement
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_namespaceURI
* @covers \MensBeam\HTML\DOM\Element::getAttribute
* @covers \MensBeam\HTML\DOM\Element::getAttributeNode
* @covers \MensBeam\HTML\DOM\NamedNodeMap::__construct
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::hasChildNodes
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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 testProperty_attributes() {
$d = new Document('<!DOCTYPE html><html id="ook" class="eek" ack="ack" foo="foo" bar="bar" xmlns="' . Node::HTML_NAMESPACE . '"></html>', 'UTF-8');
$documentElement = $d->documentElement;
$this->assertEquals(6, $documentElement->attributes->length);
$this->assertSame(Node::HTML_NAMESPACE, $documentElement->getAttribute('xmlns'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::__get_id
* @covers \MensBeam\HTML\DOM\Element::__set_id
*
* @covers \MensBeam\HTML\DOM\Attr::__get_value
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::createElement
* @covers \MensBeam\HTML\DOM\DOMImplementation::__construct
* @covers \MensBeam\HTML\DOM\Element::__construct
* @covers \MensBeam\HTML\DOM\Element::__get_namespaceURI
* @covers \MensBeam\HTML\DOM\Element::getAttribute
* @covers \MensBeam\HTML\DOM\Element::getAttributeNode
* @covers \MensBeam\HTML\DOM\Element::setAttribute
* @covers \MensBeam\HTML\DOM\Node::__construct
* @covers \MensBeam\HTML\DOM\Node::__get_ownerDocument
* @covers \MensBeam\HTML\DOM\Node::appendChild
* @covers \MensBeam\HTML\DOM\Node::getInnerDocument
* @covers \MensBeam\HTML\DOM\Node::getInnerNode
* @covers \MensBeam\HTML\DOM\Node::getRootNode
* @covers \MensBeam\HTML\DOM\Node::postInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionBugFixes
* @covers \MensBeam\HTML\DOM\Node::preInsertionValidity
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
* @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
* @covers \MensBeam\HTML\DOM\Inner\Reflection::getProtectedProperty
*/
public function testProperty_id() {
$d = new Document();
$documentElement = $d->appendChild($d->createElement('html'));
$documentElement->id = 'ook';
$this->assertSame('ook', $documentElement->id);
}
}

View file

@ -529,16 +529,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.8",
"version": "9.2.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e"
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
"shasum": ""
},
"require": {
@ -594,7 +594,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9"
},
"funding": [
{
@ -602,7 +602,7 @@
"type": "github"
}
],
"time": "2021-10-30T08:01:38+00:00"
"time": "2021-11-19T15:21:02+00:00"
},
{
"name": "phpunit/php-file-iterator",