���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home/rickpfrv/wiki.craftaro.com/vendor/wikimedia/parsoid/tests/phpunit/Parsoid/Utils/DOMCompatTest.php
���ѧ٧ѧ�
<?php namespace Test\Parsoid\Utils; use Wikimedia\Parsoid\DOM\Document; use Wikimedia\Parsoid\DOM\Element; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\Utils\DOMCompat; use Wikimedia\Parsoid\Utils\DOMCompat\TokenList; use Wikimedia\Parsoid\Utils\DOMUtils; use Wikimedia\Parsoid\Wt2Html\XMLSerializer; use Wikimedia\TestingAccessWrapper; /** * @coversDefaultClass \Wikimedia\Parsoid\Utils\DOMCompat */ class DOMCompatTest extends \PHPUnit\Framework\TestCase { /** * @covers ::getBody() */ public function testGetBody() { $html = '<html><head><title>Foo</title></head><body id="x"><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $body = DOMCompat::getBody( $doc ); $this->assertSameNode( $body, $doc->getElementById( 'x' ) ); $html = '<html><head><title>Foo</title></head></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED ); $body = DOMCompat::getBody( $doc ); $this->assertNull( $body ); } /** * @covers ::getHead() */ public function testGetHead() { $html = '<html><head id="x"><title>Foo</title></head><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $head = DOMCompat::getHead( $doc ); $this->assertSameNode( $head, $doc->getElementById( 'x' ) ); $html = '<html><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED ); $head = DOMCompat::getHead( $doc ); $this->assertNull( $head ); } /** * @covers ::getTitle() */ public function testGetTitle() { $html = '<html><head><title>Foo</title></head><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $title = DOMCompat::getTitle( $doc ); $this->assertSame( 'Foo', $title ); $html = '<html><head><title> Foo	Bar </title></head><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $title = DOMCompat::getTitle( $doc ); $this->assertSame( 'Foo Bar', $title ); $html = '<html><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED ); $title = DOMCompat::getTitle( $doc ); $this->assertSame( '', $title ); } /** * @covers ::setTitle() */ public function testSetTitle() { // modify <title> if it is exist $html = '<html><head><title>Foo</title></head><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); DOMCompat::setTitle( $doc, 'Bar' ); $title = $doc->getElementsByTagName( 'title' )->item( 0 ); $this->assertInstanceOf( Element::class, $title ); $this->assertSame( 'Bar', $title->textContent ); // ...even if it is not in <head> $html = '<html><body><title>Foo</title><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED ); DOMCompat::setTitle( $doc, 'Bar' ); $title = $doc->getElementsByTagName( 'title' )->item( 0 ); $this->assertInstanceOf( Element::class, $title ); $this->assertSame( 'Bar', $title->textContent ); // append it to <head> if it does not exist $html = '<html><head><style></style></head><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED ); DOMCompat::setTitle( $doc, 'Bar' ); $title = $doc->getElementsByTagName( 'title' )->item( 0 ); $this->assertInstanceOf( Element::class, $title ); $this->assertSame( 'Bar', $title->textContent ); $this->assertNotSame( $title, $title->parentNode->firstChild ); $this->assertSame( $title, $title->parentNode->lastChild ); // bail out if there's no <head> $html = '<html><body><div>y</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED ); DOMCompat::setTitle( $doc, 'Bar' ); $head = $doc->getElementsByTagName( 'head' )->item( 0 ); $this->assertNull( $head ); $title = $doc->getElementsByTagName( 'title' )->item( 0 ); $this->assertNull( $title ); } /** * @covers ::getParentElement() */ public function testGetParentElement() { // has parent element $html = '<html><body id="x"><div>1</div><div id="y">2</div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $element = $doc->getElementById( 'y' ); $this->assertSame( $doc->getElementById( 'x' ), DOMCompat::getParentElement( $element ) ); // no parent element $html = '<html></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $this->assertNull( DOMCompat::getParentElement( $doc->documentElement ) ); // TODO is it possible to have a node with non-Element parent element? } /** * @covers ::getElementById() */ public function testGetElementById() { $html = '<html><body><div id="x"></div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $x = $doc->getElementById( 'x' ); $this->assertSame( $x, DOMCompat::getElementById( $doc, 'x' ) ); // https://bugs.php.net/bug.php?id=77686 $x->parentNode->removeChild( $x ); $this->assertSame( $x, $doc->getElementById( 'x' ) ); $this->assertNull( DOMCompat::getElementById( $doc, 'x' ) ); } /** * @covers ::getLastElementChild() */ public function testGetLastElementChild() { $html = '<html><body><div id="a"></div>1<div id="b"></div><div id="c"></div>3</body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $html = $doc->getElementsByTagName( 'html' )->item( 0 ); '@phan-var Element $html'; /** @var Element $html */ $body = $doc->getElementsByTagName( 'body' )->item( 0 ); '@phan-var Element $body'; /** @var Element $body */ $this->assertSameNode( $doc->getElementById( 'c' ), DOMCompat::getLastElementChild( $body ) ); $this->assertSameNode( $html, DOMCompat::getLastElementChild( $doc ) ); $this->assertSameNode( $body, DOMCompat::getLastElementChild( $html ) ); $html = '<html><body></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $body = $doc->getElementsByTagName( 'body' )->item( 0 ); '@phan-var Element $body'; /** @var Element $body */ $this->assertNull( DOMCompat::getLastElementChild( $body ) ); } /** * @dataProvider provideQuerySelector * @covers ::querySelector() * @param string $html * @param string $selector * @param callback|null $contextCallback * @param string|null $expectedDataIds */ public function testQuerySelector( $html, $selector, $contextCallback, $expectedDataIds ) { $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $context = $contextCallback ? $contextCallback( $doc ) : $doc->documentElement; $result = DOMCompat::querySelector( $context, $selector ); $expectedDataId = $expectedDataIds[0] ?? null; $actualDataId = $result ? $result->getAttribute( 'data-id' ) : null; $this->assertSame( $expectedDataId, $actualDataId ); } /** * @dataProvider provideQuerySelector * @covers ::querySelectorAll() * @param string $html * @param string $selector * @param callback|null $contextCallback * @param string|null $expectedDataIds */ public function testQuerySelectorAll( $html, $selector, $contextCallback, $expectedDataIds ) { $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $context = $contextCallback ? $contextCallback( $doc ) : $doc->documentElement; $results = DOMCompat::querySelectorAll( $context, $selector ); $actualDataIds = []; foreach ( $results as $result ) { $actualDataIds[] = $result->getAttribute( 'data-id' ); } $this->assertSame( $expectedDataIds, $actualDataIds ); } public function provideQuerySelector() { // TODO would be nicer to have separate HTML per test (maybe something like parser tests) $html1 = <<<'HTML' <html><body> <div id="a" class="a" data-id="a"> <div class="b1 b2 b3" data-id="b"> <div rel="c" data-id="c" rel2="x">1</div> <div data-id="empty-div"></div> </div> </div>' <span rel2="x" data-id="span"></span> <div class="e"> <div class="xxx" data-id="x1"></div> </div> <div class="e" id="ctx1"> <div> <div class="xxx" data-id="x2"></div> </div> </div> <div class="f" id="ctx2" data-id="f"> <div class="f xxx" data-id="x3"></div> </div> </body></html> HTML; return [ // simple selectors 'id' => [ 'html' => $html1, 'selector' => '#a', 'context' => null, 'expectedDataId' => [ 'a' ], ], 'simple class' => [ 'html' => $html1, 'selector' => '.a', 'context' => null, 'expectedDataId' => [ 'a' ], ], 'compound class string, start' => [ 'html' => $html1, 'selector' => '.b1', 'context' => null, 'expectedTagHtmls' => [ 'b' ], ], 'compound class string, mid' => [ 'html' => $html1, 'selector' => '.b2', 'context' => null, 'expectedTagHtmls' => [ 'b' ], ], 'compound class string, end' => [ 'html' => $html1, 'selector' => '.b3', 'context' => null, 'expectedTagHtmls' => [ 'b' ], ], 'attribute' => [ 'html' => $html1, 'selector' => '[rel=c]', 'context' => null, 'expectedTagHtmls' => [ 'c' ], ], 'attribute #2' => [ 'html' => $html1, 'selector' => '[rel2=x]', 'context' => null, 'expectedTagHtmls' => [ 'c', 'span' ], ], 'attribute, case sensitive' => [ 'html' => $html1, 'selector' => '[rel=C]', 'context' => null, 'expectedTagHtmls' => [], ], /* not yet supported in css-parser 'attribute, case insensitive' => [ 'html' => $html1, 'selector' => '[rel="C"i]', 'context' => null, 'expectedTagHtmls' => [], ], */ 'attribute word' => [ 'html' => $html1, 'selector' => '[class~=b2]', 'context' => null, 'expectedTagHtmls' => [ 'b' ], ], 'attribute word, case sensitive' => [ 'html' => $html1, 'selector' => '[class~=B2]', 'context' => null, 'expectedTagHtmls' => [], ], /* not yet supported in css-parser 'attribute word, case insensitive' => [ 'html' => $html1, 'selector' => '[class~="B2"i]', 'context' => null, 'expectedTagHtmls' => [ 'b' ], ], */ 'tag' => [ 'html' => $html1, 'selector' => 'span', 'context' => null, 'expectedTagHtmls' => [ 'span' ], ], ':empty' => [ 'html' => $html1, 'selector' => ':empty', 'context' => null, 'expectedTagHtmls' => [ 'empty-div', 'span', 'x1', 'x2', 'x3' ], ], 'recursion' => [ 'html' => $html1, 'selector' => '.f', 'context' => null, 'expectedTagHtmls' => [ 'f', 'x3' ], ], // simple selector sequence 'id + class' => [ 'html' => $html1, 'selector' => '#a.a', 'context' => null, 'expectedTagHtmls' => [ 'a' ], ], 'id + class #2' => [ 'html' => $html1, 'selector' => '.a#a', 'context' => null, 'expectedTagHtmls' => [ 'a' ], ], 'multiple classes' => [ 'html' => $html1, 'selector' => '.b2.b3', 'context' => null, 'expectedTagHtmls' => [ 'b' ], ], 'element + attribute' => [ 'html' => $html1, 'selector' => 'div[rel2=x]', 'context' => null, 'expectedTagHtmls' => [ 'c' ], ], 'star + attribute' => [ 'html' => $html1, 'selector' => '*[rel=c]', 'context' => null, 'expectedTagHtmls' => [ 'c' ], ], // selector 'child' => [ 'html' => $html1, 'selector' => '.e > .xxx', 'context' => null, 'expectedTagHtmls' => [ 'x1' ], ], 'descendant' => [ 'html' => $html1, 'selector' => '.e .xxx', 'context' => null, 'expectedTagHtmls' => [ 'x1', 'x2' ], ], 'selector group' => [ 'html' => $html1, 'selector' => '#a, .e .xxx', 'context' => null, 'expectedTagHtmls' => [ 'a', 'x1', 'x2' ], ], // context 'context check' => [ 'html' => $html1, 'selector' => '.xxx', 'context' => null, 'expectedTagHtmls' => [ 'x1', 'x2', 'x3' ], ], 'does not select outside context' => [ 'html' => $html1, 'selector' => '.xxx', 'context' => static function ( Document $doc ) { return $doc->getElementById( 'ctx1' ); }, 'expectedTagHtmls' => [ 'x2' ], ], 'does not select context' => [ 'html' => $html1, 'selector' => '.f', 'context' => static function ( Document $doc ) { return $doc->getElementById( 'ctx2' ); }, 'expectedTagHtmls' => [ 'x3' ], ], ]; } /** * @covers ::getPreviousElementSibling() */ public function testGetPreviousElementSibling() { $html = '<html><body>0<div id="a"></div>1<div id="b"></div><div id="c"></div>3</body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $a = $doc->getElementById( 'a' ); $b = $doc->getElementById( 'b' ); $c = $doc->getElementById( 'c' ); $this->assertNull( DOMCompat::getPreviousElementSibling( $a ) ); $this->assertSameNode( $a, DOMCompat::getPreviousElementSibling( $b ) ); $this->assertSameNode( $b, DOMCompat::getPreviousElementSibling( $c ) ); } /** * @covers ::getNextElementSibling() */ public function testGetNextElementSibling() { $html = '<html><body>0<div id="a"></div>1<div id="b"></div><div id="c"></div>3</body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $a = $doc->getElementById( 'a' ); $b = $doc->getElementById( 'b' ); $c = $doc->getElementById( 'c' ); $this->assertSameNode( $b, DOMCompat::getNextElementSibling( $a ) ); $this->assertSameNode( $c, DOMCompat::getNextElementSibling( $b ) ); $this->assertNull( DOMCompat::getNextElementSibling( $c ) ); } /** * @covers ::remove() */ public function testRemove() { $html = '<html><body><div id="a"></div><div id="b"><span id="c">1</span></div>2</body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); // do not error when element has no parent $elmt = $doc->createElement( 'div' ); DOMCompat::remove( $elmt ); $b = $doc->getElementById( 'b' ); $this->assertNotNull( $doc->getElementById( 'a' ) ); $this->assertNotNull( $doc->getElementById( 'b' ) ); $this->assertNotNull( $doc->getElementById( 'c' ) ); DOMCompat::remove( $b ); $this->assertNotNull( $doc->getElementById( 'a' ) ); $this->assertSame( '<html><body><div id="a"></div>2</body></html>', DOMCompat::getOuterHTML( $doc->documentElement ) ); // FIXME these fail due to https://bugs.php.net/bug.php?id=77686 $this->markTestSkipped( 'TODO work around PHP #77686' ); $this->assertNull( $doc->getElementById( 'b' ) ); $this->assertNull( $doc->getElementById( 'c' ) ); } /** * @covers ::getInnerHTML() */ public function testGetInnerHTML() { $html = '<html><body>0<div id="a"></div>1<div id="b">2</div><div id="c"></div>3</body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $body = $doc->getElementsByTagName( 'body' )->item( 0 ); '@phan-var Element $body'; /** @var Element $body */ $b = $doc->getElementById( 'b' ); $this->assertSame( '<body>0<div id="a"></div>1<div id="b">2</div><div id="c"></div>3</body>', DOMCompat::getInnerHTML( $doc->documentElement ) ); $this->assertSame( '0<div id="a"></div>1<div id="b">2</div><div id="c"></div>3', DOMCompat::getInnerHTML( $body ) ); $this->assertSame( '2', DOMCompat::getInnerHTML( $b ) ); } /** * @covers ::setInnerHTML() */ public function testSetInnerHTML() { $html = '<html><body><div>1</div><div>2</div>3</body></html>'; $innerHtml = '<div>4</div><!-- 5 -->6'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $body = $doc->getElementsByTagName( 'body' )->item( 0 ); '@phan-var Element $body'; /** @var Element $body */ DOMCompat::setInnerHTML( $body, $innerHtml ); $this->assertSame( "<body>$innerHtml</body>", $doc->saveXML( $body, LIBXML_NSCLEAN ) ); $this->assertSame( '4', $doc->getElementsByTagName( 'body' )->item( 0 )->firstChild->textContent ); } /** * @covers ::getOuterHTML() */ public function testGetOuterHTML() { $html = '<html><body>0<div id="a"></div>1<div id="b">2</div><div id="c"></div>3</body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $body = $doc->getElementsByTagName( 'body' )->item( 0 ); '@phan-var Element $body'; /** @var Element $body */ $b = $doc->getElementById( 'b' ); $this->assertSame( '<html><body>0<div id="a"></div>1<div id="b">2</div><div id="c"></div>3</body></html>', DOMCompat::getOuterHTML( $doc->documentElement ) ); $this->assertSame( '<body>0<div id="a"></div>1<div id="b">2</div><div id="c"></div>3</body>', DOMCompat::getOuterHTML( $body ) ); $this->assertSame( '<div id="b">2</div>', DOMCompat::getOuterHTML( $b ) ); } /** * @covers ::getClassList() * @covers \Wikimedia\Parsoid\Utils\DOMCompat\TokenList */ public function testGetClassList() { $html = '<html><body><div id="x" class=" a b	c "></div></body></html>'; $doc = DOMCompat::newDocument( true ); $doc->loadHTML( $html ); $x = $doc->getElementById( 'x' ); $classList = DOMCompat::getClassList( $x ); $this->assertInstanceOf( TokenList::class, $classList ); $this->assertCount( 3, $classList ); $this->assertTrue( $classList->contains( 'a' ) ); $this->assertTrue( $classList->contains( 'b' ) ); $this->assertTrue( $classList->contains( 'c' ) ); $this->assertFalse( $classList->contains( 'd' ) ); $this->assertSame( [ 'a', 'b', 'c' ], iterator_to_array( $classList ) ); // make sure rewinding works $this->assertSame( [ 'a', 'b', 'c' ], iterator_to_array( $classList ) ); $classList->add( 'd' ); $classList->remove( 'b' ); $this->assertFalse( $classList->contains( 'b' ) ); $this->assertTrue( $classList->contains( 'd' ) ); $this->assertSame( [ 'a', 'c', 'd' ], iterator_to_array( $classList ) ); $this->assertSame( '<div id="x" class="a c d"></div>', DOMCompat::getOuterHTML( $x ) ); $x->setAttribute( 'class', 'e f g' ); $this->assertSame( [ 'e', 'f', 'g' ], iterator_to_array( $classList ) ); $classList->add( 'a' ); $classList->remove( 'g' ); $this->assertSame( 'e f a', $x->getAttribute( 'class' ) ); } /** * @covers ::stripAndCollapseASCIIWhitespace() * @dataProvider provideStripAndCollapseASCIIWhitespace */ public function testStripAndCollapseASCIIWhitespace( $input, $expectedOutput ) { $domCompat = TestingAccessWrapper::newFromClass( DOMCompat::class ); $actualOutput = $domCompat->stripAndCollapseASCIIWhitespace( $input ); $this->assertSame( $expectedOutput, $actualOutput ); } public function provideStripAndCollapseASCIIWhitespace() { return [ [ ' foo ', 'foo' ], [ " \n foo \t \n bar ", 'foo bar' ], [ "foo\r\fbar", 'foo bar' ], [ " \n ", '' ], ]; } private function assertSameNode( Node $expected, Node $actual, $message = '' ) { if ( !$expected->isSameNode( $actual ) ) { // try to give a somewhat informative error $actualHtml = XMLSerializer::serialize( $actual )['html']; $expectedHtml = XMLSerializer::serialize( $expected )['html']; $this->assertSame( $expectedHtml, $actualHtml, $message ); $this->assertSame( $expected, $actual, $message ); } else { $this->assertTrue( true ); } } /** * See https://bugs.php.net/bug.php?id=78221 for the upstream bug * we're working around here. * @covers ::normalize() * @dataProvider provideNormalize */ public function testNormalize( $textNodeCount, $interleaveSpan, $expectedNodeCount ) { $doc = DOMCompat::newDocument( true ); $doc->loadXML( "<html><body></body></html>" ); $body = $doc->getElementsByTagName( 'body' )->item( 0 ); $div = $doc->createElement( 'div' ); $body->appendChild( $div ); while ( $textNodeCount > 0 ) { $div->appendChild( $doc->createTextNode( '' ) ); if ( $interleaveSpan ) { $div->appendChild( $doc->createElement( 'span' ) ); } $textNodeCount--; } DOMCompat::normalize( $body ); $this->assertSame( $expectedNodeCount, $div->childNodes->length ); } public function provideNormalize() { return [ [ "textNodeCount" => 1, "interleaveSpan" => false, "expected" => 0 ], [ "textNodeCount" => 5, "interleaveSpan" => false, "expected" => 0 ], [ "textNodeCount" => 1, "interleaveSpan" => true, "expected" => 1 ], [ "textNodeCount" => 5, "interleaveSpan" => true, "expected" => 5 ], ]; } /** * @covers ::setIdAttribute */ public function testSetIdAttribute() { $doc = DOMUtils::parseHTML( "<p class=xyz>Hello, world</p>" ); $head = DOMCompat::getHead( $doc ); $elmt = $doc->createElement( 'div' ); $head->appendChild( $elmt ); DOMCompat::setIdAttribute( $elmt, "this-is-an-id" ); // Note we're testing the "fast path" native implementation here, // not the workaround version in DOMCompat::getElementById() $q = $doc->getElementById( 'this-is-an-id' ); $this->assertNotEquals( $q, null ); $this->assertEquals( 'this-is-an-id', $q->getAttribute( 'id' ) ); } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | ���֧ߧ֧�ѧ�ڧ� ����ѧߧڧ��: 0.7 |
proxy
|
phpinfo
|
���ѧ����ۧܧ�