653 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			653 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Masterminds\HTML5\Tests\Serializer;
 | 
						|
 | 
						|
use Masterminds\HTML5\Serializer\OutputRules;
 | 
						|
use Masterminds\HTML5\Serializer\Traverser;
 | 
						|
use Masterminds\HTML5;
 | 
						|
 | 
						|
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>';
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var HTML5
 | 
						|
     */
 | 
						|
    protected $html5;
 | 
						|
 | 
						|
    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 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));
 | 
						|
    }
 | 
						|
 | 
						|
    public 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);
 | 
						|
    }
 | 
						|
 | 
						|
    public function testAddressTag()
 | 
						|
    {
 | 
						|
        $dom = $this->html5->loadHTML(
 | 
						|
            '<!doctype html>
 | 
						|
    <html lang="en">
 | 
						|
      <body>
 | 
						|
        <address>
 | 
						|
            <a href="../People/Raggett/">Dave Raggett</a>,
 | 
						|
            <a href="../People/Arnaud/">Arnaud Le Hors</a>,
 | 
						|
            contact persons for the <a href="Activity">W3C HTML Activity</a>
 | 
						|
        </address>
 | 
						|
      </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('address');
 | 
						|
        $r->element($list->item(0));
 | 
						|
        $contents = stream_get_contents($stream, -1, 0);
 | 
						|
 | 
						|
        $this->assertRegExp('|<address>|', $contents);
 | 
						|
        $this->assertRegExp('|<a href="../People/Raggett/">Dave Raggett</a>,|', $contents);
 | 
						|
        $this->assertRegExp('|<a href="../People/Arnaud/">Arnaud Le Hors</a>,|', $contents);
 | 
						|
        $this->assertRegExp('|contact persons for the <a href="Activity">W3C HTML Activity</a>|', $contents);
 | 
						|
        $this->assertRegExp('|</address>|', $contents);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Ensure direct DOM manipulation doesn't break TEXT_RAW elements (iframe, script, etc...).
 | 
						|
     */
 | 
						|
    public function testHandlingInvalidRawContent()
 | 
						|
    {
 | 
						|
        $dom = $this->html5->loadHTML(
 | 
						|
    '<!doctype html>
 | 
						|
<html lang="en" id="base">
 | 
						|
    <body>
 | 
						|
       <script id="template" type="x-tmpl-mustache">
 | 
						|
           <h1>Hello!</h1>
 | 
						|
       </script>
 | 
						|
    </body>
 | 
						|
</html>');
 | 
						|
 | 
						|
        $badNode = $dom->createElement('p', 'Bar');
 | 
						|
 | 
						|
        // modify the content of the TEXT_RAW element: <script id="template"> appending dom nodes
 | 
						|
        $styleElement = $dom->getElementById('template');
 | 
						|
        $styleElement->appendChild($badNode);
 | 
						|
 | 
						|
        $contents = $this->html5->saveHTML($dom);
 | 
						|
 | 
						|
        $this->assertTrue(false !== strpos($contents, '<script id="template" type="x-tmpl-mustache">
 | 
						|
           <h1>Hello!</h1>
 | 
						|
       <p>Bar</p></script>'));
 | 
						|
    }
 | 
						|
}
 |