Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / vendor / symfony / css-selector / Tests / XPath / TranslatorTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\CssSelector\Tests\XPath;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
16 use Symfony\Component\CssSelector\XPath\Translator;
17
18 class TranslatorTest extends TestCase
19 {
20     /** @dataProvider getXpathLiteralTestData */
21     public function testXpathLiteral($value, $literal)
22     {
23         $this->assertEquals($literal, Translator::getXpathLiteral($value));
24     }
25
26     /** @dataProvider getCssToXPathTestData */
27     public function testCssToXPath($css, $xpath)
28     {
29         $translator = new Translator();
30         $translator->registerExtension(new HtmlExtension($translator));
31         $this->assertEquals($xpath, $translator->cssToXPath($css, ''));
32     }
33
34     /** @dataProvider getXmlLangTestData */
35     public function testXmlLang($css, array $elementsId)
36     {
37         $translator = new Translator();
38         $document = new \SimpleXMLElement(file_get_contents(__DIR__.'/Fixtures/lang.xml'));
39         $elements = $document->xpath($translator->cssToXPath($css));
40         $this->assertCount(\count($elementsId), $elements);
41         foreach ($elements as $element) {
42             $this->assertTrue(\in_array($element->attributes()->id, $elementsId));
43         }
44     }
45
46     /** @dataProvider getHtmlIdsTestData */
47     public function testHtmlIds($css, array $elementsId)
48     {
49         $translator = new Translator();
50         $translator->registerExtension(new HtmlExtension($translator));
51         $document = new \DOMDocument();
52         $document->strictErrorChecking = false;
53         $internalErrors = libxml_use_internal_errors(true);
54         $document->loadHTMLFile(__DIR__.'/Fixtures/ids.html');
55         $document = simplexml_import_dom($document);
56         $elements = $document->xpath($translator->cssToXPath($css));
57         $this->assertCount(\count($elementsId), $elementsId);
58         foreach ($elements as $element) {
59             if (null !== $element->attributes()->id) {
60                 $this->assertTrue(\in_array($element->attributes()->id, $elementsId));
61             }
62         }
63         libxml_clear_errors();
64         libxml_use_internal_errors($internalErrors);
65     }
66
67     /** @dataProvider getHtmlShakespearTestData */
68     public function testHtmlShakespear($css, $count)
69     {
70         $translator = new Translator();
71         $translator->registerExtension(new HtmlExtension($translator));
72         $document = new \DOMDocument();
73         $document->strictErrorChecking = false;
74         $document->loadHTMLFile(__DIR__.'/Fixtures/shakespear.html');
75         $document = simplexml_import_dom($document);
76         $bodies = $document->xpath('//body');
77         $elements = $bodies[0]->xpath($translator->cssToXPath($css));
78         $this->assertCount($count, $elements);
79     }
80
81     public function getXpathLiteralTestData()
82     {
83         return array(
84             array('foo', "'foo'"),
85             array("foo's bar", '"foo\'s bar"'),
86             array("foo's \"middle\" bar", 'concat(\'foo\', "\'", \'s "middle" bar\')'),
87             array("foo's 'middle' \"bar\"", 'concat(\'foo\', "\'", \'s \', "\'", \'middle\', "\'", \' "bar"\')'),
88         );
89     }
90
91     public function getCssToXPathTestData()
92     {
93         return array(
94             array('*', '*'),
95             array('e', 'e'),
96             array('*|e', 'e'),
97             array('e|f', 'e:f'),
98             array('e[foo]', 'e[@foo]'),
99             array('e[foo|bar]', 'e[@foo:bar]'),
100             array('e[foo="bar"]', "e[@foo = 'bar']"),
101             array('e[foo~="bar"]', "e[@foo and contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]"),
102             array('e[foo^="bar"]', "e[@foo and starts-with(@foo, 'bar')]"),
103             array('e[foo$="bar"]', "e[@foo and substring(@foo, string-length(@foo)-2) = 'bar']"),
104             array('e[foo*="bar"]', "e[@foo and contains(@foo, 'bar')]"),
105             array('e[foo!="bar"]', "e[not(@foo) or @foo != 'bar']"),
106             array('e[foo!="bar"][foo!="baz"]', "e[(not(@foo) or @foo != 'bar') and (not(@foo) or @foo != 'baz')]"),
107             array('e[hreflang|="en"]', "e[@hreflang and (@hreflang = 'en' or starts-with(@hreflang, 'en-'))]"),
108             array('e:nth-child(1)', "*/*[(name() = 'e') and (position() = 1)]"),
109             array('e:nth-last-child(1)', "*/*[(name() = 'e') and (position() = last() - 0)]"),
110             array('e:nth-last-child(2n+2)', "*/*[(name() = 'e') and (last() - position() - 1 >= 0 and (last() - position() - 1) mod 2 = 0)]"),
111             array('e:nth-of-type(1)', '*/e[position() = 1]'),
112             array('e:nth-last-of-type(1)', '*/e[position() = last() - 0]'),
113             array('div e:nth-last-of-type(1) .aclass', "div/descendant-or-self::*/e[position() = last() - 0]/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' aclass ')]"),
114             array('e:first-child', "*/*[(name() = 'e') and (position() = 1)]"),
115             array('e:last-child', "*/*[(name() = 'e') and (position() = last())]"),
116             array('e:first-of-type', '*/e[position() = 1]'),
117             array('e:last-of-type', '*/e[position() = last()]'),
118             array('e:only-child', "*/*[(name() = 'e') and (last() = 1)]"),
119             array('e:only-of-type', 'e[last() = 1]'),
120             array('e:empty', 'e[not(*) and not(string-length())]'),
121             array('e:EmPTY', 'e[not(*) and not(string-length())]'),
122             array('e:root', 'e[not(parent::*)]'),
123             array('e:hover', 'e[0]'),
124             array('e:contains("foo")', "e[contains(string(.), 'foo')]"),
125             array('e:ConTains(foo)', "e[contains(string(.), 'foo')]"),
126             array('e.warning', "e[@class and contains(concat(' ', normalize-space(@class), ' '), ' warning ')]"),
127             array('e#myid', "e[@id = 'myid']"),
128             array('e:not(:nth-child(odd))', 'e[not(position() - 1 >= 0 and (position() - 1) mod 2 = 0)]'),
129             array('e:nOT(*)', 'e[0]'),
130             array('e f', 'e/descendant-or-self::*/f'),
131             array('e > f', 'e/f'),
132             array('e + f', "e/following-sibling::*[(name() = 'f') and (position() = 1)]"),
133             array('e ~ f', 'e/following-sibling::f'),
134             array('div#container p', "div[@id = 'container']/descendant-or-self::*/p"),
135         );
136     }
137
138     public function getXmlLangTestData()
139     {
140         return array(
141             array(':lang("EN")', array('first', 'second', 'third', 'fourth')),
142             array(':lang("en-us")', array('second', 'fourth')),
143             array(':lang(en-nz)', array('third')),
144             array(':lang(fr)', array('fifth')),
145             array(':lang(ru)', array('sixth')),
146             array(":lang('ZH')", array('eighth')),
147             array(':lang(de) :lang(zh)', array('eighth')),
148             array(':lang(en), :lang(zh)', array('first', 'second', 'third', 'fourth', 'eighth')),
149             array(':lang(es)', array()),
150         );
151     }
152
153     public function getHtmlIdsTestData()
154     {
155         return array(
156             array('div', array('outer-div', 'li-div', 'foobar-div')),
157             array('DIV', array('outer-div', 'li-div', 'foobar-div')),  // case-insensitive in HTML
158             array('div div', array('li-div')),
159             array('div, div div', array('outer-div', 'li-div', 'foobar-div')),
160             array('a[name]', array('name-anchor')),
161             array('a[NAme]', array('name-anchor')), // case-insensitive in HTML:
162             array('a[rel]', array('tag-anchor', 'nofollow-anchor')),
163             array('a[rel="tag"]', array('tag-anchor')),
164             array('a[href*="localhost"]', array('tag-anchor')),
165             array('a[href*=""]', array()),
166             array('a[href^="http"]', array('tag-anchor', 'nofollow-anchor')),
167             array('a[href^="http:"]', array('tag-anchor')),
168             array('a[href^=""]', array()),
169             array('a[href$="org"]', array('nofollow-anchor')),
170             array('a[href$=""]', array()),
171             array('div[foobar~="bc"]', array('foobar-div')),
172             array('div[foobar~="cde"]', array('foobar-div')),
173             array('[foobar~="ab bc"]', array('foobar-div')),
174             array('[foobar~=""]', array()),
175             array('[foobar~=" \t"]', array()),
176             array('div[foobar~="cd"]', array()),
177             array('*[lang|="En"]', array('second-li')),
178             array('[lang|="En-us"]', array('second-li')),
179             // Attribute values are case sensitive
180             array('*[lang|="en"]', array()),
181             array('[lang|="en-US"]', array()),
182             array('*[lang|="e"]', array()),
183             // ... :lang() is not.
184             array(':lang("EN")', array('second-li', 'li-div')),
185             array('*:lang(en-US)', array('second-li', 'li-div')),
186             array(':lang("e")', array()),
187             array('li:nth-child(3)', array('third-li')),
188             array('li:nth-child(10)', array()),
189             array('li:nth-child(2n)', array('second-li', 'fourth-li', 'sixth-li')),
190             array('li:nth-child(even)', array('second-li', 'fourth-li', 'sixth-li')),
191             array('li:nth-child(2n+0)', array('second-li', 'fourth-li', 'sixth-li')),
192             array('li:nth-child(+2n+1)', array('first-li', 'third-li', 'fifth-li', 'seventh-li')),
193             array('li:nth-child(odd)', array('first-li', 'third-li', 'fifth-li', 'seventh-li')),
194             array('li:nth-child(2n+4)', array('fourth-li', 'sixth-li')),
195             array('li:nth-child(3n+1)', array('first-li', 'fourth-li', 'seventh-li')),
196             array('li:nth-child(n)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
197             array('li:nth-child(n-1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
198             array('li:nth-child(n+1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
199             array('li:nth-child(n+3)', array('third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
200             array('li:nth-child(-n)', array()),
201             array('li:nth-child(-n-1)', array()),
202             array('li:nth-child(-n+1)', array('first-li')),
203             array('li:nth-child(-n+3)', array('first-li', 'second-li', 'third-li')),
204             array('li:nth-last-child(0)', array()),
205             array('li:nth-last-child(2n)', array('second-li', 'fourth-li', 'sixth-li')),
206             array('li:nth-last-child(even)', array('second-li', 'fourth-li', 'sixth-li')),
207             array('li:nth-last-child(2n+2)', array('second-li', 'fourth-li', 'sixth-li')),
208             array('li:nth-last-child(n)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
209             array('li:nth-last-child(n-1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
210             array('li:nth-last-child(n-3)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
211             array('li:nth-last-child(n+1)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li', 'sixth-li', 'seventh-li')),
212             array('li:nth-last-child(n+3)', array('first-li', 'second-li', 'third-li', 'fourth-li', 'fifth-li')),
213             array('li:nth-last-child(-n)', array()),
214             array('li:nth-last-child(-n-1)', array()),
215             array('li:nth-last-child(-n+1)', array('seventh-li')),
216             array('li:nth-last-child(-n+3)', array('fifth-li', 'sixth-li', 'seventh-li')),
217             array('ol:first-of-type', array('first-ol')),
218             array('ol:nth-child(1)', array('first-ol')),
219             array('ol:nth-of-type(2)', array('second-ol')),
220             array('ol:nth-last-of-type(1)', array('second-ol')),
221             array('span:only-child', array('foobar-span')),
222             array('li div:only-child', array('li-div')),
223             array('div *:only-child', array('li-div', 'foobar-span')),
224             array('p:only-of-type', array('paragraph')),
225             array('a:empty', array('name-anchor')),
226             array('a:EMpty', array('name-anchor')),
227             array('li:empty', array('third-li', 'fourth-li', 'fifth-li', 'sixth-li')),
228             array(':root', array('html')),
229             array('html:root', array('html')),
230             array('li:root', array()),
231             array('* :root', array()),
232             array('*:contains("link")', array('html', 'outer-div', 'tag-anchor', 'nofollow-anchor')),
233             array(':CONtains("link")', array('html', 'outer-div', 'tag-anchor', 'nofollow-anchor')),
234             array('*:contains("LInk")', array()),  // case sensitive
235             array('*:contains("e")', array('html', 'nil', 'outer-div', 'first-ol', 'first-li', 'paragraph', 'p-em')),
236             array('*:contains("E")', array()),  // case-sensitive
237             array('.a', array('first-ol')),
238             array('.b', array('first-ol')),
239             array('*.a', array('first-ol')),
240             array('ol.a', array('first-ol')),
241             array('.c', array('first-ol', 'third-li', 'fourth-li')),
242             array('*.c', array('first-ol', 'third-li', 'fourth-li')),
243             array('ol *.c', array('third-li', 'fourth-li')),
244             array('ol li.c', array('third-li', 'fourth-li')),
245             array('li ~ li.c', array('third-li', 'fourth-li')),
246             array('ol > li.c', array('third-li', 'fourth-li')),
247             array('#first-li', array('first-li')),
248             array('li#first-li', array('first-li')),
249             array('*#first-li', array('first-li')),
250             array('li div', array('li-div')),
251             array('li > div', array('li-div')),
252             array('div div', array('li-div')),
253             array('div > div', array()),
254             array('div>.c', array('first-ol')),
255             array('div > .c', array('first-ol')),
256             array('div + div', array('foobar-div')),
257             array('a ~ a', array('tag-anchor', 'nofollow-anchor')),
258             array('a[rel="tag"] ~ a', array('nofollow-anchor')),
259             array('ol#first-ol li:last-child', array('seventh-li')),
260             array('ol#first-ol *:last-child', array('li-div', 'seventh-li')),
261             array('#outer-div:first-child', array('outer-div')),
262             array('#outer-div :first-child', array('name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-fieldset-disabled', 'area-href')),
263             array('a[href]', array('tag-anchor', 'nofollow-anchor')),
264             array(':not(*)', array()),
265             array('a:not([href])', array('name-anchor')),
266             array('ol :Not(li[class])', array('first-li', 'second-li', 'li-div', 'fifth-li', 'sixth-li', 'seventh-li')),
267             // HTML-specific
268             array(':link', array('link-href', 'tag-anchor', 'nofollow-anchor', 'area-href')),
269             array(':visited', array()),
270             array(':enabled', array('link-href', 'tag-anchor', 'nofollow-anchor', 'checkbox-unchecked', 'text-checked', 'checkbox-checked', 'area-href')),
271             array(':disabled', array('checkbox-disabled', 'checkbox-disabled-checked', 'fieldset', 'checkbox-fieldset-disabled')),
272             array(':checked', array('checkbox-checked', 'checkbox-disabled-checked')),
273         );
274     }
275
276     public function getHtmlShakespearTestData()
277     {
278         return array(
279             array('*', 246),
280             array('div:contains(CELIA)', 26),
281             array('div:only-child', 22), // ?
282             array('div:nth-child(even)', 106),
283             array('div:nth-child(2n)', 106),
284             array('div:nth-child(odd)', 137),
285             array('div:nth-child(2n+1)', 137),
286             array('div:nth-child(n)', 243),
287             array('div:last-child', 53),
288             array('div:first-child', 51),
289             array('div > div', 242),
290             array('div + div', 190),
291             array('div ~ div', 190),
292             array('body', 1),
293             array('body div', 243),
294             array('div', 243),
295             array('div div', 242),
296             array('div div div', 241),
297             array('div, div, div', 243),
298             array('div, a, span', 243),
299             array('.dialog', 51),
300             array('div.dialog', 51),
301             array('div .dialog', 51),
302             array('div.character, div.dialog', 99),
303             array('div.direction.dialog', 0),
304             array('div.dialog.direction', 0),
305             array('div.dialog.scene', 1),
306             array('div.scene.scene', 1),
307             array('div.scene .scene', 0),
308             array('div.direction .dialog ', 0),
309             array('div .dialog .direction', 4),
310             array('div.dialog .dialog .direction', 4),
311             array('#speech5', 1),
312             array('div#speech5', 1),
313             array('div #speech5', 1),
314             array('div.scene div.dialog', 49),
315             array('div#scene1 div.dialog div', 142),
316             array('#scene1 #speech1', 1),
317             array('div[class]', 103),
318             array('div[class=dialog]', 50),
319             array('div[class^=dia]', 51),
320             array('div[class$=log]', 50),
321             array('div[class*=sce]', 1),
322             array('div[class|=dialog]', 50), // ? Seems right
323             array('div[class!=madeup]', 243), // ? Seems right
324             array('div[class~=dialog]', 51), // ? Seems right
325         );
326     }
327 }