Browse Source

More tests

wrapper-classes
Dustin Wilson 3 years ago
parent
commit
302ca7839c
  1. 2
      lib/Comment.php
  2. 11
      lib/Document.php
  3. 2
      lib/Element.php
  4. 23
      lib/ElementMap.php
  5. 2
      lib/ProcessingInstruction.php
  6. 2
      lib/Text.php
  7. 28
      lib/traits/ChildNode.php
  8. 7
      lib/traits/DocumentOrElement.php
  9. 33
      lib/traits/LeafNode.php
  10. 6
      lib/traits/MagicProperties.php
  11. 2
      lib/traits/Node.php
  12. 2
      lib/traits/ParentNode.php
  13. 34
      tests/cases/TestChildNode.php
  14. 12
      tests/cases/TestDocument.php
  15. 39
      tests/cases/TestElementMap.php
  16. 5
      tests/cases/TestException.php
  17. 49
      tests/cases/TestLeafNode.php
  18. 3
      tests/phpunit.dist.xml

2
lib/Comment.php

@ -9,5 +9,5 @@ declare(strict_types=1);
namespace MensBeam\HTML\DOM;
class Comment extends \DOMComment {
use ChildNode, Moonwalk, ToString;
use ChildNode, LeafNode, Moonwalk, ToString;
}

11
lib/Document.php

@ -205,6 +205,10 @@ class Document extends \DOMDocument {
}
}
public function createCDATASection(string $data) {
throw new DOMException(DOMException::NOT_SUPPORTED, __CLASS__ . ' is only meant for HTML; CDATA sections do not exist in HTML DOM');
}
public function createElement(string $name, ?string $value = null): Element {
# The createElement(localName, options) method steps are:
// DEVIATION: We cannot follow the createElement parameters per the DOM spec
@ -300,11 +304,16 @@ class Document extends \DOMDocument {
}
}
public function createEntityReference(string $name): bool {
public function createEntityReference(string $name) {
throw new DOMException(DOMException::NOT_SUPPORTED, __CLASS__ . ' is only meant for HTML; entity references do not exist in HTML DOM');
}
public function importNode(\DOMNode $node, bool $deep = false) {
// Disable importing of PHP's XML DOM-specific nodes.
if ($node instanceof \DOMCDATASection || $node instanceof \DOMEntity || $node instanceof \DOMEntityReference) {
throw new DOMException(DOMException::NOT_SUPPORTED, 'Clever little fucker, aren\'t you?');
}
$node = parent::importNode($node, $deep);
if ($node instanceof \DOMElement || $node instanceof \DOMDocumentFragment) {

2
lib/Element.php

@ -11,7 +11,7 @@ use MensBeam\HTML\Parser;
class Element extends \DOMElement {
use DocumentOrElement, MagicProperties, Moonwalk, ParentNode, ToString, Walk;
use ChildNode, DocumentOrElement, MagicProperties, Moonwalk, ParentNode, ToString, Walk;
protected ?TokenList $_classList = null;

23
lib/ElementMap.php

@ -29,18 +29,16 @@ class ElementMap {
self::$documents[] = $document;
self::$elements[count(self::$documents) - 1][] = $element;
return true;
} else {
foreach (self::$elements[$index] as $v) {
if ($v->isSameNode($element)) {
return false;
}
}
}
self::$elements[$index][] = $element;
return true;
foreach (self::$elements[$index] as $v) {
if ($v->isSameNode($element)) {
return false;
}
}
return false;
self::$elements[$index][] = $element;
return true;
}
public static function delete(Element $element): bool {
@ -72,13 +70,6 @@ class ElementMap {
return false;
}
public static function getIterator(Document $document): \Traversable {
$index = self::index($document);
foreach (self::$elements[$index] as $v) {
yield $v;
}
}
public static function has(Element $element): bool {
$document = $element->ownerDocument;
$index = self::index($document);

2
lib/ProcessingInstruction.php

@ -9,5 +9,5 @@ declare(strict_types=1);
namespace MensBeam\HTML\DOM;
class ProcessingInstruction extends \DOMProcessingInstruction {
use ChildNode, Moonwalk, ToString;
use ChildNode, LeafNode, Moonwalk, ToString;
}

2
lib/Text.php

@ -9,5 +9,5 @@ declare(strict_types=1);
namespace MensBeam\HTML\DOM;
class Text extends \DOMText {
use ChildNode, Moonwalk, ToString;
use ChildNode, LeafNode, Moonwalk, ToString;
}

28
lib/traits/ChildNode.php

@ -10,8 +10,6 @@ namespace MensBeam\HTML\DOM;
trait ChildNode {
use Node;
public function after(...$nodes): void {
# The after(nodes) method steps are:
#
@ -25,15 +23,15 @@ trait ChildNode {
# 3. Let viableNextSibling be this’s first following sibling not in nodes;
# otherwise null.
$n = $this;
$nextViableSibling = null;
while ($n = $n->followingSibling) {
$viableNextSibling = null;
while ($n = $n->nextSibling) {
foreach ($nodes as $nodeOrString) {
if ($nodeOrString instanceof \DOMNode && $nodeOrString->isSameNode($n->followingSibling)) {
continue;
if ($nodeOrString instanceof \DOMNode && $nodeOrString->isSameNode($n)) {
continue 2;
}
}
$nextViableSibling = $n;
$viableNextSibling = $n;
break;
}
@ -44,20 +42,4 @@ trait ChildNode {
# 5. Pre-insert node into parent before viableNextSibling.
$parent->insertBefore($node, $viableNextSibling);
}
public function appendChild($node) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
public function insertBefore($node, $child = null) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
public function removeChild($child) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
public function replaceChild($node, $child) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
}

7
lib/traits/DocumentOrElement.php

@ -11,8 +11,11 @@ use MensBeam\HTML\Parser,
MensBeam\HTML\Parser\NameCoercion;
// This exists because the DOM spec for some stupid reason doesn't give
// DocumentFragment some methods.
/**
* Not in standard. Exists so Document and Element can share some properties and
* methods. For instance, getElementsByClassName is mentioned in the standard in
* both the Document and Element interfaces.
*/
trait DocumentOrElement {
use NameCoercion;

33
lib/traits/LeafNode.php

@ -0,0 +1,33 @@
<?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;
/**
* Not in standard. Exists so all node types that cannot contain children will have
* the insertion methods disabled.
*/
trait LeafNode {
use Node;
public function appendChild($node) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
public function insertBefore($node, $child = null) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
public function removeChild($child) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
public function replaceChild($node, $child) {
throw new DOMException(DOMException::HIERARCHY_REQUEST_ERROR);
}
}

6
lib/traits/MagicProperties.php

@ -18,8 +18,6 @@ namespace MensBeam\HTML\DOM;
*/
trait MagicProperties {
public function __get(string $name) {
// If a getter method exists return it. Otherwise, trigger a property does not
// exist fatal error.
$methodName = $this->getMagicPropertyMethodName($name);
if ($methodName === null) {
throw new Exception(Exception::NONEXISTENT_PROPERTY, $name);
@ -32,16 +30,12 @@ trait MagicProperties {
}
public function __set(string $name, $value) {
// If a setter method exists return that.
$methodName = $this->getMagicPropertyMethodName($name, false);
if ($methodName !== null) {
call_user_func([ $this, $methodName ], $value);
return;
}
// Otherwise, if a getter exists then trigger a readonly property fatal error.
// Finally, if a getter doesn't exist trigger a property does not exist fatal
// error.
if ($this->getMagicPropertyMethodName($name) !== null) {
throw new Exception(Exception::READONLY_PROPERTY, $name);
} else {

2
lib/traits/Node.php

@ -54,7 +54,7 @@ trait Node {
// The spec would have us iterate through the provided nodes and then iterate
// through them again to append. Let's optimize this a wee bit, shall we?
$document = ($this instanceof Document) ? $this : $this->ownerDocument;
$node = ($node->length > 1) ? $document->createDocumentFragment() : null;
$node = (count($nodes) > 1) ? $document->createDocumentFragment() : null;
foreach ($nodes as $k => &$n) {
// Can't do union types until PHP 8... OTL
if (!$n instanceof \DOMNode && !is_string($n)) {

2
lib/traits/ParentNode.php

@ -115,7 +115,7 @@ trait ParentNode {
}
protected function preInsertionValidity(\DOMNode $node, ?\DOMNode $child = null) {
protected function preInsertionValidity(\DOMNode $node, ?\DOMNode $child = null) {
// "parent" in the spec comments below is $this
# 1. If parent is not a Document, DocumentFragment, or Element node, then throw

34
tests/cases/TestChildNode.php

@ -0,0 +1,34 @@
<?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\ChildNode */
class TestChildNode extends \PHPUnit\Framework\TestCase {
/** @covers \MensBeam\HTML\DOM\ChildNode::after */
public function testAfter(): 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, $d->createElement('br'));
$this->assertSame('<body><div></div><span></span>ook<br><div></div></body>', (string)$d->body);
$div->after($o);
// On node with no parent
$c = $d->createComment('ook');
$this->assertNull($c->after($d->createTextNode('ook')));
}
}

12
tests/cases/TestDocument.php

@ -85,6 +85,7 @@ class TestDocument extends \PHPUnit\Framework\TestCase {
public function provideDisabledMethods(): iterable {
return [
[ 'createCDATASection', 'ook' ],
[ 'createEntityReference', 'ook' ],
[ 'loadXML', 'ook' ],
[ 'saveXML', null ],
@ -348,6 +349,17 @@ class TestDocument extends \PHPUnit\Framework\TestCase {
}
/** @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();

39
tests/cases/TestElementMap.php

@ -0,0 +1,39 @@
<?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
};
use MensBeam\HTML\Parser;
/**
* @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));
}
}

5
tests/cases/TestException.php

@ -9,11 +9,8 @@ declare(strict_types=1);
namespace MensBeam\HTML\DOM\TestCase;
use MensBeam\HTML\DOM\{
Document,
DocumentFragment,
DOMException,
Exception,
HTMLTemplateElement
Exception
};
use MensBeam\HTML\Parser;

49
tests/cases/TestLeafNode.php

@ -0,0 +1,49 @@
<?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'));
}
}

3
tests/phpunit.dist.xml

@ -16,10 +16,13 @@
</coverage>
<testsuites>
<testsuite name="DOM">
<file>cases/TestChildNode.php</file>
<file>cases/TestDocument.php</file>
<file>cases/TestDocumentFragment.php</file>
<file>cases/TestElement.php</file>
<file>cases/TestElementMap.php</file>
<file>cases/TestException.php</file>
<file>cases/TestLeafNode.php</file>
<file>cases/TestParentNode.php</file>
</testsuite>
<testsuite name="Serializer">

Loading…
Cancel
Save