Browse Source

Starting testing

wrapper-classes
Dustin Wilson 2 years ago
parent
commit
ea955e77b9
  1. 3
      .gitignore
  2. 3
      lib/Attr.php
  3. 6
      lib/CDATASection.php
  4. 76
      lib/ChildNode.php
  5. 18
      lib/Document.php
  6. 2
      lib/Element.php
  7. 2
      lib/Exception.php
  8. 25
      lib/InnerNode/Document.php
  9. 38
      lib/Node.php
  10. 37
      lib/ParentNode.php
  11. 239
      tests/cases/TestChildNode.php
  12. 532
      tests/cases/TestDocument.php
  13. 68
      tests/cases/TestDocumentFragment.php
  14. 25
      tests/cases/TestDocumentOrElement.php
  15. 303
      tests/cases/TestElement.php
  16. 38
      tests/cases/TestElementMap.php
  17. 49
      tests/cases/TestLeafNode.php
  18. 40
      tests/cases/TestNode.php
  19. 103
      tests/cases/TestNodeList.php
  20. 167
      tests/cases/TestNodeTrait.php
  21. 289
      tests/cases/TestParentNode.php
  22. 230
      tests/cases/TestTokenList.php
  23. 279
      tests/cases/serializer/TestSerializer.php
  24. 153
      tests/cases/serializer/formatted/mensbeam01.dat
  25. 33
      tests/cases/serializer/standard/mensbeam01.dat
  26. 34
      tests/cases/serializer/standard/mensbeam02.dat
  27. 913
      tests/cases/serializer/standard/wpt01.dat
  28. 15
      tests/phpunit.dist.xml

3
.gitignore

@ -3,7 +3,8 @@ manual
node_modules
/test*.html
/test*.php
lib/old
old
tests/cases/old
# General
*.DS_Store

3
lib/Attr.php

@ -27,7 +27,8 @@ class Attr extends Node {
protected function __get_ownerElement(): Element {
// PHP's DOM does this correctly already.
return $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->ownerElement);
$wrapperNode = &$this->innerNode->ownerDocument->getWrapperNode($this->innerNode->ownerElement);
return $wrapperNode;
}
protected function __get_prefix(): string {

6
lib/CDATASection.php

@ -9,4 +9,8 @@ declare(strict_types=1);
namespace MensBeam\HTML\DOM;
class CDATASection extends Text {}
class CDATASection extends Text {
public function __construct(string $data = '') {
$this->innerNode = new \DOMCDATASection($data);
}
}

76
lib/ChildNode.php

@ -7,8 +7,10 @@
declare(strict_types=1);
namespace MensBeam\HTML\DOM;
use MensBeam\Framework\MagicProperties,
MensBeam\HTML\DOM\InnerNode\Reflection;
use MensBeam\HTML\DOM\InnerNode\{
Document as InnerDocument,
Reflection
};
trait ChildNode {
@ -23,28 +25,18 @@ trait ChildNode {
*/
public function moonwalk(?\Closure $filter = null, bool $includeReferenceNode = false): \Generator {
$node = $this->parentNode;
if ($node !== null) {
$node = Reflection::getProtectedProperty($node, 'innerNode');
$doc = (!$node instanceof InnerDocument) ? $node->ownerDocument : $node;
do {
$next = $node->parentNode;
$result = ($filter === null) ? true : $filter($node);
// Have to do type checking here because PHP is lacking in advanced typing
if ($result !== true && $result !== false && $result !== null) {
$type = gettype($result);
if ($type === 'object') {
$type = get_class($result);
}
throw new Exception(Exception::RETURN_TYPE_ERROR, 'Closure', '?bool', $type);
}
$wrapperNode = $doc->getWrapperNode($node);
$result = ($filter === null) ? true : $filter($wrapperNode);
if ($result === true) {
yield $node;
}
if ($node instanceof DocumentFragment) {
$host = Reflection::getProtectedProperty($node, 'host');
if ($host !== null) {
$next = $host->get();
}
yield $wrapperNode;
}
} while ($node = $next);
}
@ -59,22 +51,23 @@ trait ChildNode {
* the iteration.
*/
public function walkFollowing(?\Closure $filter = null, bool $includeReferenceNode = false): \Generator {
$node = ($includeReferenceNode) ? $this : $this->nextSibling;
$node = null;
if ($includeReferenceNode) {
$node = $this->innerNode;
} elseif ($this->nextSibling !== null) {
$node = Reflection::getProtectedProperty($this->nextSibling, 'innerNode');
}
if ($node !== null) {
$doc = (!$node instanceof InnerDocument) ? $node->ownerDocument : $node;
do {
$next = $node->nextSibling;
$result = ($filter === null) ? true : $filter($node);
// Have to do type checking here because PHP is lacking in advanced typing
if ($result !== true && $result !== false && $result !== null) {
$type = gettype($result);
if ($type === 'object') {
$type = get_class($result);
}
throw new Exception(Exception::RETURN_TYPE_ERROR, 'Closure', '?bool', $type);
}
$wrapperNode = $doc->getWrapperNode($node);
$result = ($filter === null) ? true : $filter($wrapperNode);
if ($result === true) {
yield $node;
yield $wrapperNode;
}
} while ($node = $next);
}
@ -89,22 +82,23 @@ trait ChildNode {
* the iteration.
*/
public function walkPreceding(?\Closure $filter = null, bool $includeReferenceNode = false): \Generator {
$node = ($includeReferenceNode) ? $this : $this->previousSibling;
$node = null;
if ($includeReferenceNode) {
$node = $this->innerNode;
} elseif ($this->nextSibling !== null) {
$node = Reflection::getProtectedProperty($this->previousSibling, 'innerNode');
}
if ($node !== null) {
$doc = (!$node instanceof InnerDocument) ? $node->ownerDocument : $node;
do {
$next = $node->previousSibling;
$result = ($filter === null) ? true : $filter($node);
// Have to do type checking here because PHP is lacking in advanced typing
if ($result !== true && $result !== false && $result !== null) {
$type = gettype($result);
if ($type === 'object') {
$type = get_class($result);
}
throw new Exception(Exception::RETURN_TYPE_ERROR, 'Closure', '?bool', $type);
}
$wrapperNode = $doc->getWrapperNode($node);
$result = ($filter === null) ? true : $filter($wrapperNode);
if ($result === true) {
yield $node;
yield $wrapperNode;
}
} while ($node = $next);
}

18
lib/Document.php

@ -20,10 +20,28 @@ class Document extends Node {
protected string $_contentType = 'text/html';
protected DOMImplementation $_implementation;
protected function __get_body(): Element {
if ($this->documentElement === null || !$this->documentElement->hasChildNodes()) {
return null;
}
# The body element of a document is the first of the html element's children
# that is either a body element or a frameset element, or null if there is no
# such element.
return $this->documentElement->firstChild->walkFollowing(function($n) {
$name = strtolower($n->nodeName);
return ($n instanceof Element && $n->namespaceURI === Parser::HTML_NAMESPACE && ($name === 'body' || $name === 'frameset'));
}, true)->current();
}
protected function __get_contentType(): string {
return $this->_contentType;
}
protected function __get_documentElement(): ?Element {
return $this->innerNode->getWrapperNode($this->innerNode->documentElement);
}
protected function __get_implementation(): DOMImplementation {
return $this->_implementation;
}

2
lib/Element.php

@ -11,7 +11,7 @@ use MensBeam\HTML\Parser;
class Element extends Node {
use ParentNode;
use ChildNode, ParentNode;
protected function __get_namespaceURI(): string {
// PHP's DOM uses null incorrectly for the HTML namespace, and if you attempt to

2
lib/Exception.php

@ -10,7 +10,7 @@ namespace MensBeam\HTML\DOM;
use MensBeam\Framework\Exception as FrameworkException;
class DOMException extends FrameworkException {
class Exception extends FrameworkException {
public const CLIENT_ONLY_NOT_IMPLEMENTED = 301;

25
lib/InnerNode/Document.php

@ -42,10 +42,13 @@ class Document extends \DOMDocument {
}
public function getWrapperNode(?\DOMNode $node = null): WrapperNode {
public function getWrapperNode(?\DOMNode $node = null): ?WrapperNode {
if ($node === null) {
return null;
}
// If the node is a Document then the wrapperNode is this's wrapperNode
// property.
if ($node instanceof Document || $node === null) {
if ($node instanceof Document) {
return $this->wrapperNode;
}
@ -91,7 +94,21 @@ class Document extends \DOMDocument {
$className = 'XMLDocument';
}
// Nodes cannot be created from their constructors normally
return Reflection::createFromProtectedConstructor(self::$parentNamespace . "\\$className", $node);
// If the class is to be a CDATASection, DocumentFragment, or Text then the
// object needs to be created differently because they have public constructors,
// unlike other nodes.
if ($className === 'CDATASection' || $className === 'DocumentFragment' || $className === 'Text') {
$reflector = new \ReflectionClass(self::$parentNamespace . "\\$className");
$wrapperNode = $reflector->newInstanceWithoutConstructor();
$property = new \ReflectionProperty($wrapperNode, 'innerNode');
$property->setAccessible(true);
$property->setValue($wrapperNode, $node);
return $wrapperNode;
} else {
$wrapperNode = Reflection::createFromProtectedConstructor(self::$parentNamespace . "\\$className", $node);
}
$this->nodeMap->set($wrapperNode, $this);
return $wrapperNode;
}
}

38
lib/Node.php

@ -99,7 +99,8 @@ abstract class Node {
protected function __get_firstChild(): ?Node {
// PHP's DOM does this correctly already.
return $this->innerNode->firstChild;
$doc = ($this instanceof Document) ? $this->innerNode : $this->innerNode->ownerDocument;
return $doc->getWrapperNode($this->innerNode->firstChild);
}
protected function __get_isConnected(): bool {
@ -111,17 +112,17 @@ abstract class Node {
protected function __get_lastChild(): ?Node {
// PHP's DOM does this correctly already.
return $this->innerNode->lastChild;
return $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->lastChild);
}
protected function __get_previousSibling(): ?Node {
// PHP's DOM does this correctly already.
return $this->innerNode->previousSibling;
return $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->previousSibling);
}
protected function __get_nextSibling(): ?Node {
// PHP's DOM does this correctly already.
return $this->innerNode->nextSibling;
return $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->nextSibling);
}
protected function __get_nodeName(): string {
@ -183,7 +184,7 @@ abstract class Node {
return null;
}
return $this->innerNode->ownerDocument->getWrapperNode();
return $this->innerNode->ownerDocument->getWrapperNode($this->innerNode->ownerDocument);
}
protected function __get_parentElement(): ?Element {
@ -862,11 +863,10 @@ abstract class Node {
}
}
$childNodes = $this->childNodes;
foreach ($childNodes as $c) {
if ($c instanceof Element) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
if ($this->firstChild !== null && $this->firstChild->walkFollowing(function($n) {
return ($n instanceof Element);
}, true)->current() !== null) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
}
@ -874,11 +874,10 @@ abstract class Node {
# parent has a doctype child, child is non-null and an element is preceding
# child, or child is null and parent has an element child.
elseif ($node instanceof DocumentType) {
$childNodes = $this->childNodes;
foreach ($childNodes as $c) {
if ($c instanceof DocumentType) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
if ($this->firstChild !== null && $this->firstChild->walkFollowing(function($n) {
return ($n instanceof DocumentType);
}, true)->current() !== null) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
if ($child !== null) {
@ -889,11 +888,10 @@ abstract class Node {
}
}
} else {
$childNodes = $this->childNodes;
foreach ($childNodes as $c) {
if ($c instanceof Element) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
if ($this->firstChild !== null && $this->firstChild->walkFollowing(function($n) {
return ($n instanceof Element);
}, true)->current() !== null) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
}
}

37
lib/ParentNode.php

@ -7,7 +7,10 @@
declare(strict_types=1);
namespace MensBeam\HTML\DOM;
use MensBeam\Framework\MagicProperties;
use MensBeam\HTML\DOM\InnerNode\{
Document as InnerDocument,
Reflection
};
trait ParentNode {
@ -21,35 +24,29 @@ trait ParentNode {
* the iteration.
*/
public function walk(?\Closure $filter = null, bool $includeReferenceNode = false): \Generator {
$node = ($includeReferenceNode && !$this instanceof DocumentFragment) ? $this : $this->firstChild;
$node = null;
if ($includeReferenceNode && !$this instanceof DocumentFragment) {
$node = $this->innerNode;
} elseif ($this->firstChild !== null) {
$node = Reflection::getProtectedProperty($this->firstChild, 'innerNode');
}
if ($node !== null) {
$doc = (!$node instanceof InnerDocument) ? $node->ownerDocument : $node;
do {
$next = $node->nextSibling;
$result = ($filter === null) ? true : $filter($node);
// Have to do type checking here because PHP is lacking in advanced typing
if ($result !== true && $result !== false && $result !== null) {
$type = gettype($result);
if ($type === 'object') {
$type = get_class($result);
}
throw new Exception(Exception::RETURN_TYPE_ERROR, 'Closure', '?bool', $type);
}
$wrapperNode = $doc->getWrapperNode($node);
$result = ($filter === null) ? true : $filter($wrapperNode);
if ($result === true) {
yield $node;
yield $wrapperNode;
}
// If the filter returns true (accept) or false (skip) and the node wasn't
// removed in the filter iterate through the children
if ($result !== null && $node->parentNode !== null) {
if ($node instanceof HTMLTemplateElement) {
$node = $node->content;
}
if ($node->hasChildNodes()) {
yield from $node->walk($filter);
}
if ($result !== null && $node->parentNode !== null && $node->hasChildNodes()) {
yield from $node->walk($filter);
}
} while ($node = $next);
}

239
tests/cases/TestChildNode.php

@ -1,239 +0,0 @@
<?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,
Element,
Exception
};
/** @covers \MensBeam\HTML\DOM\ChildNode */
class TestChildNode extends \PHPUnit\Framework\TestCase {
/**
* @covers \MensBeam\HTML\DOM\ChildNode::after
* @covers \MensBeam\HTML\DOM\ChildNode::before
* @covers \MensBeam\HTML\DOM\ChildNode::replaceWith
* @covers \MensBeam\HTML\DOM\NodeTrait::convertNodesToNode
*/
public function testAfterBeforeReplaceWith(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
$o = $d->body->appendChild($d->createTextNode('ook'));
$div2 = $d->body->appendChild($d->createElement('div'));
// On node with parent
$div->after($d->createElement('span'), $o, 'eek');
$this->assertSame('<body><div></div><span></span>ookeek<div></div></body>', (string)$d->body);
$div->after($o);
$this->assertSame('<body><div></div>ook<span></span>eek<div></div></body>', (string)$d->body);
// On node with no parent
$c = $d->createComment('ook');
$this->assertNull($c->after($d->createTextNode('ook')));
// On node with parent
$br = $d->body->insertBefore($d->createElement('br'), $div);
$e = $d->createTextNode('eek');
$div->before($d->createElement('span'), $o, 'eek', $e, $br);
$this->assertSame('<body><span></span>ookeekeek<br><div></div><span></span>eek<div></div></body>', (string)$d->body);
$div->before($o);
$this->assertSame('<body><span></span>eekeek<br>ook<div></div><span></span>eek<div></div></body>', (string)$d->body);
// On node with no parent
$c = $d->createComment('ook');
$this->assertNull($c->before($d->createTextNode('ook')));
// On node with parent
$s = $d->createElement('span');
$br->replaceWith('ack', $o, $e, $s);
$this->assertSame('<body><span></span>eekackookeek<span></span><div></div><span></span>eek<div></div></body>', (string)$d->body);
$s->replaceWith($o);
$this->assertSame('<body><span></span>eekackeekook<div></div><span></span>eek<div></div></body>', (string)$d->body);
// On node with no parent
$c = $d->createComment('ook');
$this->assertNull($c->replaceWith($d->createTextNode('ook')));
// Parent within node
$o->replaceWith('poo', $o, $e);
$this->assertSame('<body><span></span>eekackpooookeek<div></div><span></span>eek<div></div></body>', (string)$d->body);
}
public function provideAfterBeforeReplaceWithFailures(): array {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
return [
[ function() use($div) {
$div->after(false);
} ],
[ function() use($div) {
$div->before(false);
} ],
[ function() use($div) {
$div->replaceWith(false);
} ],
[ function() use($div) {
$div->after(new \DateTime);
} ],
[ function() use($div) {
$div->before(new \DateTime);
} ],
[ function() use($div) {
$div->replaceWith(new \DateTime);
} ]
];
}
/**
* @dataProvider provideAfterBeforeReplaceWithFailures
* @covers \MensBeam\HTML\DOM\ChildNode::after
* @covers \MensBeam\HTML\DOM\ChildNode::before
* @covers \MensBeam\HTML\DOM\ChildNode::replaceWith
*/
public function testAfterBeforeReplaceWithFailures(\Closure $closure): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::ARGUMENT_TYPE_ERROR);
$closure();
}
/** @covers \MensBeam\HTML\DOM\ChildNode::moonwalk */
public function testMoonwalk(): void {
// Test removal of elements when moonwalking
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
$div = $div->appendChild($d->createElement('div'));
$div = $div->appendChild($d->createElement('div'));
$div->setAttribute('class', 'delete-me');
$div = $div->appendChild($d->createElement('div'));
$t = $div->appendChild($d->createTextNode('ook'));
$divs = $t->moonwalk(function($n) {
return ($n instanceof Element && $n->nodeName === 'div');
});
foreach ($divs as $div) {
if ($div->getAttribute('class') === 'delete-me') {
$div->parentNode->removeChild($div);
}
}
$this->assertSame('<body><div><div></div></div></body>', (string)$d->body);
// Test moonwalking through template barriers
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$t = $d->body->appendChild($d->createElement('template'));
$w = $t->content->appendChild($d->createTextNode('ook'))->moonwalk();
$this->assertTrue($t->content->isSameNode($w->current()));
$w->next();
$this->assertTrue($t->isSameNode($w->current()));
}
public function provideMoonwalkFailures(): iterable {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->innerHTML = '<header><h1>Ook</h1></header><main><h2>Eek</h2><p>Ook <a href="ook">eek</a>, ook?</p></main><footer></footer>';
$main = $d->body->getElementsByTagName('main')->item(0);
return [
[ function() use ($main) {
$main->moonwalk(function($n) {
return 'ook';
})->current();
} ],
[ function() use ($main) {
$main->moonwalk(function($n) {
return new \DateTime();
})->current();
} ]
];
}
/**
* @dataProvider provideMoonwalkFailures
* @covers \MensBeam\HTML\DOM\DOMException::__construct
* @covers \MensBeam\HTML\DOM\ChildNode::moonwalk
*/
public function testMoonwalkFailures(\Closure $closure): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::CLOSURE_RETURN_TYPE_ERROR);
$closure();
}
public function provideWalkFailures(): iterable {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->innerHTML = '<header><h1>Ook</h1></header><main><h2>Eek</h2><p>Ook <a href="ook">eek</a>, ook?</p></main><footer></footer>';
return [
[ function() use ($d) {
$d->body->firstChild->walkFollowing(function($n) {
return 'ook';
})->current();
} ],
[ function() use ($d) {
$d->body->firstChild->walkFollowing(function($n) {
return new \DateTime();
})->current();
} ],
[ function() use ($d) {
$d->body->lastChild->walkPreceding(function($n) {
return 'ook';
})->current();
} ],
[ function() use ($d) {
$d->body->lastChild->walkPreceding(function($n) {
return new \DateTime();
})->current();
} ]
];
}
/**
* @dataProvider provideWalkFailures
* @covers \MensBeam\HTML\DOM\DOMException::__construct
* @covers \MensBeam\HTML\DOM\ChildNode::walkFollowing
* @covers \MensBeam\HTML\DOM\ChildNode::walkPreceding
*/
public function testWalkFailures(\Closure $closure): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::CLOSURE_RETURN_TYPE_ERROR);
$closure();
}
/** @covers \MensBeam\HTML\DOM\ParentNode::walk */
public function testWalkPreceding(): void {
// Test removal of elements when walking
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->innerHTML = '<header><h1>Ook</h1></header><main><h2>Eek</h2><p>Ook <a href="ook">eek</a>, ook?</p></main><footer></footer>';
$this->assertNotNull($d->body->lastChild->walkPreceding(function($n) {
return ($n instanceof Element && $n->nodeName === 'main');
}, true)->current());
}
}

532
tests/cases/TestDocument.php

@ -1,532 +0,0 @@
<?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,
ElementMap,
Exception,
HTMLTemplateElement
};
use MensBeam\HTML\Parser,
org\bovigo\vfs\vfsStream;
/** @covers \MensBeam\HTML\DOM\Document */
class TestDocument extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\Document::adoptNode */
public function testAdoptNode() {
$d = new Document();
$t = $d->createElement('template');
$d2 = new Document();
$t2 = $d2->adoptNode($t, true);
$this->assertSame($d2, $t2->ownerDocument);
$this->assertNull($t->parentNode);
/*$d = new \DOMDocument();
$t = $d->createElement('template');
// Add a child template to cover recursive template conversions.
$t->appendChild($d->createElement('template'));
$this->assertSame(\DOMElement::class, $t::class);
$d2 = new Document();
$t2 = $d2->importNode($t, true);
$this->assertSame(HTMLTemplateElement::class, $t2::class);*/
}
public function provideAttributeNodeCreation(): iterable {
return [
[ 'test', 'test' ],
[ 'TEST', 'test' ],
[ 'test:test', 'testU00003Atest' ],
[ 'TEST:TEST', 'testU00003Atest' ]
];
}
/**
* @dataProvider provideAttributeNodeCreation
* @covers \MensBeam\HTML\DOM\Document::createAttribute
*/
public function testAttributeNodeCreation(string $nameIn, string $local): void {
// Test without a document element and with
$d = new Document();
$a = $d->createAttribute($nameIn);
$this->assertSame($local, $a->localName);
$d = new Document();
$d->appendChild($d->createElement('html'));
$a = $d->createAttribute($nameIn);
$this->assertSame($local, $a->localName);
}
/**
* @covers \MensBeam\HTML\DOM\Document::createAttribute
* @covers \MensBeam\HTML\DOM\DOMException::__construct
*/
public function testAttributeNodeCreationFailure(): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::INVALID_CHARACTER);
$d = new Document();
$d->createAttribute('<ook>');
}
public function provideAttributeNodeNSCreation(): iterable {
return [
[ 'fake_ns', 'test', 'fake_ns', '', 'test' ],
[ 'fake_ns', 'test:test', 'fake_ns', 'test', 'test' ],
[ 'fake_ns', 'TEST:TEST', 'fake_ns', 'TEST', 'TEST' ],
[ 'another_fake_ns', 'steaming💩:poop💩', 'another_fake_ns', 'steamingU01F4A9', 'poopU01F4A9' ],
// An empty string for a prefix is technically incorrect, but we cannot fix that.
[ '', 'poop💩', null, '', 'poopU01F4A9' ],
// An empty string for a prefix is technically incorrect, but we cannot fix that.
[ null, 'poop💩', null, '', 'poopU01F4A9' ]
];
}
/**
* @dataProvider provideAttributeNodeNSCreation
* @covers \MensBeam\HTML\DOM\Document::createAttributeNS
* @covers \MensBeam\HTML\DOM\Document::validateAndExtract
*/
public function testAttributeNodeNSCreation(?string $nsIn, string $nameIn, ?string $nsExpected, ?string $prefixExpected, string $localNameExpected): void {
// Test without a document element and with
$d = new Document();
$a = $d->createAttributeNS($nsIn, $nameIn);
$this->assertSame($nsExpected, $a->namespaceURI);
$this->assertSame($prefixExpected, $a->prefix);
$this->assertSame($localNameExpected, $a->localName);
$d = new Document();
$d->appendChild($d->createElement('html'));
$a = $d->createAttributeNS($nsIn, $nameIn);
$this->assertSame($nsExpected, $a->namespaceURI);
$this->assertSame($prefixExpected, $a->prefix);
$this->assertSame($localNameExpected, $a->localName);
}
public function provideDisabledMethods(): iterable {
return [
[ 'createCDATASection', 'ook' ],
[ 'createEntityReference', 'ook' ],
[ 'loadXML', 'ook' ],
[ 'registerNodeClass', 'ook', null ],
[ 'relaxNGValidate', 'ook' ],
[ 'relaxNGValidateSource', 'ook' ],
[ 'saveXML', null ],
[ 'schemaValidate', 'ook', 0 ],
[ 'schemaValidateSource', 'ook', 0 ],
[ 'validate', null ],
[ 'xinclude', null ],
];
}
/**
* @dataProvider provideDisabledMethods
* @covers \MensBeam\HTML\DOM\Document::createEntityReference
* @covers \MensBeam\HTML\DOM\Document::loadXML
* @covers \MensBeam\HTML\DOM\Document::saveXML
* @covers \MensBeam\HTML\DOM\Document::validate
* @covers \MensBeam\HTML\DOM\Document::xinclude
* @covers \MensBeam\HTML\DOM\DOMException::__construct
*/
public function testDisabledMethods(string $methodName, ...$arguments): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::DISABLED_METHOD);
$d = new Document();
$d->$methodName(...$arguments);
}
/**
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\Document::convertTemplate
* @covers \MensBeam\HTML\DOM\Document::load
* @covers \MensBeam\HTML\DOM\Document::loadDOM
* @covers \MensBeam\HTML\DOM\Document::loadHTML
* @covers \MensBeam\HTML\DOM\Document::loadHTMLFile
* @covers \MensBeam\HTML\DOM\Document::preInsertionValidity
* @covers \MensBeam\HTML\DOM\Document::replaceTemplates
* @covers \MensBeam\HTML\DOM\Document::__get_compatMode
* @covers \MensBeam\HTML\DOM\Document::__get_URL
* @covers \MensBeam\HTML\DOM\NodeTrait::getRootNode
*/
public function testDocumentCreation(): void {
// Test null source
$d = new Document();
$this->assertSame('MensBeam\HTML\DOM\Document', get_class($d));
$this->assertSame(null, $d->firstChild);
// Test compatibility mode
$d = new Document('<html><body>Ook!</body></html>');
$this->assertSame('BackCompat', $d->compatMode);
// Test DOM source
$d = new \DOMDocument();
$d->appendChild($d->createElement('html'));
$d2 = new Document();
$d2->appendChild($d2->createElement('html'));
$d2->loadDOM($d);
$d3 = new Document($d);
$this->assertSame('MensBeam\HTML\DOM\Element', get_class($d3->firstChild));
$this->assertSame('html', $d3->firstChild->nodeName);
// Test file source
$vfs = vfsStream::setup('DOM', 0777, [ 'test.html' => <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-2022-JP">
<title>Ook</title>
</head>
</html>
HTML ]);
$f = $vfs->url() . '/test.html';
// Test nonexistent file source
$d = new Document();
$this->assertFalse(@$d->load('fileDoesNotExist.html'));
$d->load($f);
$this->assertNotNull($d->documentElement);
$this->assertSame('ISO-2022-JP', $d->charset);
// Test http source
$d = new Document();
$d->load('https://google.com');
$this->assertNotNull($d->documentElement);
$this->assertSame('UTF-8', $d->charset);
$this->assertSame('https://google.com', $d->URL);
$this->assertNull($d->documentURI);
// Test document encoding
$d = new Document();
$d->loadHTMLFile($f, null, 'UTF-8');
$this->assertSame('UTF-8', $d->charset);
// Test real document loading
$d = new Document();
$d->loadHTMLFile(dirname(__FILE__) . '/../test.html', null, 'UTF-8');
$this->assertStringStartsWith('file://', $d->URL);
// Test templates in source
$d = new Document('<!DOCTYPE html><html><body><template class="test"><template></template></template></body></html>');
$t = $d->getElementsByTagName('template')->item(0);
$this->assertSame(HTMLTemplateElement::class, get_class($t));
$this->assertSame(HTMLTemplateElement::class, get_class($t->content->firstChild));
}
public function provideElementCreation(): iterable {
return [
// HTML element
[ 'div', 'div', Element::class ],
// HTML element and uppercase qualified name
[ 'DIV', 'div', Element::class ],
// Template element
[ 'template', 'template', HTMLTemplateElement::class ],
// Template element and uppercase qualified name
[ 'TEMPLATE', 'template', HTMLTemplateElement::class ],
// Name coercion
[ 'poop💩', 'poopU01F4A9', Element::class ]
];
}
/**
* @dataProvider provideElementCreation
* @covers \MensBeam\HTML\DOM\Document::createElement
*/
public function testElementCreation(string $nameIn, string $nameExpected, string $classExpected): void {
$d = new Document;
$n = $d->createElement($nameIn);
$this->assertInstanceOf($classExpected, $n);
$this->assertNotNull($n->ownerDocument);
$this->assertSame($nameExpected, $n->nodeName);
}
public function provideElementCreationFailures(): iterable {
return [
[ function() {
$d = new Document();
$d->createElement('ook', 'FAIL');
}, DOMException::NOT_SUPPORTED ],
[ function() {
$d = new Document();
$d->createElement('<ook>');
}, DOMException::INVALID_CHARACTER ]
];
}
/**
* @dataProvider provideElementCreationFailures
* @covers \MensBeam\HTML\DOM\Document::__construct
* @covers \MensBeam\HTML\DOM\DOMException::__construct
*/
public function testElementCreationFailures(\Closure $closure, int $errorCode): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode($errorCode);
$closure();
}
public function provideElementCreationNS(): iterable {
return [
// HTML element with a null namespace
[ null, null, 'div', 'div', Element::class ],
// Template element with a null namespace
[ null, null, 'template', 'template', HTMLTemplateElement::class ],
// Template element with a null namespace and uppercase name
[ null, null, 'TEMPLATE', 'TEMPLATE', HTMLTemplateElement::class ],
// Template element
[ Parser::HTML_NAMESPACE, Parser::HTML_NAMESPACE, 'template', 'template', HTMLTemplateElement::class ],
// SVG element with SVG namespace
[ Parser::SVG_NAMESPACE, Parser::SVG_NAMESPACE, 'svg', 'svg', Element::class ],
// SVG element with SVG namespace and uppercase local name
[ Parser::SVG_NAMESPACE, Parser::SVG_NAMESPACE, 'SVG', 'SVG', Element::class ],
// Name coercion
[ 'steaming💩', 'steaming💩', 'poop💩', 'poopU01F4A9', Element::class ]
];
}
/**
* @dataProvider provideElementCreationNS
* @covers \MensBeam\HTML\DOM\Document::createElementNS
* @covers \MensBeam\HTML\DOM\Document::validateAndExtract
*/
public function testElementCreationNS(?string $nsIn, ?string $nsExpected, string $localNameIn, string $localNameExpected, string $classExpected): void {
$d = new Document();
$n = $d->createElementNS($nsIn, $localNameIn);
$this->assertInstanceOf($classExpected, $n);
$this->assertNotNull($n->ownerDocument);
$this->assertSame($nsExpected, $n->namespaceURI);
$this->assertSame($localNameExpected, $n->localName);
}
public function provideElementCreationNSFailures(): iterable {
return [
[ function() {
$d = new Document();
$d->createElementNS('ook', 'ook', 'FAIL');
}, DOMException::NOT_SUPPORTED ],
[ function() {
$d = new Document();
$d->createElementNS(null, '<ook>');
}, DOMException::INVALID_CHARACTER ],
[ function() {
$d = new Document();
$d->createElementNS(null, 'xmlns');
}, DOMException::NAMESPACE_ERROR ]
];
}
/**
* @dataProvider provideElementCreationNSFailures
* @covers \MensBeam\HTML\DOM\Document::createElementNS
* @covers \MensBeam\HTML\DOM\Document::validateAndExtract
* @covers \MensBeam\HTML\DOM\DOMException::__construct
*/
public function testElementCreationNSFailures(\Closure $closure, int $errorCode): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode($errorCode);
$closure();
}
/**
* @covers \MensBeam\HTML\DOM\Document::save
* @covers \MensBeam\HTML\DOM\Document::saveHTMLFile
*/
public function testFileSaving(): void {
$vfs = vfsStream::setup('DOM', 0777);
$path = $vfs->url() . '/test.html';
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->save($path);
$this->assertSame('<html></html>', file_get_contents($path));
$d->saveHTMLFile($path);
$this->assertSame('<html></html>', file_get_contents($path));
}
/** @covers \MensBeam\HTML\DOM\Document::importNode */
public function testImportNode() {
$d = new Document();
$t = $d->createElement('template');
$d2 = new Document();
$t2 = $d2->importNode($t, true);
$this->assertFalse($t2->ownerDocument->isSameNode($t->ownerDocument));
$this->assertSame($t2::class, $t::class);
$d = new \DOMDocument();
$t = $d->createElement('template');
// Add a child template to cover recursive template conversions.
$t->appendChild($d->createElement('template'));
$this->assertSame(\DOMElement::class, $t::class);
$d2 = new Document();
$t2 = $d2->importNode($t, true);
$this->assertSame(HTMLTemplateElement::class, $t2::class);
}
/** @covers \MensBeam\HTML\DOM\Document::importNode */
public function testImportingNodesFailure() {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::NOT_SUPPORTED);
$d = new \DOMDocument();
$c = $d->createCDATASection('fail');
$d2 = new Document();
$d2->importNode($c);
}
/** @covers \MensBeam\HTML\DOM\Document::__get_body */
public function testPropertyGetBody(): void {
$d = new Document();
$this->assertNull($d->body);
$d->appendChild($d->createElement('html'));
$this->assertNull($d->body);
$d->documentElement->appendChild($d->createTextNode(' '));
$this->assertNull($d->body);
$f = $d->createElement('frameset');
$d->documentElement->appendChild($f);
$this->assertNotNull($d->body);
$d->documentElement->removeChild($f);
}
/** @covers \MensBeam\HTML\DOM\Document::__set_body */
public function testPropertySetBody(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$b = $d->createElement('body');
$d->body = $b;
$this->assertSame('body', $d->body->nodeName);
$d->body = $b;
$this->assertSame('body', $d->body->nodeName);
$b = $d->createElement('body');
$b->appendChild($d->createTextNode('Ook'));
$d->body = $b;
$this->assertSame('Ook', $d->body->firstChild->data);
}
public function providePropertySetBodyFailures(): iterable {
$result = [];
$d = new Document();
$result[] = [ $d, $d->createElement('body') ];
$d = new Document();
$result[] = [ $d, $d->createElement('div') ];
$d = new Document();
$result[] = [ $d, $d->createTextNode('FAIL') ];
return $result;
}
/**
* @dataProvider providePropertySetBodyFailures
* @covers \MensBeam\HTML\DOM\Document::__set_body
* @covers \MensBeam\HTML\DOM\DOMException::__construct
*/
public function testPropertySetBodyFailures(Document $document, \DOMNode $node): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::HIERARCHY_REQUEST_ERROR);
$document->body = $node;
}
/**
* @covers \MensBeam\HTML\DOM\Document::__get_charset
* @covers \MensBeam\HTML\DOM\Document::__get_characterSet
* @covers \MensBeam\HTML\DOM\Document::__get_inputEncoding
*/
public function testPropertyGetCharset(): void {
$d = new Document(null, 'UTF-8');
$this->assertSame('UTF-8', $d->charset);
$this->assertSame('UTF-8', $d->characterSet);
$this->assertSame('UTF-8', $d->inputEncoding);
$d = new Document('<!DOCTYPE html><html><head><meta charset="GB18030"></head></html>');
$this->assertSame('gb18030', $d->charset);
$this->assertSame('gb18030', $d->characterSet);
$this->assertSame('gb18030', $d->inputEncoding);
}
public function providePropertyGetCompatMode(): iterable {
return [
// Empty document
[ null, 'CSS1Compat' ],
// Document without doctype
[ '<html></html>', 'BackCompat' ],
// Document with doctype
[ '<!DOCTYPE html><html></html>', 'CSS1Compat' ]
];
}
/**
* @dataProvider providePropertyGetCompatMode
* @covers \MensBeam\HTML\DOM\Document::__get_compatMode
*/
public function testPropertyGetCompatMode(?string $html, string $compatMode): void {
$d = new Document($html);
$this->assertSame($compatMode, $d->compatMode);
}
/** @covers \MensBeam\HTML\DOM\Document::__get_contentType */
public function testPropertyGetContentType(): void {
$d = new Document();
$this->assertSame('text/html', $d->contentType);
}
/** @covers \MensBeam\HTML\DOM\Document::__get_xpath */
public function testPropertyGetXPath(): void {
$d = new Document();
$this->assertSame('DOMXPath', get_class($d->xpath));
}
/**
* @covers \MensBeam\HTML\DOM\Document::__destruct
* @covers \MensBeam\HTML\DOM\ElementMap::add
* @covers \MensBeam\HTML\DOM\ElementMap::delete
* @covers \MensBeam\HTML\DOM\ElementMap::destroy
* @covers \MensBeam\HTML\DOM\ElementMap::has
* @covers \MensBeam\HTML\DOM\ElementMap::index
*/
public function testTemplateElementReferences(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$t = $d->createElement('template');
$this->assertFalse(ElementMap::has($t));
$d->documentElement->appendChild($t);
$this->assertTrue(ElementMap::has($t));
$d->__destruct();
$this->assertFalse(ElementMap::has($t));
$d = new Document();
$d->appendChild($d->createElement('html'));
$t = $d->importNode($t);
$this->assertFalse(ElementMap::has($t));
$d->documentElement->appendChild($t);
$this->assertTrue(ElementMap::has($t));
$d->documentElement->removeChild($t);
$this->assertFalse(ElementMap::has($t));
}
}

68
tests/cases/TestDocumentFragment.php

@ -1,68 +0,0 @@
<?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,
DocumentFragment,
Element,
Exception,
HTMLTemplateElement
};
/** @covers \MensBeam\HTML\DOM\DocumentFragment */
class TestDocumentFragment extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\DocumentFragment::getElementById */
public function testGetElementById(): void {
$d = new Document();
$df = $d->createDocumentFragment();
$o = $df->appendChild($d->createElement('span'));
$o->setAttribute('id', 'eek');
$this->assertSame(Element::class, $df->getElementById('eek')::class);
$this->assertNull($df->getElementById('ook'));
}
/** @covers \MensBeam\HTML\DOM\DocumentFragment::__get_host */
public function testGetHost(): void {
$d = new Document();
// From a template
$t = $d->createElement('template');
$this->assertSame(HTMLTemplateElement::class, get_class($t->content->host));
// From a created document fragment
$df = $d->createDocumentFragment();
$this->assertNull($df->host);
}
public function provideSetHostFailures(): iterable {
return [
[ function() {
$d = new Document();
$t = $d->createElement('template');
$t->content->host = $d->createElement('template');
} ],
[ function() {
$d = new Document();
$df = $d->createDocumentFragment();
$df->host = $d->createElement('template');
} ]
];
}
/**
* @dataProvider provideSetHostFailures
* @covers \MensBeam\HTML\DOM\DocumentFragment::__set_host
* @covers \MensBeam\HTML\DOM\Exception::__construct
*/
public function testSetHostFailures(\Closure $closure): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::READONLY_PROPERTY);
$closure();
}
}

25
tests/cases/TestDocumentOrElement.php

@ -1,25 +0,0 @@
<?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;
/** @covers \MensBeam\HTML\DOM\DocumentOrElement */
class TestDocumentOrElement extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\DocumentOrElement::getElementsByClassName */
public function testGetElementsByClassName(): void {
$d = new Document();
$this->assertSame(0, $d->getElementsByClassName('fail')->length);
$this->assertSame(0, $d->getElementsByClassName('')->length);
$d->appendChild($d->createElement('html'));
$d->documentElement->setAttribute('class', 'ook');
$this->assertSame($d->documentElement->nodeName, $d->getElementsByClassName('ook')->item(0)->nodeName);
}
}

303
tests/cases/TestElement.php

@ -1,303 +0,0 @@
<?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
};
use MensBeam\HTML\Parser;
/** @covers \MensBeam\HTML\DOM\Element */
class TestElement extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\Element::getAttributeNames */
public function testGetAttributeNames(): void {
$d = new Document();
$e = $d->createElement('html');
$d->appendChild($e);
$this->assertSame([], $e->getAttributeNames());
$e->setAttribute('ook:eek', 'ook');
$e->setAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns:xlink', Parser::XLINK_NAMESPACE);
$e->setAttribute('ook', 'eek');
$this->assertSame([
'ook:eek',
'xmlns:xlink',
'ook'
], $e->getAttributeNames());
}
public function provideGetHasSetAttribute(): iterable {
return [
[ 'ook', 'eek', 'ook', 'eek' ],
[ 'ook:eek', 'ook', 'ook:eek', 'ook' ],
[ 'poop💩', 'soccer', 'poop💩', 'soccer' ]
];
}
/**
* @dataProvider provideGetHasSetAttribute
* @covers \MensBeam\HTML\DOM\Element::getAttribute
* @covers \MensBeam\HTML\DOM\Element::hasAttribute
* @covers \MensBeam\HTML\DOM\Element::setAttribute
*/
public function testGetHasSetAttribute(string $nameIn, string $valueIn, string $nameExpected, string $valueExpected): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$e = $d->documentElement;
$e->setAttribute($nameIn, $valueIn);
$this->assertTrue($e->hasAttribute($nameExpected));
$this->assertSame($valueExpected, $e->getAttribute($nameExpected));
}
public function provideGetHasSetAttributeNS(): iterable {
return [
[ 'fake_ns', 'ook', 'eek', 'ookeek', 'ook', 'eek', 'ookeek' ],
[ 'another_fake_ns', 'steaming💩', 'poop💩', 'soccer', 'steaming💩', 'poop💩', 'soccer' ],
[ Parser::XMLNS_NAMESPACE, 'xmlns', 'xlink', Parser::XLINK_NAMESPACE, 'xmlns', 'xlink', Parser::XLINK_NAMESPACE ]
];
}
/**
* @dataProvider provideGetHasSetAttributeNS
* @covers \MensBeam\HTML\DOM\Element::getAttributeNS
* @covers \MensBeam\HTML\DOM\Element::hasAttributeNS
* @covers \MensBeam\HTML\DOM\Element::setAttributeNS
*/
public function testGetHasSetAttributeNS(?string $namespaceIn, ?string $prefixIn, string $localNameIn, string $valueIn, ?string $prefixExpected, string $localNameExpected, string $valueExpected): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$e = $d->documentElement;
$qualifiedNameIn = ($prefixIn === null || $prefixIn === '') ? $localNameIn : "{$prefixIn}:{$localNameIn}";
$e->setAttributeNS($namespaceIn, $qualifiedNameIn, $valueIn);
$this->assertTrue($e->hasAttributeNS($namespaceIn, $localNameExpected));
$this->assertSame($valueExpected, $e->getAttributeNS($namespaceIn, $localNameExpected));
}
/**
* @covers \MensBeam\HTML\DOM\Element::__get_classList
* @covers \MensBeam\HTML\DOM\TokenList::__construct
*/
public function testPropertyGetClassList(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->setAttribute('class', 'ook eek ack ookeek');
$this->assertSame(4, $d->documentElement->classList->length);
}
/**
* @covers \MensBeam\HTML\DOM\Element::__get_innerHTML
* @covers \MensBeam\HTML\DOM\Element::__set_innerHTML
* @covers \MensBeam\HTML\DOM\Document::importNode
*/
public function testPropertyGetSetInnerHTML(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$s = $d->body->appendChild($d->createElement('span'));
$s->appendChild($d->createTextNode('ook'));
$this->assertSame('<span>ook</span>', $d->body->innerHTML);
$d->body->innerHTML = '<div id ="ook">eek</div>';
$this->assertSame('<div id="ook">eek</div>', $d->body->innerHTML);
$t = $d->body->appendChild($d->createElement('template'));
$t->innerHTML = 'ook';
$this->assertSame('ook', $t->innerHTML);
}
/**
* @covers \MensBeam\HTML\DOM\Element::__get_outerHTML
* @covers \MensBeam\HTML\DOM\Element::__set_outerHTML
*/
public function testPropertyGetSetOuterHTML(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->setAttribute('class', 'ook');
$s = $d->body->appendChild($d->createElement('span'));
$s->appendChild($d->createTextNode('ook'));
$this->assertSame('<body class="ook"><span>ook</span></body>', $d->body->outerHTML);
$d->body->outerHTML = '<body>eek</body>';
$this->assertSame('<body>eek</body>', $d->body->outerHTML);
$f = $d->createDocumentFragment();
$div = $f->appendChild($d->createElement('div'));
$div->outerHTML = 'ook';
$this->assertSame('ook', (string)$f);
$div = $d->createElement('div');
$div->appendChild($d->createTextNode('ook'));
$div->outerHTML = '<div>eek</div>';
$this->assertSame('<div>ook</div>', (string)$div);
}
/**
* @covers \MensBeam\HTML\DOM\Element::__set_outerHTML
*/
public function testPropertySetOuterHTMLFailure(): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::NO_MODIFICATION_ALLOWED);
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->outerHTML = '<html>FAIL</html>';
}
/**
* @covers \MensBeam\HTML\DOM\Element::getAttribute
*/
public function testGetAttribute(): void {
// Just need to test nonexistent attributes
$d = new Document();
$d->appendChild($d->createElement('html'));
$this->assertNull($d->documentElement->getAttribute('ook'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::getAttributeNodeNS
*/
public function testGetAttributeNodeNS(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->setAttribute('ook', 'eek');
// Empty string namespace
$ook = $d->documentElement->getAttributeNodeNS('', 'ook');
$this->assertSame('eek', $ook->value);
// Bogus attribute
$this->assertNull($d->documentElement->getAttributeNodeNS(null, 'what'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::getAttributeNS
*/
public function testGetAttributeNS(): void {
// Just need to test nonexistent attributes
$d = new Document();
$d->appendChild($d->createElement('html'));
$this->assertNull($d->documentElement->getAttributeNS(Parser::HTML_NAMESPACE, 'ook'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::hasAttributeNS
*/
public function testHasAttributeNS(): void {
// Just need to test empty string namespace
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->setAttribute('ook', 'eek');
$this->assertTrue($d->documentElement->hasAttributeNS('', 'ook'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::removeAttribute
*/
public function testRemoveAttribute(): void {
// Just need to test classList updates
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->classList->add('ook', 'eek');
$d->documentElement->removeAttribute('class');
$this->assertNull($d->documentElement->getAttribute('class'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::removeAttributeNS
*/
public function testRemoveAttributeNS(): void {
// Just need to test classList updates
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->classList->add('ook', 'eek');
$d->documentElement->removeAttributeNS(null, 'class');
$this->assertNull($d->documentElement->getAttribute('class'));
$d->documentElement->setAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns', Parser::HTML_NAMESPACE);
$d->documentElement->removeAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns');
$this->assertNull($d->documentElement->getAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttribute
* @covers \MensBeam\HTML\DOM\TokenList::add
*/
public function testSetAttribute(): void {
// Need to test classList updates
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->classList->add('ook', 'eek');
$d->documentElement->setAttribute('class', 'ack');
$this->assertSame('ack', $d->documentElement->classList[0]);
// Test setting class to empty string
$d->documentElement->setAttribute('class', '');
$this->assertSame('', $d->documentElement->getAttribute('class'));
// Test setting id attribute
$d->documentElement->setAttribute('id', 'ook');
$this->assertSame('ook', $d->documentElement->getAttribute('id'));
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttribute
* @covers \MensBeam\HTML\DOM\TokenList::add
*/
public function testSetAttributeFailure(): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::INVALID_CHARACTER);
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->setAttribute('ook eek', 'fail');
}
/**
* @covers \MensBeam\HTML\DOM\Element::setAttributeNS
* @covers \MensBeam\HTML\DOM\TokenList::add
*/
public function testSetAttributeNS(): void {
$d = new Document();
// Don't append html element and set attribute
$de = $d->createElement('html');
$de->setAttributeNS(null, 'id', 'ook');
$this->assertSame('ook', $de->getAttribute('id'));
$de->setAttributeNS(null, 'class', 'ook');
$this->assertSame('ook', $de->getAttribute('class'));
$de->setAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns', Parser::HTML_NAMESPACE);
$this->assertSame(Parser::HTML_NAMESPACE, $de->getAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns'));
$b = $d->createElement('body');
$b->setAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns', Parser::HTML_NAMESPACE);
$this->assertSame(Parser::HTML_NAMESPACE, $b->getAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns'));
$t = $d->createElement('template');
$t->setAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns', Parser::HTML_NAMESPACE);
$this->assertSame(Parser::HTML_NAMESPACE, $t->getAttributeNS(Parser::XMLNS_NAMESPACE, 'xmlns'));
// Test name coercion when namespace is null
$de->setAttributeNS(null, 'poop💩', 'ook');
$this->assertSame('ook', $de->getAttribute('poop💩'));
}
}

38
tests/cases/TestElementMap.php

@ -1,38 +0,0 @@
<?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,
ElementMap
};
/**
* @covers \MensBeam\HTML\DOM\ElementMap
*/
class TestElementMap extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\ElementMap::add */
public function testAdd(): void {
$d = new Document();
$t = $d->createElement('template');
$this->assertTrue(ElementMap::add($t));
$this->assertFalse(ElementMap::add($t));
}
/** @covers \MensBeam\HTML\DOM\ElementMap::delete */
public function testDelete(): void {
$d = new Document();
$t = $d->createElement('template');
$this->assertTrue(ElementMap::add($t));
$this->assertTrue(ElementMap::delete($t));
$this->assertFalse(ElementMap::delete($t));
}
}

49
tests/cases/TestLeafNode.php

@ -1,49 +0,0 @@
<?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
};
/** @covers \MensBeam\HTML\DOM\LeafNode */
class TestLeafNode extends \PHPUnit\Framework\TestCase {
public function provideDisabledMethods(): iterable {
return [
[ function($d, $n) {
$n->appendChild($d->createElement('fail'));
} ],
[ function($d, $n) {
$n->insertBefore($d->createElement('fail'));
} ],
[ function($d, $n) {
$n->removeChild($d->createElement('fail'));
} ],
[ function($d, $n) {
$n->replaceChild($d->createElement('fail2'), $d->createElement('fail'));
} ],
];
}
/**
* @dataProvider provideDisabledMethods
* @covers \MensBeam\HTML\DOM\LeafNode::appendChild
* @covers \MensBeam\HTML\DOM\LeafNode::insertBefore
* @covers \MensBeam\HTML\DOM\LeafNode::removeChild
* @covers \MensBeam\HTML\DOM\LeafNode::replaceChild
*/
public function testDisabledMethods(\Closure $closure): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::HIERARCHY_REQUEST_ERROR);
$d = new Document();
$closure($d, $d->createTextNode('ook'));
}
}

40
tests/cases/TestNode.php

@ -0,0 +1,40 @@
<?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,
Node
};
use MensBeam\HTML\Parser;
/** @covers \MensBeam\HTML\DOM\Document */
class TestNode extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\Node::__get_childNodes */
public function testProperty_childNodes() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$b = $d->body;
$b->appendChild($d->createElement('span'));
$b->appendChild($d->createTextNode('ook'));
// Node::childNodes on Element
$childNodes = $d->body->childNodes;
$this->assertEquals(2, $childNodes->length);
$this->assertSame('SPAN', $childNodes[0]->nodeName);
// Node::childNodes on Text
$childNodes = $d->body->lastChild->childNodes;
$this->assertEquals(0, $childNodes->length);
// Try it again to test caching
$childNodes = $d->body->lastChild->childNodes;
}
}

103
tests/cases/TestNodeList.php

@ -1,103 +0,0 @@
<?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,
Exception,
NodeList
};
/** @covers \MensBeam\HTML\DOM\NodeList */
class TestNodeList extends \PHPUnit\Framework\TestCase {
public function provideConstructorFailures(): iterable {
return [
[ function() {
new NodeList([ 'fail' ]);
} ],
[ function() {
new NodeList([ new \DateTime() ]);
} ]
];
}
/**
* @dataProvider provideConstructorFailures
* @covers \MensBeam\HTML\DOM\NodeList::__construct
*/
public function testConstructorFailures(\Closure $closure): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::ARGUMENT_TYPE_ERROR);
$closure();
}
/** @covers \MensBeam\HTML\DOM\NodeList::count */
public function testCount(): void {
$d = new Document();
$list = new NodeList([
$d->createElement('ook'),
$d->createTextNode('eek'),
$d->createComment('ack')
]);
$this->assertEquals(3, count($list));
}
/** @covers \MensBeam\HTML\DOM\NodeList::item */
public function testItem(): void {
$d = new Document();
$list = new NodeList([
$d->createElement('ook'),
$d->createTextNode('eek'),
$d->createComment('ack')
]);
$this->assertNull($list->item(42));
}
/**
* @covers \MensBeam\HTML\DOM\NodeList::current
* @covers \MensBeam\HTML\DOM\NodeList::item
* @covers \MensBeam\HTML\DOM\NodeList::key
* @covers \MensBeam\HTML\DOM\NodeList::next
* @covers \MensBeam\HTML\DOM\NodeList::rewind
* @covers \MensBeam\HTML\DOM\NodeList::offsetExists
* @covers \MensBeam\HTML\DOM\NodeList::offsetGet
* @covers \MensBeam\HTML\DOM\NodeList::valid
*/
public function testIteration(): void {
$d = new Document();
$list = new NodeList([
$d->createElement('ook'),
$d->createTextNode('eek'),
$d->createComment('ack')
]);
foreach ($list as $key => $node) {
$this->assertSame($node, $list[$key]);
// test offsetExists
$this->assertTrue(isset($list[$key]));
}
}
/** @covers \MensBeam\HTML\DOM\NodeList::__get_length */
public function testPropertyGetLength(): void {
$d = new Document();
$list = new NodeList([
$d->createElement('ook'),
$d->createTextNode('eek'),
$d->createComment('ack')
]);
$this->assertEquals(3, $list->length);
}
}

167
tests/cases/TestNodeTrait.php

@ -1,167 +0,0 @@
<?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,
Exception
};
/** @covers \MensBeam\HTML\DOM\NodeTrait */
class TestNodeTrait extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\NodeTrait::compareDocumentPosition */
public function testCompareDocumentPosition(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->innerHTML = '<header><h1>Ook</h1></header><main><h2 id="eek" class="ack">Eek</h2><p>Ook <a href="ook">eek</a>, ook?</p></main><footer></footer>';
$m = $d->getElementsByTagName('main')->item(0);
$f = $d->getElementsByTagName('footer')->item(0);
$e = $d->getElementById('eek');
$h2Id = $e->getAttributeNode('id');
$h2Class = $e->getAttributeNode('class');
$aHref = $d->getElementsByTagName('a')->item(0)->getAttributeNode('href');
$compareMainToBody = $m->compareDocumentPosition($d->body);
$this->assertEquals(10, $compareMainToBody);
$compareBodyToMain = $d->body->compareDocumentPosition($m);
$this->assertEquals(20, $compareBodyToMain);
$compareFooterToMain = $f->compareDocumentPosition($m);
$this->assertEquals(2, $compareFooterToMain);
$compareMainToFooter = $m->compareDocumentPosition($f);
$this->assertEquals(4, $compareMainToFooter);
$compareH2IdToAHref = $h2Id->compareDocumentPosition($aHref);
$this->assertEquals(4, $compareH2IdToAHref);
$compareH2IdToH2Class = $h2Id->compareDocumentPosition($h2Class);
$this->assertEquals(36, $compareH2IdToH2Class);
$compareH2ClassToH2Id = $h2Class->compareDocumentPosition($h2Id);
$this->assertEquals(34, $compareH2ClassToH2Id);
$this->assertEquals(0, $m->compareDocumentPosition($m));
$this->assertGreaterThan(0, $compareMainToBody & Document::DOCUMENT_POSITION_CONTAINS);
$this->assertGreaterThan(0, $compareMainToBody & Document::DOCUMENT_POSITION_PRECEDING);
$this->assertEquals(0, $compareMainToBody & Document::DOCUMENT_POSITION_FOLLOWING);
$this->assertGreaterThan(0, $compareBodyToMain & Document::DOCUMENT_POSITION_CONTAINED_BY);
$this->assertGreaterThan(0, $compareBodyToMain & Document::DOCUMENT_POSITION_FOLLOWING);
$this->assertEquals(0, $compareBodyToMain & Document::DOCUMENT_POSITION_PRECEDING);
$this->assertGreaterThan(0, $compareFooterToMain & Document::DOCUMENT_POSITION_PRECEDING);
$this->assertGreaterThan(0, $compareMainToFooter & Document::DOCUMENT_POSITION_FOLLOWING);
$this->assertGreaterThan(0, $compareH2IdToAHref & Document::DOCUMENT_POSITION_FOLLOWING);
$this->assertGreaterThan(0, $compareH2IdToH2Class & Document::DOCUMENT_POSITION_FOLLOWING);
$this->assertGreaterThan(0, $compareH2ClassToH2Id & Document::DOCUMENT_POSITION_PRECEDING);
$m->parentNode->removeChild($m);
$compareDetachedMainToFooter = $m->compareDocumentPosition($f);
$this->assertEquals($compareDetachedMainToFooter, $m->compareDocumentPosition($f));
$this->assertGreaterThanOrEqual(35, $compareDetachedMainToFooter);
$this->assertLessThanOrEqual(37, $compareDetachedMainToFooter);
$this->assertNotEquals(36, $compareDetachedMainToFooter);
}
/** @covers \MensBeam\HTML\DOM\NodeTrait::contains */
public function testContains(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$o = $d->body->appendChild($d->createTextNode('Ook!'));
$d2 = new Document();
$d2->appendChild($d2->createElement('html'));
$this->assertTrue($d->documentElement->contains($d->body));
$this->assertTrue($d->contains($o));
$this->assertFalse($o->contains($d));
$this->assertFalse($d->contains($d2->documentElement));
}
public function provideDisabledMethods(): iterable {
return [
[ 'C14N' ],
[ 'C14NFile', 'ook' ],
[ 'getLineNo' ]
];
}
/**
* @dataProvider provideDisabledMethods
* @covers \MensBeam\HTML\DOM\NodeTrait::C14N
* @covers \MensBeam\HTML\DOM\NodeTrait::C14NFile
* @covers \MensBeam\HTML\DOM\NodeTrait::getLineNo
*/
public function testDisabledMethods(string $methodName, ...$arguments): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::DISABLED_METHOD);
$d = new Document();
$d->$methodName(...$arguments);
}
/** @covers \MensBeam\HTML\DOM\NodeTrait::getRootNode */
public function testGetRootNode(): void {
$d = new Document();
$t = $d->createElement('template');
$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 = '<main><h1>Ook</h1><p>Eek</p></main><footer></footer>';
$d2 = new Document();
$d2->appendChild($d2->createElement('html'));
$d2->documentElement->appendChild($d2->createElement('body'));
$d2->body->innerHTML = '<main><h1>Ook</h1><p>Eek</p></main><footer></footer>';
$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('<!DOCTYPE html><html lang="en"><head><title>Ook!</title></head><body><head><h1>Eek</h1></head><footer></footer></body></html>');
$d2 = new Document('<!DOCTYPE html><html lang="en"><head><title>Eek!</title></head><body><head><h1>Eek</h1></head><footer></footer></body></html>');
$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));
}
}

289
tests/cases/TestParentNode.php

@ -1,289 +0,0 @@
<?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,
ElementMap,
Exception,
NodeList
};
/** @covers \MensBeam\HTML\DOM\ParentNode */
class TestParentNode extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\ParentNode::insertBefore */
public function testInsertBefore(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
$ook = $d->body->insertBefore($d->createTextNode('ook'), $div);
$this->assertSame('<body>ook<div></div></body>', (string)$d->body);
$t = $d->body->insertBefore($d->createElement('template'), $ook);
$this->assertSame('<body><template></template>ook<div></div></body>', (string)$d->body);
$this->assertTrue(ElementMap::has($t));
}
public function providePreInsertionValidationFailures(): iterable {
return [
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$b = $d->documentElement->appendChild($d->createElement('body'));
$b->appendChild($d->documentElement);
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$b = $d->documentElement->appendChild($d->createElement('body'));
$t = $b->appendChild($d->createElement('template'));
$t->content->appendChild($b);
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$b = $d->documentElement->appendChild($d->createElement('body'));
$d->insertBefore($d->createElement('fail'), $b);
}, DOMException::NOT_FOUND ],
[ function() {
$d = new Document();
$df = $d->createDocumentFragment();
$df->appendChild($d->createElement('html'));
$df->appendChild($d->createTextNode(' '));
$d->appendChild($df);
} ],
[ function() {
$d = new Document();
$d->appendChild($d);
} ],
[ function() {
$d = new Document();
$d->appendChild($d->implementation->createDocumentType('html'));
$d->appendChild($d->implementation->createDocumentType('html'));
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->appendChild($d->implementation->createDocumentType('html'));
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$c = $d->appendChild($d->createComment('ook'));
$d->insertBefore($d->implementation->createDocumentType('html'), $c);
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->insertBefore($d->implementation->createDocumentType('html'));
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->insertBefore($d->implementation->createDocumentType('html'));
} ],
[ function() {
$d = new Document();
$dt = $d->appendChild($d->implementation->createDocumentType('html'));
$df = $d->createDocumentFragment();
$df->appendChild($d->createElement('html'));
$d->insertBefore($df, $dt);
} ],
[ function() {
$d = new Document();
$c = $d->appendChild($d->createComment('OOK'));
$d->appendChild($d->implementation->createDocumentType('html'));
$df = $d->createDocumentFragment();
$df->appendChild($d->createElement('html'));
$d->insertBefore($df, $c);
} ],
[ function() {
$d = new Document();
$dt = $d->appendChild($d->implementation->createDocumentType('html'));
$d->insertBefore($d->createElement('html'), $dt);
} ],
[ function() {
$d = new Document();
$c = $d->appendChild($d->createComment('OOK'));
$d->appendChild($d->implementation->createDocumentType('html'));
$d->insertBefore($d->createElement('html'), $c);
} ],
[ function() {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->appendChild($d->createElement('body'));
} ]
];
}
/**
* @dataProvider providePreInsertionValidationFailures
* @covers \MensBeam\HTML\DOM\DOMException::__construct
* @covers \MensBeam\HTML\DOM\NodeTrait::getRootNode
* @covers \MensBeam\HTML\DOM\ParentNode::preInsertionValidity
*/
public function testPreInsertionValidationFailures(\Closure $closure, int $errorCode = DOMException::HIERARCHY_REQUEST_ERROR): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode($errorCode);
$closure();
}
/** @covers \MensBeam\HTML\DOM\ParentNode::__get_children */
public function testPropertyGetChildren(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$this->assertSame(1, $d->documentElement->children->length);
}
/**
* @covers \MensBeam\HTML\DOM\ParentNode::querySelector
* @covers \MensBeam\HTML\DOM\ParentNode::querySelectorAll
* @covers \MensBeam\HTML\DOM\ParentNode::scopeMatchSelector
* @covers \MensBeam\HTML\DOM\NodeList::__construct
* @covers \MensBeam\HTML\DOM\NodeList::item
*/
public function testQuerySelector(): void {
$d = new Document('<!DOCTYPE html><html><body><div>ook</div><div id="eek">eek</div></body></html>');
$div = $d->body->querySelector('div');
$this->assertSame('div', $div->nodeName);
$this->assertNull($d->querySelector('body::before'));
$divs = $d->body->querySelectorAll('div');
$this->assertEquals(2, $divs->length);
$this->assertSame('eek', $divs->item(1)->getAttribute('id'));
$this->assertNull($d->querySelector('.ook'));
$this->assertEquals(0, $d->querySelectorAll('body::before')->length);
}
/**
* @covers \MensBeam\HTML\DOM\ParentNode::querySelector
* @covers \MensBeam\HTML\DOM\ParentNode::querySelectorAll
* @covers \MensBeam\HTML\DOM\ParentNode::scopeMatchSelector
*/
public function testQuerySelectorFailure(): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode(DOMException::SYNTAX_ERROR);
$d = new Document();
$d->querySelector('ook?');
}
/** @covers \MensBeam\HTML\DOM\ParentNode::replaceChild */
public function testReplaceChild(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
$ook = $d->body->replaceChild($d->createTextNode('ook'), $div);
$this->assertSame('<body>ook</body>', (string)$d->body);
$t = $d->body->replaceChild($d->createElement('template'), $ook);
$this->assertSame('<body><template></template></body>', (string)$d->body);
$this->assertTrue(ElementMap::has($t));
$d->body->replaceChild($d->createElement('br'), $t);
$this->assertSame('<body><br></body>', (string)$d->body);
$this->assertFalse(ElementMap::has($t));
}
/** @covers \MensBeam\HTML\DOM\ParentNode::replaceChildren */
public function testReplaceChildren(): void {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$div = $d->body->appendChild($d->createElement('div'));
$ook = $d->body->appendChild($d->createTextNode('ook'), $d->body->appendChild($d->createElement('div')));
$d->body->replaceChildren($d->createElement('br'), 'ook', $d->createElement('span'), 'eek');
$this->assertSame('<body><br>ook<span></span>eek</body>', (string)$d->body);
$d->body->replaceChildren('ook');
$this->assertSame('<body>ook</body>', (string)$d->body);
}
/** @covers \MensBeam\HTML\DOM\ParentNode::walk */
public function testWalk(): void {
// Test removal of elements when walking
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->innerHTML = '<span class="one">O</span><span class="two">O</span><span class="three">O</span><span class="four">K</span>';
$spans = $d->body->walk(function($n) {
return ($n instanceof Element && $n->nodeName === 'span');
});
foreach ($spans as $s) {
if ($s->getAttribute('class') === 'three') {
$s->parentNode->removeChild($s);
}
}
$this->assertSame('<body><span class="one">O</span><span class="two">O</span><span class="four">K</span></body>', (string)$d->body);
// Test walking through templates' content
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$t = $d->body->appendChild($d->createElement('template'));
$t->content->appendChild($d->createElement('ook'));
$this->assertSame('ook', $d->body->walk(function($n) {
return ($n instanceof Element && $n->nodeName === 'ook');
})->current()->nodeName);
}
public function provideWalkFailures(): iterable {
$d = new Document();
$d->appendChild($d->createElement('html'));
$d->documentElement->appendChild($d->createElement('body'));
$d->body->innerHTML = '<header><h1>Ook</h1></header><main><h2>Eek</h2><p>Ook <a href="ook">eek</a>, ook?</p></main><footer></footer>';
return [
[ function() use ($d) {
$d->body->walk(function($n) {
return 'ook';
})->current();
} ],
[ function() use ($d) {
$d->body->walk(function($n) {
return new \DateTime();
})->current();
} ]
];
}
/**
* @dataProvider provideWalkFailures
* @covers \MensBeam\HTML\DOM\DOMException::__construct
* @covers \MensBeam\HTML\DOM\ParentNode::walk
*/
public function testWalkFailures(\Closure $closure): void {
$this->expectException(Exception::class);
$this->expectExceptionCode(Exception::CLOSURE_RETURN_TYPE_ERROR);
$closure();
}
}

230
tests/cases/TestTokenList.php

@ -1,230 +0,0 @@
<?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
};
/** @covers \MensBeam\HTML\DOM\TokenList */
class TestTokenList extends \PHPUnit\Framework\TestCase {
public function provideAddRemoveReplaceToggleFailures(): iterable {
return [
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->add('');
}, DOMException::SYNTAX_ERROR ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->remove('');
}, DOMException::SYNTAX_ERROR ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->replace('ack', '');
}, DOMException::SYNTAX_ERROR ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->toggle('');
}, DOMException::SYNTAX_ERROR ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->add('fail fail');
}, DOMException::INVALID_CHARACTER ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->remove('fail fail');
}, DOMException::INVALID_CHARACTER ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->replace('ack', 'fail fail');
}, DOMException::INVALID_CHARACTER ],
[ function() {
$d = new Document();
$e = $d->createElement('html');
$e->classList->toggle('fail fail');
}, DOMException::INVALID_CHARACTER ]
];
}
/**
* @dataProvider provideAddRemoveReplaceToggleFailures
* @covers \MensBeam\HTML\DOM\TokenList::add
* @covers \MensBeam\HTML\DOM\TokenList::remove
* @covers \MensBeam\HTML\DOM\TokenList::replace
* @covers \MensBeam\HTML\DOM\TokenList::toggle
*/
public function testAddRemoveReplaceFailures(\Closure $closure, int $errorCode): void {
$this->expectException(DOMException::class);
$this->expectExceptionCode($errorCode);
$closure();
}
/** @covers \MensBeam\HTML\DOM\TokenList::contains */
public function testContains(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertTrue($e->classList->contains('ack'));
$this->assertFalse($e->classList->contains('fail'));
}
/** @covers \MensBeam\HTML\DOM\TokenList::count */
public function testCount(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertSame(4, count($e->classList));
}
/** @covers \MensBeam\HTML\DOM\TokenList::item */
public function testItem(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertNull($e->classList->item(42));
}
/**
* @covers \MensBeam\HTML\DOM\TokenList::current
* @covers \MensBeam\HTML\DOM\TokenList::item
* @covers \MensBeam\HTML\DOM\TokenList::key
* @covers \MensBeam\HTML\DOM\TokenList::next
* @covers \MensBeam\HTML\DOM\TokenList::rewind
* @covers \MensBeam\HTML\DOM\TokenList::offsetExists
* @covers \MensBeam\HTML\DOM\TokenList::offsetGet
* @covers \MensBeam\HTML\DOM\TokenList::valid
*/
public function testIteration(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
foreach ($e->classList as $key => $className) {
$this->assertSame($className, $e->classList[$key]);
// test offsetExists
$this->assertTrue(isset($e->classList[$key]));
}
}
/** @covers \MensBeam\HTML\DOM\TokenList::__get_length */
public function testPropertyGetLength(): void {
// Test it with and without an attached document element
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertSame(4, $e->classList->length);
$d = new Document();
$e = $d->createElement('html');
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertSame(4, $e->classList->length);
}
/**
* @covers \MensBeam\HTML\DOM\TokenList::__get_value
* @covers \MensBeam\HTML\DOM\TokenList::__set_value
*/
public function testPropertyGetSetValue(): void {
// Test it with and without an attached document element
$d = new Document();
$e = $d->createElement('html');
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertSame('ook eek ack ookeek', $e->classList->value);
$this->assertSame('ook eek ack ookeek', $e->getAttribute('class'));
$e->classList->value = 'omg wtf bbq lol zor bor xxx';
$this->assertSame('lol', $e->classList[3]);
$this->assertSame('omg wtf bbq lol zor bor xxx', $e->classList->value);
$this->assertSame('omg wtf bbq lol zor bor xxx', $e->getAttribute('class'));
$e->classList->value = '';
$this->assertSame('', $e->classList->value);
$this->assertSame('', $e->getAttribute('class'));
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertSame('ook eek ack ookeek', $e->classList->value);
$this->assertSame('ook eek ack ookeek', $e->getAttribute('class'));
$e->classList->value = 'omg wtf bbq lol zor bor xxx';
$this->assertSame('lol', $e->classList[3]);
$this->assertSame('omg wtf bbq lol zor bor xxx', $e->classList->value);
$this->assertSame('omg wtf bbq lol zor bor xxx', $e->getAttribute('class'));
$e->classList->value = '';
$this->assertSame('', $e->classList->value);
$this->assertSame('', $e->getAttribute('class'));
}
/** @covers \MensBeam\HTML\DOM\TokenList::replace */
public function testReplace(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->setAttribute('class', 'ook eek ack ookeek');
$this->assertTrue($e->classList->replace('ack', 'what'));
$this->assertSame('ook eek what ookeek', $e->classList->value);
$this->assertSame('ook eek what ookeek', $e->getAttribute('class'));
$this->assertFalse($e->classList->replace('fail', 'eekook'));
}
/** @covers \MensBeam\HTML\DOM\TokenList::remove */
public function testRemove(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->setAttribute('class', 'ook eek ack ookeek');
$e->classList->remove('ack');
$this->assertSame('ook eek ookeek', $e->classList->value);
$this->assertSame('ook eek ookeek', $e->getAttribute('class'));
}
/** @covers \MensBeam\HTML\DOM\TokenList::supports */
public function testSupports(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->classList->add('ook', 'eek', 'ack', 'ookeek');
$this->assertTrue($e->classList->supports('ack'));
}
/** @covers \MensBeam\HTML\DOM\TokenList::toggle */
public function testToggle(): void {
$d = new Document();
$e = $d->appendChild($d->createElement('html'));
$e->setAttribute('class', 'ook eek ack ookeek');
$this->assertFalse($e->classList->toggle('ack'));
$this->assertSame('ook eek ookeek', $e->classList->value);
$this->assertSame('ook eek ookeek', $e->getAttribute('class'));
$this->assertTrue($e->classList->toggle('ack'));
$this->assertSame('ook eek ookeek ack', $e->classList->value);
$this->assertSame('ook eek ookeek ack', $e->getAttribute('class'));
$this->assertTrue($e->classList->toggle('ack', true));
$this->assertSame('ook eek ookeek ack', $e->classList->value);
$this->assertSame('ook eek ookeek ack', $e->getAttribute('class'));
$this->assertFalse($e->classList->toggle('eekook', false));
$this->assertSame('ook eek ookeek ack', $e->classList->value);
$this->assertSame('ook eek ookeek ack', $e->getAttribute('class'));
$this->assertTrue($e->classList->toggle('eekook', true));
$this->assertSame('ook eek ookeek ack eekook', $e->classList->value);
$this->assertSame('ook eek ookeek ack eekook', $e->getAttribute('class'));
}
}

279
tests/cases/serializer/TestSerializer.php

@ -1,279 +0,0 @@
<?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,
Exception
};
use MensBeam\HTML\Parser;
/**
* @covers \MensBeam\HTML\DOM\Comment
* @covers \MensBeam\HTML\DOM\Document
* @covers \MensBeam\HTML\DOM\DocumentFragment
* @covers \MensBeam\HTML\DOM\Element
* @covers \MensBeam\HTML\DOM\HTMLTemplateElement
* @covers \MensBeam\HTML\DOM\ProcessingInstruction
* @covers \MensBeam\HTML\DOM\Text
* @covers \MensBeam\HTML\DOM\ToString
*/
class TestSerializer extends \PHPUnit\Framework\TestCase {
public function provideStandardTreeTests(): iterable {
$blacklist = [];
$files = new \AppendIterator();
$files->append(new \GlobIterator(\MensBeam\HTML\DOM\BASE."tests/cases/Serializer/standard/*.dat", \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME));
foreach ($files as $file) {
if (!in_array(basename($file), $blacklist)) {
yield from $this->parseTreeTestFile($file);
}
}
}
/**
* @dataProvider provideStandardTreeTests
* @covers \MensBeam\HTML\DOM\Document::saveHTML
* @covers \MensBeam\HTML\DOM\Document::blockElementFilterFactory
* @covers \MensBeam\HTML\DOM\Document::serializeNode
* @covers \MensBeam\HTML\DOM\Document::__toString
* @covers \MensBeam\HTML\DOM\ToString::__toString
*/
public function testStandardTreeTests(array $data, bool $fragment, string $exp): void {
$node = $this->buildTree($data, $fragment);
$this->assertSame($exp, (string)$node);
}
public function provideFormattedTreeTests(): iterable {
$files = new \AppendIterator();
$files->append(new \GlobIterator(\MensBeam\HTML\DOM\BASE."tests/cases/Serializer/formatted/*.dat", \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME));
foreach ($files as $file) {
yield from $this->parseTreeTestFile($file);
}
}
/**
* @dataProvider provideFormattedTreeTests
* @covers \MensBeam\HTML\DOM\Document::saveHTML
* @covers \MensBeam\HTML\DOM\Document::blockElementFilterFactory
* @covers \MensBeam\HTML\DOM\Document::serializeNode
* @covers \MensBeam\HTML\DOM\Document::__toString
* @covers \MensBeam\HTML\DOM\ToString::__toString
*/
public function testFormattedTreeTests(array $data, bool $fragment, string $exp): void {
$node = $this->buildTree($data, $fragment, true);
$this->assertSame($exp, (string)$node);
}
/**
* @covers \MensBeam\HTML\DOM\Document::saveHTML
* @covers \MensBeam\HTML\DOM\Document::serializeNode
*/
public function testSerializingDocumentType(): void {
$d = new Document();
$dt = $d->implementation->createDocumentType('ook', 'eek', 'ack');
$d->appendChild($dt);
$this->assertSame('<!DOCTYPE ook>', $d->saveHTML($dt));
}
/**
* @covers \MensBeam\HTML\DOM\Document::saveHTML
* @covers \MensBeam\HTML\DOM\Document::serializeNode
*/
public function testSerializingDocumentFragments(): void {
$d = new Document();
$d->formatOutput = true;
$df = $d->createDocumentFragment();
$df->appendChild($d->createTextNode('ook'));
$this->assertSame('ook', (string)$df);
$this->assertSame('ook', $d->saveHTML($df));
}
/**
* @covers \MensBeam\HTML\DOM\Document::saveHTML
* @covers \MensBeam\HTML\DOM\Document::serializeNode
* @covers \MensBeam\HTML\DOM\ToString::__toString
*/
public function testSerializingElements(): void {
$d = new Document();
$i = $d->createElement('input');
$i->appendChild($d->createTextNode('You should not see this text'));
$this->assertSame('<input>', (string)$i);
$this->assertSame('', $d->saveHTML($i));
$t = $d->createElement('template');
$t->setAttribute('ook', 'eek');
$t->content->appendChild($d->createTextNode('Ook!'));
$this->assertSame('<template ook="eek">Ook!</template>', (string)$t);
$this->assertSame('Ook!', $d->saveHTML($t));
}
/**
* @covers \MensBeam\HTML\DOM\Document::saveHTML
* @covers \MensBeam\HTML\DOM\Document::serializeNode
* @covers \MensBeam\HTML\DOM\ToString::__toString
*/
public function testSerializingTextNodes(): void {
$d = new Document();
$d->formatOutput = true;
$i = $d->createTextNode('test');
$this->assertSame('test', (string)$i);
$this->assertSame('test', $d->saveHTML($i));
}
public function provideSerializerFailures(): iterable {
return [
[ function() {
$d = new Document();
$h = $d->createElement('html');
$d2 = new Document();
$d2->saveHTML($h);
}, DOMException::class, DOMException::WRONG_DOCUMENT ],
[ function() {
$d = new Document();
$d->saveHTML($d->createAttribute('fail'));
}, Exception::class, Exception::ARGUMENT_TYPE_ERROR ],
[ function() {
$d = new Document();
$d->saveHTML(new \DOMDocument());
}, Exception::class, Exception::ARGUMENT_TYPE_ERROR ],
[ function() {
$d = new Document();
$d2 = new \DOMDocument();
$d->saveHTML($d2->createComment('fail'));
}, Exception::class, Exception::ARGUMENT_TYPE_ERROR ]
];
}
/**
* @dataProvider provideSerializerFailures
* @covers \MensBeam\HTML\DOM\Document::saveHTML
*/
public function testSerializerFailures(\Closure $closure, string $exceptionClassName, int $errorCode): void {
$this->expectException($exceptionClassName);
$this->expectExceptionCode($errorCode);
$closure();
}
protected function buildTree(array $data, bool $fragment, bool $formatOutput = false): \DOMNode {
$document = new Document;
$document->formatOutput = $formatOutput;
if ($fragment) {
$document->appendChild($document->createElement("html"));
$out = $document->createDocumentFragment();
} else {
$out = $document;
}
$cur = $out;
$pad = 2;
// process each line in turn
for ($l = 0; $l < sizeof($data); $l++) {
preg_match('/^(\|\s+)(.+)/', $data[$l], $m);
// pop any parents as long as the padding of the line is less than the expected padding
$p = strlen((string) $m[1]);
assert($p >= 2 && $p <= $pad && !($p % 2), new \Exception("Input data is invalid on line ".($l + 1)));
while ($p < $pad) {
$pad -= 2;
$cur = $cur->parentNode;
}
// act based upon what the rest of the line looks like
$d = $m[2];
if (preg_match('/^<!-- (.*?) -->$/', $d, $m)) {
// comment
$cur->appendChild($document->createComment($m[1]));
} elseif (preg_match('/^<!DOCTYPE(?: ([^ >]*)(?: "([^"]*)" "([^"]*)")?)?>$/', $d, $m)) {
// doctype
$name = strlen((string) ($m[1] ?? "")) ? $m[1] : " ";
$public = strlen((string) ($m[2] ?? "")) ? $m[2] : "";
$system = strlen((string) ($m[3] ?? "")) ? $m[3] : "";
$cur->appendChild($document->implementation->createDocumentType($name, $public, $system));
} elseif (preg_match('/^<\?([^ ]+) ([^>]*)>$/', $d, $m)) {
$cur->appendChild($document->createProcessingInstruction($m[1], $m[2]));
} elseif (preg_match('/^<(?:([^ ]+) )?([^>]+)>$/', $d, $m)) {
// element
$ns = strlen((string) $m[1]) ? (array_flip(Parser::NAMESPACE_MAP)[$m[1]] ?? $m[1]) : null;
$cur = $cur->appendChild($document->createElementNS($ns, $m[2]));
$pad += 2;
} elseif (preg_match('/^(?:([^" ]+) )?([^"=]+)="((?:[^"]|"(?!$))*)"$/', $d, $m)) {
// attribute
$ns = strlen((string) $m[1]) ? (array_flip(Parser::NAMESPACE_MAP)[$m[1]] ?? $m[1]) : "";
if ($ns === '') {
$cur->setAttribute($m[2], $m[3]);
} else {
$cur->setAttributeNS($ns, $m[2], $m[3]);
}
} elseif (preg_match('/^"((?:[^"]|"(?!$))*)("?)$/', $d, $m)) {
// text
$t = $m[1];
while (!strlen((string) $m[2])) {
preg_match('/^((?:[^"]|"(?!$))*)("?)$/', $data[++$l], $m);
$t .= "\n".$m[1];
}
$cur->appendChild($document->createTextNode($t));
} else {
throw new \Exception("Input data is invalid on line ".($l + 1));
}
}
return $out;
}
protected function parseTreeTestFile(string $file): \Generator {
$index = 0;
$l = 0;
$lines = array_map(function($v) {
return rtrim($v, "\n");
}, file($file));
while ($l < sizeof($lines)) {
$pos = $l + 1;
assert(in_array($lines[$l], ["#document", "#fragment"]), new \Exception("Test $file #$index does not start with #document or #fragment tag at line ".($l + 1)));
$fragment = $lines[$l] === "#fragment";
// collect the test input
$data = [];
for (++$l; $l < sizeof($lines); $l++) {
if (preg_match('/^#(script-(on|off)|output)$/', $lines[$l])) {
break;
}
$data[] = $lines[$l];
}
// set the script mode, if present
assert(preg_match('/^#(script-(on|off)|output)$/', $lines[$l]) === 1, new \Exception("Test $file #$index follows data with something other than script flag or output at line ".($l + 1)));
$script = null;
if ($lines[$l] === "#script-off") {
$script = false;
$l++;
} elseif ($lines[$l] === "#script-on") {
$script = true;
$l++;
}
// collect the output string
$exp = [];
assert($lines[$l] === "#output", new \Exception("Test $file #$index follows input with something other than output at line ".($l + 1)));
for (++$l; $l < sizeof($lines); $l++) {
if ($lines[$l] === "" && in_array(($lines[$l + 1] ?? ""), ["#document", "#fragment"])) {
break;
}
assert(preg_match('/^([^#]|$)/', $lines[$l]) === 1, new \Exception("Test $file #$index contains unrecognized data after output at line ".($l + 1)));
$exp[] = $lines[$l];
}
$exp = implode("\n", $exp);
if (!$script) {
yield basename($file)." #$index (line $pos)" => [$data, $fragment, $exp];
}
$l++;
$index++;
}
}
}

153
tests/cases/serializer/formatted/mensbeam01.dat

@ -1,153 +0,0 @@
#fragment
| <html>
#output
<html></html>
#document
| <!-- data -->
| <!DOCTYPE html>
| <html>
#output
<!--data-->
<!DOCTYPE html>
<html></html>
#document
| <!DOCTYPE html>
| <html>
| <head>
| <body>
#output
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>
#document
| <html>
| <body>
| <pre>
| <code>
#output
<html>
<body>
<pre><code></code></pre>
</body>
</html>
#document
| <html>
| <body>
| <svg>
#output
<html>
<body><svg></svg></body>
</html>
#fragment
| <body>
| <div>
| <svg svg>
#output
<body>
<div></div>
<svg></svg>
</body>
#fragment
| <body>
| <div>
| <svg svg>
| <svg tspan>
#output
<body>
<div></div>
<svg>
<tspan/>
</svg>
</body>
#document
| <!DOCTYPE html>
| <html>
| "
"
| <head>
| <body>
| "ook
"
#output
<!DOCTYPE html>
<html>
<head></head>
<body>ook
</body>
</html>
#fragment
| <div>
| <div>
| "
"
#output
<div>
<div></div>
</div>
#fragment
| <div>
| <a>
| <div>
| <svg>
#output
<div>
<a>
<div></div>
</a>
<svg></svg>
</div>
#fragment
| <div>
| <!-- data -->
| <div>
#output
<div>
<!--data-->
<div></div>
</div>
#fragment
| <div>
| <div>
| <!-- data -->
| <div>
#output
<div>
<div></div>
<!--data-->
<div></div>
</div>
#fragment
| <div>
| <div>
| <?php echo "Hello world!"; ?>
| <div>
#output
<div>
<div></div>
<?php echo "Hello world!"; ?>
<div></div>
</div>

33
tests/cases/serializer/standard/mensbeam01.dat

@ -1,33 +0,0 @@
#fragment
| <fake_ns test:test>
#output
<test:test></test:test>
#fragment
| <span>
| test💩test="test"
#output
<span test💩test="test"></span>
#fragment
| <wbr>
| "You should not see this text."
#output
<wbr>
#fragment
| <wbr>
| class="test"
#output
<wbr class="test">
#fragment
| <poop💩>
#output
<poop💩></poop💩>
#fragment
| <test>
| poop💩="soccer"
#output
<test poop💩="soccer"></test>

34
tests/cases/serializer/standard/mensbeam02.dat

@ -1,34 +0,0 @@
#document
| <html>
#output
<html></html>
#document
| <!DOCTYPE html>
| <html>
#output
<!DOCTYPE html><html></html>
#document
| <!DOCTYPE html "public" "system">
| <html>
#output
<!DOCTYPE html><html></html>
#document
| <!DOCTYPE test>
| <html>
#output
<!DOCTYPE test><html></html>
#document
| <!DOCTYPE>
| <html>
#output
<!DOCTYPE ><html></html>
#document
| <html>
| <?php echo "Hello world!"; ?>
#output
<html><?php echo "Hello world!"; ?></html>

913
tests/cases/serializer/standard/wpt01.dat

@ -1,913 +0,0 @@
#fragment
| <span>
#output
<span></span>
#fragment
| <span>
| <a>
#output
<span><a></a></span>
#fragment
| <span>
| <a>
| b="c"
#output
<span><a b="c"></a></span>
#fragment
| <span>
| <a>
| b="&"
#output
<span><a b="&amp;"></a></span>
#fragment
| <span>
| <a>
| b=" "
#output
<span><a b="&nbsp;"></a></span>
#fragment
| <span>
| <a>
| b="""
#output
<span><a b="&quot;"></a></span>
#fragment
| <span>
| <a>
| b="<"
#output
<span><a b="<"></a></span>
#fragment
| <span>
| <a>
| b=">"
#output
<span><a b=">"></a></span>
#fragment
| <span>
| <a>
| href="javascript:"<>""
#output
<span><a href="javascript:&quot;<>&quot;"></a></span>
#fragment
| <span>
| <svg svg>
| xlink xlink:href="a"
#output
<span><svg xlink:href="a"></svg></span>
#fragment
| <span>
| <svg svg>
| xmlns xmlns:svg="test"
#output
<span><svg xmlns:svg="test"></svg></span>
#fragment
| <span>
| "a"
#output
<span>a</span>
#fragment
| <span>
| "&"
#output
<span>&amp;</span>
#fragment
| <span>
| " "
#output
<span>&nbsp;</span>
#fragment
| <span>
| "<"
#output
<span>&lt;</span>
#fragment
| <span>
| ">"
#output
<span>&gt;</span>
#fragment
| <span>
| """
#output
<span>"</span>
#fragment
| <span>
| <style>
| "<&>"
#output
<span><style><&></style></span>
#fragment
| <span>
| <script>
| type="test"
| "<&>"
#output
<span><script type="test"><&></script></span>
#fragment
| <script>
| type="test"
| "<&>"
#output
<script type="test"><&></script>
#fragment
| <span>
| <xmp>
| "<&>"
#output
<span><xmp><&></xmp></span>
#fragment
| <span>
| <iframe>
| "<&>"
#output
<span><iframe><&></iframe></span>
#fragment
| <span>
| <noembed>
| "<&>"
#output
<span><noembed><&></noembed></span>
#fragment
| <span>
| <noframes>
| "<&>"
#output
<span><noframes><&></noframes></span>
#fragment
| <span>
| <noscript>
| "<&>"
#script-off
#output
<span><noscript>&lt;&amp;&gt;</noscript></span>
#fragment
| <span>
| <noscript>
| "<&>"
#script-on
#output
<span><noscript><&></noscript></span>
#fragment
| <span>
| <!-- data -->
#output
<span><!--data--></span>
#fragment
| <span>
| <a>
| <b>
| <c>
| <d>
| "e"
| <f>
| <g>
| "h"
#output
<span><a><b><c></c></b><d>e</d><f><g>h</g></f></a></span>
#fragment
| <span>
| b="c"
#output
<span b="c"></span>
#fragment
| <span>
| <svg svg>
| xml xml:foo="test"
#output
<span><svg xml:foo="test"></svg></span>
#fragment
| <span>
| <svg svg>
| xml abc:foo="test"
#output
<span><svg xml:foo="test"></svg></span>
#fragment
| <span>
| <svg svg>
| xmlns xmlns:foo="test"
#output
<span><svg xmlns:foo="test"></svg></span>
#fragment
| <span>
| <svg svg>
| xmlns xmlns="test"
#output
<span><svg xmlns="test"></svg></span>
#fragment
| <span>
| <svg svg>
| fake_ns abc:def="test"
#output
<span><svg abc:def="test"></svg></span>
#fragment
| <pre>
| "
"
#output
<pre>
</pre>
#fragment
| <pre>
| "a
"
#output
<pre>a
</pre>
#fragment
| <span>
| <pre>
| "
"
#output
<span><pre>
</pre></span>
#fragment
| <span>
| <pre>
| "a
"
#output
<span><pre>a
</pre></span>
#fragment
| <textarea>
| "
"
#output
<textarea>
</textarea>
#fragment
| <textarea>
| "a
"
#output
<textarea>a
</textarea>
#fragment
| <span>
| <textarea>
| "
"
#output
<span><textarea>
</textarea></span>
#fragment
| <span>
| <textarea>
| "a
"
#output
<span><textarea>a
</textarea></span>
#fragment
| <listing>
| "
"
#output
<listing>
</listing>
#fragment
| <listing>
| "a
"
#output
<listing>a
</listing>
#fragment
| <span>
| <listing>
| "
"
#output
<span><listing>
</listing></span>
#fragment
| <span>
| <listing>
| "a
"
#output
<span><listing>a
</listing></span>
#fragment
| <area>
#output
<area>
#fragment
| <span>
| <area>
| <a>
| "test"
| <b>
#output
<span><area><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <area>
| <b>
#output
<span><a>test</a><area><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <area>
#output
<span><a>test</a><b></b><area></span>
#fragment
| <base>
#output
<base>
#fragment
| <span>
| <base>
| <a>
| "test"
| <b>
#output
<span><base><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <base>
| <b>
#output
<span><a>test</a><base><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <base>
#output
<span><a>test</a><b></b><base></span>
#fragment
| <basefont>
#output
<basefont>
#fragment
| <span>
| <basefont>
| <a>
| "test"
| <b>
#output
<span><basefont><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <basefont>
| <b>
#output
<span><a>test</a><basefont><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <basefont>
#output
<span><a>test</a><b></b><basefont></span>
#fragment
| <bgsound>
#output
<bgsound>
#fragment
| <span>
| <bgsound>
| <a>
| "test"
| <b>
#output
<span><bgsound><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <bgsound>
| <b>
#output
<span><a>test</a><bgsound><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <bgsound>
#output
<span><a>test</a><b></b><bgsound></span>
#fragment
| <br>
#output
<br>
#fragment
| <span>
| <br>
| <a>
| "test"
| <b>
#output
<span><br><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <br>
| <b>
#output
<span><a>test</a><br><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <br>
#output
<span><a>test</a><b></b><br></span>
#fragment
| <col>
#output
<col>
#fragment
| <span>
| <col>
| <a>
| "test"
| <b>
#output
<span><col><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <col>
| <b>
#output
<span><a>test</a><col><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <col>
#output
<span><a>test</a><b></b><col></span>
#fragment
| <embed>
#output
<embed>
#fragment
| <span>
| <embed>
| <a>
| "test"
| <b>
#output
<span><embed><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <embed>
| <b>
#output
<span><a>test</a><embed><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <embed>
#output
<span><a>test</a><b></b><embed></span>
#fragment
| <frame>
#output
<frame>
#fragment
| <span>
| <frame>
| <a>
| "test"
| <b>
#output
<span><frame><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <frame>
| <b>
#output
<span><a>test</a><frame><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <frame>
#output
<span><a>test</a><b></b><frame></span>
#fragment
| <hr>
#output
<hr>
#fragment
| <span>
| <hr>
| <a>
| "test"
| <b>
#output
<span><hr><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <hr>
| <b>
#output
<span><a>test</a><hr><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <hr>
#output
<span><a>test</a><b></b><hr></span>
#fragment
| <img>
#output
<img>
#fragment
| <span>
| <img>
| <a>
| "test"
| <b>
#output
<span><img><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <img>
| <b>
#output
<span><a>test</a><img><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <img>
#output
<span><a>test</a><b></b><img></span>
#fragment
| <input>
#output
<input>
#fragment
| <span>
| <input>
| <a>
| "test"
| <b>
#output
<span><input><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <input>
| <b>
#output
<span><a>test</a><input><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <input>
#output
<span><a>test</a><b></b><input></span>
#fragment
| <keygen>
#output
<keygen>
#fragment
| <span>
| <keygen>
| <a>
| "test"
| <b>
#output
<span><keygen><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <keygen>
| <b>
#output
<span><a>test</a><keygen><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <keygen>
#output
<span><a>test</a><b></b><keygen></span>
#fragment
| <link>
#output
<link>
#fragment
| <span>
| <link>
| <a>
| "test"
| <b>
#output
<span><link><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <link>
| <b>
#output
<span><a>test</a><link><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <link>
#output
<span><a>test</a><b></b><link></span>
#fragment
| <meta>
#output
<meta>
#fragment
| <span>
| <meta>
| <a>
| "test"
| <b>
#output
<span><meta><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <meta>
| <b>
#output
<span><a>test</a><meta><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <meta>
#output
<span><a>test</a><b></b><meta></span>
#fragment
| <param>
#output
<param>
#fragment
| <span>
| <param>
| <a>
| "test"
| <b>
#output
<span><param><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <param>
| <b>
#output
<span><a>test</a><param><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <param>
#output
<span><a>test</a><b></b><param></span>
#fragment
| <source>
#output
<source>
#fragment
| <span>
| <source>
| <a>
| "test"
| <b>
#output
<span><source><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <source>
| <b>
#output
<span><a>test</a><source><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <source>
#output
<span><a>test</a><b></b><source></span>
#fragment
| <track>
#output
<track>
#fragment
| <span>
| <track>
| <a>
| "test"
| <b>
#output
<span><track><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <track>
| <b>
#output
<span><a>test</a><track><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <track>
#output
<span><a>test</a><b></b><track></span>
#fragment
| <wbr>
#output
<wbr>
#fragment
| <span>
| <wbr>
| <a>
| "test"
| <b>
#output
<span><wbr><a>test</a><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <wbr>
| <b>
#output
<span><a>test</a><wbr><b></b></span>
#fragment
| <span>
| <a>
| "test"
| <b>
| <wbr>
#output
<span><a>test</a><b></b><wbr></span>

15
tests/phpunit.dist.xml

@ -16,20 +16,7 @@
</coverage>
<testsuites>
<testsuite name="DOM">
<file>cases/TestChildNode.php</file>
<file>cases/TestDocument.php</file>
<file>cases/TestDocumentFragment.php</file>
<file>cases/TestDocumentOrElement.php</file>
<file>cases/TestElement.php</file>
<file>cases/TestElementMap.php</file>
<file>cases/TestLeafNode.php</file>
<file>cases/TestNodeList.php</file>
<file>cases/TestNodeTrait.php</file>
<file>cases/TestParentNode.php</file>
<file>cases/TestTokenList.php</file>
</testsuite>
<testsuite name="Serializer">
<file>cases/Serializer/TestSerializer.php</file>
<file>cases/TestNode.php</file>
</testsuite>
</testsuites>
</phpunit>

Loading…
Cancel
Save