Continuing with tests
This commit is contained in:
parent
c03aebc52a
commit
82c9dac054
9 changed files with 138 additions and 56 deletions
|
@ -5,7 +5,7 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.0",
|
"php": ">=8.0",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"mensbeam/html-parser": "dev-pretty-print",
|
"mensbeam/html-parser": "dev-master",
|
||||||
"mensbeam/framework": "dev-main",
|
"mensbeam/framework": "dev-main",
|
||||||
"symfony/css-selector": "^5.3"
|
"symfony/css-selector": "^5.3"
|
||||||
},
|
},
|
||||||
|
|
9
composer.lock
generated
9
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "80f59b5505ffc9b8d7fd2a408538d861",
|
"content-hash": "6ed06e9556bdcc4bbbb5f3f23958e33d",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "mensbeam/framework",
|
"name": "mensbeam/framework",
|
||||||
|
@ -59,11 +59,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mensbeam/html-parser",
|
"name": "mensbeam/html-parser",
|
||||||
"version": "dev-pretty-print",
|
"version": "dev-master",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "mensbeam-gitea:MensBeam/HTML-Parser.git",
|
"url": "mensbeam-gitea:MensBeam/HTML-Parser.git",
|
||||||
"reference": "8361ea0d88c4406213e39e2cb983bfcb1e9b9b37"
|
"reference": "5495e7c81e36409bebb998962f8624b5744a1b30"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
|
@ -77,6 +77,7 @@
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-ctype": "Improved performance"
|
"ext-ctype": "Improved performance"
|
||||||
},
|
},
|
||||||
|
"default-branch": true,
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
@ -129,7 +130,7 @@
|
||||||
"parsing",
|
"parsing",
|
||||||
"whatwg"
|
"whatwg"
|
||||||
],
|
],
|
||||||
"time": "2021-11-17T05:59:36+00:00"
|
"time": "2021-11-18T17:39:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mensbeam/intl",
|
"name": "mensbeam/intl",
|
||||||
|
|
|
@ -438,41 +438,7 @@ class Document extends Node {
|
||||||
$node = $node->innerNode;
|
$node = $node->innerNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parserConfig = new ParserConfig();
|
return Serializer::serialize($node, $config);
|
||||||
foreach ($config as $key => $value) {
|
|
||||||
switch ($key) {
|
|
||||||
case 'indentStep':
|
|
||||||
if (!is_int($value)) {
|
|
||||||
$type = gettype($value);
|
|
||||||
if ($type === 'object') {
|
|
||||||
$type = get_class($value);
|
|
||||||
}
|
|
||||||
trigger_error("Value for serializer configuration option \"$key\" must be an integer; $type given", \E_USER_WARNING);
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'indentWithSpaces':
|
|
||||||
case 'reformatWhitespace':
|
|
||||||
case 'serializeBooleanAttributeValues':
|
|
||||||
case 'serializeForeignVoidEndTags':
|
|
||||||
if (!is_bool($value)) {
|
|
||||||
$type = gettype($value);
|
|
||||||
if ($type === 'object') {
|
|
||||||
$type = get_class($value);
|
|
||||||
}
|
|
||||||
trigger_error("Value for serializer configuration option \"$key\" must be an integer; $type given", \E_USER_WARNING);
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
trigger_error("\"$key\" is an invalid serializer configuration option", \E_USER_WARNING);
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parserConfig->$key = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Serializer::serialize($node, $parserConfig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,21 @@ class Element extends Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getAttribute(string $qualifiedName): ?string {
|
||||||
|
# The getAttribute(qualifiedName) method steps are:
|
||||||
|
#
|
||||||
|
# 1. Let attr be the result of getting an attribute given qualifiedName and this.
|
||||||
|
$attr = $this->getAttributeNode($qualifiedName);
|
||||||
|
# 2. If attr is null, return null.
|
||||||
|
if ($attr === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
# 3. Return attr’s value.
|
||||||
|
// Uncoerce the value if necessary
|
||||||
|
$value = $attr->value;
|
||||||
|
return (!strpos($value, 'U')) ? $value : $this->uncoerceName($value);
|
||||||
|
}
|
||||||
|
|
||||||
public function getAttributeNames(): array {
|
public function getAttributeNames(): array {
|
||||||
# The getAttributeNames() method steps are to return the qualified names of the
|
# The getAttributeNames() method steps are to return the qualified names of the
|
||||||
# attributes in this’s attribute list, in order; otherwise a new list.
|
# attributes in this’s attribute list, in order; otherwise a new list.
|
||||||
|
@ -78,8 +93,40 @@ class Element extends Node {
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAttributeNS(string $namespace, string $localName): ?string {
|
public function getAttributeNodeNS(?string $namespace, string $localName): ?Attr {
|
||||||
return $this->innerNode->getAttributeNS($namespace, $localName);
|
# The getAttributeNodeNS(namespace, localName) method steps are to return the
|
||||||
|
# result of getting an attribute given namespace, localName, and this.
|
||||||
|
#
|
||||||
|
# To get an attribute by namespace and local name given a namespace, localName,
|
||||||
|
# and element element, run these steps:
|
||||||
|
#
|
||||||
|
# 1. If namespace is the empty string, then set it to null.
|
||||||
|
if ($namespace === '') {
|
||||||
|
$namespace = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. Return the attribute in element’s 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($value !== false) ? $this->innerNode->ownerDocument->getWrapperNode($value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAttributeNode(string $qualifiedName): ?Attr {
|
public function getAttributeNode(string $qualifiedName): ?Attr {
|
||||||
|
@ -118,6 +165,23 @@ class Element extends Node {
|
||||||
return ($attr !== false) ? $this->innerNode->ownerDocument->getWrapperNode($attr) : null;
|
return ($attr !== false) ? $this->innerNode->ownerDocument->getWrapperNode($attr) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAttributeNS(?string $namespace, string $localName): ?string {
|
||||||
|
# The getAttributeNS(namespace, localName) method steps are:
|
||||||
|
#
|
||||||
|
# 1. Let attr be the result of getting an attribute given namespace, localName,
|
||||||
|
# and this.
|
||||||
|
$attr = $this->getAttributeNodeNS($namespace, $localName);
|
||||||
|
|
||||||
|
# 2. If attr is null, return null.
|
||||||
|
if ($attr === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. Return attr’s value.
|
||||||
|
// Uncoerce the value if necessary
|
||||||
|
return $attr->value;
|
||||||
|
}
|
||||||
|
|
||||||
public function hasAttributes(): bool {
|
public function hasAttributes(): bool {
|
||||||
# The hasAttributes() method steps are to return false if this’s attribute list
|
# The hasAttributes() method steps are to return false if this’s attribute list
|
||||||
# is empty; otherwise true.
|
# is empty; otherwise true.
|
||||||
|
|
|
@ -48,10 +48,6 @@ class Document extends \DOMDocument {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getInnerNode(WrapperNode $node): ?\DOMNode {
|
|
||||||
return Reflection::getProtectedProperty($node, 'innerNode');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getWrapperNode(\DOMNode $node): ?WrapperNode {
|
public function getWrapperNode(\DOMNode $node): ?WrapperNode {
|
||||||
// If the node is a Document then the wrapperNode is this's wrapperNode
|
// If the node is a Document then the wrapperNode is this's wrapperNode
|
||||||
// property.
|
// property.
|
||||||
|
|
|
@ -16,18 +16,11 @@ use MensBeam\HTML\Parser\{
|
||||||
|
|
||||||
|
|
||||||
class Serializer extends ParserSerializer {
|
class Serializer extends ParserSerializer {
|
||||||
protected static function getTemplateContent(\DOMElement $node, ?Config $config = null): \DOMNode {
|
protected static function getTemplateContent(\DOMElement $node): \DOMNode {
|
||||||
// NOTE: PHP's DOM does not support the content property on template elements
|
|
||||||
// natively. This method exists purely so implementors of userland PHP DOM
|
|
||||||
// solutions may extend this method to get template contents how they need them.
|
|
||||||
return Reflection::getProtectedProperty($node->ownerDocument->getWrapperNode($node)->content, 'innerNode');
|
return Reflection::getProtectedProperty($node->ownerDocument->getWrapperNode($node)->content, 'innerNode');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function isPreformattedContent(\DOMNode $node): bool {
|
protected static function isPreformattedContent(\DOMNode $node): bool {
|
||||||
// NOTE: This method is used only when pretty printing. Implementors of userland
|
|
||||||
// PHP DOM solutions with template contents will need to extend this method to
|
|
||||||
// be able to moonwalk through document fragment hosts.
|
|
||||||
|
|
||||||
$n = $node;
|
$n = $node;
|
||||||
do {
|
do {
|
||||||
if ($n instanceof \DOMElement) {
|
if ($n instanceof \DOMElement) {
|
||||||
|
|
63
tests/cases/TestElement.php
Normal file
63
tests/cases/TestElement.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?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\{
|
||||||
|
Document,
|
||||||
|
DOMException,
|
||||||
|
Element,
|
||||||
|
Node,
|
||||||
|
Text,
|
||||||
|
XMLDocument
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @covers \MensBeam\HTML\DOM\Element */
|
||||||
|
class TestElement extends \PHPUnit\Framework\TestCase {
|
||||||
|
/**
|
||||||
|
* @covers \MensBeam\HTML\DOM\Element::getAttributeNames
|
||||||
|
*
|
||||||
|
* @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::getElementsByTagName
|
||||||
|
* @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_getAttributeNames() {
|
||||||
|
$d = new Document('<!DOCTYPE html><html><body><div id="ook" class="eek" ack="ack" foo="foo" bar="bar"></div></body></html>');
|
||||||
|
$div = $d->getElementsByTagName('div')[0];
|
||||||
|
$this->assertSame([ 'id', 'class', 'ack', 'foo', 'bar' ], $div->getAttributeNames());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testMethod_getAttributeNS() {
|
||||||
|
$d = new Document('<!DOCTYPE html><html><head></head><body><svg xmlns="' . Node::SVG_NAMESPACE . '" xmlns:xlink="' . Node::XLINK_NAMESPACE . '"></svg></body></html>');
|
||||||
|
$svg = $d->getElementsByTagNameNS(Node::SVG_NAMESPACE, 'svg')[0];
|
||||||
|
// Parser 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');
|
||||||
|
|
||||||
|
$this->assertSame(Node::SVG_NAMESPACE, $svg->getAttributeNS(Node::XMLNS_NAMESPACE, 'xmlns'));
|
||||||
|
$this->assertSame(Node::XLINK_NAMESPACE, $svg->getAttributeNS(Node::XMLNS_NAMESPACE, 'xlink'));
|
||||||
|
$this->assertSame('https://poop💩.poop', $svg->getAttributeNS(Node::XMLNS_NAMESPACE, 'poop💩'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -289,7 +289,6 @@ class TestNode extends \PHPUnit\Framework\TestCase {
|
||||||
* @covers \MensBeam\HTML\DOM\Text::__construct
|
* @covers \MensBeam\HTML\DOM\Text::__construct
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
|
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
|
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::getInnerNode
|
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode
|
* @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::get
|
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::get
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::has
|
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::has
|
||||||
|
@ -864,7 +863,6 @@ class TestNode extends \PHPUnit\Framework\TestCase {
|
||||||
* @covers \MensBeam\HTML\DOM\Text::__construct
|
* @covers \MensBeam\HTML\DOM\Text::__construct
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
|
* @covers \MensBeam\HTML\DOM\Inner\Document::__construct
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
|
* @covers \MensBeam\HTML\DOM\Inner\Document::__get_wrapperNode
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::getInnerNode
|
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode
|
* @covers \MensBeam\HTML\DOM\Inner\Document::getWrapperNode
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::get
|
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::get
|
||||||
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::has
|
* @covers \MensBeam\HTML\DOM\Inner\NodeCache::has
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<testsuite name="DOM">
|
<testsuite name="DOM">
|
||||||
<file>cases/TestDocument.php</file>
|
<file>cases/TestDocument.php</file>
|
||||||
<file>cases/TestDocumentOrElement.php</file>
|
<file>cases/TestDocumentOrElement.php</file>
|
||||||
|
<file>cases/TestElement.php</file>
|
||||||
<file>cases/TestNode.php</file>
|
<file>cases/TestNode.php</file>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
Loading…
Reference in a new issue