Update to drupal-org-drupal 8.0.0-rc2. For more information, see https://www.drupal.org/node/2598668
This commit is contained in:
parent
f32e58e4b1
commit
8e18df8c36
3062 changed files with 15044 additions and 172506 deletions
486
vendor/masterminds/html5/test/HTML5/ElementsTest.php
vendored
486
vendor/masterminds/html5/test/HTML5/ElementsTest.php
vendored
|
@ -1,486 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests;
|
||||
|
||||
use Masterminds\HTML5\Elements;
|
||||
|
||||
class ElementsTest extends TestCase
|
||||
{
|
||||
|
||||
public $html5Elements = array(
|
||||
"a",
|
||||
"abbr",
|
||||
"address",
|
||||
"area",
|
||||
"article",
|
||||
"aside",
|
||||
"audio",
|
||||
"b",
|
||||
"base",
|
||||
"bdi",
|
||||
"bdo",
|
||||
"blockquote",
|
||||
"body",
|
||||
"br",
|
||||
"button",
|
||||
"canvas",
|
||||
"caption",
|
||||
"cite",
|
||||
"code",
|
||||
"col",
|
||||
"colgroup",
|
||||
"command",
|
||||
// "data",
|
||||
"datalist",
|
||||
"dd",
|
||||
"del",
|
||||
"details",
|
||||
"dfn",
|
||||
"dialog",
|
||||
"div",
|
||||
"dl",
|
||||
"dt",
|
||||
"em",
|
||||
"embed",
|
||||
"fieldset",
|
||||
"figcaption",
|
||||
"figure",
|
||||
"footer",
|
||||
"form",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"head",
|
||||
"header",
|
||||
"hgroup",
|
||||
"hr",
|
||||
"html",
|
||||
"i",
|
||||
"iframe",
|
||||
"img",
|
||||
"input",
|
||||
"ins",
|
||||
"kbd",
|
||||
"keygen",
|
||||
"label",
|
||||
"legend",
|
||||
"li",
|
||||
"link",
|
||||
"map",
|
||||
"mark",
|
||||
"menu",
|
||||
"meta",
|
||||
"meter",
|
||||
"nav",
|
||||
"noscript",
|
||||
"object",
|
||||
"ol",
|
||||
"optgroup",
|
||||
"option",
|
||||
"output",
|
||||
"p",
|
||||
"param",
|
||||
"pre",
|
||||
"progress",
|
||||
"q",
|
||||
"rp",
|
||||
"rt",
|
||||
"ruby",
|
||||
"s",
|
||||
"samp",
|
||||
"script",
|
||||
"section",
|
||||
"select",
|
||||
"small",
|
||||
"source",
|
||||
"span",
|
||||
"strong",
|
||||
"style",
|
||||
"sub",
|
||||
"summary",
|
||||
"sup",
|
||||
"table",
|
||||
"tbody",
|
||||
"td",
|
||||
"textarea",
|
||||
"tfoot",
|
||||
"th",
|
||||
"thead",
|
||||
"time",
|
||||
"title",
|
||||
"tr",
|
||||
"track",
|
||||
"u",
|
||||
"ul",
|
||||
"var",
|
||||
"video",
|
||||
"wbr"
|
||||
);
|
||||
|
||||
public $mathmlElements = array(
|
||||
"maction",
|
||||
"maligngroup",
|
||||
"malignmark",
|
||||
"math",
|
||||
"menclose",
|
||||
"merror",
|
||||
"mfenced",
|
||||
"mfrac",
|
||||
"mglyph",
|
||||
"mi",
|
||||
"mlabeledtr",
|
||||
"mlongdiv",
|
||||
"mmultiscripts",
|
||||
"mn",
|
||||
"mo",
|
||||
"mover",
|
||||
"mpadded",
|
||||
"mphantom",
|
||||
"mroot",
|
||||
"mrow",
|
||||
"ms",
|
||||
"mscarries",
|
||||
"mscarry",
|
||||
"msgroup",
|
||||
"msline",
|
||||
"mspace",
|
||||
"msqrt",
|
||||
"msrow",
|
||||
"mstack",
|
||||
"mstyle",
|
||||
"msub",
|
||||
"msup",
|
||||
"msubsup",
|
||||
"mtable",
|
||||
"mtd",
|
||||
"mtext",
|
||||
"mtr",
|
||||
"munder",
|
||||
"munderover"
|
||||
);
|
||||
|
||||
public $svgElements = array(
|
||||
"a",
|
||||
"altGlyph",
|
||||
"altGlyphDef",
|
||||
"altGlyphItem",
|
||||
"animate",
|
||||
"animateColor",
|
||||
"animateMotion",
|
||||
"animateTransform",
|
||||
"circle",
|
||||
"clipPath",
|
||||
"color-profile",
|
||||
"cursor",
|
||||
"defs",
|
||||
"desc",
|
||||
"ellipse",
|
||||
"feBlend",
|
||||
"feColorMatrix",
|
||||
"feComponentTransfer",
|
||||
"feComposite",
|
||||
"feConvolveMatrix",
|
||||
"feDiffuseLighting",
|
||||
"feDisplacementMap",
|
||||
"feDistantLight",
|
||||
"feFlood",
|
||||
"feFuncA",
|
||||
"feFuncB",
|
||||
"feFuncG",
|
||||
"feFuncR",
|
||||
"feGaussianBlur",
|
||||
"feImage",
|
||||
"feMerge",
|
||||
"feMergeNode",
|
||||
"feMorphology",
|
||||
"feOffset",
|
||||
"fePointLight",
|
||||
"feSpecularLighting",
|
||||
"feSpotLight",
|
||||
"feTile",
|
||||
"feTurbulence",
|
||||
"filter",
|
||||
"font",
|
||||
"font-face",
|
||||
"font-face-format",
|
||||
"font-face-name",
|
||||
"font-face-src",
|
||||
"font-face-uri",
|
||||
"foreignObject",
|
||||
"g",
|
||||
"glyph",
|
||||
"glyphRef",
|
||||
"hkern",
|
||||
"image",
|
||||
"line",
|
||||
"linearGradient",
|
||||
"marker",
|
||||
"mask",
|
||||
"metadata",
|
||||
"missing-glyph",
|
||||
"mpath",
|
||||
"path",
|
||||
"pattern",
|
||||
"polygon",
|
||||
"polyline",
|
||||
"radialGradient",
|
||||
"rect",
|
||||
"script",
|
||||
"set",
|
||||
"stop",
|
||||
"style",
|
||||
"svg",
|
||||
"switch",
|
||||
"symbol",
|
||||
"text",
|
||||
"textPath",
|
||||
"title",
|
||||
"tref",
|
||||
"tspan",
|
||||
"use",
|
||||
"view",
|
||||
"vkern"
|
||||
);
|
||||
|
||||
public function testIsHtml5Element()
|
||||
{
|
||||
foreach ($this->html5Elements as $element) {
|
||||
$this->assertTrue(Elements::isHtml5Element($element), 'html5 element test failed on: ' . $element);
|
||||
|
||||
$this->assertTrue(Elements::isHtml5Element(strtoupper($element)), 'html5 element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
|
||||
$nonhtml5 = array(
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
);
|
||||
foreach ($nonhtml5 as $element) {
|
||||
$this->assertFalse(Elements::isHtml5Element($element), 'html5 element test failed on: ' . $element);
|
||||
|
||||
$this->assertFalse(Elements::isHtml5Element(strtoupper($element)), 'html5 element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
}
|
||||
|
||||
public function testIsMathMLElement()
|
||||
{
|
||||
foreach ($this->mathmlElements as $element) {
|
||||
$this->assertTrue(Elements::isMathMLElement($element), 'MathML element test failed on: ' . $element);
|
||||
|
||||
// MathML is case sensetitive so these should all fail.
|
||||
$this->assertFalse(Elements::isMathMLElement(strtoupper($element)), 'MathML element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
|
||||
$nonMathML = array(
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
);
|
||||
foreach ($nonMathML as $element) {
|
||||
$this->assertFalse(Elements::isMathMLElement($element), 'MathML element test failed on: ' . $element);
|
||||
}
|
||||
}
|
||||
|
||||
public function testIsSvgElement()
|
||||
{
|
||||
foreach ($this->svgElements as $element) {
|
||||
$this->assertTrue(Elements::isSvgElement($element), 'SVG element test failed on: ' . $element);
|
||||
|
||||
// SVG is case sensetitive so these should all fail.
|
||||
$this->assertFalse(Elements::isSvgElement(strtoupper($element)), 'SVG element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
|
||||
$nonSVG = array(
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
);
|
||||
foreach ($nonSVG as $element) {
|
||||
$this->assertFalse(Elements::isSvgElement($element), 'SVG element test failed on: ' . $element);
|
||||
}
|
||||
}
|
||||
|
||||
public function testIsElement()
|
||||
{
|
||||
foreach ($this->html5Elements as $element) {
|
||||
$this->assertTrue(Elements::isElement($element), 'html5 element test failed on: ' . $element);
|
||||
|
||||
$this->assertTrue(Elements::isElement(strtoupper($element)), 'html5 element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
|
||||
foreach ($this->mathmlElements as $element) {
|
||||
$this->assertTrue(Elements::isElement($element), 'MathML element test failed on: ' . $element);
|
||||
|
||||
// MathML is case sensetitive so these should all fail.
|
||||
$this->assertFalse(Elements::isElement(strtoupper($element)), 'MathML element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
|
||||
foreach ($this->svgElements as $element) {
|
||||
$this->assertTrue(Elements::isElement($element), 'SVG element test failed on: ' . $element);
|
||||
|
||||
// SVG is case sensetitive so these should all fail. But, there is duplication
|
||||
// html5 and SVG. Since html5 is case insensetitive we need to make sure
|
||||
// it's not a html5 element first.
|
||||
if (! in_array($element, $this->html5Elements)) {
|
||||
$this->assertFalse(Elements::isElement(strtoupper($element)), 'SVG element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
}
|
||||
|
||||
$nonhtml5 = array(
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
);
|
||||
foreach ($nonhtml5 as $element) {
|
||||
$this->assertFalse(Elements::isElement($element), 'html5 element test failed on: ' . $element);
|
||||
|
||||
$this->assertFalse(Elements::isElement(strtoupper($element)), 'html5 element test failed on: ' . strtoupper($element));
|
||||
}
|
||||
}
|
||||
|
||||
public function testElement()
|
||||
{
|
||||
foreach ($this->html5Elements as $element) {
|
||||
$this->assertGreaterThan(0, Elements::element($element));
|
||||
}
|
||||
$nonhtml5 = array(
|
||||
'foo',
|
||||
'bar',
|
||||
'baz'
|
||||
);
|
||||
foreach ($nonhtml5 as $element) {
|
||||
$this->assertFalse(Elements::element($element));
|
||||
}
|
||||
}
|
||||
|
||||
public function testIsA()
|
||||
{
|
||||
$this->assertTrue(Elements::isA('script', Elements::KNOWN_ELEMENT));
|
||||
$this->assertFalse(Elements::isA('scriptypoo', Elements::KNOWN_ELEMENT));
|
||||
$this->assertTrue(Elements::isA('script', Elements::TEXT_RAW));
|
||||
$this->assertFalse(Elements::isA('script', Elements::TEXT_RCDATA));
|
||||
|
||||
$voidElements = array(
|
||||
'area',
|
||||
'base',
|
||||
'basefont',
|
||||
'bgsound',
|
||||
'br',
|
||||
'col',
|
||||
'command',
|
||||
'embed',
|
||||
'frame',
|
||||
'hr',
|
||||
'img'
|
||||
);
|
||||
|
||||
foreach ($voidElements as $element) {
|
||||
$this->assertTrue(Elements::isA($element, Elements::VOID_TAG), 'Void element test failed on: ' . $element);
|
||||
}
|
||||
|
||||
$nonVoid = array(
|
||||
'span',
|
||||
'a',
|
||||
'div'
|
||||
);
|
||||
foreach ($nonVoid as $tag) {
|
||||
$this->assertFalse(Elements::isA($tag, Elements::VOID_TAG), 'Void element test failed on: ' . $tag);
|
||||
}
|
||||
|
||||
$blockTags = array(
|
||||
'address',
|
||||
'article',
|
||||
'aside',
|
||||
'audio',
|
||||
'blockquote',
|
||||
'canvas',
|
||||
'dd',
|
||||
'div',
|
||||
'dl',
|
||||
'fieldset',
|
||||
'figcaption',
|
||||
'figure',
|
||||
'footer',
|
||||
'form',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'header',
|
||||
'hgroup',
|
||||
'hr',
|
||||
'noscript',
|
||||
'ol',
|
||||
'output',
|
||||
'p',
|
||||
'pre',
|
||||
'section',
|
||||
'table',
|
||||
'tfoot',
|
||||
'ul',
|
||||
'video'
|
||||
);
|
||||
|
||||
foreach ($blockTags as $tag) {
|
||||
$this->assertTrue(Elements::isA($tag, Elements::BLOCK_TAG), 'Block tag test failed on: ' . $tag);
|
||||
}
|
||||
|
||||
$nonBlockTags = array(
|
||||
'span',
|
||||
'img',
|
||||
'label'
|
||||
);
|
||||
foreach ($nonBlockTags as $tag) {
|
||||
$this->assertFalse(Elements::isA($tag, Elements::BLOCK_TAG), 'Block tag test failed on: ' . $tag);
|
||||
}
|
||||
}
|
||||
|
||||
public function testNormalizeSvgElement()
|
||||
{
|
||||
$tests = array(
|
||||
'foo' => 'foo',
|
||||
'altglyph' => 'altGlyph',
|
||||
'BAR' => 'bar',
|
||||
'fespecularlighting' => 'feSpecularLighting',
|
||||
'bAz' => 'baz',
|
||||
'foreignobject' => 'foreignObject'
|
||||
);
|
||||
|
||||
foreach ($tests as $input => $expected) {
|
||||
$this->assertEquals($expected, Elements::normalizeSvgElement($input));
|
||||
}
|
||||
}
|
||||
|
||||
public function testNormalizeSvgAttribute()
|
||||
{
|
||||
$tests = array(
|
||||
'foo' => 'foo',
|
||||
'attributename' => 'attributeName',
|
||||
'BAR' => 'bar',
|
||||
'limitingconeangle' => 'limitingConeAngle',
|
||||
'bAz' => 'baz',
|
||||
'patterncontentunits' => 'patternContentUnits'
|
||||
);
|
||||
|
||||
foreach ($tests as $input => $expected) {
|
||||
$this->assertEquals($expected, Elements::normalizeSvgAttribute($input));
|
||||
}
|
||||
}
|
||||
|
||||
public function testNormalizeMathMlAttribute()
|
||||
{
|
||||
$tests = array(
|
||||
'foo' => 'foo',
|
||||
'definitionurl' => 'definitionURL',
|
||||
'BAR' => 'bar'
|
||||
);
|
||||
|
||||
foreach ($tests as $input => $expected) {
|
||||
$this->assertEquals($expected, Elements::normalizeMathMlAttribute($input));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is a test.</p>
|
||||
</body>
|
||||
</html>
|
401
vendor/masterminds/html5/test/HTML5/Html5Test.php
vendored
401
vendor/masterminds/html5/test/HTML5/Html5Test.php
vendored
|
@ -1,401 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests;
|
||||
|
||||
class Html5Test extends TestCase
|
||||
{
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->html5 = $this->getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and serialize a string.
|
||||
*/
|
||||
protected function cycle($html)
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!DOCTYPE html><html><body>' . $html . '</body></html>');
|
||||
$out = $this->html5->saveHTML($dom);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
protected function cycleFragment($fragment)
|
||||
{
|
||||
$dom = $this->html5->loadHTMLFragment($fragment);
|
||||
$out = $this->html5->saveHTML($dom);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function testLoadOptions()
|
||||
{
|
||||
// doc
|
||||
$dom = $this->html5->loadHTML($this->wrap('<t:tag/>'), array(
|
||||
'implicitNamespaces' => array('t' => 'http://example.com'),
|
||||
"xmlNamespaces" => true
|
||||
));
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
$this->assertFalse($this->html5->hasErrors());
|
||||
|
||||
$xpath = new \DOMXPath( $dom );
|
||||
$xpath->registerNamespace( "t", "http://example.com" );
|
||||
$this->assertEquals(1, $xpath->query( "//t:tag" )->length);
|
||||
|
||||
// doc fragment
|
||||
$frag = $this->html5->loadHTMLFragment('<t:tag/>', array(
|
||||
'implicitNamespaces' => array('t' => 'http://example.com'),
|
||||
"xmlNamespaces" => true
|
||||
));
|
||||
$this->assertInstanceOf('\DOMDocumentFragment', $frag);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
$this->assertFalse($this->html5->hasErrors());
|
||||
|
||||
$frag->ownerDocument->appendChild($frag);
|
||||
$xpath = new \DOMXPath( $frag->ownerDocument );
|
||||
$xpath->registerNamespace( "t", "http://example.com" );
|
||||
$this->assertEquals(1, $xpath->query( "//t:tag" , $frag)->length);
|
||||
}
|
||||
|
||||
public function testErrors()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<xx as>');
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
|
||||
$this->assertNotEmpty($this->html5->getErrors());
|
||||
$this->assertTrue($this->html5->hasErrors());
|
||||
}
|
||||
|
||||
public function testLoad()
|
||||
{
|
||||
$dom = $this->html5->load(__DIR__ . '/Html5Test.html');
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
$this->assertFalse($this->html5->hasErrors());
|
||||
|
||||
$file = fopen(__DIR__ . '/Html5Test.html', 'r');
|
||||
$dom = $this->html5->load($file);
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
|
||||
$dom = $this->html5->loadHTMLFile(__DIR__ . '/Html5Test.html');
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
}
|
||||
|
||||
public function testLoadHTML()
|
||||
{
|
||||
$contents = file_get_contents(__DIR__ . '/Html5Test.html');
|
||||
$dom = $this->html5->loadHTML($contents);
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
}
|
||||
|
||||
public function testLoadHTMLFragment()
|
||||
{
|
||||
$fragment = '<section id="Foo"><div class="Bar">Baz</div></section>';
|
||||
$dom = $this->html5->loadHTMLFragment($fragment);
|
||||
$this->assertInstanceOf('\DOMDocumentFragment', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
}
|
||||
|
||||
public function testSaveHTML()
|
||||
{
|
||||
$dom = $this->html5->load(__DIR__ . '/Html5Test.html');
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
|
||||
$saved = $this->html5->saveHTML($dom);
|
||||
$this->assertRegExp('|<p>This is a test.</p>|', $saved);
|
||||
}
|
||||
|
||||
public function testSaveHTMLFragment()
|
||||
{
|
||||
$fragment = '<section id="Foo"><div class="Bar">Baz</div></section>';
|
||||
$dom = $this->html5->loadHTMLFragment($fragment);
|
||||
|
||||
$string = $this->html5->saveHTML($dom);
|
||||
$this->assertEquals($fragment, $string);
|
||||
}
|
||||
|
||||
public function testSave()
|
||||
{
|
||||
$dom = $this->html5->load(__DIR__ . '/Html5Test.html');
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
|
||||
// Test resource
|
||||
$file = fopen('php://temp', 'w');
|
||||
$this->html5->save($dom, $file);
|
||||
$content = stream_get_contents($file, - 1, 0);
|
||||
$this->assertRegExp('|<p>This is a test.</p>|', $content);
|
||||
|
||||
// Test file
|
||||
$tmpfname = tempnam(sys_get_temp_dir(), "html5-php");
|
||||
$this->html5->save($dom, $tmpfname);
|
||||
$content = file_get_contents($tmpfname);
|
||||
$this->assertRegExp('|<p>This is a test.</p>|', $content);
|
||||
unlink($tmpfname);
|
||||
}
|
||||
|
||||
// This test reads a document into a dom, turn the dom into a document,
|
||||
// then tries to read that document again. This makes sure we are reading,
|
||||
// and generating a document that works at a high level.
|
||||
public function testItWorks()
|
||||
{
|
||||
$dom = $this->html5->load(__DIR__ . '/Html5Test.html');
|
||||
$this->assertInstanceOf('\DOMDocument', $dom);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
|
||||
$saved = $this->html5->saveHTML($dom);
|
||||
|
||||
$dom2 = $this->html5->loadHTML($saved);
|
||||
$this->assertInstanceOf('\DOMDocument', $dom2);
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
}
|
||||
|
||||
public function testConfig()
|
||||
{
|
||||
$html5 = $this->getInstance();
|
||||
$options = $html5->getOptions();
|
||||
$this->assertEquals(false, $options['encode_entities']);
|
||||
|
||||
$html5 = $this->getInstance(array(
|
||||
'foo' => 'bar',
|
||||
'encode_entities' => true
|
||||
));
|
||||
$options = $html5->getOptions();
|
||||
$this->assertEquals('bar', $options['foo']);
|
||||
$this->assertEquals(true, $options['encode_entities']);
|
||||
|
||||
// Need to reset to original so future tests pass as expected.
|
||||
// $this->getInstance()->setOption('encode_entities', false);
|
||||
}
|
||||
|
||||
public function testSvg()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
<svg width="150" height="100" viewBox="0 0 3 2">
|
||||
<rect width="1" height="2" x="0" fill="#008d46" />
|
||||
<rect width="1" height="2" x="1" fill="#ffffff" />
|
||||
<rect width="1" height="2" x="2" fill="#d2232c" />
|
||||
<text font-family="Verdana" font-size="32">
|
||||
<textPath xlink:href="#Foo">
|
||||
Test Text.
|
||||
</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
|
||||
// Test a mixed case attribute.
|
||||
$list = $dom->getElementsByTagName('svg');
|
||||
$this->assertNotEmpty($list->length);
|
||||
$svg = $list->item(0);
|
||||
$this->assertEquals("0 0 3 2", $svg->getAttribute('viewBox'));
|
||||
$this->assertFalse($svg->hasAttribute('viewbox'));
|
||||
|
||||
// Test a mixed case tag.
|
||||
// Note: getElementsByTagName is not case sensetitive.
|
||||
$list = $dom->getElementsByTagName('textPath');
|
||||
$this->assertNotEmpty($list->length);
|
||||
$textPath = $list->item(0);
|
||||
$this->assertEquals('textPath', $textPath->tagName);
|
||||
$this->assertNotEquals('textpath', $textPath->tagName);
|
||||
|
||||
$html = $this->html5->saveHTML($dom);
|
||||
$this->assertRegExp('|<svg width="150" height="100" viewBox="0 0 3 2">|', $html);
|
||||
$this->assertRegExp('|<rect width="1" height="2" x="0" fill="#008d46" />|', $html);
|
||||
}
|
||||
|
||||
public function testMathMl()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz" definitionURL="http://example.com">foo bar baz</div>
|
||||
<math>
|
||||
<mi>x</mi>
|
||||
<csymbol definitionURL="http://www.example.com/mathops/multiops.html#plusminus">
|
||||
<mo>±</mo>
|
||||
</csymbol>
|
||||
<mi>y</mi>
|
||||
</math>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
$list = $dom->getElementsByTagName('math');
|
||||
$this->assertNotEmpty($list->length);
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$this->assertNotEmpty($list->length);
|
||||
$div = $list->item(0);
|
||||
$this->assertEquals('http://example.com', $div->getAttribute('definitionurl'));
|
||||
$this->assertFalse($div->hasAttribute('definitionURL'));
|
||||
$list = $dom->getElementsByTagName('csymbol');
|
||||
$csymbol = $list->item(0);
|
||||
$this->assertEquals('http://www.example.com/mathops/multiops.html#plusminus', $csymbol->getAttribute('definitionURL'));
|
||||
$this->assertFalse($csymbol->hasAttribute('definitionurl'));
|
||||
|
||||
$html = $this->html5->saveHTML($dom);
|
||||
$this->assertRegExp('|<csymbol definitionURL="http://www.example.com/mathops/multiops.html#plusminus">|', $html);
|
||||
$this->assertRegExp('|<mi>y</mi>|', $html);
|
||||
}
|
||||
|
||||
public function testUnknownElements()
|
||||
{
|
||||
// The : should not have special handling accourding to section 2.9 of the
|
||||
// spec. This is differenant than XML. Since we don't know these elements
|
||||
// they are handled as normal elements. Note, to do this is really
|
||||
// an invalid example and you should not embed prefixed xml in html5.
|
||||
$dom = $this->html5->loadHTMLFragment(
|
||||
"<f:rug>
|
||||
<f:name>Big rectangle thing</f:name>
|
||||
<f:width>40</f:width>
|
||||
<f:length>80</f:length>
|
||||
</f:rug>
|
||||
<sarcasm>um, yeah</sarcasm>");
|
||||
|
||||
$this->assertEmpty($this->html5->getErrors());
|
||||
$markup = $this->html5->saveHTML($dom);
|
||||
$this->assertRegExp('|<f:name>Big rectangle thing</f:name>|', $markup);
|
||||
$this->assertRegExp('|<sarcasm>um, yeah</sarcasm>|', $markup);
|
||||
}
|
||||
|
||||
public function testElements()
|
||||
{
|
||||
// Should have content.
|
||||
$res = $this->cycle('<div>FOO</div>');
|
||||
$this->assertRegExp('|<div>FOO</div>|', $res);
|
||||
|
||||
// Should be empty
|
||||
$res = $this->cycle('<span></span>');
|
||||
$this->assertRegExp('|<span></span>|', $res);
|
||||
|
||||
// Should have content.
|
||||
$res = $this->cycleFragment('<div>FOO</div>');
|
||||
$this->assertRegExp('|<div>FOO</div>|', $res);
|
||||
|
||||
// Should be empty
|
||||
$res = $this->cycleFragment('<span></span>');
|
||||
$this->assertRegExp('|<span></span>|', $res);
|
||||
|
||||
// Elements with dashes and underscores
|
||||
$res = $this->cycleFragment('<sp-an></sp-an>');
|
||||
$this->assertRegExp('|<sp-an></sp-an>|', $res);
|
||||
$res = $this->cycleFragment('<sp_an></sp_an>');
|
||||
$this->assertRegExp('|<sp_an></sp_an>|', $res);
|
||||
|
||||
// Should have no closing tag.
|
||||
$res = $this->cycle('<hr>');
|
||||
$this->assertRegExp('|<hr></body>|', $res);
|
||||
}
|
||||
|
||||
public function testAttributes()
|
||||
{
|
||||
$res = $this->cycle('<div attr="val">FOO</div>');
|
||||
$this->assertRegExp('|<div attr="val">FOO</div>|', $res);
|
||||
|
||||
// XXX: Note that spec does NOT require attrs in the same order.
|
||||
$res = $this->cycle('<div attr="val" class="even">FOO</div>');
|
||||
$this->assertRegExp('|<div attr="val" class="even">FOO</div>|', $res);
|
||||
|
||||
$res = $this->cycle('<div xmlns:foo="http://example.com">FOO</div>');
|
||||
$this->assertRegExp('|<div xmlns:foo="http://example.com">FOO</div>|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<div attr="val">FOO</div>');
|
||||
$this->assertRegExp('|<div attr="val">FOO</div>|', $res);
|
||||
|
||||
// XXX: Note that spec does NOT require attrs in the same order.
|
||||
$res = $this->cycleFragment('<div attr="val" class="even">FOO</div>');
|
||||
$this->assertRegExp('|<div attr="val" class="even">FOO</div>|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<div xmlns:foo="http://example.com">FOO</div>');
|
||||
$this->assertRegExp('|<div xmlns:foo="http://example.com">FOO</div>|', $res);
|
||||
}
|
||||
|
||||
public function testPCData()
|
||||
{
|
||||
$res = $this->cycle('<a>This is a test.</a>');
|
||||
$this->assertRegExp('|This is a test.|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<a>This is a test.</a>');
|
||||
$this->assertRegExp('|This is a test.|', $res);
|
||||
|
||||
$res = $this->cycle('This
|
||||
is
|
||||
a
|
||||
test.');
|
||||
|
||||
// Check that newlines are there, but don't count spaces.
|
||||
$this->assertRegExp('|This\n\s*is\n\s*a\n\s*test.|', $res);
|
||||
|
||||
$res = $this->cycleFragment('This
|
||||
is
|
||||
a
|
||||
test.');
|
||||
|
||||
// Check that newlines are there, but don't count spaces.
|
||||
$this->assertRegExp('|This\n\s*is\n\s*a\n\s*test.|', $res);
|
||||
|
||||
$res = $this->cycle('<a>This <em>is</em> a test.</a>');
|
||||
$this->assertRegExp('|This <em>is</em> a test.|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<a>This <em>is</em> a test.</a>');
|
||||
$this->assertRegExp('|This <em>is</em> a test.|', $res);
|
||||
}
|
||||
|
||||
public function testUnescaped()
|
||||
{
|
||||
$res = $this->cycle('<script>2 < 1</script>');
|
||||
$this->assertRegExp('|2 < 1|', $res);
|
||||
|
||||
$res = $this->cycle('<style>div>div>div</style>');
|
||||
$this->assertRegExp('|div>div>div|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<script>2 < 1</script>');
|
||||
$this->assertRegExp('|2 < 1|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<style>div>div>div</style>');
|
||||
$this->assertRegExp('|div>div>div|', $res);
|
||||
}
|
||||
|
||||
public function testEntities()
|
||||
{
|
||||
$res = $this->cycle('<a>Apples & bananas.</a>');
|
||||
$this->assertRegExp('|Apples & bananas.|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<a>Apples & bananas.</a>');
|
||||
$this->assertRegExp('|Apples & bananas.|', $res);
|
||||
|
||||
$res = $this->cycleFragment('<p>R&D</p>');
|
||||
$this->assertRegExp('|R&D|', $res);
|
||||
}
|
||||
|
||||
public function testComment()
|
||||
{
|
||||
$res = $this->cycle('a<!-- This is a test. -->b');
|
||||
$this->assertRegExp('|<!-- This is a test. -->|', $res);
|
||||
|
||||
$res = $this->cycleFragment('a<!-- This is a test. -->b');
|
||||
$this->assertRegExp('|<!-- This is a test. -->|', $res);
|
||||
}
|
||||
|
||||
public function testCDATA()
|
||||
{
|
||||
$res = $this->cycle('a<![CDATA[ This <is> a test. ]]>b');
|
||||
$this->assertRegExp('|<!\[CDATA\[ This <is> a test\. \]\]>|', $res);
|
||||
|
||||
$res = $this->cycleFragment('a<![CDATA[ This <is> a test. ]]>b');
|
||||
$this->assertRegExp('|<!\[CDATA\[ This <is> a test\. \]\]>|', $res);
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test the Scanner. This requires the InputStream tests are all good.
|
||||
*/
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\CharacterReference;
|
||||
|
||||
class CharacterReferenceTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
public function testLookupName()
|
||||
{
|
||||
$this->assertEquals('&', CharacterReference::lookupName('amp'));
|
||||
$this->assertEquals('<', CharacterReference::lookupName('lt'));
|
||||
$this->assertEquals('>', CharacterReference::lookupName('gt'));
|
||||
$this->assertEquals('"', CharacterReference::lookupName('quot'));
|
||||
$this->assertEquals('∌', CharacterReference::lookupName('NotReverseElement'));
|
||||
|
||||
$this->assertNull(CharacterReference::lookupName('StinkyCheese'));
|
||||
}
|
||||
|
||||
public function testLookupHex()
|
||||
{
|
||||
$this->assertEquals('<', CharacterReference::lookupHex('3c'));
|
||||
$this->assertEquals('<', CharacterReference::lookupHex('003c'));
|
||||
$this->assertEquals('&', CharacterReference::lookupHex('26'));
|
||||
$this->assertEquals('}', CharacterReference::lookupHex('7d'));
|
||||
$this->assertEquals('Σ', CharacterReference::lookupHex('3A3'));
|
||||
$this->assertEquals('Σ', CharacterReference::lookupHex('03A3'));
|
||||
$this->assertEquals('Σ', CharacterReference::lookupHex('3a3'));
|
||||
$this->assertEquals('Σ', CharacterReference::lookupHex('03a3'));
|
||||
}
|
||||
|
||||
public function testLookupDecimal()
|
||||
{
|
||||
$this->assertEquals('&', CharacterReference::lookupDecimal(38));
|
||||
$this->assertEquals('&', CharacterReference::lookupDecimal('38'));
|
||||
$this->assertEquals('<', CharacterReference::lookupDecimal(60));
|
||||
$this->assertEquals('Σ', CharacterReference::lookupDecimal(931));
|
||||
$this->assertEquals('Σ', CharacterReference::lookupDecimal('0931'));
|
||||
}
|
||||
}
|
|
@ -1,537 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test the Tree Builder.
|
||||
*/
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\StringInputStream;
|
||||
use Masterminds\HTML5\Parser\Scanner;
|
||||
use Masterminds\HTML5\Parser\Tokenizer;
|
||||
use Masterminds\HTML5\Parser\DOMTreeBuilder;
|
||||
|
||||
/**
|
||||
* These tests are functional, not necessarily unit tests.
|
||||
*/
|
||||
class DOMTreeBuilderTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
protected $errors = array();
|
||||
/**
|
||||
* Convenience function for parsing.
|
||||
*/
|
||||
protected function parse($string, array $options = array())
|
||||
{
|
||||
$treeBuilder = new DOMTreeBuilder(false, $options);
|
||||
$input = new StringInputStream($string);
|
||||
$scanner = new Scanner($input);
|
||||
$parser = new Tokenizer($scanner, $treeBuilder);
|
||||
|
||||
$parser->parse();
|
||||
$this->errors = $treeBuilder->getErrors();
|
||||
|
||||
return $treeBuilder->document();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for parsing a fragment of HTML5.
|
||||
*/
|
||||
protected function parseFragment($string)
|
||||
{
|
||||
$treeBuilder = new DOMTreeBuilder(true);
|
||||
$input = new StringInputStream($string);
|
||||
$scanner = new Scanner($input);
|
||||
$parser = new Tokenizer($scanner, $treeBuilder);
|
||||
|
||||
$parser->parse();
|
||||
$this->errors = $treeBuilder->getErrors();
|
||||
|
||||
return $treeBuilder->fragment();
|
||||
}
|
||||
|
||||
public function testDocument()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html></html>";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$this->assertInstanceOf('\DOMDocument', $doc);
|
||||
$this->assertEquals('html', $doc->documentElement->tagName);
|
||||
$this->assertEquals('http://www.w3.org/1999/xhtml', $doc->documentElement->namespaceURI);
|
||||
}
|
||||
|
||||
public function testStrangeCapitalization()
|
||||
{
|
||||
$html = "<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<Title>Hello, world!</TitlE>
|
||||
</head>
|
||||
<body>TheBody<script>foo</script></body>
|
||||
</html>";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$this->assertInstanceOf('\DOMDocument', $doc);
|
||||
$this->assertEquals('html', $doc->documentElement->tagName);
|
||||
|
||||
$xpath = new \DOMXPath( $doc );
|
||||
$xpath->registerNamespace( "x", "http://www.w3.org/1999/xhtml" );
|
||||
|
||||
$this->assertEquals("Hello, world!", $xpath->query( "//x:title" )->item( 0 )->nodeValue);
|
||||
$this->assertEquals("foo", $xpath->query( "//x:script" )->item( 0 )->nodeValue);
|
||||
}
|
||||
|
||||
public function testDocumentWithDisabledNamespaces()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html></html>";
|
||||
$doc = $this->parse($html, array('disable_html_ns' => true));
|
||||
|
||||
$this->assertInstanceOf('\DOMDocument', $doc);
|
||||
$this->assertEquals('html', $doc->documentElement->tagName);
|
||||
$this->assertNull($doc->documentElement->namespaceURI);
|
||||
}
|
||||
|
||||
public function testDocumentWithATargetDocument()
|
||||
{
|
||||
$targetDom = new \DOMDocument();
|
||||
|
||||
$html = "<!DOCTYPE html><html></html>";
|
||||
$doc = $this->parse($html, array('target_document' => $targetDom));
|
||||
|
||||
$this->assertInstanceOf('\DOMDocument', $doc);
|
||||
$this->assertSame($doc, $targetDom);
|
||||
$this->assertEquals('html', $doc->documentElement->tagName);
|
||||
}
|
||||
|
||||
public function testDocumentFakeAttrAbsence()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><body>foo</body></html>";
|
||||
$doc = $this->parse($html, array('xmlNamespaces'=>true));
|
||||
|
||||
$xp = new \DOMXPath($doc);
|
||||
$this->assertEquals(0, $xp->query("//@html5-php-fake-id-attribute")->length);
|
||||
}
|
||||
|
||||
public function testFragment()
|
||||
{
|
||||
$html = "<div>test</div><span>test2</span>";
|
||||
$doc = $this->parseFragment($html);
|
||||
|
||||
$this->assertInstanceOf('\DOMDocumentFragment', $doc);
|
||||
$this->assertTrue($doc->hasChildNodes());
|
||||
$this->assertEquals('div', $doc->childNodes->item(0)->tagName);
|
||||
$this->assertEquals('test', $doc->childNodes->item(0)->textContent);
|
||||
$this->assertEquals('span', $doc->childNodes->item(1)->tagName);
|
||||
$this->assertEquals('test2', $doc->childNodes->item(1)->textContent);
|
||||
}
|
||||
|
||||
public function testElements()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html><head><title></title></head><body></body></html>";
|
||||
$doc = $this->parse($html);
|
||||
$root = $doc->documentElement;
|
||||
|
||||
$this->assertEquals('html', $root->tagName);
|
||||
$this->assertEquals('html', $root->localName);
|
||||
$this->assertEquals('html', $root->nodeName);
|
||||
|
||||
$this->assertEquals(2, $root->childNodes->length);
|
||||
$kids = $root->childNodes;
|
||||
|
||||
$this->assertEquals('head', $kids->item(0)->tagName);
|
||||
$this->assertEquals('body', $kids->item(1)->tagName);
|
||||
|
||||
$head = $kids->item(0);
|
||||
$this->assertEquals(1, $head->childNodes->length);
|
||||
$this->assertEquals('title', $head->childNodes->item(0)->tagName);
|
||||
}
|
||||
|
||||
public function testImplicitNamespaces()
|
||||
{
|
||||
$dom = $this->parse('<!DOCTYPE html><html><body><a xlink:href="bar">foo</a></body></html>');
|
||||
$a = $dom->getElementsByTagName('a')->item(0);
|
||||
$attr = $a->getAttributeNode('xlink:href');
|
||||
$this->assertEquals('http://www.w3.org/1999/xlink', $attr->namespaceURI);
|
||||
|
||||
$dom = $this->parse('<!DOCTYPE html><html><body><a xml:base="bar">foo</a></body></html>');
|
||||
$a = $dom->getElementsByTagName('a')->item(0);
|
||||
$attr = $a->getAttributeNode('xml:base');
|
||||
$this->assertEquals('http://www.w3.org/XML/1998/namespace', $attr->namespaceURI);
|
||||
}
|
||||
|
||||
public function testCustomImplicitNamespaces()
|
||||
{
|
||||
$dom = $this->parse('<!DOCTYPE html><html><body><a t:href="bar">foo</a></body></html>', array(
|
||||
'implicitNamespaces' => array(
|
||||
't' => 'http://www.example.com'
|
||||
)
|
||||
));
|
||||
$a = $dom->getElementsByTagName('a')->item(0);
|
||||
$attr = $a->getAttributeNode('t:href');
|
||||
$this->assertEquals('http://www.example.com', $attr->namespaceURI);
|
||||
|
||||
$dom = $this->parse('<!DOCTYPE html><html><body><t:a>foo</t:a></body></html>', array(
|
||||
'implicitNamespaces' => array(
|
||||
't' => 'http://www.example.com'
|
||||
)
|
||||
));
|
||||
$list = $dom->getElementsByTagNameNS('http://www.example.com', 'a');
|
||||
$this->assertEquals(1, $list->length);
|
||||
}
|
||||
|
||||
public function testXmlNamespaces()
|
||||
{
|
||||
$dom = $this->parse(
|
||||
'<!DOCTYPE html><html>
|
||||
<t:body xmlns:t="http://www.example.com">
|
||||
<a t:href="bar">foo</a>
|
||||
</body>
|
||||
<div>foo</div>
|
||||
</html>', array(
|
||||
'xmlNamespaces' => true
|
||||
));
|
||||
$a = $dom->getElementsByTagName('a')->item(0);
|
||||
$attr = $a->getAttributeNode('t:href');
|
||||
$this->assertEquals('http://www.example.com', $attr->namespaceURI);
|
||||
|
||||
$list = $dom->getElementsByTagNameNS('http://www.example.com', 'body');
|
||||
$this->assertEquals(1, $list->length);
|
||||
}
|
||||
|
||||
public function testXmlNamespaceNesting()
|
||||
{
|
||||
$dom = $this->parse(
|
||||
'<!DOCTYPE html><html>
|
||||
<body xmlns:x="http://www.prefixed.com" id="body">
|
||||
<a id="bar1" xmlns="http://www.prefixed.com/bar1">
|
||||
<b id="bar4" xmlns="http://www.prefixed.com/bar4"><x:prefixed id="prefixed"/></b>
|
||||
</a>
|
||||
<svg id="svg"></svg>
|
||||
<c id="bar2" xmlns="http://www.prefixed.com/bar2"></c>
|
||||
<div id="div"></div>
|
||||
<d id="bar3"></d>
|
||||
<xn:d xmlns:xn="http://www.prefixed.com/xn" xmlns="http://www.prefixed.com/bar5_x" id="bar5"><x id="bar5_x"/></xn:d>
|
||||
</body>
|
||||
</html>', array(
|
||||
'xmlNamespaces' => true
|
||||
));
|
||||
|
||||
|
||||
$this->assertEmpty($this->errors);
|
||||
|
||||
$div = $dom->getElementById('div');
|
||||
$this->assertEquals('http://www.w3.org/1999/xhtml', $div->namespaceURI);
|
||||
|
||||
$body = $dom->getElementById('body');
|
||||
$this->assertEquals('http://www.w3.org/1999/xhtml', $body->namespaceURI);
|
||||
|
||||
$bar1 = $dom->getElementById('bar1');
|
||||
$this->assertEquals('http://www.prefixed.com/bar1', $bar1->namespaceURI);
|
||||
|
||||
$bar2 = $dom->getElementById('bar2');
|
||||
$this->assertEquals("http://www.prefixed.com/bar2", $bar2->namespaceURI);
|
||||
|
||||
$bar3 = $dom->getElementById('bar3');
|
||||
$this->assertEquals("http://www.w3.org/1999/xhtml", $bar3->namespaceURI);
|
||||
|
||||
$bar4 = $dom->getElementById('bar4');
|
||||
$this->assertEquals("http://www.prefixed.com/bar4", $bar4->namespaceURI);
|
||||
|
||||
$svg = $dom->getElementById('svg');
|
||||
$this->assertEquals("http://www.w3.org/2000/svg", $svg->namespaceURI);
|
||||
|
||||
$prefixed = $dom->getElementById('prefixed');
|
||||
$this->assertEquals("http://www.prefixed.com", $prefixed->namespaceURI);
|
||||
|
||||
$prefixed = $dom->getElementById('bar5');
|
||||
$this->assertEquals("http://www.prefixed.com/xn", $prefixed->namespaceURI);
|
||||
|
||||
$prefixed = $dom->getElementById('bar5_x');
|
||||
$this->assertEquals("http://www.prefixed.com/bar5_x", $prefixed->namespaceURI);
|
||||
}
|
||||
|
||||
public function testMoveNonInlineElements()
|
||||
{
|
||||
$doc = $this->parse('<p>line1<br/><hr/>line2</p>');
|
||||
$this->assertEquals('<html xmlns="http://www.w3.org/1999/xhtml"><p>line1<br/></p><hr/>line2</html>', $doc->saveXML($doc->documentElement), 'Move non-inline elements outside of inline containers.');
|
||||
|
||||
$doc = $this->parse('<p>line1<div>line2</div></p>');
|
||||
$this->assertEquals('<html xmlns="http://www.w3.org/1999/xhtml"><p>line1</p><div>line2</div></html>', $doc->saveXML($doc->documentElement), 'Move non-inline elements outside of inline containers.');
|
||||
}
|
||||
|
||||
public function testAttributes()
|
||||
{
|
||||
$html = "<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title></title></head>
|
||||
<body id='a' class='b c'></body>
|
||||
</html>";
|
||||
$doc = $this->parse($html);
|
||||
$root = $doc->documentElement;
|
||||
|
||||
$body = $root->GetElementsByTagName('body')->item(0);
|
||||
$this->assertEquals('body', $body->tagName);
|
||||
$this->assertTrue($body->hasAttributes());
|
||||
$this->assertEquals('a', $body->getAttribute('id'));
|
||||
$this->assertEquals('b c', $body->getAttribute('class'));
|
||||
|
||||
$body2 = $doc->getElementById('a');
|
||||
$this->assertEquals('body', $body2->tagName);
|
||||
$this->assertEquals('a', $body2->getAttribute('id'));
|
||||
}
|
||||
|
||||
public function testSVGAttributes()
|
||||
{
|
||||
$html = "<!DOCTYPE html>
|
||||
<html><body>
|
||||
<svg width='150' viewbox='2'>
|
||||
<rect textlength='2'/>
|
||||
<animatecolor>foo</animatecolor>
|
||||
</svg>
|
||||
</body></html>";
|
||||
$doc = $this->parse($html);
|
||||
$root = $doc->documentElement;
|
||||
|
||||
$svg = $root->getElementsByTagName('svg')->item(0);
|
||||
$this->assertTrue($svg->hasAttribute('viewBox'));
|
||||
|
||||
$rect = $root->getElementsByTagName('rect')->item(0);
|
||||
$this->assertTrue($rect->hasAttribute('textLength'));
|
||||
|
||||
$ac = $root->getElementsByTagName('animateColor');
|
||||
$this->assertEquals(1, $ac->length);
|
||||
}
|
||||
|
||||
public function testMathMLAttribute()
|
||||
{
|
||||
$html = '<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<math>
|
||||
<mi>x</mi>
|
||||
<csymbol definitionurl="http://www.example.com/mathops/multiops.html#plusminus">
|
||||
<mo>±</mo>
|
||||
</csymbol>
|
||||
<mi>y</mi>
|
||||
</math>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$doc = $this->parse($html);
|
||||
$root = $doc->documentElement;
|
||||
|
||||
$csymbol = $root->getElementsByTagName('csymbol')->item(0);
|
||||
$this->assertTrue($csymbol->hasAttribute('definitionURL'));
|
||||
}
|
||||
|
||||
public function testMissingHtmlTag()
|
||||
{
|
||||
$html = "<!DOCTYPE html><title>test</title>";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$this->assertEquals('html', $doc->documentElement->tagName);
|
||||
$this->assertEquals('title', $doc->documentElement->childNodes->item(0)->tagName);
|
||||
}
|
||||
|
||||
public function testComment()
|
||||
{
|
||||
$html = '<html><!--Hello World.--></html>';
|
||||
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$comment = $doc->documentElement->childNodes->item(0);
|
||||
$this->assertEquals(XML_COMMENT_NODE, $comment->nodeType);
|
||||
$this->assertEquals("Hello World.", $comment->data);
|
||||
|
||||
$html = '<!--Hello World.--><html></html>';
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$comment = $doc->childNodes->item(1);
|
||||
$this->assertEquals(XML_COMMENT_NODE, $comment->nodeType);
|
||||
$this->assertEquals("Hello World.", $comment->data);
|
||||
|
||||
$comment = $doc->childNodes->item(2);
|
||||
$this->assertEquals(XML_ELEMENT_NODE, $comment->nodeType);
|
||||
$this->assertEquals("html", $comment->tagName);
|
||||
}
|
||||
|
||||
public function testCDATA()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html><math><![CDATA[test]]></math></html>";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$wrapper = $doc->getElementsByTagName('math')->item(0);
|
||||
$this->assertEquals(1, $wrapper->childNodes->length);
|
||||
$cdata = $wrapper->childNodes->item(0);
|
||||
$this->assertEquals(XML_CDATA_SECTION_NODE, $cdata->nodeType);
|
||||
$this->assertEquals('test', $cdata->data);
|
||||
}
|
||||
|
||||
public function testText()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html><head></head><body><math>test</math></body></html>";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$wrapper = $doc->getElementsByTagName('math')->item(0);
|
||||
$this->assertEquals(1, $wrapper->childNodes->length);
|
||||
$data = $wrapper->childNodes->item(0);
|
||||
$this->assertEquals(XML_TEXT_NODE, $data->nodeType);
|
||||
$this->assertEquals('test', $data->data);
|
||||
|
||||
// The DomTreeBuilder has special handling for text when in before head mode.
|
||||
$html = "<!DOCTYPE html><html>
|
||||
Foo<head></head><body></body></html>";
|
||||
$doc = $this->parse($html);
|
||||
$this->assertEquals('Line 0, Col 0: Unexpected text. Ignoring: Foo', $this->errors[0]);
|
||||
$headElement = $doc->documentElement->firstChild;
|
||||
$this->assertEquals('head', $headElement->tagName);
|
||||
}
|
||||
|
||||
public function testParseErrors()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html><math><![CDATA[test";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
// We're JUST testing that we can access errors. Actual testing of
|
||||
// error messages happen in the Tokenizer's tests.
|
||||
$this->assertGreaterThan(0, count($this->errors));
|
||||
$this->assertTrue(is_string($this->errors[0]));
|
||||
}
|
||||
|
||||
public function testProcessingInstruction()
|
||||
{
|
||||
// Test the simple case, which is where PIs are inserted into the DOM.
|
||||
$doc = $this->parse('<!DOCTYPE html><html><?foo bar?>');
|
||||
$this->assertEquals(1, $doc->documentElement->childNodes->length);
|
||||
$pi = $doc->documentElement->firstChild;
|
||||
$this->assertInstanceOf('\DOMProcessingInstruction', $pi);
|
||||
$this->assertEquals('foo', $pi->nodeName);
|
||||
$this->assertEquals('bar', $pi->data);
|
||||
|
||||
// Leading xml PIs should be ignored.
|
||||
$doc = $this->parse('<?xml version="1.0"?><!DOCTYPE html><html><head></head></html>');
|
||||
|
||||
$this->assertEquals(2, $doc->childNodes->length);
|
||||
$this->assertInstanceOf('\DOMDocumentType', $doc->childNodes->item(0));
|
||||
$this->assertInstanceOf('\DOMElement', $doc->childNodes->item(1));
|
||||
}
|
||||
|
||||
public function testAutocloseP()
|
||||
{
|
||||
$html = "<!DOCTYPE html><html><body><p><figure></body></html>";
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$p = $doc->getElementsByTagName('p')->item(0);
|
||||
$this->assertEquals(0, $p->childNodes->length);
|
||||
$this->assertEquals('figure', $p->nextSibling->tagName);
|
||||
}
|
||||
|
||||
public function testAutocloseLI()
|
||||
{
|
||||
$html = '<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<ul><li>Foo<li>Bar<li>Baz</ul>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$doc = $this->parse($html);
|
||||
$length = $doc->getElementsByTagName('ul')->item(0)->childNodes->length;
|
||||
$this->assertEquals(3, $length);
|
||||
}
|
||||
|
||||
public function testMathML()
|
||||
{
|
||||
$html = '<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<math xmlns="http://www.w3.org/1998/Math/MathML">
|
||||
<mi>x</mi>
|
||||
<csymbol definitionurl="http://www.example.com/mathops/multiops.html#plusminus">
|
||||
<mo>±</mo>
|
||||
</csymbol>
|
||||
<mi>y</mi>
|
||||
</math>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$doc = $this->parse($html);
|
||||
$math = $doc->getElementsByTagName('math')->item(0);
|
||||
$this->assertEquals('math', $math->tagName);
|
||||
$this->assertEquals('math', $math->nodeName);
|
||||
$this->assertEquals('math', $math->localName);
|
||||
$this->assertEquals('http://www.w3.org/1998/Math/MathML', $math->namespaceURI);
|
||||
}
|
||||
|
||||
public function testSVG()
|
||||
{
|
||||
$html = '<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<svg width="150" height="100" viewBox="0 0 3 2" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1" height="2" x="2" fill="#d2232c" />
|
||||
<text font-family="Verdana" font-size="32">
|
||||
<textpath xlink:href="#Foo">
|
||||
Test Text.
|
||||
</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$doc = $this->parse($html);
|
||||
$svg = $doc->getElementsByTagName('svg')->item(0);
|
||||
$this->assertEquals('svg', $svg->tagName);
|
||||
$this->assertEquals('svg', $svg->nodeName);
|
||||
$this->assertEquals('svg', $svg->localName);
|
||||
$this->assertEquals('http://www.w3.org/2000/svg', $svg->namespaceURI);
|
||||
|
||||
$textPath = $doc->getElementsByTagName('textPath')->item(0);
|
||||
$this->assertEquals('textPath', $textPath->tagName);
|
||||
}
|
||||
|
||||
public function testNoScript()
|
||||
{
|
||||
$html = '<!DOCTYPE html><html><head><noscript>No JS</noscript></head></html>';
|
||||
$doc = $this->parse($html);
|
||||
$this->assertEmpty($this->errors);
|
||||
$noscript = $doc->getElementsByTagName('noscript')->item(0);
|
||||
$this->assertEquals('noscript', $noscript->tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression for issue #13
|
||||
*/
|
||||
public function testRegressionHTMLNoBody()
|
||||
{
|
||||
$html = '<!DOCTYPE html><html><span id="test">Test</span></html>';
|
||||
$doc = $this->parse($html);
|
||||
$span = $doc->getElementById('test');
|
||||
|
||||
$this->assertEmpty($this->errors);
|
||||
|
||||
$this->assertEquals('span', $span->tagName);
|
||||
$this->assertEquals('Test', $span->textContent);
|
||||
}
|
||||
|
||||
public function testInstructionProcessor()
|
||||
{
|
||||
$string = '<!DOCTYPE html><html><?foo bar ?></html>';
|
||||
|
||||
$treeBuilder = new DOMTreeBuilder();
|
||||
$is = new InstructionProcessorMock();
|
||||
$treeBuilder->setInstructionProcessor($is);
|
||||
|
||||
$input = new StringInputStream($string);
|
||||
$scanner = new Scanner($input);
|
||||
$parser = new Tokenizer($scanner, $treeBuilder);
|
||||
|
||||
$parser->parse();
|
||||
$dom = $treeBuilder->document();
|
||||
$div = $dom->getElementsByTagName('div')->item(0);
|
||||
|
||||
$this->assertEquals(1, $is->count);
|
||||
$this->assertEquals('foo', $is->name);
|
||||
$this->assertEquals('bar ', $is->data);
|
||||
$this->assertEquals('div', $div->tagName);
|
||||
$this->assertEquals('foo', $div->textContent);
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Elements;
|
||||
use Masterminds\HTML5\Parser\EventHandler;
|
||||
|
||||
/**
|
||||
* This testing class gathers events from a parser and builds a stack of events.
|
||||
* It is useful for checking the output of a tokenizer.
|
||||
*
|
||||
* IMPORTANT:
|
||||
*
|
||||
* The startTag event also kicks the parser into TEXT_RAW when it encounters
|
||||
* script or pre tags. This is to match the behavior required by the HTML5 spec,
|
||||
* which says that the tree builder must tell the tokenizer when to switch states.
|
||||
*/
|
||||
class EventStack implements EventHandler
|
||||
{
|
||||
|
||||
protected $stack;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->stack = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event stack.
|
||||
*/
|
||||
public function events()
|
||||
{
|
||||
return $this->stack;
|
||||
}
|
||||
|
||||
public function depth()
|
||||
{
|
||||
return count($this->stack);
|
||||
}
|
||||
|
||||
public function get($index)
|
||||
{
|
||||
return $this->stack[$index];
|
||||
}
|
||||
|
||||
protected function store($event, $data = null)
|
||||
{
|
||||
$this->stack[] = array(
|
||||
'name' => $event,
|
||||
'data' => $data
|
||||
);
|
||||
}
|
||||
|
||||
public function doctype($name, $type = 0, $id = null, $quirks = false)
|
||||
{
|
||||
$args = array(
|
||||
$name,
|
||||
$type,
|
||||
$id,
|
||||
$quirks
|
||||
);
|
||||
$this->store('doctype', $args);
|
||||
}
|
||||
|
||||
public function startTag($name, $attributes = array(), $selfClosing = false)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->store('startTag', $args);
|
||||
if ($name == 'pre' || $name == 'script') {
|
||||
return Elements::TEXT_RAW;
|
||||
}
|
||||
}
|
||||
|
||||
public function endTag($name)
|
||||
{
|
||||
$this->store('endTag', array(
|
||||
$name
|
||||
));
|
||||
}
|
||||
|
||||
public function comment($cdata)
|
||||
{
|
||||
$this->store('comment', array(
|
||||
$cdata
|
||||
));
|
||||
}
|
||||
|
||||
public function cdata($data)
|
||||
{
|
||||
$this->store('cdata', func_get_args());
|
||||
}
|
||||
|
||||
public function text($cdata)
|
||||
{
|
||||
// fprintf(STDOUT, "Received TEXT event with: " . $cdata);
|
||||
$this->store('text', array(
|
||||
$cdata
|
||||
));
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
$this->store('eof');
|
||||
}
|
||||
|
||||
public function parseError($msg, $line, $col)
|
||||
{
|
||||
// throw new EventStackParseError(sprintf("%s (line %d, col %d)", $msg, $line, $col));
|
||||
// $this->store(sprintf("%s (line %d, col %d)", $msg, $line, $col));
|
||||
$this->store('error', func_get_args());
|
||||
}
|
||||
|
||||
public function processingInstruction($name, $data = null)
|
||||
{
|
||||
$this->store('pi', func_get_args());
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
class EventStackError extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is a test.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,195 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\FileInputStream;
|
||||
|
||||
class FileInputStreamTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertInstanceOf('\Masterminds\HTML5\Parser\FileInputStream', $s);
|
||||
}
|
||||
|
||||
public function testNext()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('!', $s->current());
|
||||
$s->next();
|
||||
$this->assertEquals('d', $s->current());
|
||||
}
|
||||
|
||||
public function testKey()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertEquals(0, $s->key());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals(1, $s->key());
|
||||
}
|
||||
|
||||
public function testPeek()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertEquals('!', $s->peek());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('d', $s->peek());
|
||||
}
|
||||
|
||||
public function testCurrent()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertEquals('<', $s->current());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('!', $s->current());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('d', $s->current());
|
||||
}
|
||||
|
||||
public function testColumnOffset()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
$this->assertEquals(0, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(1, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(2, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(3, $s->columnOffset());
|
||||
|
||||
// Make sure we get to the second line
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$this->assertEquals(0, $s->columnOffset());
|
||||
|
||||
$s->next();
|
||||
$canary = $s->current(); // h
|
||||
$this->assertEquals('h', $canary);
|
||||
$this->assertEquals(1, $s->columnOffset());
|
||||
}
|
||||
|
||||
public function testCurrentLine()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertEquals(1, $s->currentLine());
|
||||
|
||||
// Make sure we get to the second line
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$this->assertEquals(2, $s->currentLine());
|
||||
|
||||
// Make sure we get to the third line
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$this->assertEquals(3, $s->currentLine());
|
||||
}
|
||||
|
||||
public function testRemainingChars()
|
||||
{
|
||||
$text = file_get_contents(__DIR__ . '/FileInputStreamTest.html');
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
$this->assertEquals($text, $s->remainingChars());
|
||||
|
||||
$text = substr(file_get_contents(__DIR__ . '/FileInputStreamTest.html'), 1);
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
$s->next(); // Pop one.
|
||||
$this->assertEquals($text, $s->remainingChars());
|
||||
}
|
||||
|
||||
public function testCharsUnitl()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertEquals('', $s->charsUntil('<'));
|
||||
// Pointer at '<', moves to ' '
|
||||
$this->assertEquals('<!doctype', $s->charsUntil(' ', 20));
|
||||
|
||||
// Pointer at ' ', moves to '>'
|
||||
$this->assertEquals(' html', $s->charsUntil('>'));
|
||||
|
||||
// Pointer at '>', moves to '\n'.
|
||||
$this->assertEquals('>', $s->charsUntil("\n"));
|
||||
|
||||
// Pointer at '\n', move forward then to the next'\n'.
|
||||
$s->next();
|
||||
$this->assertEquals('<html lang="en">', $s->charsUntil("\n"));
|
||||
|
||||
// Ony get one of the spaces.
|
||||
$this->assertEquals("\n ", $s->charsUntil('<', 2));
|
||||
|
||||
// Get the other space.
|
||||
$this->assertEquals(" ", $s->charsUntil('<'));
|
||||
|
||||
// This should scan to the end of the file.
|
||||
$text = "<head>
|
||||
<meta charset=\"utf-8\">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is a test.</p>
|
||||
</body>
|
||||
</html>";
|
||||
$this->assertEquals($text, $s->charsUntil("\t"));
|
||||
}
|
||||
|
||||
public function testCharsWhile()
|
||||
{
|
||||
$s = new FileInputStream(__DIR__ . '/FileInputStreamTest.html');
|
||||
|
||||
$this->assertEquals('<!', $s->charsWhile('!<'));
|
||||
$this->assertEquals('', $s->charsWhile('>'));
|
||||
$this->assertEquals('doctype', $s->charsWhile('odcyept'));
|
||||
$this->assertEquals(' htm', $s->charsWhile('html ', 4));
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
class InstructionProcessorMock implements \Masterminds\HTML5\InstructionProcessor
|
||||
{
|
||||
|
||||
public $name = null;
|
||||
|
||||
public $data = null;
|
||||
|
||||
public $count = 0;
|
||||
|
||||
public function process(\DOMElement $element, $name, $data)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->data = $data;
|
||||
$this->count ++;
|
||||
|
||||
$div = $element->ownerDocument->createElement("div");
|
||||
$div->nodeValue = 'foo';
|
||||
|
||||
$element->appendChild($div);
|
||||
|
||||
return $div;
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test the Scanner. This requires the InputStream tests are all good.
|
||||
*/
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\StringInputStream;
|
||||
use Masterminds\HTML5\Parser\Scanner;
|
||||
|
||||
class ScannerTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* A canary test to make sure the basics are setup and working.
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$is = new StringInputStream("abc");
|
||||
$s = new Scanner($is);
|
||||
|
||||
$this->assertInstanceOf('\Masterminds\HTML5\Parser\Scanner', $s);
|
||||
}
|
||||
|
||||
public function testNext()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abc"));
|
||||
|
||||
$this->assertEquals('b', $s->next());
|
||||
$this->assertEquals('c', $s->next());
|
||||
}
|
||||
|
||||
public function testPosition()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abc"));
|
||||
|
||||
$this->assertEquals(0, $s->position());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals(1, $s->position());
|
||||
}
|
||||
|
||||
public function testPeek()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abc"));
|
||||
|
||||
$this->assertEquals('b', $s->peek());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('c', $s->peek());
|
||||
}
|
||||
|
||||
public function testCurrent()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abc"));
|
||||
|
||||
// Before scanning the string begins the current is empty.
|
||||
$this->assertEquals('a', $s->current());
|
||||
|
||||
$c = $s->next();
|
||||
$this->assertEquals('b', $s->current());
|
||||
|
||||
// Test movement through the string.
|
||||
$c = $s->next();
|
||||
$this->assertEquals('c', $s->current());
|
||||
}
|
||||
|
||||
public function testUnconsume()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abcdefghijklmnopqrst"));
|
||||
|
||||
// Get initial position.
|
||||
$s->next();
|
||||
$start = $s->position();
|
||||
|
||||
// Move forward a bunch of positions.
|
||||
$amount = 7;
|
||||
for ($i = 0; $i < $amount; $i ++) {
|
||||
$s->next();
|
||||
}
|
||||
|
||||
// Roll back the amount we moved forward.
|
||||
$s->unconsume($amount);
|
||||
|
||||
$this->assertEquals($start, $s->position());
|
||||
}
|
||||
|
||||
public function testGetHex()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("ab13ck45DE*"));
|
||||
|
||||
$this->assertEquals('ab13c', $s->getHex());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('45DE', $s->getHex());
|
||||
}
|
||||
|
||||
public function testGetAsciiAlpha()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abcdef1%mnop*"));
|
||||
|
||||
$this->assertEquals('abcdef', $s->getAsciiAlpha());
|
||||
|
||||
// Move past the 1% to scan the next group of text.
|
||||
$s->next();
|
||||
$s->next();
|
||||
$this->assertEquals('mnop', $s->getAsciiAlpha());
|
||||
}
|
||||
|
||||
public function testGetAsciiAlphaNum()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("abcdef1ghpo#mn94op"));
|
||||
|
||||
$this->assertEquals('abcdef1ghpo', $s->getAsciiAlphaNum());
|
||||
|
||||
// Move past the # to scan the next group of text.
|
||||
$s->next();
|
||||
$this->assertEquals('mn94op', $s->getAsciiAlphaNum());
|
||||
}
|
||||
|
||||
public function testGetNumeric()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("1784a 45 9867 #"));
|
||||
|
||||
$this->assertEquals('1784', $s->getNumeric());
|
||||
|
||||
// Move past the 'a ' to scan the next group of text.
|
||||
$s->next();
|
||||
$s->next();
|
||||
$this->assertEquals('45', $s->getNumeric());
|
||||
}
|
||||
|
||||
public function testCurrentLine()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("1784a\n45\n9867 #\nThis is a test."));
|
||||
|
||||
$this->assertEquals(1, $s->currentLine());
|
||||
|
||||
// Move to the next line.
|
||||
$s->getAsciiAlphaNum();
|
||||
$s->next();
|
||||
$this->assertEquals(2, $s->currentLine());
|
||||
}
|
||||
|
||||
public function testColumnOffset()
|
||||
{
|
||||
$s = new Scanner(new StringInputStream("1784a a\n45 9867 #\nThis is a test."));
|
||||
|
||||
// Move the pointer to the space.
|
||||
$s->getAsciiAlphaNum();
|
||||
$this->assertEquals(5, $s->columnOffset());
|
||||
|
||||
// We move the pointer ahead. There must be a better way to do this.
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$s->next();
|
||||
$this->assertEquals(3, $s->columnOffset());
|
||||
}
|
||||
|
||||
public function testRemainingChars()
|
||||
{
|
||||
$string = "\n45\n9867 #\nThis is a test.";
|
||||
$s = new Scanner(new StringInputStream("1784a\n45\n9867 #\nThis is a test."));
|
||||
|
||||
$s->getAsciiAlphaNum();
|
||||
$this->assertEquals($string, $s->remainingChars());
|
||||
}
|
||||
}
|
|
@ -1,327 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\StringInputStream;
|
||||
|
||||
class StringInputStreamTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* A canary test to make sure the basics are setup and working.
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$s = new StringInputStream("abc");
|
||||
|
||||
$this->assertInstanceOf('\Masterminds\HTML5\Parser\StringInputStream', $s);
|
||||
}
|
||||
|
||||
public function testNext()
|
||||
{
|
||||
$s = new StringInputStream("abc");
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('b', $s->current());
|
||||
$s->next();
|
||||
$this->assertEquals('c', $s->current());
|
||||
}
|
||||
|
||||
public function testKey()
|
||||
{
|
||||
$s = new StringInputStream("abc");
|
||||
|
||||
$this->assertEquals(0, $s->key());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals(1, $s->key());
|
||||
}
|
||||
|
||||
public function testPeek()
|
||||
{
|
||||
$s = new StringInputStream("abc");
|
||||
|
||||
$this->assertEquals('b', $s->peek());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('c', $s->peek());
|
||||
}
|
||||
|
||||
public function testCurrent()
|
||||
{
|
||||
$s = new StringInputStream("abc");
|
||||
|
||||
// Before scanning the string begins the current is empty.
|
||||
$this->assertEquals('a', $s->current());
|
||||
|
||||
$s->next();
|
||||
$this->assertEquals('b', $s->current());
|
||||
|
||||
// Test movement through the string.
|
||||
$s->next();
|
||||
$this->assertEquals('c', $s->current());
|
||||
}
|
||||
|
||||
public function testColumnOffset()
|
||||
{
|
||||
$s = new StringInputStream("abc\ndef\n");
|
||||
$this->assertEquals(0, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(1, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(2, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(3, $s->columnOffset());
|
||||
$s->next(); // LF
|
||||
$this->assertEquals(0, $s->columnOffset());
|
||||
$s->next();
|
||||
$canary = $s->current(); // e
|
||||
$this->assertEquals('e', $canary);
|
||||
$this->assertEquals(1, $s->columnOffset());
|
||||
|
||||
$s = new StringInputStream("abc");
|
||||
$this->assertEquals(0, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(1, $s->columnOffset());
|
||||
$s->next();
|
||||
$this->assertEquals(2, $s->columnOffset());
|
||||
}
|
||||
|
||||
public function testCurrentLine()
|
||||
{
|
||||
$txt = "1\n2\n\n\n\n3";
|
||||
$stream = new StringInputStream($txt);
|
||||
$this->assertEquals(1, $stream->currentLine());
|
||||
|
||||
// Advance over 1 and LF on to line 2 value 2.
|
||||
$stream->next();
|
||||
$stream->next();
|
||||
$canary = $stream->current();
|
||||
$this->assertEquals(2, $stream->currentLine());
|
||||
$this->assertEquals('2', $canary);
|
||||
|
||||
// Advance over 4x LF
|
||||
$stream->next();
|
||||
$stream->next();
|
||||
$stream->next();
|
||||
$stream->next();
|
||||
$stream->next();
|
||||
$this->assertEquals(6, $stream->currentLine());
|
||||
$this->assertEquals('3', $stream->current());
|
||||
|
||||
// Make sure it doesn't do 7.
|
||||
$this->assertEquals(6, $stream->currentLine());
|
||||
}
|
||||
|
||||
public function testRemainingChars()
|
||||
{
|
||||
$text = "abcd";
|
||||
$s = new StringInputStream($text);
|
||||
$this->assertEquals($text, $s->remainingChars());
|
||||
|
||||
$text = "abcd";
|
||||
$s = new StringInputStream($text);
|
||||
$s->next(); // Pop one.
|
||||
$this->assertEquals('bcd', $s->remainingChars());
|
||||
}
|
||||
|
||||
public function testCharsUnitl()
|
||||
{
|
||||
$text = "abcdefffffffghi";
|
||||
$s = new StringInputStream($text);
|
||||
$this->assertEquals('', $s->charsUntil('a'));
|
||||
// Pointer at 'a', moves 2 to 'c'
|
||||
$this->assertEquals('ab', $s->charsUntil('w', 2));
|
||||
|
||||
// Pointer at 'c', moves to first 'f'
|
||||
$this->assertEquals('cde', $s->charsUntil('fzxv'));
|
||||
|
||||
// Only get five 'f's
|
||||
$this->assertEquals('fffff', $s->charsUntil('g', 5));
|
||||
|
||||
// Get just the last two 'f's
|
||||
$this->assertEquals('ff', $s->charsUntil('g'));
|
||||
|
||||
// This should scan to the end.
|
||||
$this->assertEquals('ghi', $s->charsUntil('w', 9));
|
||||
}
|
||||
|
||||
public function testCharsWhile()
|
||||
{
|
||||
$text = "abcdefffffffghi";
|
||||
$s = new StringInputStream($text);
|
||||
|
||||
$this->assertEquals('ab', $s->charsWhile('ba'));
|
||||
|
||||
$this->assertEquals('', $s->charsWhile('a'));
|
||||
$this->assertEquals('cde', $s->charsWhile('cdeba'));
|
||||
$this->assertEquals('ff', $s->charsWhile('f', 2));
|
||||
$this->assertEquals('fffff', $s->charsWhile('f'));
|
||||
$this->assertEquals('g', $s->charsWhile('fg'));
|
||||
$this->assertEquals('hi', $s->charsWhile('fghi', 99));
|
||||
}
|
||||
|
||||
public function testBOM()
|
||||
{
|
||||
// Ignore in-text BOM.
|
||||
$stream = new StringInputStream("a\xEF\xBB\xBF");
|
||||
$this->assertEquals("a\xEF\xBB\xBF", $stream->remainingChars(), 'A non-leading U+FEFF (BOM/ZWNBSP) should remain');
|
||||
|
||||
// Strip leading BOM
|
||||
$leading = new StringInputStream("\xEF\xBB\xBFa");
|
||||
$this->assertEquals('a', $leading->current(), 'BOM should be stripped');
|
||||
}
|
||||
|
||||
public function testCarriageReturn()
|
||||
{
|
||||
// Replace NULL with Unicode replacement.
|
||||
$stream = new StringInputStream("\0\0\0");
|
||||
$this->assertEquals("\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD", $stream->remainingChars(), 'Null character should be replaced by U+FFFD');
|
||||
$this->assertEquals(3, count($stream->errors), 'Null character should set parse error: ' . print_r($stream->errors, true));
|
||||
|
||||
// Remove CR when next to LF.
|
||||
$stream = new StringInputStream("\r\n");
|
||||
$this->assertEquals("\n", $stream->remainingChars(), 'CRLF should be replaced by LF');
|
||||
|
||||
// Convert CR to LF when on its own.
|
||||
$stream = new StringInputStream("\r");
|
||||
$this->assertEquals("\n", $stream->remainingChars(), 'CR should be replaced by LF');
|
||||
}
|
||||
|
||||
public function invalidParseErrorTestHandler($input, $numErrors, $name)
|
||||
{
|
||||
$stream = new StringInputStream($input, 'UTF-8');
|
||||
$this->assertEquals($input, $stream->remainingChars(), $name . ' (stream content)');
|
||||
$this->assertEquals($numErrors, count($stream->errors), $name . ' (number of errors)');
|
||||
}
|
||||
|
||||
public function testInvalidReplace()
|
||||
{
|
||||
$invalidTest = array(
|
||||
|
||||
// Min/max overlong
|
||||
"\xC0\x80a" => 'Overlong representation of U+0000',
|
||||
"\xE0\x80\x80a" => 'Overlong representation of U+0000',
|
||||
"\xF0\x80\x80\x80a" => 'Overlong representation of U+0000',
|
||||
"\xF8\x80\x80\x80\x80a" => 'Overlong representation of U+0000',
|
||||
"\xFC\x80\x80\x80\x80\x80a" => 'Overlong representation of U+0000',
|
||||
"\xC1\xBFa" => 'Overlong representation of U+007F',
|
||||
"\xE0\x9F\xBFa" => 'Overlong representation of U+07FF',
|
||||
"\xF0\x8F\xBF\xBFa" => 'Overlong representation of U+FFFF',
|
||||
|
||||
"a\xDF" => 'Incomplete two byte sequence (missing final byte)',
|
||||
"a\xEF\xBF" => 'Incomplete three byte sequence (missing final byte)',
|
||||
"a\xF4\xBF\xBF" => 'Incomplete four byte sequence (missing final byte)',
|
||||
|
||||
// Min/max continuation bytes
|
||||
"a\x80" => 'Lone 80 continuation byte',
|
||||
"a\xBF" => 'Lone BF continuation byte',
|
||||
|
||||
// Invalid bytes (these can never occur)
|
||||
"a\xFE" => 'Invalid FE byte',
|
||||
"a\xFF" => 'Invalid FF byte'
|
||||
);
|
||||
foreach ($invalidTest as $test => $note) {
|
||||
$stream = new StringInputStream($test);
|
||||
$this->assertEquals('a', $stream->remainingChars(), $note);
|
||||
}
|
||||
|
||||
// MPB:
|
||||
// It appears that iconv just leaves these alone. Not sure what to
|
||||
// do.
|
||||
/*
|
||||
* $converted = array( "a\xF5\x90\x80\x80" => 'U+110000, off unicode planes.', ); foreach ($converted as $test => $note) { $stream = new StringInputStream($test); $this->assertEquals(2, mb_strlen($stream->remainingChars()), $note); }
|
||||
*/
|
||||
}
|
||||
|
||||
public function testInvalidParseError()
|
||||
{
|
||||
// C0 controls (except U+0000 and U+000D due to different handling)
|
||||
$this->invalidParseErrorTestHandler("\x01", 1, 'U+0001 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x02", 1, 'U+0002 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x03", 1, 'U+0003 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x04", 1, 'U+0004 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x05", 1, 'U+0005 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x06", 1, 'U+0006 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x07", 1, 'U+0007 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x08", 1, 'U+0008 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x09", 0, 'U+0009 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x0A", 0, 'U+000A (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x0B", 1, 'U+000B (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x0C", 0, 'U+000C (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x0E", 1, 'U+000E (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x0F", 1, 'U+000F (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x10", 1, 'U+0010 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x11", 1, 'U+0011 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x12", 1, 'U+0012 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x13", 1, 'U+0013 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x14", 1, 'U+0014 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x15", 1, 'U+0015 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x16", 1, 'U+0016 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x17", 1, 'U+0017 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x18", 1, 'U+0018 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x19", 1, 'U+0019 (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x1A", 1, 'U+001A (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x1B", 1, 'U+001B (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x1C", 1, 'U+001C (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x1D", 1, 'U+001D (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x1E", 1, 'U+001E (C0 control)');
|
||||
$this->invalidParseErrorTestHandler("\x1F", 1, 'U+001F (C0 control)');
|
||||
|
||||
// DEL (U+007F)
|
||||
$this->invalidParseErrorTestHandler("\x7F", 1, 'U+007F');
|
||||
|
||||
// C1 Controls
|
||||
$this->invalidParseErrorTestHandler("\xC2\x80", 1, 'U+0080 (C1 control)');
|
||||
$this->invalidParseErrorTestHandler("\xC2\x9F", 1, 'U+009F (C1 control)');
|
||||
$this->invalidParseErrorTestHandler("\xC2\xA0", 0, 'U+00A0 (first codepoint above highest C1 control)');
|
||||
|
||||
// Charcters surrounding surrogates
|
||||
$this->invalidParseErrorTestHandler("\xED\x9F\xBF", 0, 'U+D7FF (one codepoint below lowest surrogate codepoint)');
|
||||
$this->invalidParseErrorTestHandler("\xEF\xBF\xBD", 0, 'U+DE00 (one codepoint above highest surrogate codepoint)');
|
||||
|
||||
// Permanent noncharacters
|
||||
$this->invalidParseErrorTestHandler("\xEF\xB7\x90", 1, 'U+FDD0 (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xEF\xB7\xAF", 1, 'U+FDEF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xEF\xBF\xBE", 1, 'U+FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xEF\xBF\xBF", 1, 'U+FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF0\x9F\xBF\xBE", 1, 'U+1FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF0\x9F\xBF\xBF", 1, 'U+1FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF0\xAF\xBF\xBE", 1, 'U+2FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF0\xAF\xBF\xBF", 1, 'U+2FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF0\xBF\xBF\xBE", 1, 'U+3FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF0\xBF\xBF\xBF", 1, 'U+3FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\x8F\xBF\xBE", 1, 'U+4FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\x8F\xBF\xBF", 1, 'U+4FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\x9F\xBF\xBE", 1, 'U+5FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\x9F\xBF\xBF", 1, 'U+5FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\xAF\xBF\xBE", 1, 'U+6FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\xAF\xBF\xBF", 1, 'U+6FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\xBF\xBF\xBE", 1, 'U+7FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF1\xBF\xBF\xBF", 1, 'U+7FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\x8F\xBF\xBE", 1, 'U+8FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\x8F\xBF\xBF", 1, 'U+8FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\x9F\xBF\xBE", 1, 'U+9FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\x9F\xBF\xBF", 1, 'U+9FFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\xAF\xBF\xBE", 1, 'U+AFFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\xAF\xBF\xBF", 1, 'U+AFFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\xBF\xBF\xBE", 1, 'U+BFFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF2\xBF\xBF\xBF", 1, 'U+BFFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\x8F\xBF\xBE", 1, 'U+CFFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\x8F\xBF\xBF", 1, 'U+CFFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\x9F\xBF\xBE", 1, 'U+DFFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\x9F\xBF\xBF", 1, 'U+DFFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\xAF\xBF\xBE", 1, 'U+EFFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\xAF\xBF\xBF", 1, 'U+EFFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\xBF\xBF\xBE", 1, 'U+FFFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF3\xBF\xBF\xBF", 1, 'U+FFFFF (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF4\x8F\xBF\xBE", 1, 'U+10FFFE (permanent noncharacter)');
|
||||
$this->invalidParseErrorTestHandler("\xF4\x8F\xBF\xBF", 1, 'U+10FFFF (permanent noncharacter)');
|
||||
|
||||
// MPB: These pass on some versions of iconv, and fail on others. Since we aren't in the
|
||||
// business of writing tests against iconv, I've just commented these out. Should revisit
|
||||
// at a later point.
|
||||
/*
|
||||
* $this->invalidParseErrorTestHandler("\xED\xA0\x80", 1, 'U+D800 (UTF-16 surrogate character)'); $this->invalidParseErrorTestHandler("\xED\xAD\xBF", 1, 'U+DB7F (UTF-16 surrogate character)'); $this->invalidParseErrorTestHandler("\xED\xAE\x80", 1, 'U+DB80 (UTF-16 surrogate character)'); $this->invalidParseErrorTestHandler("\xED\xAF\xBF", 1, 'U+DBFF (UTF-16 surrogate character)'); $this->invalidParseErrorTestHandler("\xED\xB0\x80", 1, 'U+DC00 (UTF-16 surrogate character)'); $this->invalidParseErrorTestHandler("\xED\xBE\x80", 1, 'U+DF80 (UTF-16 surrogate character)'); $this->invalidParseErrorTestHandler("\xED\xBF\xBF", 1, 'U+DFFF (UTF-16 surrogate character)'); // Paired UTF-16 surrogates $this->invalidParseErrorTestHandler("\xED\xA0\x80\xED\xB0\x80", 2, 'U+D800 U+DC00 (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xA0\x80\xED\xBF\xBF", 2, 'U+D800 U+DFFF (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xAD\xBF\xED\xB0\x80", 2, 'U+DB7F U+DC00 (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xAD\xBF\xED\xBF\xBF", 2, 'U+DB7F U+DFFF (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xAE\x80\xED\xB0\x80", 2, 'U+DB80 U+DC00 (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xAE\x80\xED\xBF\xBF", 2, 'U+DB80 U+DFFF (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xAF\xBF\xED\xB0\x80", 2, 'U+DBFF U+DC00 (paired UTF-16 surrogates)'); $this->invalidParseErrorTestHandler("\xED\xAF\xBF\xED\xBF\xBF", 2, 'U+DBFF U+DFFF (paired UTF-16 surrogates)');
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -1,970 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\UTF8Utils;
|
||||
use Masterminds\HTML5\Parser\StringInputStream;
|
||||
use Masterminds\HTML5\Parser\Scanner;
|
||||
use Masterminds\HTML5\Parser\Tokenizer;
|
||||
|
||||
class TokenizerTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
// ================================================================
|
||||
// Additional assertions.
|
||||
// ================================================================
|
||||
/**
|
||||
* Tests that an event matches both the event type and the expected value.
|
||||
*
|
||||
* @param string $type
|
||||
* Expected event type.
|
||||
* @param string $expects
|
||||
* The value expected in $event['data'][0].
|
||||
*/
|
||||
public function assertEventEquals($type, $expects, $event)
|
||||
{
|
||||
$this->assertEquals($type, $event['name'], "Event $type for " . print_r($event, true));
|
||||
if (is_array($expects)) {
|
||||
$this->assertEquals($expects, $event['data'], "Event $type should equal " . print_r($expects, true) . ": " . print_r($event, true));
|
||||
} else {
|
||||
$this->assertEquals($expects, $event['data'][0], "Event $type should equal $expects: " . print_r($event, true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a given event is 'error'.
|
||||
*/
|
||||
public function assertEventError($event)
|
||||
{
|
||||
$this->assertEquals('error', $event['name'], "Expected error for event: " . print_r($event, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all of the tests are good.
|
||||
*
|
||||
* This loops through a map of tests/expectations and runs a few assertions on each test.
|
||||
*
|
||||
* Checks:
|
||||
* - depth (if depth is > 0)
|
||||
* - event name
|
||||
* - matches on event 0.
|
||||
*/
|
||||
protected function isAllGood($name, $depth, $tests, $debug = false)
|
||||
{
|
||||
foreach ($tests as $try => $expects) {
|
||||
if ($debug) {
|
||||
fprintf(STDOUT, "%s expects %s\n", $try, print_r($expects, true));
|
||||
}
|
||||
$e = $this->parse($try);
|
||||
if ($depth > 0) {
|
||||
$this->assertEquals($depth, $e->depth(), "Expected depth $depth for test $try." . print_r($e, true));
|
||||
}
|
||||
$this->assertEventEquals($name, $expects, $e->get(0));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Utility functions.
|
||||
// ================================================================
|
||||
public function testParse()
|
||||
{
|
||||
list ($tok, $events) = $this->createTokenizer('');
|
||||
|
||||
$tok->parse();
|
||||
$e1 = $events->get(0);
|
||||
|
||||
$this->assertEquals(1, $events->Depth());
|
||||
$this->assertEquals('eof', $e1['name']);
|
||||
}
|
||||
|
||||
public function testWhitespace()
|
||||
{
|
||||
$spaces = ' ';
|
||||
list ($tok, $events) = $this->createTokenizer($spaces);
|
||||
|
||||
$tok->parse();
|
||||
|
||||
$this->assertEquals(2, $events->depth());
|
||||
|
||||
$e1 = $events->get(0);
|
||||
|
||||
$this->assertEquals('text', $e1['name']);
|
||||
$this->assertEquals($spaces, $e1['data'][0]);
|
||||
}
|
||||
|
||||
public function testCharacterReference()
|
||||
{
|
||||
$good = array(
|
||||
'&' => '&',
|
||||
'<' => '<',
|
||||
'&' => '&',
|
||||
'&' => '&'
|
||||
);
|
||||
$this->isAllGood('text', 2, $good);
|
||||
|
||||
// Test with broken charref
|
||||
$str = '&foo';
|
||||
$events = $this->parse($str);
|
||||
$e1 = $events->get(0);
|
||||
$this->assertEquals('error', $e1['name']);
|
||||
|
||||
$str = 'oo';
|
||||
$events = $this->parse($str);
|
||||
$e1 = $events->get(0);
|
||||
$this->assertEquals('error', $e1['name']);
|
||||
|
||||
$str = '&#foo';
|
||||
$events = $this->parse($str);
|
||||
$e1 = $events->get(0);
|
||||
$this->assertEquals('error', $e1['name']);
|
||||
|
||||
// FIXME: Once the text processor is done, need to verify that the
|
||||
// tokens are transformed correctly into text.
|
||||
}
|
||||
|
||||
public function testBogusComment()
|
||||
{
|
||||
$bogus = array(
|
||||
'</+this is a bogus comment. +>',
|
||||
'<!+this is a bogus comment. !>',
|
||||
'<!D OCTYPE foo bar>',
|
||||
'<!DOCTYEP foo bar>',
|
||||
'<![CADATA[ TEST ]]>',
|
||||
'<![CDATA Hello ]]>',
|
||||
'<![CDATA[ Hello [[>',
|
||||
'<!CDATA[[ test ]]>',
|
||||
'<![CDATA[',
|
||||
'<![CDATA[hellooooo hello',
|
||||
'<? Hello World ?>',
|
||||
'<? Hello World'
|
||||
);
|
||||
foreach ($bogus as $str) {
|
||||
$events = $this->parse($str);
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('comment', $str, $events->get(1));
|
||||
}
|
||||
}
|
||||
|
||||
public function testEndTag()
|
||||
{
|
||||
$succeed = array(
|
||||
'</a>' => 'a',
|
||||
'</test>' => 'test',
|
||||
'</test
|
||||
>' => 'test',
|
||||
'</thisIsTheTagThatDoesntEndItJustGoesOnAndOnMyFriend>' => 'thisisthetagthatdoesntenditjustgoesonandonmyfriend',
|
||||
// See 8.2.4.10, which requires this and does not say error.
|
||||
'</a<b>' => 'a<b'
|
||||
);
|
||||
$this->isAllGood('endTag', 2, $succeed);
|
||||
|
||||
// Recoverable failures
|
||||
$fail = array(
|
||||
'</a class="monkey">' => 'a',
|
||||
'</a <b>' => 'a',
|
||||
'</a <b <c>' => 'a',
|
||||
'</a is the loneliest letter>' => 'a',
|
||||
'</a' => 'a'
|
||||
);
|
||||
foreach ($fail as $test => $result) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(3, $events->depth());
|
||||
// Should have triggered an error.
|
||||
$this->assertEventError($events->get(0));
|
||||
// Should have tried to parse anyway.
|
||||
$this->assertEventEquals('endTag', $result, $events->get(1));
|
||||
}
|
||||
|
||||
// BogoComments
|
||||
$comments = array(
|
||||
'</>' => '</>',
|
||||
'</ >' => '</ >',
|
||||
'</ a>' => '</ a>'
|
||||
);
|
||||
foreach ($comments as $test => $result) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(3, $events->depth());
|
||||
|
||||
// Should have triggered an error.
|
||||
$this->assertEventError($events->get(0));
|
||||
|
||||
// Should have tried to parse anyway.
|
||||
$this->assertEventEquals('comment', $result, $events->get(1));
|
||||
}
|
||||
}
|
||||
|
||||
public function testComment()
|
||||
{
|
||||
$good = array(
|
||||
'<!--easy-->' => 'easy',
|
||||
'<!-- 1 > 0 -->' => ' 1 > 0 ',
|
||||
'<!-- --$i -->' => ' --$i ',
|
||||
'<!----$i-->' => '--$i',
|
||||
'<!-- 1 > 0 -->' => ' 1 > 0 ',
|
||||
"<!--\nHello World.\na-->" => "\nHello World.\na",
|
||||
'<!-- <!-- -->' => ' <!-- '
|
||||
);
|
||||
foreach ($good as $test => $expected) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEventEquals('comment', $expected, $events->get(0));
|
||||
}
|
||||
|
||||
$fail = array(
|
||||
'<!-->' => '',
|
||||
'<!--Hello' => 'Hello',
|
||||
"<!--\0Hello" => UTF8Utils::FFFD . 'Hello',
|
||||
'<!--' => ''
|
||||
);
|
||||
foreach ($fail as $test => $expected) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(3, $events->depth());
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('comment', $expected, $events->get(1));
|
||||
}
|
||||
}
|
||||
|
||||
public function testCDATASection()
|
||||
{
|
||||
$good = array(
|
||||
'<![CDATA[ This is a test. ]]>' => ' This is a test. ',
|
||||
'<![CDATA[CDATA]]>' => 'CDATA',
|
||||
'<![CDATA[ ]] > ]]>' => ' ]] > ',
|
||||
'<![CDATA[ ]]>' => ' '
|
||||
);
|
||||
$this->isAllGood('cdata', 2, $good);
|
||||
}
|
||||
|
||||
public function testDoctype()
|
||||
{
|
||||
$good = array(
|
||||
'<!DOCTYPE html>' => array(
|
||||
'html',
|
||||
0,
|
||||
null,
|
||||
false
|
||||
),
|
||||
'<!doctype html>' => array(
|
||||
'html',
|
||||
0,
|
||||
null,
|
||||
false
|
||||
),
|
||||
'<!DocType html>' => array(
|
||||
'html',
|
||||
0,
|
||||
null,
|
||||
false
|
||||
),
|
||||
"<!DOCTYPE\nhtml>" => array(
|
||||
'html',
|
||||
0,
|
||||
null,
|
||||
false
|
||||
),
|
||||
"<!DOCTYPE\fhtml>" => array(
|
||||
'html',
|
||||
0,
|
||||
null,
|
||||
false
|
||||
),
|
||||
'<!DOCTYPE html PUBLIC "foo bar">' => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_PUBLIC,
|
||||
'foo bar',
|
||||
false
|
||||
),
|
||||
"<!DOCTYPE html PUBLIC 'foo bar'>" => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_PUBLIC,
|
||||
'foo bar',
|
||||
false
|
||||
),
|
||||
'<!DOCTYPE html PUBLIC "foo bar" >' => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_PUBLIC,
|
||||
'foo bar',
|
||||
false
|
||||
),
|
||||
"<!DOCTYPE html \nPUBLIC\n'foo bar'>" => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_PUBLIC,
|
||||
'foo bar',
|
||||
false
|
||||
),
|
||||
'<!DOCTYPE html SYSTEM "foo bar">' => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_SYSTEM,
|
||||
'foo bar',
|
||||
false
|
||||
),
|
||||
"<!DOCTYPE html SYSTEM 'foo bar'>" => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_SYSTEM,
|
||||
'foo bar',
|
||||
false
|
||||
),
|
||||
'<!DOCTYPE html SYSTEM "foo/bar" >' => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_SYSTEM,
|
||||
'foo/bar',
|
||||
false
|
||||
),
|
||||
"<!DOCTYPE html \nSYSTEM\n'foo bar'>" => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_SYSTEM,
|
||||
'foo bar',
|
||||
false
|
||||
)
|
||||
);
|
||||
$this->isAllGood('doctype', 2, $good);
|
||||
|
||||
$bad = array(
|
||||
'<!DOCTYPE>' => array(
|
||||
null,
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE >' => array(
|
||||
null,
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo PUB' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo PUB>' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo PUB "Looks good">' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo SYSTME "Looks good"' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
// Can't tell whether these are ids or ID types, since the context is chopped.
|
||||
'<!DOCTYPE foo PUBLIC' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo PUBLIC>' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo SYSTEM' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE foo SYSTEM>' => array(
|
||||
'foo',
|
||||
EventStack::DOCTYPE_NONE,
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
'<!DOCTYPE html SYSTEM "foo bar"' => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_SYSTEM,
|
||||
'foo bar',
|
||||
true
|
||||
),
|
||||
'<!DOCTYPE html SYSTEM "foo bar" more stuff>' => array(
|
||||
'html',
|
||||
EventStack::DOCTYPE_SYSTEM,
|
||||
'foo bar',
|
||||
true
|
||||
)
|
||||
);
|
||||
foreach ($bad as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
// fprintf(STDOUT, $test . PHP_EOL);
|
||||
$this->assertEquals(3, $events->depth(), "Counting events for '$test': " . print_r($events, true));
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('doctype', $expects, $events->get(1));
|
||||
}
|
||||
}
|
||||
|
||||
public function testProcessorInstruction()
|
||||
{
|
||||
$good = array(
|
||||
'<?hph ?>' => 'hph',
|
||||
'<?hph echo "Hello World"; ?>' => array(
|
||||
'hph',
|
||||
'echo "Hello World"; '
|
||||
),
|
||||
"<?hph \necho 'Hello World';\n?>" => array(
|
||||
'hph',
|
||||
"echo 'Hello World';\n"
|
||||
)
|
||||
);
|
||||
$this->isAllGood('pi', 2, $good);
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests just simple tags.
|
||||
*/
|
||||
public function testSimpleTags()
|
||||
{
|
||||
$open = array(
|
||||
'<foo>' => 'foo',
|
||||
'<FOO>' => 'foo',
|
||||
'<fOO>' => 'foo',
|
||||
'<foo >' => 'foo',
|
||||
"<foo\n\n\n\n>" => 'foo',
|
||||
'<foo:bar>' => 'foo:bar'
|
||||
);
|
||||
$this->isAllGood('startTag', 2, $open);
|
||||
|
||||
$selfClose = array(
|
||||
'<foo/>' => 'foo',
|
||||
'<FOO/>' => 'foo',
|
||||
'<foo />' => 'foo',
|
||||
"<foo\n\n\n\n/>" => 'foo',
|
||||
'<foo:bar/>' => 'foo:bar'
|
||||
);
|
||||
foreach ($selfClose as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(3, $events->depth(), "Counting events for '$test'" . print_r($events, true));
|
||||
$this->assertEventEquals('startTag', $expects, $events->get(0));
|
||||
$this->assertEventEquals('endTag', $expects, $events->get(1));
|
||||
}
|
||||
|
||||
$bad = array(
|
||||
'<foo' => 'foo',
|
||||
'<foo ' => 'foo',
|
||||
'<foo/' => 'foo',
|
||||
'<foo /' => 'foo'
|
||||
);
|
||||
|
||||
foreach ($bad as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(3, $events->depth(), "Counting events for '$test': " . print_r($events, true));
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', $expects, $events->get(1));
|
||||
}
|
||||
}
|
||||
|
||||
public function testTagsWithAttributeAndMissingName()
|
||||
{
|
||||
$cases = array(
|
||||
'<id="top_featured">' => 'id',
|
||||
'<color="white">' => 'color',
|
||||
"<class='neaktivni_stranka'>" => 'class',
|
||||
'<bgcolor="white">' => 'bgcolor',
|
||||
'<class="nom">' => 'class'
|
||||
);
|
||||
|
||||
foreach ($cases as $html => $expected) {
|
||||
$events = $this->parse($html);
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventError($events->get(1));
|
||||
$this->assertEventError($events->get(2));
|
||||
$this->assertEventEquals('startTag', $expected, $events->get(3));
|
||||
$this->assertEventEquals('eof', null, $events->get(4));
|
||||
}
|
||||
}
|
||||
|
||||
public function testTagNotClosedAfterTagName()
|
||||
{
|
||||
$cases = array(
|
||||
"<noscript<img>" => array(
|
||||
'noscript',
|
||||
'img'
|
||||
),
|
||||
'<center<a>' => array(
|
||||
'center',
|
||||
'a'
|
||||
),
|
||||
'<br<br>' => array(
|
||||
'br',
|
||||
'br'
|
||||
)
|
||||
);
|
||||
|
||||
foreach ($cases as $html => $expected) {
|
||||
$events = $this->parse($html);
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', $expected[0], $events->get(1));
|
||||
$this->assertEventEquals('startTag', $expected[1], $events->get(2));
|
||||
$this->assertEventEquals('eof', null, $events->get(3));
|
||||
}
|
||||
|
||||
$events = $this->parse('<span<>02</span>');
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', 'span', $events->get(1));
|
||||
$this->assertEventError($events->get(2));
|
||||
$this->assertEventEquals('text', '>02', $events->get(3));
|
||||
$this->assertEventEquals('endTag', 'span', $events->get(4));
|
||||
$this->assertEventEquals('eof', null, $events->get(5));
|
||||
|
||||
$events = $this->parse('<p</p>');
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', 'p', $events->get(1));
|
||||
$this->assertEventEquals('endTag', 'p', $events->get(2));
|
||||
$this->assertEventEquals('eof', null, $events->get(3));
|
||||
|
||||
$events = $this->parse('<strong><WordPress</strong>');
|
||||
$this->assertEventEquals('startTag', 'strong', $events->get(0));
|
||||
$this->assertEventError($events->get(1));
|
||||
$this->assertEventEquals('startTag', 'wordpress', $events->get(2));
|
||||
$this->assertEventEquals('endTag', 'strong', $events->get(3));
|
||||
$this->assertEventEquals('eof', null, $events->get(4));
|
||||
|
||||
$events = $this->parse('<src=<a>');
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventError($events->get(1));
|
||||
$this->assertEventError($events->get(2));
|
||||
$this->assertEventEquals('startTag', 'src', $events->get(3));
|
||||
$this->assertEventEquals('startTag', 'a', $events->get(4));
|
||||
$this->assertEventEquals('eof', null, $events->get(5));
|
||||
|
||||
$events = $this->parse('<br...<a>');
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', 'br', $events->get(1));
|
||||
$this->assertEventEquals('eof', null, $events->get(2));
|
||||
}
|
||||
|
||||
public function testIllegalTagNames()
|
||||
{
|
||||
$cases = array(
|
||||
'<li">' => 'li',
|
||||
'<p">' => 'p',
|
||||
'<b >' => 'b',
|
||||
'<static*all>' => 'static',
|
||||
'<h*0720/>' => 'h',
|
||||
'<st*ATTRIBUTE />' => 'st',
|
||||
);
|
||||
|
||||
foreach ($cases as $html => $expected) {
|
||||
$events = $this->parse($html);
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', $expected, $events->get(1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCharacterReference
|
||||
*/
|
||||
public function testTagAttributes()
|
||||
{
|
||||
// Opening tags.
|
||||
$good = array(
|
||||
'<foo bar="baz">' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar=" baz ">' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => ' baz '
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo bar=\"\nbaz\n\">" => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => "\nbaz\n"
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo bar='baz'>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar="A full sentence.">' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'A full sentence.'
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo a='1' b=\"2\">" => array(
|
||||
'foo',
|
||||
array(
|
||||
'a' => '1',
|
||||
'b' => '2'
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo ns:bar='baz'>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'ns:bar' => 'baz'
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo a='blue&red'>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'a' => 'blue&red'
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo a='blue&&red'>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'a' => 'blue&&red'
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo\nbar='baz'\n>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
false
|
||||
),
|
||||
'<doe a deer>' => array(
|
||||
'doe',
|
||||
array(
|
||||
'a' => null,
|
||||
'deer' => null
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar=baz>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
false
|
||||
),
|
||||
|
||||
// Updated for 8.1.2.3
|
||||
'<foo bar = "baz" >' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
false
|
||||
),
|
||||
|
||||
// The spec allows an unquoted value '/'. This will not be a closing
|
||||
// tag.
|
||||
'<foo bar=/>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => '/'
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar=baz/>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz/'
|
||||
),
|
||||
false
|
||||
)
|
||||
);
|
||||
$this->isAllGood('startTag', 2, $good);
|
||||
|
||||
// Self-closing tags.
|
||||
$withEnd = array(
|
||||
'<foo bar="baz"/>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
true
|
||||
),
|
||||
'<foo BAR="baz"/>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'baz'
|
||||
),
|
||||
true
|
||||
),
|
||||
'<foo BAR="BAZ"/>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'BAZ'
|
||||
),
|
||||
true
|
||||
),
|
||||
"<foo a='1' b=\"2\" c=3 d/>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'a' => '1',
|
||||
'b' => '2',
|
||||
'c' => '3',
|
||||
'd' => null
|
||||
),
|
||||
true
|
||||
)
|
||||
);
|
||||
$this->isAllGood('startTag', 3, $withEnd);
|
||||
|
||||
// Cause a parse error.
|
||||
$bad = array(
|
||||
// This will emit an entity lookup failure for &red.
|
||||
"<foo a='blue&red'>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'a' => 'blue&red'
|
||||
),
|
||||
false
|
||||
),
|
||||
"<foo a='blue&&&red'>" => array(
|
||||
'foo',
|
||||
array(
|
||||
'a' => 'blue&&&red'
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar=>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => null
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar="oh' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'oh'
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo bar=oh">' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'oh"'
|
||||
),
|
||||
false
|
||||
),
|
||||
|
||||
// these attributes are ignored because of current implementation
|
||||
// of method "DOMElement::setAttribute"
|
||||
// see issue #23: https://github.com/Masterminds/html5-php/issues/23
|
||||
'<foo b"="baz">' => array(
|
||||
'foo',
|
||||
array(),
|
||||
false
|
||||
),
|
||||
'<foo 2abc="baz">' => array(
|
||||
'foo',
|
||||
array(),
|
||||
false
|
||||
),
|
||||
'<foo ?="baz">' => array(
|
||||
'foo',
|
||||
array(),
|
||||
false
|
||||
),
|
||||
'<foo foo?bar="baz">' => array(
|
||||
'foo',
|
||||
array(),
|
||||
false
|
||||
)
|
||||
)
|
||||
;
|
||||
foreach ($bad as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(3, $events->depth(), "Counting events for '$test': " . print_r($events, true));
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', $expects, $events->get(1));
|
||||
}
|
||||
|
||||
// Cause multiple parse errors.
|
||||
$reallyBad = array(
|
||||
'<foo ="bar">' => array(
|
||||
'foo',
|
||||
array(
|
||||
'=' => null,
|
||||
'"bar"' => null
|
||||
),
|
||||
false
|
||||
),
|
||||
'<foo////>' => array(
|
||||
'foo',
|
||||
array(),
|
||||
true
|
||||
),
|
||||
// character "&" in unquoted attribute shouldn't cause an infinite loop
|
||||
'<foo bar=index.php?str=1&id=29>' => array(
|
||||
'foo',
|
||||
array(
|
||||
'bar' => 'index.php?str=1&id=29'
|
||||
),
|
||||
false
|
||||
)
|
||||
);
|
||||
foreach ($reallyBad as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
// fprintf(STDOUT, $test . print_r($events, true));
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventError($events->get(1));
|
||||
// $this->assertEventEquals('startTag', $expects, $events->get(1));
|
||||
}
|
||||
|
||||
// Regression: Malformed elements should be detected.
|
||||
// '<foo baz="1" <bar></foo>' => array('foo', array('baz' => '1'), false),
|
||||
$events = $this->parse('<foo baz="1" <bar></foo>');
|
||||
$this->assertEventError($events->get(0));
|
||||
$this->assertEventEquals('startTag', array(
|
||||
'foo',
|
||||
array(
|
||||
'baz' => '1'
|
||||
),
|
||||
false
|
||||
), $events->get(1));
|
||||
$this->assertEventEquals('startTag', array(
|
||||
'bar',
|
||||
array(),
|
||||
false
|
||||
), $events->get(2));
|
||||
$this->assertEventEquals('endTag', array(
|
||||
'foo'
|
||||
), $events->get(3));
|
||||
}
|
||||
|
||||
public function testRawText()
|
||||
{
|
||||
$good = array(
|
||||
'<script>abcd efg hijk lmnop</script> ' => 'abcd efg hijk lmnop',
|
||||
'<script><not/><the/><tag></script>' => '<not/><the/><tag>',
|
||||
'<script><<<<<<<<</script>' => '<<<<<<<<',
|
||||
'<script>hello</script</script>' => 'hello</script',
|
||||
"<script>\nhello</script\n</script>" => "\nhello</script\n",
|
||||
'<script>&</script>' => '&',
|
||||
'<script><!--not a comment--></script>' => '<!--not a comment-->',
|
||||
'<script><![CDATA[not a comment]]></script>' => '<![CDATA[not a comment]]>'
|
||||
);
|
||||
foreach ($good as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEventEquals('startTag', 'script', $events->get(0));
|
||||
$this->assertEventEquals('text', $expects, $events->get(1));
|
||||
$this->assertEventEquals('endTag', 'script', $events->get(2));
|
||||
}
|
||||
|
||||
$bad = array(
|
||||
'<script>&</script' => '&</script',
|
||||
'<script>Hello world' => 'Hello world'
|
||||
);
|
||||
foreach ($bad as $test => $expects) {
|
||||
$events = $this->parse($test);
|
||||
$this->assertEquals(4, $events->depth(), "Counting events for '$test': " . print_r($events, true));
|
||||
$this->assertEventEquals('startTag', 'script', $events->get(0));
|
||||
$this->assertEventError($events->get(1));
|
||||
$this->assertEventEquals('text', $expects, $events->get(2));
|
||||
}
|
||||
|
||||
// Testing case sensitivity
|
||||
$events = $this->parse('<TITLE>a test</TITLE>');
|
||||
$this->assertEventEquals('startTag', 'title', $events->get(0));
|
||||
$this->assertEventEquals('text', 'a test', $events->get(1));
|
||||
$this->assertEventEquals('endTag', 'title', $events->get(2));
|
||||
|
||||
// Testing end tags with whitespaces
|
||||
$events = $this->parse('<title>Whitespaces are tasty</title >');
|
||||
$this->assertEventEquals('startTag', 'title', $events->get(0));
|
||||
$this->assertEventEquals('text', 'Whitespaces are tasty', $events->get(1));
|
||||
$this->assertEventEquals('endTag', 'title', $events->get(2));
|
||||
}
|
||||
|
||||
public function testRcdata()
|
||||
{
|
||||
list ($tok, $events) = $this->createTokenizer('<title>'<!-- not a comment --></TITLE>');
|
||||
$tok->setTextMode(\Masterminds\HTML5\Elements::TEXT_RCDATA, 'title');
|
||||
$tok->parse();
|
||||
$this->assertEventEquals('text', "'<!-- not a comment -->", $events->get(1));
|
||||
}
|
||||
|
||||
public function testText()
|
||||
{
|
||||
$events = $this->parse('a<br>b');
|
||||
$this->assertEquals(4, $events->depth(), "Events: " . print_r($events, true));
|
||||
$this->assertEventEquals('text', 'a', $events->get(0));
|
||||
$this->assertEventEquals('startTag', 'br', $events->get(1));
|
||||
$this->assertEventEquals('text', 'b', $events->get(2));
|
||||
|
||||
$events = $this->parse('<a>Test</a>');
|
||||
$this->assertEquals(4, $events->depth(), "Events: " . print_r($events, true));
|
||||
$this->assertEventEquals('startTag', 'a', $events->get(0));
|
||||
$this->assertEventEquals('text', 'Test', $events->get(1));
|
||||
$this->assertEventEquals('endTag', 'a', $events->get(2));
|
||||
|
||||
$events = $this->parse('<p>0</p><p>1</p>');
|
||||
$this->assertEquals(7, $events->depth(), "Events: " . print_r($events, true));
|
||||
|
||||
$this->assertEventEquals('startTag', 'p', $events->get(0));
|
||||
$this->assertEventEquals('text', '0', $events->get(1));
|
||||
$this->assertEventEquals('endTag', 'p', $events->get(2));
|
||||
|
||||
$this->assertEventEquals('startTag', 'p', $events->get(3));
|
||||
$this->assertEventEquals('text', '1', $events->get(4));
|
||||
$this->assertEventEquals('endTag', 'p', $events->get(5));
|
||||
|
||||
|
||||
$events = $this->parse('a<![CDATA[test]]>b');
|
||||
$this->assertEquals(4, $events->depth(), "Events: " . print_r($events, true));
|
||||
$this->assertEventEquals('text', 'a', $events->get(0));
|
||||
$this->assertEventEquals('cdata', 'test', $events->get(1));
|
||||
$this->assertEventEquals('text', 'b', $events->get(2));
|
||||
|
||||
$events = $this->parse('a<!--test-->b');
|
||||
$this->assertEquals(4, $events->depth(), "Events: " . print_r($events, true));
|
||||
$this->assertEventEquals('text', 'a', $events->get(0));
|
||||
$this->assertEventEquals('comment', 'test', $events->get(1));
|
||||
$this->assertEventEquals('text', 'b', $events->get(2));
|
||||
|
||||
$events = $this->parse('a&b');
|
||||
$this->assertEquals(2, $events->depth(), "Events: " . print_r($events, true));
|
||||
$this->assertEventEquals('text', 'a&b', $events->get(0));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Utility functions.
|
||||
// ================================================================
|
||||
protected function createTokenizer($string, $debug = false)
|
||||
{
|
||||
$eventHandler = new EventStack();
|
||||
$stream = new StringInputStream($string);
|
||||
$scanner = new Scanner($stream);
|
||||
|
||||
$scanner->debug = $debug;
|
||||
|
||||
return array(
|
||||
new Tokenizer($scanner, $eventHandler),
|
||||
$eventHandler
|
||||
);
|
||||
}
|
||||
|
||||
public function parse($string, $debug = false)
|
||||
{
|
||||
list ($tok, $events) = $this->createTokenizer($string, $debug);
|
||||
$tok->parse();
|
||||
|
||||
return $events;
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test the Tree Builder's special-case rules.
|
||||
*/
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\TreeBuildingRules;
|
||||
use Masterminds\HTML5\Parser\Tokenizer;
|
||||
use Masterminds\HTML5\Parser\Scanner;
|
||||
use Masterminds\HTML5\Parser\StringInputStream;
|
||||
use Masterminds\HTML5\Parser\DOMTreeBuilder;
|
||||
|
||||
/**
|
||||
* These tests are functional, not necessarily unit tests.
|
||||
*/
|
||||
class TreeBuildingRulesTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
const HTML_STUB = '<!DOCTYPE html><html><head><title>test</title></head><body>%s</body></html>';
|
||||
|
||||
/**
|
||||
* Convenience function for parsing.
|
||||
*/
|
||||
protected function parse($string)
|
||||
{
|
||||
$treeBuilder = new DOMTreeBuilder();
|
||||
$scanner = new Scanner(new StringInputStream($string));
|
||||
$parser = new Tokenizer($scanner, $treeBuilder);
|
||||
|
||||
$parser->parse();
|
||||
return $treeBuilder->document();
|
||||
}
|
||||
/**
|
||||
* Convenience function for parsing fragments.
|
||||
*/
|
||||
protected function parseFragment($string)
|
||||
{
|
||||
$events = new DOMTreeBuilder(true);
|
||||
$scanner = new Scanner(new StringInputStream($string));
|
||||
$parser = new Tokenizer($scanner, $events);
|
||||
|
||||
$parser->parse();
|
||||
return $events->fragment();
|
||||
}
|
||||
|
||||
public function testTDFragment()
|
||||
{
|
||||
|
||||
$frag = $this->parseFragment("<td>This is a test of the HTML5 parser</td>");
|
||||
|
||||
$td = $frag->childNodes->item(0);
|
||||
|
||||
$this->assertEquals(1, $frag->childNodes->length);
|
||||
$this->assertEquals('td', $td->tagName);
|
||||
$this->assertEquals('This is a test of the HTML5 parser', $td->nodeValue);
|
||||
}
|
||||
|
||||
public function testHasRules()
|
||||
{
|
||||
$doc = new \DOMDocument('1.0');
|
||||
$engine = new TreeBuildingRules($doc);
|
||||
|
||||
$this->assertTrue($engine->hasRules('li'));
|
||||
$this->assertFalse($engine->hasRules('imaginary'));
|
||||
}
|
||||
|
||||
public function testHandleLI()
|
||||
{
|
||||
$html = sprintf(self::HTML_STUB, '<ul id="a"><li>test<li>test2</ul><a></a>');
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$list = $doc->getElementById('a');
|
||||
|
||||
$this->assertEquals(2, $list->childNodes->length);
|
||||
foreach ($list->childNodes as $ele) {
|
||||
$this->assertEquals('li', $ele->tagName);
|
||||
}
|
||||
}
|
||||
|
||||
public function testHandleDT()
|
||||
{
|
||||
$html = sprintf(self::HTML_STUB, '<dl id="a"><dt>Hello<dd>Hi</dl><a></a>');
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$list = $doc->getElementById('a');
|
||||
|
||||
$this->assertEquals(2, $list->childNodes->length);
|
||||
$this->assertEquals('dt', $list->firstChild->tagName);
|
||||
$this->assertEquals('dd', $list->lastChild->tagName);
|
||||
}
|
||||
|
||||
public function testTable()
|
||||
{
|
||||
$html = sprintf(self::HTML_STUB, '<table><thead id="a"><th>foo<td>bar<td>baz');
|
||||
$doc = $this->parse($html);
|
||||
|
||||
$list = $doc->getElementById('a');
|
||||
|
||||
$this->assertEquals(3, $list->childNodes->length);
|
||||
$this->assertEquals('th', $list->firstChild->tagName);
|
||||
$this->assertEquals('td', $list->lastChild->tagName);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Tests\Parser;
|
||||
|
||||
use Masterminds\HTML5\Parser\UTF8Utils;
|
||||
|
||||
class UTF8UtilsTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
public function testConvertToUTF8() {
|
||||
$out = UTF8Utils::convertToUTF8('éàa', 'ISO-8859-1');
|
||||
$this->assertEquals('éà a', $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo add tests for invalid codepoints
|
||||
*/
|
||||
public function testCheckForIllegalCodepoints() {
|
||||
$smoke = "Smoke test";
|
||||
$err = UTF8Utils::checkForIllegalCodepoints($smoke);
|
||||
$this->assertEmpty($err);
|
||||
|
||||
$data = "Foo Bar \0 Baz";
|
||||
$errors = UTF8Utils::checkForIllegalCodepoints($data);
|
||||
$this->assertContains('null-character', $errors);
|
||||
}
|
||||
}
|
|
@ -1,587 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Serializer;
|
||||
|
||||
use Masterminds\HTML5\Serializer\OutputRules;
|
||||
use Masterminds\HTML5\Serializer\Traverser;
|
||||
|
||||
class OutputRulesTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
protected $markup = '<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is a test.</p>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->html5 = $this->getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Using reflection we make a protected method accessible for testing.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the method on the Traverser class to test.
|
||||
*
|
||||
* @return \ReflectionMethod \ReflectionMethod for the specified method
|
||||
*/
|
||||
public function getProtectedMethod($name)
|
||||
{
|
||||
$class = new \ReflectionClass('\Masterminds\HTML5\Serializer\OutputRules');
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
public function getTraverserProtectedProperty($name)
|
||||
{
|
||||
$class = new \ReflectionClass('\Masterminds\HTML5\Serializer\Traverser');
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
|
||||
return $property;
|
||||
}
|
||||
|
||||
public function getOutputRules($options = array())
|
||||
{
|
||||
$options = $options + $this->html5->getOptions();
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$dom = $this->html5->loadHTML($this->markup);
|
||||
$r = new OutputRules($stream, $options);
|
||||
$t = new Traverser($dom, $stream, $r, $options);
|
||||
|
||||
return array(
|
||||
$r,
|
||||
$stream
|
||||
);
|
||||
}
|
||||
|
||||
public function testDocument()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html><html lang="en"><body>foo</body></html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$r->document($dom);
|
||||
$expected = '<!DOCTYPE html>' . PHP_EOL . '<html lang="en"><body>foo</body></html>' . PHP_EOL;
|
||||
$this->assertEquals($expected, stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testEmptyDocument()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$r->document($dom);
|
||||
$expected = '<!DOCTYPE html>' . PHP_EOL;
|
||||
$this->assertEquals($expected, stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testDoctype()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html><html lang="en"><body>foo</body></html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$m = $this->getProtectedMethod('doctype');
|
||||
$m->invoke($r, 'foo');
|
||||
$this->assertEquals("<!DOCTYPE html>" . PHP_EOL, stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testElement()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
<svg width="150" height="100" viewBox="0 0 3 2">
|
||||
<rect width="1" height="2" x="0" fill="#008d46" />
|
||||
<rect width="1" height="2" x="1" fill="#ffffff" />
|
||||
<rect width="1" height="2" x="2" fill="#d2232c" />
|
||||
</svg>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$r->element($list->item(0));
|
||||
$this->assertEquals('<div id="foo" class="bar baz">foo bar baz</div>', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
function testSerializeWithNamespaces()
|
||||
{
|
||||
$this->html5 = $this->getInstance(array(
|
||||
'xmlNamespaces' => true
|
||||
));
|
||||
|
||||
$source = '
|
||||
<!DOCTYPE html>
|
||||
<html><body id="body" xmlns:x="http://www.prefixed.com">
|
||||
<a id="bar1" xmlns="http://www.prefixed.com/bar1">
|
||||
<b id="bar4" xmlns="http://www.prefixed.com/bar4"><x:prefixed id="prefixed">xy</x:prefixed></b>
|
||||
</a>
|
||||
<svg id="svg">svg</svg>
|
||||
<c id="bar2" xmlns="http://www.prefixed.com/bar2"></c>
|
||||
<div id="div"></div>
|
||||
<d id="bar3"></d>
|
||||
<xn:d id="bar5" xmlns:xn="http://www.prefixed.com/xn" xmlns="http://www.prefixed.com/bar5_x"><x id="bar5_x">y</x></xn:d>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
$dom = $this->html5->loadHTML($source, array(
|
||||
'xmlNamespaces' => true
|
||||
));
|
||||
$this->assertFalse($this->html5->hasErrors(), print_r($this->html5->getErrors(), 1));
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$t->walk();
|
||||
$rendered = stream_get_contents($stream, - 1, 0);
|
||||
|
||||
$clear = function($s){
|
||||
return trim(preg_replace('/[\s]+/', " ", $s));
|
||||
};
|
||||
|
||||
$this->assertEquals($clear($source), $clear($rendered));
|
||||
}
|
||||
|
||||
public function testElementWithScript()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script>
|
||||
var $jQ = jQuery.noConflict();
|
||||
// Use jQuery via $jQ(...)
|
||||
$jQ(document).ready(function () {
|
||||
$jQ("#mktFrmSubmit").wrap("<div class=\'buttonSubmit\'></div>");
|
||||
$jQ(".buttonSubmit").prepend("<span></span>");
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$script = $dom->getElementsByTagName('script');
|
||||
$r->element($script->item(0));
|
||||
$this->assertEquals(
|
||||
'<script>
|
||||
var $jQ = jQuery.noConflict();
|
||||
// Use jQuery via $jQ(...)
|
||||
$jQ(document).ready(function () {
|
||||
$jQ("#mktFrmSubmit").wrap("<div class=\'buttonSubmit\'></div>");
|
||||
$jQ(".buttonSubmit").prepend("<span></span>");
|
||||
});
|
||||
</script>', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testElementWithStyle()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<style>
|
||||
body > .bar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$style = $dom->getElementsByTagName('style');
|
||||
$r->element($style->item(0));
|
||||
$this->assertEquals('<style>
|
||||
body > .bar {
|
||||
display: none;
|
||||
}
|
||||
</style>', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testOpenTag()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$m = $this->getProtectedMethod('openTag');
|
||||
$m->invoke($r, $list->item(0));
|
||||
$this->assertEquals('<div id="foo" class="bar baz">', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testCData()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div><![CDATA[bar]]></div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$r->cdata($list->item(0)->childNodes->item(0));
|
||||
$this->assertEquals('<![CDATA[bar]]>', stream_get_contents($stream, - 1, 0));
|
||||
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo"></div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$dom->getElementById('foo')->appendChild(new \DOMCdataSection("]]>Foo<[![CDATA test ]]>"));
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$r->cdata($list->item(0)->childNodes->item(0));
|
||||
|
||||
$this->assertEquals('<![CDATA[]]]]><![CDATA[>Foo<[![CDATA test ]]]]><![CDATA[>]]>', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testComment()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div><!-- foo --></div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$r->comment($list->item(0)->childNodes->item(0));
|
||||
$this->assertEquals('<!-- foo -->', stream_get_contents($stream, - 1, 0));
|
||||
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo"></div>
|
||||
</body>
|
||||
</html>');
|
||||
$dom->getElementById('foo')->appendChild(new \DOMComment('<!-- --> --> Foo -->'));
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
$r->comment($list->item(0)->childNodes->item(0));
|
||||
|
||||
// Could not find more definitive guidelines on what this should be. Went with
|
||||
// what the HTML5 spec says and what \DOMDocument::saveXML() produces.
|
||||
$this->assertEquals('<!--<!-- --> --> Foo -->-->', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testText()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script>baz();</script>
|
||||
</head>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('script');
|
||||
$r->text($list->item(0)->childNodes->item(0));
|
||||
$this->assertEquals('baz();', stream_get_contents($stream, - 1, 0));
|
||||
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<head id="foo"></head>
|
||||
</html>');
|
||||
$foo = $dom->getElementById('foo');
|
||||
$foo->appendChild(new \DOMText('<script>alert("hi");</script>'));
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$r->text($foo->firstChild);
|
||||
$this->assertEquals('<script>alert("hi");</script>', stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testNl()
|
||||
{
|
||||
list ($o, $s) = $this->getOutputRules();
|
||||
|
||||
$m = $this->getProtectedMethod('nl');
|
||||
$m->invoke($o);
|
||||
$this->assertEquals(PHP_EOL, stream_get_contents($s, - 1, 0));
|
||||
}
|
||||
|
||||
public function testWr()
|
||||
{
|
||||
list ($o, $s) = $this->getOutputRules();
|
||||
|
||||
$m = $this->getProtectedMethod('wr');
|
||||
$m->invoke($o, 'foo');
|
||||
$this->assertEquals('foo', stream_get_contents($s, - 1, 0));
|
||||
}
|
||||
|
||||
public function getEncData()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
false,
|
||||
'&\'<>"',
|
||||
'&\'<>"',
|
||||
'&'<>"'
|
||||
),
|
||||
array(
|
||||
false,
|
||||
'This + is. a < test',
|
||||
'This + is. a < test',
|
||||
'This + is. a < test'
|
||||
),
|
||||
array(
|
||||
false,
|
||||
'.+#',
|
||||
'.+#',
|
||||
'.+#'
|
||||
),
|
||||
|
||||
array(
|
||||
true,
|
||||
'.+#\'',
|
||||
'.+#\'',
|
||||
'.+#''
|
||||
),
|
||||
array(
|
||||
true,
|
||||
'&".<',
|
||||
'&".<',
|
||||
'&".<'
|
||||
),
|
||||
array(
|
||||
true,
|
||||
'&\'<>"',
|
||||
'&\'<>"',
|
||||
'&'<>"'
|
||||
),
|
||||
array(
|
||||
true,
|
||||
"\xc2\xa0\"'",
|
||||
' "\'',
|
||||
' "''
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test basic encoding of text.
|
||||
* @dataProvider getEncData
|
||||
*/
|
||||
public function testEnc($isAttribute, $test, $expected, $expectedEncoded)
|
||||
{
|
||||
list ($o, $s) = $this->getOutputRules();
|
||||
$m = $this->getProtectedMethod('enc');
|
||||
|
||||
$this->assertEquals($expected, $m->invoke($o, $test, $isAttribute));
|
||||
|
||||
list ($o, $s) = $this->getOutputRules(array(
|
||||
'encode_entities' => true
|
||||
));
|
||||
$m = $this->getProtectedMethod('enc');
|
||||
$this->assertEquals($expectedEncoded, $m->invoke($o, $test, $isAttribute));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test basic encoding of text.
|
||||
* @dataProvider getEncData
|
||||
*/
|
||||
public function testEscape($isAttribute, $test, $expected, $expectedEncoded)
|
||||
{
|
||||
list ($o, $s) = $this->getOutputRules();
|
||||
$m = $this->getProtectedMethod('escape');
|
||||
|
||||
$this->assertEquals($expected, $m->invoke($o, $test, $isAttribute));
|
||||
}
|
||||
|
||||
public function booleanAttributes()
|
||||
{
|
||||
return array(
|
||||
array('<img alt="" ismap>'),
|
||||
array('<img alt="">'),
|
||||
array('<input type="radio" readonly>'),
|
||||
array('<input type="radio" checked disabled>'),
|
||||
array('<input type="checkbox" checked disabled>'),
|
||||
array('<input type="radio" value="" checked disabled>'),
|
||||
array('<div data-value=""></div>'),
|
||||
array('<select disabled></select>'),
|
||||
array('<div ng-app></div>'),
|
||||
array('<script defer></script>'),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @dataProvider booleanAttributes
|
||||
*/
|
||||
public function testBooleanAttrs($html)
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html><html lang="en"><body>'.$html.'</body></html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$node = $dom->getElementsByTagName('body')->item(0)->firstChild;
|
||||
|
||||
$m = $this->getProtectedMethod('attrs');
|
||||
$m->invoke($r, $node);
|
||||
|
||||
$content = stream_get_contents($stream, - 1, 0);
|
||||
|
||||
$html = preg_replace('~<[a-z]+(.*)></[a-z]+>~', '\1', $html);
|
||||
$html = preg_replace('~<[a-z]+(.*)/?>~', '\1', $html);
|
||||
|
||||
$this->assertEquals($content, $html);
|
||||
|
||||
}
|
||||
|
||||
public function testAttrs()
|
||||
{
|
||||
$dom = $this->html5->loadHTML('<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('div');
|
||||
|
||||
$m = $this->getProtectedMethod('attrs');
|
||||
$m->invoke($r, $list->item(0));
|
||||
|
||||
$content = stream_get_contents($stream, - 1, 0);
|
||||
$this->assertEquals(' id="foo" class="bar baz"', $content);
|
||||
}
|
||||
|
||||
public function testSvg()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
<svg width="150" height="100" viewBox="0 0 3 2">
|
||||
<rect width="1" height="2" x="0" fill="#008d46" />
|
||||
<rect width="1" height="2" x="1" fill="#ffffff" />
|
||||
<rect width="1" height="2" x="2" fill="#d2232c" />
|
||||
<rect id="Bar" x="300" y="100" width="300" height="100" fill="rgb(255,255,0)">
|
||||
<animate attributeName="x" attributeType="XML" begin="0s" dur="9s" fill="freeze" from="300" to="0" />
|
||||
</rect>
|
||||
</svg>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('svg');
|
||||
$r->element($list->item(0));
|
||||
$contents = stream_get_contents($stream, - 1, 0);
|
||||
$this->assertRegExp('|<svg width="150" height="100" viewBox="0 0 3 2">|', $contents);
|
||||
$this->assertRegExp('|<rect width="1" height="2" x="0" fill="#008d46" />|', $contents);
|
||||
$this->assertRegExp('|<rect id="Bar" x="300" y="100" width="300" height="100" fill="rgb\(255,255,0\)">|', $contents);
|
||||
}
|
||||
|
||||
public function testMath()
|
||||
{
|
||||
$dom = $this->html5->loadHTML(
|
||||
'<!doctype html>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div id="foo" class="bar baz">foo bar baz</div>
|
||||
<math>
|
||||
<mi>x</mi>
|
||||
<csymbol definitionURL="http://www.example.com/mathops/multiops.html#plusminus">
|
||||
<mo>±</mo>
|
||||
</csymbol>
|
||||
<mi>y</mi>
|
||||
</math>
|
||||
</body>
|
||||
</html>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$list = $dom->getElementsByTagName('math');
|
||||
$r->element($list->item(0));
|
||||
$content = stream_get_contents($stream, - 1, 0);
|
||||
$this->assertRegExp('|<math>|', $content);
|
||||
$this->assertRegExp('|<csymbol definitionURL="http://www.example.com/mathops/multiops.html#plusminus">|', $content);
|
||||
}
|
||||
|
||||
public function testProcessorInstruction()
|
||||
{
|
||||
$dom = $this->html5->loadHTMLFragment('<?foo bar ?>');
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$r->processorInstruction($dom->firstChild);
|
||||
$content = stream_get_contents($stream, - 1, 0);
|
||||
$this->assertRegExp('|<\?foo bar \?>|', $content);
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests\Serializer;
|
||||
|
||||
use Masterminds\HTML5\Serializer\OutputRules;
|
||||
use Masterminds\HTML5\Serializer\Traverser;
|
||||
use Masterminds\HTML5\Parser;
|
||||
|
||||
class TraverserTest extends \Masterminds\HTML5\Tests\TestCase
|
||||
{
|
||||
|
||||
protected $markup = '<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is a test.</p>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->html5 = $this->getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Using reflection we make a protected method accessible for testing.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the method on the Traverser class to test.
|
||||
*
|
||||
* @return \ReflectionMethod \ReflectionMethod for the specified method
|
||||
*/
|
||||
public function getProtectedMethod($name)
|
||||
{
|
||||
$class = new \ReflectionClass('\Masterminds\HTML5\Serializer\Traverser');
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
public function getTraverser()
|
||||
{
|
||||
$stream = fopen('php://temp', 'w');
|
||||
|
||||
$dom = $this->html5->loadHTML($this->markup);
|
||||
$t = new Traverser($dom, $stream, $html5->getOptions());
|
||||
|
||||
// We return both the traverser and stream so we can pull from it.
|
||||
return array(
|
||||
$t,
|
||||
$stream
|
||||
);
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
// The traverser needs a place to write the output to. In our case we
|
||||
// use a stream in temp space.
|
||||
$stream = fopen('php://temp', 'w');
|
||||
|
||||
$html5 = $this->getInstance();
|
||||
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$dom = $this->html5->loadHTML($this->markup);
|
||||
|
||||
$t = new Traverser($dom, $stream, $r, $html5->getOptions());
|
||||
|
||||
$this->assertInstanceOf('\Masterminds\HTML5\Serializer\Traverser', $t);
|
||||
}
|
||||
|
||||
public function testFragment()
|
||||
{
|
||||
$html = '<span class="bar">foo</span><span></span><div>bar</div>';
|
||||
$input = new \Masterminds\HTML5\Parser\StringInputStream($html);
|
||||
$dom = $this->html5->parseFragment($input);
|
||||
|
||||
$this->assertInstanceOf('\DOMDocumentFragment', $dom);
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$out = $t->walk();
|
||||
$this->assertEquals($html, stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
|
||||
public function testProcessorInstruction()
|
||||
{
|
||||
$html = '<?foo bar ?>';
|
||||
$input = new \Masterminds\HTML5\Parser\StringInputStream($html);
|
||||
$dom = $this->html5->parseFragment($input);
|
||||
|
||||
$this->assertInstanceOf('\DOMDocumentFragment', $dom);
|
||||
|
||||
$stream = fopen('php://temp', 'w');
|
||||
$r = new OutputRules($stream, $this->html5->getOptions());
|
||||
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
|
||||
|
||||
$out = $t->walk();
|
||||
$this->assertEquals($html, stream_get_contents($stream, - 1, 0));
|
||||
}
|
||||
}
|
27
vendor/masterminds/html5/test/HTML5/TestCase.php
vendored
27
vendor/masterminds/html5/test/HTML5/TestCase.php
vendored
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
namespace Masterminds\HTML5\Tests;
|
||||
|
||||
use Masterminds\HTML5;
|
||||
|
||||
class TestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
const DOC_OPEN = '<!DOCTYPE html><html><head><title>test</title></head><body>';
|
||||
|
||||
const DOC_CLOSE = '</body></html>';
|
||||
|
||||
public function testFoo()
|
||||
{
|
||||
// Placeholder. Why is PHPUnit emitting warnings about no tests?
|
||||
}
|
||||
|
||||
public function getInstance(array $options = array())
|
||||
{
|
||||
return new HTML5($options);
|
||||
}
|
||||
|
||||
protected function wrap($fragment)
|
||||
{
|
||||
return self::DOC_OPEN . $fragment . self::DOC_CLOSE;
|
||||
}
|
||||
}
|
Reference in a new issue