From 9a9c04512e5dcb77c7fe5d850e3f2a0250cc160e Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 18 Jan 2017 20:07:16 +0100 Subject: * Motor Sport Magazine feed provider --- .../test/Tests/QueryPath/CSS/DOMTraverserTest.php | 357 ++++ .../test/Tests/QueryPath/CSS/ParserTest.php | 520 ++++++ .../test/Tests/QueryPath/CSS/PseudoClassTest.php | 828 +++++++++ .../QueryPath/CSS/QueryPathEventHandlerTest.php | 1439 +++++++++++++++ .../test/Tests/QueryPath/CSS/SelectorTest.php | 120 ++ .../test/Tests/QueryPath/CSS/TokenTest.php | 23 + .../test/Tests/QueryPath/CSS/UtilTest.php | 51 + .../test/Tests/QueryPath/DOMQueryTest.php | 1865 ++++++++++++++++++++ .../test/Tests/QueryPath/EntitiesTest.php | 54 + .../test/Tests/QueryPath/ExtensionTest.php | 153 ++ .../test/Tests/QueryPath/Extensions/QPXMLTest.php | 41 + .../test/Tests/QueryPath/Extensions/QPXSLTest.php | 60 + lib/querypath/test/Tests/QueryPath/OptionsTest.php | 60 + .../test/Tests/QueryPath/QueryPathTest.php | 56 + lib/querypath/test/Tests/QueryPath/TestCase.php | 22 + lib/querypath/test/Tests/QueryPath/XMLIshTest.php | 63 + 16 files changed, 5712 insertions(+) create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/DOMTraverserTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/ParserTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/PseudoClassTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/QueryPathEventHandlerTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/SelectorTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/TokenTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/CSS/UtilTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/DOMQueryTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/EntitiesTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/ExtensionTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/Extensions/QPXMLTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/Extensions/QPXSLTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/OptionsTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/QueryPathTest.php create mode 100644 lib/querypath/test/Tests/QueryPath/TestCase.php create mode 100644 lib/querypath/test/Tests/QueryPath/XMLIshTest.php (limited to 'lib/querypath/test/Tests') diff --git a/lib/querypath/test/Tests/QueryPath/CSS/DOMTraverserTest.php b/lib/querypath/test/Tests/QueryPath/CSS/DOMTraverserTest.php new file mode 100644 index 0000000..9542482 --- /dev/null +++ b/lib/querypath/test/Tests/QueryPath/CSS/DOMTraverserTest.php @@ -0,0 +1,357 @@ +load($this->xml_file); + + $splos = new \SPLObjectStorage(); + $splos->attach($dom); + + $traverser = new DOMTraverser($splos); + + $this->assertInstanceOf('\QueryPath\CSS\Traverser', $traverser); + $this->assertInstanceOf('\QueryPath\CSS\DOMTraverser', $traverser); + } + + protected function traverser() { + $dom = new \DOMDocument('1.0'); + $dom->load($this->xml_file); + + $splos = new \SPLObjectStorage(); + $splos->attach($dom->documentElement); + + $traverser = new DOMTraverser($splos); + + return $traverser; + } + + protected function find($selector) { + return $this->traverser()->find($selector)->matches(); + } + + public function testFind() { + $res = $this->traverser()->find('root'); + + // Ensure that return contract is not violated. + $this->assertInstanceOf('\QueryPath\CSS\Traverser', $res); + } + + public function testMatches() { + $res = $this->traverser()->matches(); + $this->assertEquals(1, count($res)); + } + + public function testMatchElement() { + // Canary: If element does not exist, must return FALSE. + $matches = $this->find('NO_SUCH_ELEMENT'); + $this->assertEquals(0, count($matches)); + + // Test without namespace + $matches = $this->find('root'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('crowded'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('outside'); + $this->assertEquals(3, count($matches)); + + // Check nested elements. + $matches = $this->find('a'); + $this->assertEquals(3, count($matches)); + + // Test wildcard. + $traverser = $this->traverser(); + $matches = $traverser->find('*')->matches(); + $actual= $traverser->getDocument()->getElementsByTagName('*'); + $this->assertEquals($actual->length, count($matches)); + + + // Test with namespace + //$this->markTestIncomplete(); + $matches = $this->find('ns_test'); + $this->assertEquals(3, count($matches)); + + $matches = $this->find('test|ns_test'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('test|ns_test>ns_attr'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('*|ns_test'); + $this->assertEquals(3, count($matches)); + + $matches = $this->find('test|*'); + $this->assertEquals(1, count($matches)); + + // Test where namespace is declared on the element. + $matches = $this->find('newns|my_element'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('test|ns_test>newns|my_element'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('test|*>newns|my_element'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('*|ns_test>newns|my_element'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('*|*>newns|my_element'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('*>newns|my_element'); + $this->assertEquals(1, count($matches)); + } + + public function testMatchAttributes() { + + $matches = $this->find('crowded[attr1]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('crowded[attr1=one]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('crowded[attr2^=tw]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('classtest[class~=two]'); + $this->assertEquals(1, count($matches)); + $matches = $this->find('classtest[class~=one]'); + $this->assertEquals(1, count($matches)); + $matches = $this->find('classtest[class~=seven]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('crowded[attr0]'); + $this->assertEquals(0, count($matches)); + + $matches = $this->find('[level=1]'); + $this->assertEquals(3, count($matches)); + + $matches = $this->find('[attr1]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('[test|myattr]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('[test|myattr=foo]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('[*|myattr=foo]'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('[|myattr=foo]'); + $this->assertEquals(0, count($matches)); + + $matches = $this->find('[|level=1]'); + $this->assertEquals(3, count($matches)); + + $matches = $this->find('[*|level=1]'); + $this->assertEquals(4, count($matches)); + + // Test namespace on attr where namespace + // is declared on that element + $matches = $this->find('[nuther|ping]'); + $this->assertEquals(1, count($matches)); + + // Test multiple namespaces on an element. + $matches = $this->find('[*|ping=3]'); + $this->assertEquals(1, count($matches)); + + // Test multiple namespaces on an element. + $matches = $this->find('[*|ping]'); + $this->assertEquals(1, count($matches)); + } + + public function testMatchId() { + $matches = $this->find('idtest#idtest-one'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('#idtest-one'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('outter#fake'); + $this->assertEquals(0, count($matches)); + + $matches = $this->find('#fake'); + $this->assertEquals(0, count($matches)); + } + + public function testMatchClasses() { + // Basic test. + $matches = $this->find('a.a1'); + $this->assertEquals(1, count($matches)); + + // Count multiple. + $matches = $this->find('.first'); + $this->assertEquals(2, count($matches)); + + // Grab one in the middle of a list. + $matches = $this->find('.four'); + $this->assertEquals(1, count($matches)); + + // One element with two classes. + $matches = $this->find('.three.four'); + $this->assertEquals(1, count($matches)); + } + + public function testMatchPseudoClasses() { + + $matches = $this->find('ul>li:first'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('ul>li:not(.first)'); + $this->assertEquals(5, count($matches)); + + } + + public function testMatchPseudoElements() { + $matches = $this->find('p::first-line'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('p::first-letter'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('p::before'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('p::after'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('bottom::after'); + $this->assertEquals(0, count($matches)); + } + + public function testCombineAdjacent() { + // Simple test + $matches = $this->find('idtest + p'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('p', $m->tagName); + } + + // Test ignoring PCDATA + $matches = $this->find('p + one'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('one', $m->tagName); + } + + // Test that non-adjacent elements don't match. + $matches = $this->find('idtest + one'); + foreach ($matches as $m) { + $this->assertEquals('one', $m->tagName); + } + $this->assertEquals(0, count($matches), 'Non-adjacents should not match.'); + + // Test that elements BEFORE don't match + $matches = $this->find('one + p'); + foreach ($matches as $m) { + $this->assertEquals('one', $m->tagName); + } + $this->assertEquals(0, count($matches), 'Match only if b is after a'); + } + + public function testCombineSibling() { + // Canary: + $matches = $this->find('one ~ two'); + $this->assertEquals(0, count($matches)); + + // Canary 2: + $matches = $this->find('NO_SUCH_ELEMENT ~ two'); + $this->assertEquals(0, count($matches)); + + // Simple test + $matches = $this->find('idtest ~ p'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('p', $m->tagName); + } + + // Simple test + $matches = $this->find('outside ~ p'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('p', $m->tagName); + } + + // Matches only go left, not right. + $matches = $this->find('p ~ outside'); + $this->assertEquals(0, count($matches)); + } + public function testCombineDirectDescendant() { + // Canary: + $matches = $this->find('one > four'); + $this->assertEquals(0, count($matches)); + + $matches = $this->find('two>three'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('three', $m->tagName); + } + + $matches = $this->find('one > two > three'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('three', $m->tagName); + } + + $matches = $this->find('a>a>a'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('a>a'); + $this->assertEquals(2, count($matches)); + } + public function testCombineAnyDescendant() { + // Canary + $matches = $this->find('four one'); + $this->assertEquals(0, count($matches)); + + $matches = $this->find('one two'); + $this->assertEquals(1, count($matches)); + foreach ($matches as $m) { + $this->assertEquals('two', $m->tagName); + } + + $matches = $this->find('one four'); + $this->assertEquals(1, count($matches)); + + $matches = $this->find('a a'); + $this->assertEquals(2, count($matches)); + + $matches = $this->find('root two four'); + $this->assertEquals(1, count($matches)); + } + public function testMultipleSelectors() { + // fprintf(STDOUT, "=========TEST=========\n\n"); + $matches = $this->find('one, two'); + $this->assertEquals(2, count($matches)); + } + +} + diff --git a/lib/querypath/test/Tests/QueryPath/CSS/ParserTest.php b/lib/querypath/test/Tests/QueryPath/CSS/ParserTest.php new file mode 100644 index 0000000..981ddd1 --- /dev/null +++ b/lib/querypath/test/Tests/QueryPath/CSS/ParserTest.php @@ -0,0 +1,520 @@ +getMock('\QueryPath\Tests\TestEventHandler', array($method)); + $mock->expects($this->once()) + ->method($method) + ->with($this->equalTo('mytest')); + return $mock; + } + + public function testElementID() { + $mock = $this->getMockHandler('elementID'); + $parser = new Parser('#mytest', $mock); + $parser->parse(); + + } + + public function testElement() { + + // Without namespace + $mock = $this->getMockHandler('element'); + $parser = new Parser('mytest', $mock); + $parser->parse(); + + // With empty namespace + $mock = $this->getMockHandler('element'); + $parser = new Parser('|mytest', $mock); + $parser->parse(); + } + + public function testElementNS() { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('elementNS')); + $mock->expects($this->once()) + ->method('elementNS') + ->with($this->equalTo('mytest'), $this->equalTo('myns')); + + $parser = new Parser('myns|mytest', $mock); + $parser->parse(); + + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('elementNS')); + $mock->expects($this->once()) + ->method('elementNS') + ->with($this->equalTo('mytest'), $this->equalTo('*')); + + $parser = new Parser('*|mytest', $mock); + $parser->parse(); + + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('anyElementInNS')); + $mock->expects($this->once()) + ->method('anyElementInNS') + ->with($this->equalTo('*')); + + $parser = new Parser('*|*', $mock); + $parser->parse(); + } + + public function testAnyElement() { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('anyElement', 'element')); + $mock->expects($this->once()) + ->method('anyElement'); + + $parser = new Parser('*', $mock); + $parser->parse(); + } + + public function testAnyElementInNS() { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('anyElementInNS', 'element')); + $mock->expects($this->once()) + ->method('anyElementInNS') + ->with($this->equalTo('myns')); + + $parser = new Parser('myns|*', $mock); + $parser->parse(); + } + + public function testElementClass() { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('elementClass')); + $mock->expects($this->once()) + ->method('elementClass') + ->with($this->equalTo('myclass')); + + $parser = new Parser('.myclass', $mock); + $parser->parse(); + } + + public function testPseudoClass() { + + // Test empty pseudoclass + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('pseudoClass')); + $mock->expects($this->once()) + ->method('pseudoClass') + ->with($this->equalTo('mypclass')); + + $parser = new Parser('myele:mypclass', $mock); + $parser->parse(); + + // Test pseudoclass with value + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('pseudoClass')); + $mock->expects($this->once()) + ->method('pseudoClass') + ->with($this->equalTo('mypclass'), $this->equalTo('myval')); + + $parser = new Parser('myele:mypclass(myval)', $mock); + $parser->parse(); + + // Test pseudclass with pseudoclass: + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('pseudoClass')); + $mock->expects($this->once()) + ->method('pseudoClass') + ->with($this->equalTo('mypclass'), $this->equalTo(':anotherPseudo')); + + $parser = new Parser('myele:mypclass(:anotherPseudo)', $mock); + $parser->parse(); + + } + + public function testPseudoElement() { + // Test pseudo-element + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('pseudoElement')); + $mock->expects($this->once()) + ->method('pseudoElement') + ->with($this->equalTo('mypele')); + + $parser = new Parser('myele::mypele', $mock); + $parser->parse(); + } + + public function testDirectDescendant() { + // Test direct Descendant + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('directDescendant')); + $mock->expects($this->once()) + ->method('directDescendant'); + + $parser = new Parser('ele1 > ele2', $mock); + $parser->parse(); + + } + + public function testAnyDescendant() { + // Test direct Descendant + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('anyDescendant')); + $mock->expects($this->once()) + ->method('anyDescendant'); + + $parser = new Parser('ele1 .class', $mock); + $parser->parse(); + + } + + public function testAdjacent() { + // Test sibling + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('adjacent')); + $mock->expects($this->once()) + ->method('adjacent'); + + $parser = new Parser('ele1 + ele2', $mock); + $parser->parse(); + } + + public function testSibling() { + // Test adjacent + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('sibling')); + $mock->expects($this->once()) + ->method('sibling'); + + $parser = new Parser('ele1 ~ ele2', $mock); + $parser->parse(); + } + + public function testAnotherSelector() { + // Test adjacent + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('anotherSelector')); + $mock->expects($this->once()) + ->method('anotherSelector'); + + $parser = new Parser('ele1 , ele2', $mock); + $parser->parse(); + } + + /** + * @expectedException \QueryPath\CSS\ParseException + */ + public function testIllegalAttribute() { + + // Note that this is designed to test throwError() as well as + // bad selector handling. + + $parser = new Parser('[test=~far]', new TestEventHandler()); + try { + $parser->parse(); + } + catch (Exception $e) { + //print $e->getMessage(); + throw $e; + } + } + + public function testAttribute() { + $selectors = array( + 'element[attr]' => 'attr', + '*[attr]' => 'attr', + 'element[attr]:class' => 'attr', + 'element[attr2]' => 'attr2', // Issue # + ); + foreach ($selectors as $filter => $expected) { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('attribute')); + $mock->expects($this->once()) + ->method('attribute') + ->with($this->equalTo($expected)); + + $parser = new Parser($filter, $mock); + $parser->parse(); + } + + $selectors = array( + '*[attr="value"]' => array('attr','value',EventHandler::isExactly), + '*[attr^="value"]' => array('attr','value',EventHandler::beginsWith), + '*[attr$="value"]' => array('attr','value',EventHandler::endsWith), + '*[attr*="value"]' => array('attr','value',EventHandler::containsInString), + '*[attr~="value"]' => array('attr','value',EventHandler::containsWithSpace), + '*[attr|="value"]' => array('attr','value',EventHandler::containsWithHyphen), + + // This should act like [attr="value"] + '*[|attr="value"]' => array('attr', 'value', EventHandler::isExactly), + + // This behavior is displayed in the spec, but not accounted for in the + // grammar: + '*[attr=value]' => array('attr','value',EventHandler::isExactly), + + // Should be able to escape chars using backslash. + '*[attr="\.value"]' => array('attr','.value',EventHandler::isExactly), + '*[attr="\.\]\]\]"]' => array('attr','.]]]',EventHandler::isExactly), + + // Backslash-backslash should resolve to single backslash. + '*[attr="\\\c"]' => array('attr','\\c',EventHandler::isExactly), + + // Should return an empty value. It seems, though, that a value should be + // passed here. + '*[attr=""]' => array('attr','',EventHandler::isExactly), + ); + foreach ($selectors as $filter => $expected) { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('attribute')); + $mock->expects($this->once()) + ->method('attribute') + ->with($this->equalTo($expected[0]), $this->equalTo($expected[1]), $this->equalTo($expected[2])); + + $parser = new Parser($filter, $mock); + $parser->parse(); + } + } + + public function testAttributeNS() { + $selectors = array( + '*[ns|attr="value"]' => array('attr', 'ns', 'value',EventHandler::isExactly), + '*[*|attr^="value"]' => array('attr', '*', 'value',EventHandler::beginsWith), + '*[*|attr|="value"]' => array('attr', '*', 'value',EventHandler::containsWithHyphen), + ); + + foreach ($selectors as $filter => $expected) { + $mock = $this->getMock('\QueryPath\Tests\TestEventHandler', array('attributeNS')); + $mock->expects($this->once()) + ->method('attributeNS') + ->with($this->equalTo($expected[0]), $this->equalTo($expected[1]), $this->equalTo($expected[2]), $this->equalTo($expected[3])); + + $parser = new Parser($filter, $mock); + $parser->parse(); + } + } + + // Test things that should break... + + /** + * @expectedException \QueryPath\CSS\ParseException + */ + public function testIllegalCombinators1() { + $handler = new TestEventHandler(); + $parser = new Parser('ele1 > > ele2', $handler); + $parser->parse(); + } + + /** + * @expectedException \QueryPath\CSS\ParseException + */ + public function testIllegalCombinators2() { + $handler = new TestEventHandler(); + $parser = new Parser('ele1+ ,ele2', $handler); + $parser->parse(); + } + + /** + * @expectedException \QueryPath\CSS\ParseException + */ + public function testIllegalID() { + $handler = new TestEventHandler(); + $parser = new Parser('##ID', $handler); + $parser->parse(); + } + + // Test combinations + + public function testElementNSClassAndAttribute() { + + $expect = array( + new TestEvent(TestEvent::elementNS, 'element', 'ns'), + new TestEvent(TestEvent::elementClass, 'class'), + new TestEvent(TestEvent::attribute, 'name', 'value', EventHandler::isExactly), + ); + $selector = 'ns|element.class[name="value"]'; + + $handler = new TestEventHandler(); + $handler->expects($expect); + $parser = new Parser($selector, $handler); + $parser->parse(); + $this->assertTrue($handler->success()); + + // Again, with spaces this time: + $selector = ' ns|element. class[ name = "value" ]'; + + $handler = new TestEventHandler(); + $handler->expects($expect); + $parser = new Parser($selector, $handler); + $parser->parse(); + + //$handler->dumpStack(); + $this->assertTrue($handler->success()); + } + + public function testAllCombo() { + + $selector = '*|ele1 > ele2.class1 + ns1|ele3.class2[attr=simple] ~ + .class2[attr2~="longer string of text."]:pseudoClass(value) + .class3::pseudoElement'; + $expect = array( + new TestEvent(TestEvent::elementNS, 'ele1', '*'), + new TestEvent(TestEvent::directDescendant), + new TestEvent(TestEvent::element, 'ele2'), + new TestEvent(TestEvent::elementClass, 'class1'), + new TestEvent(TestEvent::adjacent), + new TestEvent(TestEvent::elementNS, 'ele3', 'ns1'), + new TestEvent(TestEvent::elementClass, 'class2'), + new TestEvent(TestEvent::attribute, 'attr', 'simple', EventHandler::isExactly), + new TestEvent(TestEvent::sibling), + new TestEvent(TestEvent::elementClass, 'class2'), + new TestEvent(TestEvent::attribute, 'attr2', 'longer string of text.', EventHandler::containsWithSpace), + new TestEvent(TestEvent::pseudoClass, 'pseudoClass', 'value'), + new TestEvent(TestEvent::anyDescendant), + new TestEvent(TestEvent::elementClass, 'class3'), + new TestEvent(TestEvent::pseudoElement, 'pseudoElement'), + ); + + + $handler = new TestEventHandler(); + $handler->expects($expect); + $parser = new Parser($selector, $handler); + $parser->parse(); + + //$handler->dumpStack(); + + $this->assertTrue($handler->success()); + + /* + // Again, with spaces this time: + $selector = ' *|ele1 > ele2. class1 + ns1|ele3. class2[ attr=simple] ~ .class2[attr2 ~= "longer string of text."]:pseudoClass(value) .class3::pseudoElement'; + + $handler = new TestEventHandler(); + $handler->expects($expect); + $parser = new Parser($selector, $handler); + $parser->parse(); + + $handler->dumpStack(); + $this->assertTrue($handler->success()); + */ + } +} + +/** + * Testing harness for the EventHandler. + * + * @ingroup querypath_tests + * @group CSS + */ +class TestEventHandler implements EventHandler { + var $stack = NULL; + var $expect = array(); + + public function __construct() { + $this->stack = array(); + } + + public function getStack() { + return $this->stack; + } + + public function dumpStack() { + print "\nExpected:\n"; + $format = "Element %d: %s\n"; + foreach ($this->expect as $item) { + printf($format, $item->eventType(), implode(',', $item->params())); + } + + print "Got:\n"; + foreach($this->stack as $item){ + printf($format, $item->eventType(), implode(',', $item->params())); + } + } + + public function expects($stack) { + $this->expect = $stack; + } + + public function success() { + return ($this->expect == $this->stack); + } + + public function elementID($id) { + $this->stack[] = new TestEvent(TestEvent::elementID, $id); + } + public function element($name) { + $this->stack[] = new TestEvent(TestEvent::element, $name); + } + public function elementNS($name, $namespace = NULL){ + $this->stack[] = new TestEvent(TestEvent::elementNS, $name, $namespace); + } + public function anyElement(){ + $this->stack[] = new TestEvent(TestEvent::anyElement); + } + public function anyElementInNS($ns){ + $this->stack[] = new TestEvent(TestEvent::anyElementInNS, $ns); + } + public function elementClass($name){ + $this->stack[] = new TestEvent(TestEvent::elementClass, $name); + } + public function attribute($name, $value = NULL, $operation = EventHandler::isExactly){ + $this->stack[] = new TestEvent(TestEvent::attribute, $name, $value, $operation); + } + public function attributeNS($name, $ns, $value = NULL, $operation = EventHandler::isExactly){ + $this->stack[] = new TestEvent(TestEvent::attributeNS, $name, $ns, $value, $operation); + } + public function pseudoClass($name, $value = NULL){ + $this->stack[] = new TestEvent(TestEvent::pseudoClass, $name, $value); + } + public function pseudoElement($name){ + $this->stack[] = new TestEvent(TestEvent::pseudoElement, $name); + } + public function directDescendant(){ + $this->stack[] = new TestEvent(TestEvent::directDescendant); + } + public function anyDescendant() { + $this->stack[] = new TestEvent(TestEvent::anyDescendant); + } + public function adjacent(){ + $this->stack[] = new TestEvent(TestEvent::adjacent); + } + public function anotherSelector(){ + $this->stack[] = new TestEvent(TestEvent::anotherSelector); + } + public function sibling(){ + $this->stack[] = new TestEvent(TestEvent::sibling); + } +} + +/** + * Simple utility object for use with the TestEventHandler. + * + * @ingroup querypath_tests + * @group CSS + */ +class TestEvent { + const elementID = 0; + const element = 1; + const elementNS = 2; + const anyElement = 3; + const elementClass = 4; + const attribute = 5; + const attributeNS = 6; + const pseudoClass = 7; + const pseudoElement = 8; + const directDescendant = 9; + const adjacent = 10; + const anotherSelector = 11; + const sibling = 12; + const anyElementInNS = 13; + const anyDescendant = 14; + + var $type = NULL; + var $params = NULL; + + public function __construct($event_type) { + $this->type = $event_type; + $args = func_get_args(); + array_shift($args); + $this->params = $args; + } + + public function eventType() { + return $this->type; + } + + public function params() { + return $this->params; + } +} diff --git a/lib/querypath/test/Tests/QueryPath/CSS/PseudoClassTest.php b/lib/querypath/test/Tests/QueryPath/CSS/PseudoClassTest.php new file mode 100644 index 0000000..6798b1c --- /dev/null +++ b/lib/querypath/test/Tests/QueryPath/CSS/PseudoClassTest.php @@ -0,0 +1,828 @@ +loadXML($string); + + $found = $doc->getElementsByTagName($tagname)->item(0); + + return array($found, $doc->documentElement); + + } + + /** + * @expectedException \QueryPath\CSS\ParseException + */ + public function testUnknownPseudoClass() { + $xml = 'test'; + + list($ele, $root) = $this->doc($xml, 'foo'); + $ps = new PseudoClass(); + + $ps->elementMatches('TotallyFake', $ele, $root); + } + + public function testLang() { + $xml = 'test'; + + list($ele, $root) = $this->doc($xml, 'foo'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('lang', $ele, $root, 'en-US'); + $this->assertTrue($ret); + $ret = $ps->elementMatches('lang', $ele, $root, 'en'); + $this->assertTrue($ret); + $ret = $ps->elementMatches('lang', $ele, $root, 'fr-FR'); + $this->assertFalse($ret); + $ret = $ps->elementMatches('lang', $ele, $root, 'fr'); + $this->assertFalse($ret); + + + // Check on ele that doesn't have lang. + $ret = $ps->elementMatches('lang', $root, $root, 'fr'); + $this->assertFalse($ret); + + } + + public function testLangNS() { + $xml = 'test'; + + list($ele, $root) = $this->doc($xml, 'foo'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('lang', $ele, $root, 'en-US'); + $this->assertTrue($ret); + $ret = $ps->elementMatches('lang', $ele, $root, 'en'); + $this->assertTrue($ret); + $ret = $ps->elementMatches('lang', $ele, $root, 'fr-FR'); + $this->assertFalse($ret); + $ret = $ps->elementMatches('lang', $ele, $root, 'fr'); + $this->assertFalse($ret); + + + // Check on ele that doesn't have lang. + $ret = $ps->elementMatches('lang', $root, $root, 'fr'); + $this->assertFalse($ret); + } + + public function testFormType() { + $xml = 'test'; + + list($ele, $root) = $this->doc($xml, 'foo'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('submit', $ele, $root); + $this->assertTrue($ret); + + $ret = $ps->elementMatches('reset', $ele, $root); + $this->assertFalse($ret); + + } + + public function testHasAttribute() { + $xml = 'test'; + + list($ele, $root) = $this->doc($xml, 'foo'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('enabled', $ele, $root); + $this->assertTrue($ret); + $ret = $ps->elementMatches('disabled', $ele, $root); + $this->assertFalse($ret); + } + + public function testHeader() { + $xml = '

TEST

'; + + list($ele, $root) = $this->doc($xml, 'h1'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('header', $ele, $root); + $this->assertTrue($ret); + + list($ele, $root) = $this->doc($xml, 'H6'); + $ret = $ps->elementMatches('header', $ele, $root); + $this->assertTrue($ret); + + list($ele, $root) = $this->doc($xml, 'hi'); + $ret = $ps->elementMatches('header', $ele, $root); + $this->assertFalse($ret); + list($ele, $root) = $this->doc($xml, 'h1i'); + $ret = $ps->elementMatches('header', $ele, $root); + $this->assertFalse($ret); + list($ele, $root) = $this->doc($xml, 'h12'); + $ret = $ps->elementMatches('header', $ele, $root); + $this->assertFalse($ret); + } + + public function testContains(){ + $xml = 'This is a test of :contains.'; + + list($ele, $root) = $this->doc($xml, 'h'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('contains', $ele, $root, 'test'); + $this->assertTrue($ret); + + $ret = $ps->elementMatches('contains', $ele, $root, 'is a test'); + $this->assertTrue($ret); + + $ret = $ps->elementMatches('contains', $ele, $root, 'This is a test of :contains.'); + $this->assertTrue($ret); + + $ret = $ps->elementMatches('contains', $ele, $root, 'Agent P, here is your mission.'); + $this->assertFalse($ret); + + $ret = $ps->elementMatches('contains', $ele, $root, "'Agent P, here is your mission.'"); + $this->assertFalse($ret); + + } + public function testContainsExactly() { + $xml = 'This is a test of :contains-exactly.'; + + list($ele, $root) = $this->doc($xml, 'h'); + $ps = new PseudoClass(); + + $ret = $ps->elementMatches('contains-exactly', $ele, $root, 'test'); + $this->assertFalse($ret); + + $ret = $ps->elementMatches('contains-exactly', $ele, $root, 'This is a test of :contains-exactly.'); + $this->assertTrue($ret); + + $ret = $ps->elementMatches('contains-exactly', $ele, $root, 'Agent P, here is your mission.'); + $this->assertFalse($ret); + + $ret = $ps->elementMatches('contains-exactly', $ele, $root, '"Agent P, here is your mission."'); + $this->assertFalse($ret); + } + public function testHas() { + $xml = '