Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 <!DOCTYPE HTML>
2 <html>
3 <head>
4 <title>Test for CSS Selectors</title>
5 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
7 </head>
8 <body onload="run()">
9 <p id="display"><iframe id="iframe" src="about:blank"></iframe><iframe id="cloneiframe" src="about:blank"></iframe></p>
10 <pre id="test">
11 <script class="testbody" type="text/javascript">
13 SimpleTest.waitForExplicitFinish();
15 var cloneiframe;
17 function run() {
19 var iframe = document.getElementById("iframe");
20 var ifwin = iframe.contentWindow;
21 var ifdoc = iframe.contentDocument;
23 cloneiframe = document.getElementById("cloneiframe");
25 var style_elem = ifdoc.createElement("style");
26 style_elem.setAttribute("type", "text/css");
27 ifdoc.getElementsByTagName("head")[0].appendChild(style_elem);
28 var style_text = ifdoc.createTextNode("");
29 style_elem.appendChild(style_text);
31 var gCounter = 0;
33 /*
34 * selector: the selector to test
35 * body_contents: what to set the body's innerHTML to
36 * match_fn: a function that, given the document object into which
37 * body_contents has been inserted, produces an array of nodes that
38 * should match selector
39 * notmatch_fn: likewise, but for nodes that should not match
40 * namespaces (optional): @namespace rules to be included in the sheet
41 */
42 function test_selector_in_html(selector, body_contents, match_fn, notmatch_fn, namespaces)
43 {
44 var zi = ++gCounter;
45 if (typeof(body_contents) == "string") {
46 ifdoc.body.innerHTML = body_contents;
47 } else {
48 // It's a function.
49 ifdoc.body.innerHTML = "";
50 body_contents(ifdoc.body);
51 }
52 if (!namespaces) {
53 namespaces = "";
54 }
55 style_text.data = namespaces + selector + "{ z-index: " + zi + " }";
57 var idx = style_text.parentNode.sheet.cssRules.length - 1;
58 if (namespaces == "") {
59 is(idx, 0, "unexpected rule index");
60 }
61 if (idx < 0 ||
62 style_text.parentNode.sheet.cssRules[idx].type !=
63 CSSRule.STYLE_RULE)
64 {
65 ok(false, "selector " + selector + " could not be parsed");
66 return;
67 }
69 var should_match = match_fn(ifdoc);
70 var should_not_match = notmatch_fn(ifdoc);
71 if (should_match.length + should_not_match.length == 0) {
72 ok(false, "nothing to check");
73 }
75 for (var i = 0; i < should_match.length; ++i) {
76 var e = should_match[i];
77 is(ifwin.getComputedStyle(e, "").zIndex, zi,
78 "element in " + body_contents + " matched " + selector);
79 }
80 for (var i = 0; i < should_not_match.length; ++i) {
81 var e = should_not_match[i];
82 is(ifwin.getComputedStyle(e, "").zIndex, "auto",
83 "element in " + body_contents + " did not match " + selector);
84 }
86 // Now, since we're here, may as well make sure serialization
87 // works correctly. It need not produce the exact same text,
88 // but it should produce a selector that matches the same
89 // elements.
90 zi = ++gCounter;
91 var ser1 = style_text.parentNode.sheet.cssRules[idx].selectorText;
92 style_text.data = namespaces + ser1 + "{ z-index: " + zi + " }";
93 for (var i = 0; i < should_match.length; ++i) {
94 var e = should_match[i];
95 is(ifwin.getComputedStyle(e, "").zIndex, zi,
96 "element in " + body_contents + " matched " + ser1 +
97 " which is the reserialization of " + selector);
98 }
99 for (var i = 0; i < should_not_match.length; ++i) {
100 var e = should_not_match[i];
101 is(ifwin.getComputedStyle(e, "").zIndex, "auto",
102 "element in " + body_contents + " did not match " + ser1 +
103 " which is the reserialization of " + selector);
104 }
106 // But when we serialize the serialized result, we should get
107 // the same text.
108 var ser2 = style_text.parentNode.sheet.cssRules[idx].selectorText;
109 is(ser2, ser1, "parse+serialize of selector \"" + selector +
110 "\" is idempotent");
112 ifdoc.body.innerHTML = "";
113 style_text.data = "";
115 // And now test that when we clone the style sheet, we end up
116 // with the same selector (serializes to same string, and
117 // matches the same things).
118 zi = ++gCounter;
119 var style_sheet = "data:text/css," +
120 escape(namespaces + selector + "{ z-index: " + zi + " }");
121 var style_sheet_link =
122 "<link rel='stylesheet' href='" + style_sheet + "'>";
123 var html_doc = "<!DOCTYPE HTML>" +
124 style_sheet_link + style_sheet_link +
125 "<body>";
126 if (typeof(body_contents) == "string") {
127 html_doc += body_contents;
128 }
129 var docurl = "data:text/html," + escape(html_doc);
130 defer_clonedoc_tests(docurl, function() {
131 var clonedoc = cloneiframe.contentDocument;
132 var clonewin = cloneiframe.contentWindow;
134 if (typeof(body_contents) != "string") {
135 body_contents(clonedoc.body);
136 }
138 var links = clonedoc.getElementsByTagName("link");
139 // cause a clone
140 links[1].sheet.insertRule("#nonexistent { color: purple}", idx + 1);
141 // remove the uncloned sheet
142 links[0].parentNode.removeChild(links[0]);
144 var should_match = match_fn(clonedoc);
145 var should_not_match = notmatch_fn(clonedoc);
147 if (should_match.length + should_not_match.length == 0) {
148 ok(false, "nothing to check");
149 }
151 for (var i = 0; i < should_match.length; ++i) {
152 var e = should_match[i];
153 is(clonewin.getComputedStyle(e, "").zIndex, zi,
154 "element in " + body_contents + " matched clone of " +
155 selector);
156 }
157 for (var i = 0; i < should_not_match.length; ++i) {
158 var e = should_not_match[i];
159 is(clonewin.getComputedStyle(e, "").zIndex, "auto",
160 "element in " + body_contents + " did not match clone of " +
161 selector);
162 }
164 var ser3 = links[0].sheet.cssRules[idx].selectorText;
165 is(ser3, ser1,
166 "selector " + selector + " serializes correctly after cloning");
167 });
168 }
170 function should_serialize_to(selector, serialization)
171 {
172 style_text.data = selector + "{ z-index: 0 }";
173 is(style_text.parentNode.sheet.cssRules[0].selectorText,
174 serialization,
175 "selector '" + selector + "' should serialize to '" +
176 serialization + "'.");
177 }
179 function test_parseable(selector)
180 {
181 ifdoc.body.innerHTML = "<p></p>";
183 var zi = ++gCounter;
184 style_text.data = "p, " + selector + "{ z-index: " + zi + " }";
185 var should_match = ifdoc.getElementsByTagName("p")[0];
186 var parsed = ifwin.getComputedStyle(should_match, "").zIndex == zi;
187 ok(parsed, "selector " + selector + " was parsed");
188 if (!parsed) {
189 return;
190 }
192 // Test that it serializes to something that is also parseable.
193 var ser1 = style_elem.sheet.cssRules[0].selectorText;
194 zi = ++gCounter;
195 style_text.data = ser1 + "{ z-index: " + zi + " }";
196 is(ifwin.getComputedStyle(should_match, "").zIndex, zi,
197 "serialization " + ser1 + " of selector p, " + selector +
198 " was parsed");
199 var ser2 = style_elem.sheet.cssRules[0].selectorText;
200 is(ser2, ser1,
201 "parse+serialize of selector " + selector + " is idempotent");
203 ifdoc.body.innerHTML = "";
204 style_text.data = "";
206 // Test that it clones to the same thing it serializes to.
207 zi = ++gCounter;
208 var style_sheet = "data:text/css," +
209 escape("p, " + selector + "{ z-index: " + zi + " }");
210 var style_sheet_link =
211 "<link rel='stylesheet' href='" + style_sheet + "'>";
212 var html_doc = "<!DOCTYPE HTML>" +
213 style_sheet_link + style_sheet_link +
214 "<p></p>";
215 var docurl = "data:text/html," + escape(html_doc);
217 defer_clonedoc_tests(docurl, function() {
218 var clonedoc = cloneiframe.contentDocument;
219 var clonewin = cloneiframe.contentWindow;
220 var links = clonedoc.getElementsByTagName("link");
221 // cause a clone
222 links[1].sheet.insertRule("#nonexistent { color: purple}", 0);
223 // remove the uncloned sheet
224 links[0].parentNode.removeChild(links[0]);
226 should_match = clonedoc.getElementsByTagName("p")[0];
227 is(clonewin.getComputedStyle(should_match, "").zIndex, zi,
228 "selector " + selector + " was cloned correctly");
229 var ser3 = links[0].sheet.cssRules[1].selectorText;
230 is(ser3, ser1,
231 "selector " + selector + " serializes correctly after cloning");
232 });
233 }
235 function test_unparseable_via_api(selector)
236 {
237 try {
238 // Test that it is also unparseable when followed by EOF.
239 ifdoc.body.mozMatchesSelector(selector);
240 ok(false, "selector '" + selector + "' plus EOF is parse error");
241 } catch(ex) {
242 is(ex.name, "SyntaxError",
243 "selector '" + selector + "' plus EOF is parse error");
244 is(ex.code, DOMException.SYNTAX_ERR,
245 "selector '" + selector + "' plus EOF is parse error");
246 }
247 }
249 function test_parseable_via_api(selector)
250 {
251 var threw = false;
252 try {
253 // Test that a selector is parseable when followed by EOF.
254 ifdoc.body.mozMatchesSelector(selector);
255 } catch(ex) {
256 threw = true;
257 }
258 ok(!threw, "selector '" + selector + "' was parsed");
259 }
261 function test_balanced_unparseable(selector)
262 {
263 var zi1 = ++gCounter;
264 var zi2 = ++gCounter;
265 ifdoc.body.innerHTML = "<p></p><div></div>";
266 style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" +
267 "div { z-index: " + zi2 + " }";
268 var should_not_match = ifdoc.getElementsByTagName("p")[0];
269 var should_match = ifdoc.getElementsByTagName("div")[0];
270 is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
271 "selector " + selector + " was a parser error");
272 is(ifwin.getComputedStyle(should_match, "").zIndex, zi2,
273 "selector " + selector + " error was recovered from");
274 ifdoc.body.innerHTML = "";
275 style_text.data = "";
276 test_unparseable_via_api(selector);
277 }
279 function test_unbalanced_unparseable(selector)
280 {
281 var zi1 = ++gCounter;
282 var zi2 = ++gCounter;
283 ifdoc.body.innerHTML = "<p></p>";
284 style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }";
285 var should_not_match = ifdoc.getElementsByTagName("p")[0];
286 is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
287 "selector " + selector + " was a parser error");
288 is(style_text.parentNode.sheet.cssRules.length, 0,
289 "sheet should have no rules since " + selector + " is parse error");
290 ifdoc.body.innerHTML = "";
291 style_text.data = "";
292 test_unparseable_via_api(selector);
293 }
296 // [attr= ] selector
297 test_parseable("[attr=\"x\"]");
298 test_parseable("[attr='x']");
299 test_parseable("[attr=x]");
300 test_parseable("[attr=\"\"]");
301 test_parseable("[attr='']");
302 test_parseable("[attr=\"foo bar\"]");
304 test_balanced_unparseable("[attr=]");
305 test_balanced_unparseable("[attr=foo bar]");
307 test_selector_in_html(
308 '[title=""]',
309 '<p title=""></p>'
310 + '<div lang=" "></div><div lang="\t"></div><div lang="\n"></div>',
311 function(doc) { return doc.getElementsByTagName("p"); },
312 function(doc) { return doc.getElementsByTagName("div"); }
313 );
315 // [attr~= ] selector
316 test_parseable("[attr~=\"x\"]");
317 test_parseable("[attr~='x']");
318 test_parseable("[attr~=x]");
319 test_parseable("[attr~=\"\"]");
320 test_parseable("[attr~='']");
321 test_parseable("[attr~=\"foo bar\"]");
323 test_balanced_unparseable("[attr~=]");
324 test_balanced_unparseable("[attr~=foo bar]");
326 test_selector_in_html(
327 '[class~="x x"]',
328 '<div class="x x"></div><div class="x"></div><div class="x\tx"></div>div class="x\nx"></div>',
329 function(doc) { return []; },
330 function(doc) { return doc.getElementsByTagName("div"); }
331 );
333 // [attr|="x"]
334 test_parseable('[attr|="x"]');
335 test_parseable("[attr|='x']");
336 test_parseable('[attr|=x]');
338 test_parseable('[attr|=""]');
339 test_parseable("[attr|='']");
340 test_balanced_unparseable('[attr|=]');
342 test_selector_in_html(
343 '[lang|=""]',
344 '<p lang=""></p><p lang="-"></p><p lang="-GB"></p>'
345 + '<div lang="en-GB"></div><div lang="en-"></div>',
346 function(doc) { return doc.getElementsByTagName("p"); },
347 function(doc) { return doc.getElementsByTagName("div"); }
348 );
350 // [attr$= ] selector
351 test_parseable("[attr$=\"x\"]");
352 test_parseable("[attr$='x']");
353 test_parseable("[attr$=x]");
354 test_parseable("[attr$=\"\"]");
355 test_parseable("[attr$='']");
356 test_parseable("[attr$=\"foo bar\"]");
358 test_balanced_unparseable("[attr$=]");
359 test_balanced_unparseable("[attr$=foo bar]");
361 // [attr^= ] selector
362 test_parseable("[attr^=\"x\"]");
363 test_parseable("[attr^='x']");
364 test_parseable("[attr^=x]");
365 test_parseable("[attr^=\"\"]");
366 test_parseable("[attr^='']");
367 test_parseable("[attr^=\"foo bar\"]");
369 test_balanced_unparseable("[attr^=]");
370 test_balanced_unparseable("[attr^=foo bar]");
372 // attr[*= ] selector
373 test_parseable("[attr*=\"x\"]");
374 test_parseable("[attr*='x']");
375 test_parseable("[attr*=x]");
376 test_parseable("[attr*=\"\"]");
377 test_parseable("[attr*='']");
378 test_parseable("[attr*=\"foo bar\"]");
380 test_balanced_unparseable("[attr*=]");
381 test_balanced_unparseable("[attr*=foo bar]");
384 // Bug 420814
385 test_selector_in_html(
386 "div ~ div p",
387 "<div></div><div><div><p>match</p></div></div>",
388 function(doc) { return doc.getElementsByTagName("p"); },
389 function(doc) { return []; }
390 );
392 // Bug 420245
393 test_selector_in_html(
394 "p[attr$=\"\"]",
395 "<p attr=\"foo\">This should not match</p>",
396 function(doc) { return []; },
397 function(doc) { return doc.getElementsByTagName("p"); }
398 );
399 test_selector_in_html(
400 "div + p[attr~=\"\"]",
401 "<div>Dummy</div><p attr=\"foo\">This should not match</p>",
402 function(doc) { return []; },
403 function(doc) { return doc.getElementsByTagName("p"); }
404 );
405 test_selector_in_html(
406 "div[attr^=\"\"]",
407 "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
408 function(doc) { return []; },
409 function(doc) { return doc.getElementsByTagName("div"); }
410 );
411 test_selector_in_html(
412 "div[attr*=\"\"]",
413 "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
414 function(doc) { return []; },
415 function(doc) { return doc.getElementsByTagName("div"); }
416 );
418 // :nth-child(), etc.
419 // Follow the whitespace rules as proposed in
420 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
421 test_balanced_unparseable(":nth-child()");
422 test_balanced_unparseable(":nth-of-type( )");
423 test_parseable(":nth-last-child( odd)");
424 test_parseable(":nth-last-of-type(even )");
425 test_parseable(":nth-child(n )");
426 test_parseable(":nth-of-type( 2n)");
427 test_parseable(":nth-last-child( -n)");
428 test_parseable(":nth-last-of-type(-2n )");
429 test_balanced_unparseable(":nth-child(- n)");
430 test_balanced_unparseable(":nth-of-type(-2 n)");
431 test_balanced_unparseable(":nth-last-of-type(2n1)");
432 test_balanced_unparseable(":nth-child(2n++1)");
433 test_balanced_unparseable(":nth-of-type(2n-+1)");
434 test_balanced_unparseable(":nth-last-child(2n+-1)");
435 test_balanced_unparseable(":nth-last-of-type(2n--1)");
436 test_parseable(":nth-child( 3n + 1 )");
437 test_parseable(":nth-child( +3n - 2 )");
438 test_parseable(":nth-child( -n+ 6)");
439 test_parseable(":nth-child( +6 )");
440 test_balanced_unparseable(":nth-child(3 n)");
441 test_balanced_unparseable(":nth-child(+ 2n)");
442 test_balanced_unparseable(":nth-child(+ 2)");
443 test_parseable(":nth-child(3)");
444 test_parseable(":nth-of-type(-3)");
445 test_parseable(":nth-last-child(+3)");
446 test_parseable(":nth-last-of-type(0)");
447 test_parseable(":nth-child(-0)");
448 test_parseable(":nth-of-type(3n)");
449 test_parseable(":nth-last-child(-3n)");
450 test_parseable(":nth-last-of-type(+3n)");
451 test_parseable(":nth-last-of-type(0n)");
452 test_parseable(":nth-child(-0n)");
453 test_parseable(":nth-of-type(n)");
454 test_parseable(":nth-last-child(-n)");
455 test_parseable(":nth-last-of-type(2n+1)");
456 test_parseable(":nth-child(2n-1)");
457 test_parseable(":nth-of-type(2n+0)");
458 test_parseable(":nth-last-child(2n-0)");
459 test_parseable(":nth-child(-0n+0)");
460 test_parseable(":nth-of-type(n+1)");
461 test_parseable(":nth-last-child(n-1)");
462 test_parseable(":nth-last-of-type(-n+1)");
463 test_parseable(":nth-child(-n-1)");
464 test_balanced_unparseable(":nth-child(2-n)");
465 test_balanced_unparseable(":nth-child(2-n-1)");
466 test_balanced_unparseable(":nth-child(n-2-1)");
467 // Bug 750388
468 test_parseable(":nth-child(+n)");
469 test_balanced_unparseable(":nth-child(+ n)");
470 test_parseable(":nth-child(+n+2)");
471 test_parseable(":nth-child(+n-2)");
472 test_parseable(":nth-child(+n + 2)");
473 test_parseable(":nth-child(+n - 2)");
474 test_balanced_unparseable(":nth-child(+ n+2)");
475 test_balanced_unparseable(":nth-child(+ n-2)");
476 test_balanced_unparseable(":nth-child(+ n + 2)");
477 test_balanced_unparseable(":nth-child(+ n - 2)");
478 test_parseable(":nth-child(+n-100)");
479 test_parseable(":nth-child(+n - 100)");
480 test_balanced_unparseable(":nth-child(+ n-100)");
481 test_balanced_unparseable(":nth-child(+-n+2)");
482 test_balanced_unparseable(":nth-child(+ -n+2)");
483 test_balanced_unparseable(":nth-child(+-n-100)");
484 test_balanced_unparseable(":nth-child(+ -n-100)");
485 test_balanced_unparseable(":nth-child(++n-100)");
486 test_balanced_unparseable(":nth-child(-+n-100)");
487 test_balanced_unparseable(":nth-child(++2n - 100)");
488 test_balanced_unparseable(":nth-child(+-2n - 100)");
489 test_balanced_unparseable(":nth-child(-+2n - 100)");
490 test_balanced_unparseable(":nth-child(--2n - 100)");
491 test_balanced_unparseable(":nth-child(+/**/+2n - 100)");
492 test_balanced_unparseable(":nth-child(+/**/-2n - 100)");
493 test_balanced_unparseable(":nth-child(-/**/+2n - 100)");
494 test_balanced_unparseable(":nth-child(-/**/-2n - 100)");
495 test_balanced_unparseable(":nth-child(+/**/+/**/2n - 100)");
496 test_balanced_unparseable(":nth-child(+/**/-/**/2n - 100)");
497 test_balanced_unparseable(":nth-child(-/**/+/**/2n - 100)");
498 test_balanced_unparseable(":nth-child(-/**/-/**/2n - 100)");
499 test_balanced_unparseable(":nth-child(++/**/2n - 100)");
500 test_balanced_unparseable(":nth-child(+-/**/2n - 100)");
501 test_balanced_unparseable(":nth-child(-+/**/2n - 100)");
502 test_balanced_unparseable(":nth-child(--/**/2n - 100)");
503 test_balanced_unparseable(":nth-child(-even)");
504 test_balanced_unparseable(":nth-child(-odd)");
505 test_balanced_unparseable(":nth-child(+even)");
506 test_balanced_unparseable(":nth-child(+odd)");
507 test_balanced_unparseable(":nth-child(+ even)");
508 test_balanced_unparseable(":nth-child(+ odd)");
509 test_balanced_unparseable(":nth-child(+-n)");
510 test_balanced_unparseable(":nth-child(+-n-)");
511 test_balanced_unparseable(":nth-child(-+n)");
512 test_balanced_unparseable(":nth-child(+n--)");
513 test_parseable(":nth-child(n+2)");
514 test_parseable(":nth-child(n/**/+/**/2)");
515 test_parseable(":nth-child(n-2)");
516 test_parseable(":nth-child(n/**/-/**/2)");
517 test_balanced_unparseable(":nth-child(n++2)");
518 test_balanced_unparseable(":nth-child(n+-2)");
519 test_balanced_unparseable(":nth-child(n-+2)");
520 test_balanced_unparseable(":nth-child(n--2)");
521 test_balanced_unparseable(":nth-child(n/**/++2)");
522 test_balanced_unparseable(":nth-child(n/**/+-2)");
523 test_balanced_unparseable(":nth-child(n/**/-+2)");
524 test_balanced_unparseable(":nth-child(n/**/--2)");
525 test_balanced_unparseable(":nth-child(n/**/+/**/+2)");
526 test_balanced_unparseable(":nth-child(n/**/+/**/-2)");
527 test_balanced_unparseable(":nth-child(n/**/-/**/+2)");
528 test_balanced_unparseable(":nth-child(n/**/-/**/-2)");
529 test_balanced_unparseable(":nth-child(n+/**/+2)");
530 test_balanced_unparseable(":nth-child(n+/**/-2)");
531 test_balanced_unparseable(":nth-child(n-/**/+2)");
532 test_balanced_unparseable(":nth-child(n-/**/-2)");
533 test_balanced_unparseable(":nth-child(n++/**/2)");
534 test_balanced_unparseable(":nth-child(n+-/**/2)");
535 test_balanced_unparseable(":nth-child(n-+/**/2)");
536 test_balanced_unparseable(":nth-child(n--/**/2)");
537 test_balanced_unparseable(":nth-child(n/**/++/**/2)");
538 test_balanced_unparseable(":nth-child(n/**/+-/**/2)");
539 test_balanced_unparseable(":nth-child(n/**/-+/**/2)");
540 test_balanced_unparseable(":nth-child(n/**/--/**/2)");
541 test_balanced_unparseable(":nth-child(n/**/+/**/+/**/2)");
542 test_balanced_unparseable(":nth-child(n/**/+/**/-/**/2)");
543 test_balanced_unparseable(":nth-child(n/**/-/**/+/**/2)");
544 test_balanced_unparseable(":nth-child(n/**/-/**/-/**/2)");
545 test_balanced_unparseable(":nth-child(n+/**/+/**/2)");
546 test_balanced_unparseable(":nth-child(n+/**/-/**/2)");
547 test_balanced_unparseable(":nth-child(n-/**/+/**/2)");
548 test_balanced_unparseable(":nth-child(n-/**/-/**/2)");
549 test_parseable(":nth-child(2n+2)");
550 test_parseable(":nth-child(2n/**/+/**/2)");
551 test_parseable(":nth-child(2n-2)");
552 test_parseable(":nth-child(2n/**/-/**/2)");
553 test_balanced_unparseable(":nth-child(2n++2)");
554 test_balanced_unparseable(":nth-child(2n+-2)");
555 test_balanced_unparseable(":nth-child(2n-+2)");
556 test_balanced_unparseable(":nth-child(2n--2)");
557 test_balanced_unparseable(":nth-child(2n/**/++2)");
558 test_balanced_unparseable(":nth-child(2n/**/+-2)");
559 test_balanced_unparseable(":nth-child(2n/**/-+2)");
560 test_balanced_unparseable(":nth-child(2n/**/--2)");
561 test_balanced_unparseable(":nth-child(2n/**/+/**/+2)");
562 test_balanced_unparseable(":nth-child(2n/**/+/**/-2)");
563 test_balanced_unparseable(":nth-child(2n/**/-/**/+2)");
564 test_balanced_unparseable(":nth-child(2n/**/-/**/-2)");
565 test_balanced_unparseable(":nth-child(2n+/**/+2)");
566 test_balanced_unparseable(":nth-child(2n+/**/-2)");
567 test_balanced_unparseable(":nth-child(2n-/**/+2)");
568 test_balanced_unparseable(":nth-child(2n-/**/-2)");
569 test_balanced_unparseable(":nth-child(2n++/**/2)");
570 test_balanced_unparseable(":nth-child(2n+-/**/2)");
571 test_balanced_unparseable(":nth-child(2n-+/**/2)");
572 test_balanced_unparseable(":nth-child(2n--/**/2)");
573 test_balanced_unparseable(":nth-child(2n/**/++/**/2)");
574 test_balanced_unparseable(":nth-child(2n/**/+-/**/2)");
575 test_balanced_unparseable(":nth-child(2n/**/-+/**/2)");
576 test_balanced_unparseable(":nth-child(2n/**/--/**/2)");
577 test_balanced_unparseable(":nth-child(2n/**/+/**/+/**/2)");
578 test_balanced_unparseable(":nth-child(2n/**/+/**/-/**/2)");
579 test_balanced_unparseable(":nth-child(2n/**/-/**/+/**/2)");
580 test_balanced_unparseable(":nth-child(2n/**/-/**/-/**/2)");
581 test_balanced_unparseable(":nth-child(2n+/**/+/**/2)");
582 test_balanced_unparseable(":nth-child(2n+/**/-/**/2)");
583 test_balanced_unparseable(":nth-child(2n-/**/+/**/2)");
584 test_balanced_unparseable(":nth-child(2n-/**/-/**/2)");
585 test_parseable(":nth-child(+/**/n+2)");
586 test_parseable(":nth-child(+n/**/+2)");
587 test_parseable(":nth-child(+n/**/+2)");
588 test_parseable(":nth-child(+n+/**/2)");
589 test_parseable(":nth-child(+n+2/**/)");
590 test_parseable(":nth-child(+1/**/n+2)");
591 test_parseable(":nth-child(+1n/**/+2)");
592 test_parseable(":nth-child(+1n/**/+2)");
593 test_parseable(":nth-child(+1n+/**/2)");
594 test_parseable(":nth-child(+1n+2/**/)");
595 test_parseable(":nth-child(-/**/n+2)");
596 test_parseable(":nth-child(-n/**/+2)");
597 test_parseable(":nth-child(-n/**/+2)");
598 test_parseable(":nth-child(-n+/**/2)");
599 test_parseable(":nth-child(-n+2/**/)");
600 test_parseable(":nth-child(-1/**/n+2)");
601 test_parseable(":nth-child(-1n/**/+2)");
602 test_parseable(":nth-child(-1n/**/+2)");
603 test_parseable(":nth-child(-1n+/**/2)");
604 test_parseable(":nth-child(-1n+2/**/)");
605 test_balanced_unparseable(":nth-child(-/**/ n+2)");
606 test_balanced_unparseable(":nth-child(- /**/n+2)");
607 test_balanced_unparseable(":nth-child(+/**/ n+2)");
608 test_balanced_unparseable(":nth-child(+ /**/n+2)");
609 test_parseable(":nth-child(+/**/n-2)");
610 test_parseable(":nth-child(+n/**/-2)");
611 test_parseable(":nth-child(+n/**/-2)");
612 test_parseable(":nth-child(+n-/**/2)");
613 test_parseable(":nth-child(+n-2/**/)");
614 test_parseable(":nth-child(+1/**/n-2)");
615 test_parseable(":nth-child(+1n/**/-2)");
616 test_parseable(":nth-child(+1n/**/-2)");
617 test_parseable(":nth-child(+1n-/**/2)");
618 test_parseable(":nth-child(+1n-2/**/)");
619 test_parseable(":nth-child(-/**/n-2)");
620 test_parseable(":nth-child(-n/**/-2)");
621 test_parseable(":nth-child(-n/**/-2)");
622 test_parseable(":nth-child(-n-/**/2)");
623 test_parseable(":nth-child(-n-2/**/)");
624 test_parseable(":nth-child(-1/**/n-2)");
625 test_parseable(":nth-child(-1n/**/-2)");
626 test_parseable(":nth-child(-1n/**/-2)");
627 test_parseable(":nth-child(-1n-/**/2)");
628 test_parseable(":nth-child(-1n-2/**/)");
629 test_balanced_unparseable(":nth-child(-/**/ n-2)");
630 test_balanced_unparseable(":nth-child(- /**/n-2)");
631 test_balanced_unparseable(":nth-child(+/**/ n-2)");
632 test_balanced_unparseable(":nth-child(+ /**/n-2)");
633 test_parseable(":nth-child( +n + 1 )");
634 test_parseable(":nth-child( +/**/n + 1 )");
635 test_parseable(":nth-child( -/**/2/**/n/**/+/**/4 )");
636 test_balanced_unparseable(":nth-child( -/**/ 2/**/n/**/+/**/4 )");
637 test_balanced_unparseable(":nth-child( -/**/2 /**/n/**/+/**/4 )");
638 test_balanced_unparseable(":nth-child( -/**/2/**/ n/**/+/**/4 )");
639 test_parseable(":nth-child( -/**/2/**/n /**/+/**/4 )");
640 test_parseable(":nth-child( -/**/2/**/n/**/ +/**/4 )");
641 test_parseable(":nth-child(+1/**/n-1)");
642 test_parseable(":nth-child(1/**/n-1)");
643 // bug 876570
644 test_balanced_unparseable(":nth-child(+2n-)");
645 test_balanced_unparseable(":nth-child(+n-)");
646 test_balanced_unparseable(":nth-child(-2n-)");
647 test_balanced_unparseable(":nth-child(-n-)");
648 test_balanced_unparseable(":nth-child(2n-)");
649 test_balanced_unparseable(":nth-child(n-)");
650 test_balanced_unparseable(":nth-child(+2n+)");
651 test_balanced_unparseable(":nth-child(+n+)");
652 test_balanced_unparseable(":nth-child(-2n+)");
653 test_balanced_unparseable(":nth-child(-n+)");
654 test_balanced_unparseable(":nth-child(2n+)");
655 test_balanced_unparseable(":nth-child(n+)");
657 // exercise the an+b matching logic particularly hard for
658 // :nth-child() (since we know we use the same code for all 4)
659 var seven_ps = "<p></p><p></p><p></p><p></p><p></p><p></p><p></p>";
660 function pset(indices) { // takes an array of 1-based indices
661 return function pset_filter(doc) {
662 var a = doc.getElementsByTagName("p");
663 var result = [];
664 for (var i in indices)
665 result.push(a[indices[i] - 1]);
666 return result;
667 }
668 }
669 test_selector_in_html(":nth-child(0)", seven_ps,
670 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
671 test_selector_in_html(":nth-child(-3)", seven_ps,
672 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
673 test_selector_in_html(":nth-child(3)", seven_ps,
674 pset([3]), pset([1, 2, 4, 5, 6, 7]));
675 test_selector_in_html(":nth-child(0n+3)", seven_ps,
676 pset([3]), pset([1, 2, 4, 5, 6, 7]));
677 test_selector_in_html(":nth-child(-0n+3)", seven_ps,
678 pset([3]), pset([1, 2, 4, 5, 6, 7]));
679 test_selector_in_html(":nth-child(8)", seven_ps,
680 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
681 test_selector_in_html(":nth-child(odd)", seven_ps,
682 pset([1, 3, 5, 7]), pset([2, 4, 6]));
683 test_selector_in_html(":nth-child(even)", seven_ps,
684 pset([2, 4, 6]), pset([1, 3, 5, 7]));
685 test_selector_in_html(":nth-child(2n-1)", seven_ps,
686 pset([1, 3, 5, 7]), pset([2, 4, 6]));
687 test_selector_in_html(":nth-child( 2n - 1 )", seven_ps,
688 pset([1, 3, 5, 7]), pset([2, 4, 6]));
689 test_selector_in_html(":nth-child(2n+1)", seven_ps,
690 pset([1, 3, 5, 7]), pset([2, 4, 6]));
691 test_selector_in_html(":nth-child( 2n + 1 )", seven_ps,
692 pset([1, 3, 5, 7]), pset([2, 4, 6]));
693 test_selector_in_html(":nth-child(2n+0)", seven_ps,
694 pset([2, 4, 6]), pset([1, 3, 5, 7]));
695 test_selector_in_html(":nth-child(2n-0)", seven_ps,
696 pset([2, 4, 6]), pset([1, 3, 5, 7]));
697 test_selector_in_html(":nth-child(-n+3)", seven_ps,
698 pset([1, 2, 3]), pset([4, 5, 6, 7]));
699 test_selector_in_html(":nth-child(-n-3)", seven_ps,
700 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
701 test_selector_in_html(":nth-child(n)", seven_ps,
702 pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
703 test_selector_in_html(":nth-child(n-3)", seven_ps,
704 pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
705 test_selector_in_html(":nth-child(n+3)", seven_ps,
706 pset([3, 4, 5, 6, 7]), pset([1, 2]));
707 test_selector_in_html(":nth-child(2n+3)", seven_ps,
708 pset([3, 5, 7]), pset([1, 2, 4, 6]));
709 test_selector_in_html(":nth-child(2n)", seven_ps,
710 pset([2, 4, 6]), pset([1, 3, 5, 7]));
711 test_selector_in_html(":nth-child(2n-3)", seven_ps,
712 pset([1, 3, 5, 7]), pset([2, 4, 6]));
713 test_selector_in_html(":nth-child(-1n+3)", seven_ps,
714 pset([1, 2, 3]), pset([4, 5, 6, 7]));
715 test_selector_in_html(":nth-child(-2n+3)", seven_ps,
716 pset([1, 3]), pset([2, 4, 5, 6, 7]));
717 // And a few spot-checks for the other :nth-* selectors
718 test_selector_in_html(":nth-child(4n+1)", seven_ps,
719 pset([1, 5]), pset([2, 3, 4, 6, 7]));
720 test_selector_in_html(":nth-last-child(4n+1)", seven_ps,
721 pset([3, 7]), pset([1, 2, 4, 5, 6]));
722 test_selector_in_html(":nth-of-type(4n+1)", seven_ps,
723 pset([1, 5]), pset([2, 3, 4, 6, 7]));
724 test_selector_in_html(":nth-last-of-type(4n+1)", seven_ps,
725 pset([3, 7]), pset([1, 2, 4, 5, 6]));
726 test_selector_in_html(":nth-child(6)", seven_ps,
727 pset([6]), pset([1, 2, 3, 4, 5, 7]));
728 test_selector_in_html(":nth-last-child(6)", seven_ps,
729 pset([2]), pset([1, 3, 4, 5, 6, 7]));
730 test_selector_in_html(":nth-of-type(6)", seven_ps,
731 pset([6]), pset([1, 2, 3, 4, 5, 7]));
732 test_selector_in_html(":nth-last-of-type(6)", seven_ps,
733 pset([2]), pset([1, 3, 4, 5, 6, 7]));
735 // Test [first|last|only]-[child|node|of-type]
736 var interesting_doc = "<!----> <div id='p1'> <!---->x<p id='s1'></p> <!----><p id='s2'></p> <!----></div> <!----><p id='p2'> <!----><span id='s3'></span> <!----><span id='s4'></span> <!---->x</p> <!----><div id='p3'> <!----><p id='s5'></p> <!----></div> <!---->";
737 function idset(ids) { // takes an array of ids
738 return function idset_filter(doc) {
739 var result = [];
740 for (var id of ids)
741 result.push(doc.getElementById(id));
742 return result;
743 }
744 }
745 function classset(classes) { // takes an array of classes
746 return function classset_filter(doc) {
747 var i, j, els;
748 var result = [];
749 for (i = 0; i < classes.length; i++) {
750 els = doc.getElementsByClassName(classes[i]);
751 for (j = 0; j < els.length; j++) {
752 result.push(els[j]);
753 }
754 }
755 return result;
756 }
757 }
758 function emptyset(doc) { return []; }
759 test_parseable(":first-child");
760 test_parseable(":last-child");
761 test_parseable(":only-child");
762 test_parseable(":-moz-first-node");
763 test_parseable(":-moz-last-node");
764 test_parseable(":first-of-type");
765 test_parseable(":last-of-type");
766 test_parseable(":only-of-type");
767 test_selector_in_html(":first-child", seven_ps,
768 pset([1]), pset([2, 3, 4, 5, 6, 7]));
769 test_selector_in_html(":first-child", interesting_doc,
770 idset(["p1", "s1", "s3", "s5"]),
771 idset(["s2", "p2", "s4", "p3"]));
772 test_selector_in_html(":-moz-first-node", interesting_doc,
773 idset(["p1", "s3", "s5"]),
774 idset(["s1", "s2", "p2", "s4", "p3"]));
775 test_selector_in_html(":last-child", seven_ps,
776 pset([7]), pset([1, 2, 3, 4, 5, 6]));
777 test_selector_in_html(":last-child", interesting_doc,
778 idset(["s2", "s4", "p3", "s5"]),
779 idset(["p1", "s1", "p2", "s3"]));
780 test_selector_in_html(":-moz-last-node", interesting_doc,
781 idset(["s2", "p3", "s5"]),
782 idset(["p1", "s1", "p2", "s3", "s4"]));
783 test_selector_in_html(":only-child", seven_ps,
784 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
785 test_selector_in_html(":only-child", interesting_doc,
786 idset(["s5"]),
787 idset(["p1", "s1", "s2", "p2", "s3", "s4", "p3"]));
788 test_selector_in_html(":first-of-type", seven_ps,
789 pset([1]), pset([2, 3, 4, 5, 6, 7]));
790 test_selector_in_html(":first-of-type", interesting_doc,
791 idset(["p1", "s1", "p2", "s3", "s5"]),
792 idset(["s2", "s4", "p3"]));
793 test_selector_in_html(":last-of-type", seven_ps,
794 pset([7]), pset([1, 2, 3, 4, 5, 6]));
795 test_selector_in_html(":last-of-type", interesting_doc,
796 idset(["s2", "p2", "s4", "p3", "s5"]),
797 idset(["p1", "s1", "s3"]));
798 test_selector_in_html(":only-of-type", seven_ps,
799 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
800 test_selector_in_html(":only-of-type", interesting_doc,
801 idset(["p2", "s5"]),
802 idset(["p1", "s1", "s2", "s3", "s4", "p3"]));
804 // And a bunch of tests for the of-type aspect of :nth-of-type() and
805 // :nth-last-of-type(). Note that the last div here contains two
806 // children.
807 var mixed_elements="<p></p><p></p><div></div><p></p><div><p></p><address></address></div><address></address>";
808 function pdaset(ps, divs, addresses) { // takes an array of 1-based indices
809 var l = { p: ps, div: divs, address: addresses };
810 return function pdaset_filter(doc) {
811 var result = [];
812 for (var tag in l) {
813 var a = doc.getElementsByTagName(tag);
814 var indices = l[tag];
815 for (var i in indices)
816 result.push(a[indices[i] - 1]);
817 }
818 return result;
819 }
820 }
821 test_selector_in_html(":nth-of-type(odd)", mixed_elements,
822 pdaset([1, 3, 4], [1], [1, 2]),
823 pdaset([2], [2], []));
824 test_selector_in_html(":nth-of-type(2n-0)", mixed_elements,
825 pdaset([2], [2], []),
826 pdaset([1, 3, 4], [1], [1, 2]));
827 test_selector_in_html(":nth-last-of-type(even)", mixed_elements,
828 pdaset([2], [1], []),
829 pdaset([1, 3, 4], [2], [1, 2]));
831 // Test greediness of descendant combinators.
832 var four_children="<div id='a'><div id='b'><div id='c'><div id='d'><\/div><\/div><\/div><\/div>";
833 test_selector_in_html("#a > div div", four_children,
834 idset(["c", "d"]), idset(["a", "b"]));
835 test_selector_in_html("#a > #b div", four_children,
836 idset(["c", "d"]), idset(["a", "b"]));
837 test_selector_in_html("#a div > div", four_children,
838 idset(["c", "d"]), idset(["a", "b"]));
839 test_selector_in_html("#a #b > div", four_children,
840 idset(["c"]), idset(["a", "b", "d"]));
841 test_selector_in_html("#a > #b div", four_children,
842 idset(["c", "d"]), idset(["a", "b"]));
843 test_selector_in_html("#a #c > div", four_children,
844 idset(["d"]), idset(["a", "b", "c"]));
845 test_selector_in_html("#a > #c div", four_children,
846 idset([]), idset(["a", "b", "c", "d"]));
848 // More descendant combinator greediness (bug 511147)
849 test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div></div>',
850 classset(["match"]), classset(["a", "b"]));
851 test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="x"></div><div class="match"></div></div>',
852 classset(["match"]), classset(["a", "b", "x"]));
853 test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"><p>filler filler <i>filler</i> filler</p></div><div class="match"></div></div>',
854 classset(["match"]), classset(["a", "b", "x"]));
855 test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="x"><p>filler filler <i>filler</i> filler</p></div><div></div><div class="b"></div><div></div><div class="x"><p>filler filler <i>filler</i> filler</p></div><div class="match"></div></div>',
856 classset(["match"]), classset(["a", "b", "x"]));
857 test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div><div class="match"></div></div>',
858 classset(["match"]), classset(["a", "b"]));
860 test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div></div>',
861 emptyset, classset(["a", "b", "nomatch"]));
862 test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div><div class="nomatch"></div></div>',
863 emptyset, classset(["a", "b", "nomatch"]));
864 test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div><div><div class="nomatch"></div></div><div></div></div>',
865 emptyset, classset(["a", "b", "nomatch"]));
866 test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div></div><div class="nomatch"></div>',
867 emptyset, classset(["a", "b", "nomatch"]));
869 // Test serialization of pseudo-elements.
870 should_serialize_to("p:first-letter", "p:first-letter");
871 should_serialize_to("div>p:first-letter", "div > p:first-letter");
872 should_serialize_to("span +div:first-line", "span + div:first-line");
874 // Test default namespaces, including inside :not().
875 var html_default_ns = "@namespace url(http://www.w3.org/1999/xhtml);";
876 var html_ns = "@namespace html url(http://www.w3.org/1999/xhtml);";
877 var xul_default_ns = "@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);";
878 var single_a = "<a id='a' href='data:text/plain,this_better_be_unvisited'></a>";
879 var set_single = idset(['a']);
880 var empty_set = idset([]);
881 test_selector_in_html("a", single_a, set_single, empty_set,
882 html_default_ns);
883 test_selector_in_html("a", single_a, empty_set, set_single,
884 xul_default_ns);
885 test_selector_in_html("*|a", single_a, set_single, empty_set,
886 xul_default_ns);
887 test_selector_in_html("html|a", single_a, set_single, empty_set,
888 xul_default_ns + html_ns);
889 // Type selectors inside :not() bring in default namespaces, but
890 // non-type selectors don't.
891 test_selector_in_html("*|a:not(*)", single_a, set_single, empty_set,
892 xul_default_ns);
893 test_selector_in_html("*|a:not(a)", single_a, set_single, empty_set,
894 xul_default_ns);
895 test_selector_in_html("*|a:not(*|*)", single_a, empty_set, set_single,
896 xul_default_ns);
897 test_selector_in_html("*|a:not(*|a)", single_a, empty_set, set_single,
898 xul_default_ns);
899 test_selector_in_html("*|a:not(:link)", single_a + "<a id='b'></a>",
900 idset(["b"]), set_single,
901 xul_default_ns);
902 test_selector_in_html("*|a:not(:visited)", single_a + "<a id='b'></a>",
903 idset(["a", "b"]), empty_set,
904 xul_default_ns);
905 test_selector_in_html("*|a:not(html|*)", single_a, empty_set, set_single,
906 xul_default_ns + html_ns);
907 test_selector_in_html("*|a:not(html|a)", single_a, empty_set, set_single,
908 xul_default_ns + html_ns);
909 test_selector_in_html("*|a:not(|*)", single_a, set_single, empty_set,
910 xul_default_ns + html_ns);
911 test_selector_in_html("*|a:not(|a)", single_a, set_single, empty_set,
912 xul_default_ns + html_ns);
913 test_selector_in_html("html|a:not(|*)", single_a, set_single, empty_set,
914 xul_default_ns + html_ns);
915 test_selector_in_html("html|a:not(|a)", single_a, set_single, empty_set,
916 xul_default_ns + html_ns);
917 test_selector_in_html("html|a:not(*|*)", single_a, empty_set, set_single,
918 xul_default_ns + html_ns);
919 test_selector_in_html("html|a:not(*|a)", single_a, empty_set, set_single,
920 xul_default_ns + html_ns);
922 // Test -moz-locale-dir
923 test_parseable(":-moz-locale-dir(ltr)");
924 test_parseable(":-moz-locale-dir(rtl)");
925 test_parseable(":-moz-locale-dir(rTl)");
926 test_parseable(":-moz-locale-dir(LTR)");
927 if (document.body.mozMatchesSelector(":-moz-locale-dir(ltr)")) {
928 test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
929 set_single, empty_set);
930 test_selector_in_html("a:-moz-locale-dir(ltR)", single_a,
931 set_single, empty_set);
932 test_selector_in_html("a:-moz-locale-dir(LTR)", single_a,
933 set_single, empty_set);
934 test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
935 empty_set, set_single);
936 } else {
937 test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
938 set_single, empty_set);
939 test_selector_in_html("a:-moz-locale-dir(rtL)", single_a,
940 set_single, empty_set);
941 test_selector_in_html("a:-moz-locale-dir(RTL)", single_a,
942 set_single, empty_set);
943 test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
944 empty_set, set_single);
945 }
947 test_balanced_unparseable(":-moz-locale-dir(other)");
948 test_balanced_unparseable(":-moz-locale-dir()");
949 test_balanced_unparseable(":-moz-locale-dir(())");
950 test_balanced_unparseable(":-moz-locale-dir(3())");
951 test_balanced_unparseable(":-moz-locale-dir(f{})");
952 test_balanced_unparseable(":-moz-locale-dir('ltr')");
953 test_balanced_unparseable(":-moz-locale-dir(ltr, other)");
954 test_balanced_unparseable(":-moz-locale-dir");
956 // Test :-moz-dir()
957 test_parseable(":-moz-dir(ltr)");
958 test_parseable(":-moz-dir(rtl)");
959 test_parseable(":-moz-dir(rTl)");
960 test_parseable(":-moz-dir(LTR)");
961 if (document.body.mozMatchesSelector(":-moz-dir(ltr)")) {
962 test_selector_in_html("a:-moz-dir(LTr)", single_a,
963 set_single, empty_set);
964 test_selector_in_html("a:-moz-dir(ltR)", single_a,
965 set_single, empty_set);
966 test_selector_in_html("a:-moz-dir(LTR)", single_a,
967 set_single, empty_set);
968 test_selector_in_html("a:-moz-dir(RTl)", single_a,
969 empty_set, set_single);
970 } else {
971 test_selector_in_html("a:-moz-dir(RTl)", single_a,
972 set_single, empty_set);
973 test_selector_in_html("a:-moz-dir(rtL)", single_a,
974 set_single, empty_set);
975 test_selector_in_html("a:-moz-dir(RTL)", single_a,
976 set_single, empty_set);
977 test_selector_in_html("a:-moz-dir(LTr)", single_a,
978 empty_set, set_single);
979 }
981 test_balanced_unparseable(":-moz-dir(other)");
982 test_balanced_unparseable(":-moz-dir()");
983 test_balanced_unparseable(":-moz-dir(())");
984 test_balanced_unparseable(":-moz-dir(3())");
985 test_balanced_unparseable(":-moz-dir(f{})");
986 test_balanced_unparseable(":-moz-dir('ltr')");
987 test_balanced_unparseable(":-moz-dir(ltr, other)");
988 test_balanced_unparseable(":-moz-dir");
990 // Test -moz-lwtheme and -moz-lwtheme-[darktext|brighttext]
991 test_parseable(":-moz-lwtheme");
992 test_parseable(":-moz-lwtheme-brighttext");
993 test_parseable(":-moz-lwtheme-darktext");
995 test_parseable(":-moz-tree-row(selected)");
996 test_parseable("::-moz-tree-row(selected)");
997 test_parseable(":-moz-tree-row(selected focus)");
998 test_parseable(":-moz-tree-row(selected , focus)");
999 test_parseable("::-moz-tree-row(selected ,focus)");
1000 test_parseable(":-moz-tree-row(selected, focus)");
1001 test_parseable("::-moz-tree-row(selected,focus)");
1002 test_parseable(":-moz-tree-row(selected focus)");
1003 test_parseable("::-moz-tree-row(selected , focus)");
1004 test_parseable("::-moz-tree-twisty( hover open )");
1005 test_balanced_unparseable("::-moz-tree-row(selected {[]} )");
1006 test_balanced_unparseable(":-moz-tree-twisty(open())");
1007 test_balanced_unparseable("::-moz-tree-twisty(hover ())");
1009 test_parseable(":-moz-window-inactive");
1010 test_parseable("div p:-moz-window-inactive:hover span");
1012 // Plugin pseudoclasses
1013 test_parseable(":-moz-type-unsupported");
1014 test_parseable(":-moz-handler-disabled");
1015 test_parseable(":-moz-handler-blocked");
1016 test_parseable(":-moz-handler-crashed");
1018 // Case sensitivity of tag selectors
1019 function setup_cased_spans(body) {
1020 var data = [
1021 { tag: "span" },
1022 { tag: "sPaN" },
1023 { tag: "Span" },
1024 { tag: "SPAN" },
1025 { ns: "http://www.w3.org/1999/xhtml", tag: "span" },
1026 { ns: "http://www.w3.org/1999/xhtml", tag: "sPaN" },
1027 { ns: "http://www.w3.org/1999/xhtml", tag: "Span" },
1028 { ns: "http://www.w3.org/1999/xhtml", tag: "SPAN" },
1029 { ns: "http://example.com/useless", tag: "span" },
1030 { ns: "http://example.com/useless", tag: "sPaN" },
1031 { ns: "http://example.com/useless", tag: "Span" },
1032 { ns: "http://example.com/useless", tag: "SPAN" },
1033 ]
1034 for (var i in data) {
1035 var ent = data[i];
1036 var elem;
1037 if ("ns" in ent) {
1038 elem = body.ownerDocument.createElementNS(ent.ns, ent.tag);
1039 } else {
1040 elem = body.ownerDocument.createElement(ent.tag);
1041 }
1042 body.appendChild(elem);
1043 }
1044 }
1045 function bodychildset(indices) {
1046 return function bodychildset_filter(doc) {
1047 var body = doc.body;
1048 var result = [];
1049 for (var i in indices) {
1050 result.push(body.childNodes[indices[i]]);
1051 }
1052 return result;
1053 }
1054 }
1055 test_selector_in_html("span", setup_cased_spans,
1056 bodychildset([0, 1, 2, 3, 4, 8]),
1057 bodychildset([5, 6, 7, 9, 10, 11]));
1058 test_selector_in_html("sPaN", setup_cased_spans,
1059 bodychildset([0, 1, 2, 3, 4, 9]),
1060 bodychildset([5, 6, 7, 8, 10, 11]));
1061 test_selector_in_html("Span", setup_cased_spans,
1062 bodychildset([0, 1, 2, 3, 4, 10]),
1063 bodychildset([5, 6, 7, 8, 9, 11]));
1064 test_selector_in_html("SPAN", setup_cased_spans,
1065 bodychildset([0, 1, 2, 3, 4, 11]),
1066 bodychildset([5, 6, 7, 8, 9, 10]));
1068 // bug 528096 (tree pseudos)
1069 test_unbalanced_unparseable(":-moz-tree-column((){} a");
1070 test_unbalanced_unparseable(":-moz-tree-column(x(){} a");
1071 test_unbalanced_unparseable(":-moz-tree-column(a b (){} a");
1072 test_unbalanced_unparseable(":-moz-tree-column(a, b (){} a");
1074 // Bug 543428 (escaping)
1075 test_selector_in_html("\\32|a", single_a, set_single, empty_set,
1076 "@namespace \\32 url(http://www.w3.org/1999/xhtml);");
1077 test_selector_in_html("-\\32|a", single_a, set_single, empty_set,
1078 "@namespace -\\32 url(http://www.w3.org/1999/xhtml);");
1079 test_selector_in_html("\\2|a", single_a, set_single, empty_set,
1080 "@namespace \\0002 url(http://www.w3.org/1999/xhtml);");
1081 test_selector_in_html("-\\2|a", single_a, set_single, empty_set,
1082 "@namespace -\\000002 url(http://www.w3.org/1999/xhtml);");
1083 var spans = "<span class='2'></span><span class=''></span>" +
1084 "<span id='2'></span><span id=''></span>"
1085 test_selector_in_html(".\\32", spans,
1086 bodychildset([0]), bodychildset([1, 2, 3]));
1087 test_selector_in_html("[class=\\32]", spans,
1088 bodychildset([0]), bodychildset([1, 2, 3]));
1089 test_selector_in_html(".\\2", spans,
1090 bodychildset([1]), bodychildset([0, 2, 3]));
1091 test_selector_in_html("[class=\\2]", spans,
1092 bodychildset([1]), bodychildset([0, 2, 3]));
1093 test_selector_in_html("#\\32", spans,
1094 bodychildset([2]), bodychildset([0, 1, 3]));
1095 test_selector_in_html("[id=\\32]", spans,
1096 bodychildset([2]), bodychildset([0, 1, 3]));
1097 test_selector_in_html("#\\2", spans,
1098 bodychildset([3]), bodychildset([0, 1, 2]));
1099 test_selector_in_html("[id=\\2]", spans,
1100 bodychildset([3]), bodychildset([0, 1, 2]));
1101 test_balanced_unparseable("#2");
1103 // Bug 553805: :not() containing nothing is forbidden
1104 test_balanced_unparseable(":not()");
1105 test_balanced_unparseable(":not( )");
1106 test_balanced_unparseable(":not( \t\n )");
1107 test_balanced_unparseable(":not(/*comment*/)");
1108 test_balanced_unparseable(":not( /*comment*/ /* comment */ )");
1109 test_balanced_unparseable("p :not()");
1110 test_balanced_unparseable("p :not( )");
1111 test_balanced_unparseable("p :not( \t\n )");
1112 test_balanced_unparseable("p :not(/*comment*/)");
1113 test_balanced_unparseable("p :not( /*comment*/ /* comment */ )");
1114 test_balanced_unparseable("p:not()");
1115 test_balanced_unparseable("p:not( )");
1116 test_balanced_unparseable("p:not( \t\n )");
1117 test_balanced_unparseable("p:not(/*comment*/)");
1118 test_balanced_unparseable("p:not( /*comment*/ /* comment */ )");
1120 test_balanced_unparseable(":not(:nth-child(2k))");
1121 test_balanced_unparseable(":not(:nth-child(()))");
1123 // :-moz-any()
1124 test_balanced_unparseable(":-moz-any()");
1125 test_balanced_unparseable(":-moz-any(div p)");
1126 test_balanced_unparseable(":-moz-any(div ~ p)");
1127 test_balanced_unparseable(":-moz-any(div~p)");
1128 test_balanced_unparseable(":-moz-any(div + p)");
1129 test_balanced_unparseable(":-moz-any(div+p)");
1130 test_balanced_unparseable(":-moz-any(div > p)");
1131 test_balanced_unparseable(":-moz-any(div>p)");
1132 test_parseable(":-moz-any(div, p)");
1133 test_parseable(":-moz-any( div , p )");
1134 test_parseable(":-moz-any(div,p)");
1135 test_parseable(":-moz-any(div)");
1136 test_parseable(":-moz-any(div,p,:link,span:focus)");
1137 test_parseable(":-moz-any(:active,:focus)");
1138 test_parseable(":-moz-any(:active,:link:focus)");
1139 test_balanced_unparseable(":-moz-any(div,:nonexistentpseudo)");
1140 var any_elts = "<input type='text'><a href='http://www.example.com/'></a><div></div><a name='foo'>";
1141 test_selector_in_html(":-moz-any(a,input)", any_elts,
1142 bodychildset([0, 1, 3]), bodychildset([2]));
1143 test_selector_in_html(":-moz-any(:link,:not(a))", any_elts,
1144 bodychildset([0, 1, 2]), bodychildset([3]));
1145 test_selector_in_html(":-moz-any([href],input[type],input[name])", any_elts,
1146 bodychildset([0, 1]), bodychildset([2, 3]));
1147 test_selector_in_html(":-moz-any(div,a):-moz-any([type],[href],[name])",
1148 any_elts,
1149 bodychildset([1, 3]), bodychildset([0, 2]));
1151 test_selector_in_html(":-moz-table-border-nonzero",
1152 "<p></p>" +
1153 "<p border='2'></p>" +
1154 "<table border='2'></table>" +
1155 "<table border></table>" +
1156 "<table></table>" +
1157 "<table frame='border'></table>" +
1158 "<table border='0'></table>" +
1159 "<table border='0pt'></table>" +
1160 "<table border='3pt'></table>",
1161 bodychildset([2, 3, 8]),
1162 bodychildset([0, 1, 4, 5, 6, 7]));
1164 // Test that we don't tokenize an empty HASH.
1165 test_balanced_unparseable("#");
1166 test_balanced_unparseable("# ");
1167 test_balanced_unparseable("#, p");
1168 test_balanced_unparseable("# , p");
1169 test_balanced_unparseable("p #");
1170 test_balanced_unparseable("p # ");
1171 test_balanced_unparseable("p #, p");
1172 test_balanced_unparseable("p # , p");
1174 // Test that a backslash alone at EOF outside of a string is treated
1175 // as U+FFFD.
1176 test_parseable_via_api("#a\\");
1177 test_parseable_via_api("#\\");
1178 test_parseable_via_api("\\");
1180 // Test that newline escapes are only supported in strings.
1181 test_balanced_unparseable("di\\\nv");
1182 test_balanced_unparseable("div \\\n p");
1183 test_balanced_unparseable("div\\\n p");
1184 test_balanced_unparseable("div \\\np");
1185 test_balanced_unparseable("div\\\np");
1187 // Test that :-moz-placeholder is parsable.
1188 test_parseable(":-moz-placeholder");
1190 run_deferred_tests();
1191 }
1193 var deferred_tests = [];
1195 function defer_clonedoc_tests(docurl, onloadfunc)
1196 {
1197 deferred_tests.push( { docurl: docurl, onloadfunc: onloadfunc } );
1198 }
1200 function run_deferred_tests()
1201 {
1202 if (deferred_tests.length == 0) {
1203 SimpleTest.finish();
1204 return;
1205 }
1207 cloneiframe.onload = deferred_tests_onload;
1208 cloneiframe.src = deferred_tests[0].docurl;
1209 }
1211 function deferred_tests_onload(event)
1212 {
1213 if (event.target != cloneiframe)
1214 return;
1216 deferred_tests[0].onloadfunc();
1217 deferred_tests.shift();
1219 run_deferred_tests();
1220 }
1222 </script>
1223 </pre>
1224 </body>
1225 </html>