1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/test/test_selectors.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1225 @@ 1.4 +<!DOCTYPE HTML> 1.5 +<html> 1.6 +<head> 1.7 + <title>Test for CSS Selectors</title> 1.8 + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.9 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 1.10 +</head> 1.11 +<body onload="run()"> 1.12 +<p id="display"><iframe id="iframe" src="about:blank"></iframe><iframe id="cloneiframe" src="about:blank"></iframe></p> 1.13 +<pre id="test"> 1.14 +<script class="testbody" type="text/javascript"> 1.15 + 1.16 +SimpleTest.waitForExplicitFinish(); 1.17 + 1.18 +var cloneiframe; 1.19 + 1.20 +function run() { 1.21 + 1.22 + var iframe = document.getElementById("iframe"); 1.23 + var ifwin = iframe.contentWindow; 1.24 + var ifdoc = iframe.contentDocument; 1.25 + 1.26 + cloneiframe = document.getElementById("cloneiframe"); 1.27 + 1.28 + var style_elem = ifdoc.createElement("style"); 1.29 + style_elem.setAttribute("type", "text/css"); 1.30 + ifdoc.getElementsByTagName("head")[0].appendChild(style_elem); 1.31 + var style_text = ifdoc.createTextNode(""); 1.32 + style_elem.appendChild(style_text); 1.33 + 1.34 + var gCounter = 0; 1.35 + 1.36 + /* 1.37 + * selector: the selector to test 1.38 + * body_contents: what to set the body's innerHTML to 1.39 + * match_fn: a function that, given the document object into which 1.40 + * body_contents has been inserted, produces an array of nodes that 1.41 + * should match selector 1.42 + * notmatch_fn: likewise, but for nodes that should not match 1.43 + * namespaces (optional): @namespace rules to be included in the sheet 1.44 + */ 1.45 + function test_selector_in_html(selector, body_contents, match_fn, notmatch_fn, namespaces) 1.46 + { 1.47 + var zi = ++gCounter; 1.48 + if (typeof(body_contents) == "string") { 1.49 + ifdoc.body.innerHTML = body_contents; 1.50 + } else { 1.51 + // It's a function. 1.52 + ifdoc.body.innerHTML = ""; 1.53 + body_contents(ifdoc.body); 1.54 + } 1.55 + if (!namespaces) { 1.56 + namespaces = ""; 1.57 + } 1.58 + style_text.data = namespaces + selector + "{ z-index: " + zi + " }"; 1.59 + 1.60 + var idx = style_text.parentNode.sheet.cssRules.length - 1; 1.61 + if (namespaces == "") { 1.62 + is(idx, 0, "unexpected rule index"); 1.63 + } 1.64 + if (idx < 0 || 1.65 + style_text.parentNode.sheet.cssRules[idx].type != 1.66 + CSSRule.STYLE_RULE) 1.67 + { 1.68 + ok(false, "selector " + selector + " could not be parsed"); 1.69 + return; 1.70 + } 1.71 + 1.72 + var should_match = match_fn(ifdoc); 1.73 + var should_not_match = notmatch_fn(ifdoc); 1.74 + if (should_match.length + should_not_match.length == 0) { 1.75 + ok(false, "nothing to check"); 1.76 + } 1.77 + 1.78 + for (var i = 0; i < should_match.length; ++i) { 1.79 + var e = should_match[i]; 1.80 + is(ifwin.getComputedStyle(e, "").zIndex, zi, 1.81 + "element in " + body_contents + " matched " + selector); 1.82 + } 1.83 + for (var i = 0; i < should_not_match.length; ++i) { 1.84 + var e = should_not_match[i]; 1.85 + is(ifwin.getComputedStyle(e, "").zIndex, "auto", 1.86 + "element in " + body_contents + " did not match " + selector); 1.87 + } 1.88 + 1.89 + // Now, since we're here, may as well make sure serialization 1.90 + // works correctly. It need not produce the exact same text, 1.91 + // but it should produce a selector that matches the same 1.92 + // elements. 1.93 + zi = ++gCounter; 1.94 + var ser1 = style_text.parentNode.sheet.cssRules[idx].selectorText; 1.95 + style_text.data = namespaces + ser1 + "{ z-index: " + zi + " }"; 1.96 + for (var i = 0; i < should_match.length; ++i) { 1.97 + var e = should_match[i]; 1.98 + is(ifwin.getComputedStyle(e, "").zIndex, zi, 1.99 + "element in " + body_contents + " matched " + ser1 + 1.100 + " which is the reserialization of " + selector); 1.101 + } 1.102 + for (var i = 0; i < should_not_match.length; ++i) { 1.103 + var e = should_not_match[i]; 1.104 + is(ifwin.getComputedStyle(e, "").zIndex, "auto", 1.105 + "element in " + body_contents + " did not match " + ser1 + 1.106 + " which is the reserialization of " + selector); 1.107 + } 1.108 + 1.109 + // But when we serialize the serialized result, we should get 1.110 + // the same text. 1.111 + var ser2 = style_text.parentNode.sheet.cssRules[idx].selectorText; 1.112 + is(ser2, ser1, "parse+serialize of selector \"" + selector + 1.113 + "\" is idempotent"); 1.114 + 1.115 + ifdoc.body.innerHTML = ""; 1.116 + style_text.data = ""; 1.117 + 1.118 + // And now test that when we clone the style sheet, we end up 1.119 + // with the same selector (serializes to same string, and 1.120 + // matches the same things). 1.121 + zi = ++gCounter; 1.122 + var style_sheet = "data:text/css," + 1.123 + escape(namespaces + selector + "{ z-index: " + zi + " }"); 1.124 + var style_sheet_link = 1.125 + "<link rel='stylesheet' href='" + style_sheet + "'>"; 1.126 + var html_doc = "<!DOCTYPE HTML>" + 1.127 + style_sheet_link + style_sheet_link + 1.128 + "<body>"; 1.129 + if (typeof(body_contents) == "string") { 1.130 + html_doc += body_contents; 1.131 + } 1.132 + var docurl = "data:text/html," + escape(html_doc); 1.133 + defer_clonedoc_tests(docurl, function() { 1.134 + var clonedoc = cloneiframe.contentDocument; 1.135 + var clonewin = cloneiframe.contentWindow; 1.136 + 1.137 + if (typeof(body_contents) != "string") { 1.138 + body_contents(clonedoc.body); 1.139 + } 1.140 + 1.141 + var links = clonedoc.getElementsByTagName("link"); 1.142 + // cause a clone 1.143 + links[1].sheet.insertRule("#nonexistent { color: purple}", idx + 1); 1.144 + // remove the uncloned sheet 1.145 + links[0].parentNode.removeChild(links[0]); 1.146 + 1.147 + var should_match = match_fn(clonedoc); 1.148 + var should_not_match = notmatch_fn(clonedoc); 1.149 + 1.150 + if (should_match.length + should_not_match.length == 0) { 1.151 + ok(false, "nothing to check"); 1.152 + } 1.153 + 1.154 + for (var i = 0; i < should_match.length; ++i) { 1.155 + var e = should_match[i]; 1.156 + is(clonewin.getComputedStyle(e, "").zIndex, zi, 1.157 + "element in " + body_contents + " matched clone of " + 1.158 + selector); 1.159 + } 1.160 + for (var i = 0; i < should_not_match.length; ++i) { 1.161 + var e = should_not_match[i]; 1.162 + is(clonewin.getComputedStyle(e, "").zIndex, "auto", 1.163 + "element in " + body_contents + " did not match clone of " + 1.164 + selector); 1.165 + } 1.166 + 1.167 + var ser3 = links[0].sheet.cssRules[idx].selectorText; 1.168 + is(ser3, ser1, 1.169 + "selector " + selector + " serializes correctly after cloning"); 1.170 + }); 1.171 + } 1.172 + 1.173 + function should_serialize_to(selector, serialization) 1.174 + { 1.175 + style_text.data = selector + "{ z-index: 0 }"; 1.176 + is(style_text.parentNode.sheet.cssRules[0].selectorText, 1.177 + serialization, 1.178 + "selector '" + selector + "' should serialize to '" + 1.179 + serialization + "'."); 1.180 + } 1.181 + 1.182 + function test_parseable(selector) 1.183 + { 1.184 + ifdoc.body.innerHTML = "<p></p>"; 1.185 + 1.186 + var zi = ++gCounter; 1.187 + style_text.data = "p, " + selector + "{ z-index: " + zi + " }"; 1.188 + var should_match = ifdoc.getElementsByTagName("p")[0]; 1.189 + var parsed = ifwin.getComputedStyle(should_match, "").zIndex == zi; 1.190 + ok(parsed, "selector " + selector + " was parsed"); 1.191 + if (!parsed) { 1.192 + return; 1.193 + } 1.194 + 1.195 + // Test that it serializes to something that is also parseable. 1.196 + var ser1 = style_elem.sheet.cssRules[0].selectorText; 1.197 + zi = ++gCounter; 1.198 + style_text.data = ser1 + "{ z-index: " + zi + " }"; 1.199 + is(ifwin.getComputedStyle(should_match, "").zIndex, zi, 1.200 + "serialization " + ser1 + " of selector p, " + selector + 1.201 + " was parsed"); 1.202 + var ser2 = style_elem.sheet.cssRules[0].selectorText; 1.203 + is(ser2, ser1, 1.204 + "parse+serialize of selector " + selector + " is idempotent"); 1.205 + 1.206 + ifdoc.body.innerHTML = ""; 1.207 + style_text.data = ""; 1.208 + 1.209 + // Test that it clones to the same thing it serializes to. 1.210 + zi = ++gCounter; 1.211 + var style_sheet = "data:text/css," + 1.212 + escape("p, " + selector + "{ z-index: " + zi + " }"); 1.213 + var style_sheet_link = 1.214 + "<link rel='stylesheet' href='" + style_sheet + "'>"; 1.215 + var html_doc = "<!DOCTYPE HTML>" + 1.216 + style_sheet_link + style_sheet_link + 1.217 + "<p></p>"; 1.218 + var docurl = "data:text/html," + escape(html_doc); 1.219 + 1.220 + defer_clonedoc_tests(docurl, function() { 1.221 + var clonedoc = cloneiframe.contentDocument; 1.222 + var clonewin = cloneiframe.contentWindow; 1.223 + var links = clonedoc.getElementsByTagName("link"); 1.224 + // cause a clone 1.225 + links[1].sheet.insertRule("#nonexistent { color: purple}", 0); 1.226 + // remove the uncloned sheet 1.227 + links[0].parentNode.removeChild(links[0]); 1.228 + 1.229 + should_match = clonedoc.getElementsByTagName("p")[0]; 1.230 + is(clonewin.getComputedStyle(should_match, "").zIndex, zi, 1.231 + "selector " + selector + " was cloned correctly"); 1.232 + var ser3 = links[0].sheet.cssRules[1].selectorText; 1.233 + is(ser3, ser1, 1.234 + "selector " + selector + " serializes correctly after cloning"); 1.235 + }); 1.236 + } 1.237 + 1.238 + function test_unparseable_via_api(selector) 1.239 + { 1.240 + try { 1.241 + // Test that it is also unparseable when followed by EOF. 1.242 + ifdoc.body.mozMatchesSelector(selector); 1.243 + ok(false, "selector '" + selector + "' plus EOF is parse error"); 1.244 + } catch(ex) { 1.245 + is(ex.name, "SyntaxError", 1.246 + "selector '" + selector + "' plus EOF is parse error"); 1.247 + is(ex.code, DOMException.SYNTAX_ERR, 1.248 + "selector '" + selector + "' plus EOF is parse error"); 1.249 + } 1.250 + } 1.251 + 1.252 + function test_parseable_via_api(selector) 1.253 + { 1.254 + var threw = false; 1.255 + try { 1.256 + // Test that a selector is parseable when followed by EOF. 1.257 + ifdoc.body.mozMatchesSelector(selector); 1.258 + } catch(ex) { 1.259 + threw = true; 1.260 + } 1.261 + ok(!threw, "selector '" + selector + "' was parsed"); 1.262 + } 1.263 + 1.264 + function test_balanced_unparseable(selector) 1.265 + { 1.266 + var zi1 = ++gCounter; 1.267 + var zi2 = ++gCounter; 1.268 + ifdoc.body.innerHTML = "<p></p><div></div>"; 1.269 + style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" + 1.270 + "div { z-index: " + zi2 + " }"; 1.271 + var should_not_match = ifdoc.getElementsByTagName("p")[0]; 1.272 + var should_match = ifdoc.getElementsByTagName("div")[0]; 1.273 + is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto", 1.274 + "selector " + selector + " was a parser error"); 1.275 + is(ifwin.getComputedStyle(should_match, "").zIndex, zi2, 1.276 + "selector " + selector + " error was recovered from"); 1.277 + ifdoc.body.innerHTML = ""; 1.278 + style_text.data = ""; 1.279 + test_unparseable_via_api(selector); 1.280 + } 1.281 + 1.282 + function test_unbalanced_unparseable(selector) 1.283 + { 1.284 + var zi1 = ++gCounter; 1.285 + var zi2 = ++gCounter; 1.286 + ifdoc.body.innerHTML = "<p></p>"; 1.287 + style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }"; 1.288 + var should_not_match = ifdoc.getElementsByTagName("p")[0]; 1.289 + is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto", 1.290 + "selector " + selector + " was a parser error"); 1.291 + is(style_text.parentNode.sheet.cssRules.length, 0, 1.292 + "sheet should have no rules since " + selector + " is parse error"); 1.293 + ifdoc.body.innerHTML = ""; 1.294 + style_text.data = ""; 1.295 + test_unparseable_via_api(selector); 1.296 + } 1.297 + 1.298 + 1.299 + // [attr= ] selector 1.300 + test_parseable("[attr=\"x\"]"); 1.301 + test_parseable("[attr='x']"); 1.302 + test_parseable("[attr=x]"); 1.303 + test_parseable("[attr=\"\"]"); 1.304 + test_parseable("[attr='']"); 1.305 + test_parseable("[attr=\"foo bar\"]"); 1.306 + 1.307 + test_balanced_unparseable("[attr=]"); 1.308 + test_balanced_unparseable("[attr=foo bar]"); 1.309 + 1.310 + test_selector_in_html( 1.311 + '[title=""]', 1.312 + '<p title=""></p>' 1.313 + + '<div lang=" "></div><div lang="\t"></div><div lang="\n"></div>', 1.314 + function(doc) { return doc.getElementsByTagName("p"); }, 1.315 + function(doc) { return doc.getElementsByTagName("div"); } 1.316 + ); 1.317 + 1.318 + // [attr~= ] selector 1.319 + test_parseable("[attr~=\"x\"]"); 1.320 + test_parseable("[attr~='x']"); 1.321 + test_parseable("[attr~=x]"); 1.322 + test_parseable("[attr~=\"\"]"); 1.323 + test_parseable("[attr~='']"); 1.324 + test_parseable("[attr~=\"foo bar\"]"); 1.325 + 1.326 + test_balanced_unparseable("[attr~=]"); 1.327 + test_balanced_unparseable("[attr~=foo bar]"); 1.328 + 1.329 + test_selector_in_html( 1.330 + '[class~="x x"]', 1.331 + '<div class="x x"></div><div class="x"></div><div class="x\tx"></div>div class="x\nx"></div>', 1.332 + function(doc) { return []; }, 1.333 + function(doc) { return doc.getElementsByTagName("div"); } 1.334 + ); 1.335 + 1.336 + // [attr|="x"] 1.337 + test_parseable('[attr|="x"]'); 1.338 + test_parseable("[attr|='x']"); 1.339 + test_parseable('[attr|=x]'); 1.340 + 1.341 + test_parseable('[attr|=""]'); 1.342 + test_parseable("[attr|='']"); 1.343 + test_balanced_unparseable('[attr|=]'); 1.344 + 1.345 + test_selector_in_html( 1.346 + '[lang|=""]', 1.347 + '<p lang=""></p><p lang="-"></p><p lang="-GB"></p>' 1.348 + + '<div lang="en-GB"></div><div lang="en-"></div>', 1.349 + function(doc) { return doc.getElementsByTagName("p"); }, 1.350 + function(doc) { return doc.getElementsByTagName("div"); } 1.351 + ); 1.352 + 1.353 + // [attr$= ] selector 1.354 + test_parseable("[attr$=\"x\"]"); 1.355 + test_parseable("[attr$='x']"); 1.356 + test_parseable("[attr$=x]"); 1.357 + test_parseable("[attr$=\"\"]"); 1.358 + test_parseable("[attr$='']"); 1.359 + test_parseable("[attr$=\"foo bar\"]"); 1.360 + 1.361 + test_balanced_unparseable("[attr$=]"); 1.362 + test_balanced_unparseable("[attr$=foo bar]"); 1.363 + 1.364 + // [attr^= ] selector 1.365 + test_parseable("[attr^=\"x\"]"); 1.366 + test_parseable("[attr^='x']"); 1.367 + test_parseable("[attr^=x]"); 1.368 + test_parseable("[attr^=\"\"]"); 1.369 + test_parseable("[attr^='']"); 1.370 + test_parseable("[attr^=\"foo bar\"]"); 1.371 + 1.372 + test_balanced_unparseable("[attr^=]"); 1.373 + test_balanced_unparseable("[attr^=foo bar]"); 1.374 + 1.375 + // attr[*= ] selector 1.376 + test_parseable("[attr*=\"x\"]"); 1.377 + test_parseable("[attr*='x']"); 1.378 + test_parseable("[attr*=x]"); 1.379 + test_parseable("[attr*=\"\"]"); 1.380 + test_parseable("[attr*='']"); 1.381 + test_parseable("[attr*=\"foo bar\"]"); 1.382 + 1.383 + test_balanced_unparseable("[attr*=]"); 1.384 + test_balanced_unparseable("[attr*=foo bar]"); 1.385 + 1.386 + 1.387 + // Bug 420814 1.388 + test_selector_in_html( 1.389 + "div ~ div p", 1.390 + "<div></div><div><div><p>match</p></div></div>", 1.391 + function(doc) { return doc.getElementsByTagName("p"); }, 1.392 + function(doc) { return []; } 1.393 + ); 1.394 + 1.395 + // Bug 420245 1.396 + test_selector_in_html( 1.397 + "p[attr$=\"\"]", 1.398 + "<p attr=\"foo\">This should not match</p>", 1.399 + function(doc) { return []; }, 1.400 + function(doc) { return doc.getElementsByTagName("p"); } 1.401 + ); 1.402 + test_selector_in_html( 1.403 + "div + p[attr~=\"\"]", 1.404 + "<div>Dummy</div><p attr=\"foo\">This should not match</p>", 1.405 + function(doc) { return []; }, 1.406 + function(doc) { return doc.getElementsByTagName("p"); } 1.407 + ); 1.408 + test_selector_in_html( 1.409 + "div[attr^=\"\"]", 1.410 + "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>", 1.411 + function(doc) { return []; }, 1.412 + function(doc) { return doc.getElementsByTagName("div"); } 1.413 + ); 1.414 + test_selector_in_html( 1.415 + "div[attr*=\"\"]", 1.416 + "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>", 1.417 + function(doc) { return []; }, 1.418 + function(doc) { return doc.getElementsByTagName("div"); } 1.419 + ); 1.420 + 1.421 + // :nth-child(), etc. 1.422 + // Follow the whitespace rules as proposed in 1.423 + // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html 1.424 + test_balanced_unparseable(":nth-child()"); 1.425 + test_balanced_unparseable(":nth-of-type( )"); 1.426 + test_parseable(":nth-last-child( odd)"); 1.427 + test_parseable(":nth-last-of-type(even )"); 1.428 + test_parseable(":nth-child(n )"); 1.429 + test_parseable(":nth-of-type( 2n)"); 1.430 + test_parseable(":nth-last-child( -n)"); 1.431 + test_parseable(":nth-last-of-type(-2n )"); 1.432 + test_balanced_unparseable(":nth-child(- n)"); 1.433 + test_balanced_unparseable(":nth-of-type(-2 n)"); 1.434 + test_balanced_unparseable(":nth-last-of-type(2n1)"); 1.435 + test_balanced_unparseable(":nth-child(2n++1)"); 1.436 + test_balanced_unparseable(":nth-of-type(2n-+1)"); 1.437 + test_balanced_unparseable(":nth-last-child(2n+-1)"); 1.438 + test_balanced_unparseable(":nth-last-of-type(2n--1)"); 1.439 + test_parseable(":nth-child( 3n + 1 )"); 1.440 + test_parseable(":nth-child( +3n - 2 )"); 1.441 + test_parseable(":nth-child( -n+ 6)"); 1.442 + test_parseable(":nth-child( +6 )"); 1.443 + test_balanced_unparseable(":nth-child(3 n)"); 1.444 + test_balanced_unparseable(":nth-child(+ 2n)"); 1.445 + test_balanced_unparseable(":nth-child(+ 2)"); 1.446 + test_parseable(":nth-child(3)"); 1.447 + test_parseable(":nth-of-type(-3)"); 1.448 + test_parseable(":nth-last-child(+3)"); 1.449 + test_parseable(":nth-last-of-type(0)"); 1.450 + test_parseable(":nth-child(-0)"); 1.451 + test_parseable(":nth-of-type(3n)"); 1.452 + test_parseable(":nth-last-child(-3n)"); 1.453 + test_parseable(":nth-last-of-type(+3n)"); 1.454 + test_parseable(":nth-last-of-type(0n)"); 1.455 + test_parseable(":nth-child(-0n)"); 1.456 + test_parseable(":nth-of-type(n)"); 1.457 + test_parseable(":nth-last-child(-n)"); 1.458 + test_parseable(":nth-last-of-type(2n+1)"); 1.459 + test_parseable(":nth-child(2n-1)"); 1.460 + test_parseable(":nth-of-type(2n+0)"); 1.461 + test_parseable(":nth-last-child(2n-0)"); 1.462 + test_parseable(":nth-child(-0n+0)"); 1.463 + test_parseable(":nth-of-type(n+1)"); 1.464 + test_parseable(":nth-last-child(n-1)"); 1.465 + test_parseable(":nth-last-of-type(-n+1)"); 1.466 + test_parseable(":nth-child(-n-1)"); 1.467 + test_balanced_unparseable(":nth-child(2-n)"); 1.468 + test_balanced_unparseable(":nth-child(2-n-1)"); 1.469 + test_balanced_unparseable(":nth-child(n-2-1)"); 1.470 + // Bug 750388 1.471 + test_parseable(":nth-child(+n)"); 1.472 + test_balanced_unparseable(":nth-child(+ n)"); 1.473 + test_parseable(":nth-child(+n+2)"); 1.474 + test_parseable(":nth-child(+n-2)"); 1.475 + test_parseable(":nth-child(+n + 2)"); 1.476 + test_parseable(":nth-child(+n - 2)"); 1.477 + test_balanced_unparseable(":nth-child(+ n+2)"); 1.478 + test_balanced_unparseable(":nth-child(+ n-2)"); 1.479 + test_balanced_unparseable(":nth-child(+ n + 2)"); 1.480 + test_balanced_unparseable(":nth-child(+ n - 2)"); 1.481 + test_parseable(":nth-child(+n-100)"); 1.482 + test_parseable(":nth-child(+n - 100)"); 1.483 + test_balanced_unparseable(":nth-child(+ n-100)"); 1.484 + test_balanced_unparseable(":nth-child(+-n+2)"); 1.485 + test_balanced_unparseable(":nth-child(+ -n+2)"); 1.486 + test_balanced_unparseable(":nth-child(+-n-100)"); 1.487 + test_balanced_unparseable(":nth-child(+ -n-100)"); 1.488 + test_balanced_unparseable(":nth-child(++n-100)"); 1.489 + test_balanced_unparseable(":nth-child(-+n-100)"); 1.490 + test_balanced_unparseable(":nth-child(++2n - 100)"); 1.491 + test_balanced_unparseable(":nth-child(+-2n - 100)"); 1.492 + test_balanced_unparseable(":nth-child(-+2n - 100)"); 1.493 + test_balanced_unparseable(":nth-child(--2n - 100)"); 1.494 + test_balanced_unparseable(":nth-child(+/**/+2n - 100)"); 1.495 + test_balanced_unparseable(":nth-child(+/**/-2n - 100)"); 1.496 + test_balanced_unparseable(":nth-child(-/**/+2n - 100)"); 1.497 + test_balanced_unparseable(":nth-child(-/**/-2n - 100)"); 1.498 + test_balanced_unparseable(":nth-child(+/**/+/**/2n - 100)"); 1.499 + test_balanced_unparseable(":nth-child(+/**/-/**/2n - 100)"); 1.500 + test_balanced_unparseable(":nth-child(-/**/+/**/2n - 100)"); 1.501 + test_balanced_unparseable(":nth-child(-/**/-/**/2n - 100)"); 1.502 + test_balanced_unparseable(":nth-child(++/**/2n - 100)"); 1.503 + test_balanced_unparseable(":nth-child(+-/**/2n - 100)"); 1.504 + test_balanced_unparseable(":nth-child(-+/**/2n - 100)"); 1.505 + test_balanced_unparseable(":nth-child(--/**/2n - 100)"); 1.506 + test_balanced_unparseable(":nth-child(-even)"); 1.507 + test_balanced_unparseable(":nth-child(-odd)"); 1.508 + test_balanced_unparseable(":nth-child(+even)"); 1.509 + test_balanced_unparseable(":nth-child(+odd)"); 1.510 + test_balanced_unparseable(":nth-child(+ even)"); 1.511 + test_balanced_unparseable(":nth-child(+ odd)"); 1.512 + test_balanced_unparseable(":nth-child(+-n)"); 1.513 + test_balanced_unparseable(":nth-child(+-n-)"); 1.514 + test_balanced_unparseable(":nth-child(-+n)"); 1.515 + test_balanced_unparseable(":nth-child(+n--)"); 1.516 + test_parseable(":nth-child(n+2)"); 1.517 + test_parseable(":nth-child(n/**/+/**/2)"); 1.518 + test_parseable(":nth-child(n-2)"); 1.519 + test_parseable(":nth-child(n/**/-/**/2)"); 1.520 + test_balanced_unparseable(":nth-child(n++2)"); 1.521 + test_balanced_unparseable(":nth-child(n+-2)"); 1.522 + test_balanced_unparseable(":nth-child(n-+2)"); 1.523 + test_balanced_unparseable(":nth-child(n--2)"); 1.524 + test_balanced_unparseable(":nth-child(n/**/++2)"); 1.525 + test_balanced_unparseable(":nth-child(n/**/+-2)"); 1.526 + test_balanced_unparseable(":nth-child(n/**/-+2)"); 1.527 + test_balanced_unparseable(":nth-child(n/**/--2)"); 1.528 + test_balanced_unparseable(":nth-child(n/**/+/**/+2)"); 1.529 + test_balanced_unparseable(":nth-child(n/**/+/**/-2)"); 1.530 + test_balanced_unparseable(":nth-child(n/**/-/**/+2)"); 1.531 + test_balanced_unparseable(":nth-child(n/**/-/**/-2)"); 1.532 + test_balanced_unparseable(":nth-child(n+/**/+2)"); 1.533 + test_balanced_unparseable(":nth-child(n+/**/-2)"); 1.534 + test_balanced_unparseable(":nth-child(n-/**/+2)"); 1.535 + test_balanced_unparseable(":nth-child(n-/**/-2)"); 1.536 + test_balanced_unparseable(":nth-child(n++/**/2)"); 1.537 + test_balanced_unparseable(":nth-child(n+-/**/2)"); 1.538 + test_balanced_unparseable(":nth-child(n-+/**/2)"); 1.539 + test_balanced_unparseable(":nth-child(n--/**/2)"); 1.540 + test_balanced_unparseable(":nth-child(n/**/++/**/2)"); 1.541 + test_balanced_unparseable(":nth-child(n/**/+-/**/2)"); 1.542 + test_balanced_unparseable(":nth-child(n/**/-+/**/2)"); 1.543 + test_balanced_unparseable(":nth-child(n/**/--/**/2)"); 1.544 + test_balanced_unparseable(":nth-child(n/**/+/**/+/**/2)"); 1.545 + test_balanced_unparseable(":nth-child(n/**/+/**/-/**/2)"); 1.546 + test_balanced_unparseable(":nth-child(n/**/-/**/+/**/2)"); 1.547 + test_balanced_unparseable(":nth-child(n/**/-/**/-/**/2)"); 1.548 + test_balanced_unparseable(":nth-child(n+/**/+/**/2)"); 1.549 + test_balanced_unparseable(":nth-child(n+/**/-/**/2)"); 1.550 + test_balanced_unparseable(":nth-child(n-/**/+/**/2)"); 1.551 + test_balanced_unparseable(":nth-child(n-/**/-/**/2)"); 1.552 + test_parseable(":nth-child(2n+2)"); 1.553 + test_parseable(":nth-child(2n/**/+/**/2)"); 1.554 + test_parseable(":nth-child(2n-2)"); 1.555 + test_parseable(":nth-child(2n/**/-/**/2)"); 1.556 + test_balanced_unparseable(":nth-child(2n++2)"); 1.557 + test_balanced_unparseable(":nth-child(2n+-2)"); 1.558 + test_balanced_unparseable(":nth-child(2n-+2)"); 1.559 + test_balanced_unparseable(":nth-child(2n--2)"); 1.560 + test_balanced_unparseable(":nth-child(2n/**/++2)"); 1.561 + test_balanced_unparseable(":nth-child(2n/**/+-2)"); 1.562 + test_balanced_unparseable(":nth-child(2n/**/-+2)"); 1.563 + test_balanced_unparseable(":nth-child(2n/**/--2)"); 1.564 + test_balanced_unparseable(":nth-child(2n/**/+/**/+2)"); 1.565 + test_balanced_unparseable(":nth-child(2n/**/+/**/-2)"); 1.566 + test_balanced_unparseable(":nth-child(2n/**/-/**/+2)"); 1.567 + test_balanced_unparseable(":nth-child(2n/**/-/**/-2)"); 1.568 + test_balanced_unparseable(":nth-child(2n+/**/+2)"); 1.569 + test_balanced_unparseable(":nth-child(2n+/**/-2)"); 1.570 + test_balanced_unparseable(":nth-child(2n-/**/+2)"); 1.571 + test_balanced_unparseable(":nth-child(2n-/**/-2)"); 1.572 + test_balanced_unparseable(":nth-child(2n++/**/2)"); 1.573 + test_balanced_unparseable(":nth-child(2n+-/**/2)"); 1.574 + test_balanced_unparseable(":nth-child(2n-+/**/2)"); 1.575 + test_balanced_unparseable(":nth-child(2n--/**/2)"); 1.576 + test_balanced_unparseable(":nth-child(2n/**/++/**/2)"); 1.577 + test_balanced_unparseable(":nth-child(2n/**/+-/**/2)"); 1.578 + test_balanced_unparseable(":nth-child(2n/**/-+/**/2)"); 1.579 + test_balanced_unparseable(":nth-child(2n/**/--/**/2)"); 1.580 + test_balanced_unparseable(":nth-child(2n/**/+/**/+/**/2)"); 1.581 + test_balanced_unparseable(":nth-child(2n/**/+/**/-/**/2)"); 1.582 + test_balanced_unparseable(":nth-child(2n/**/-/**/+/**/2)"); 1.583 + test_balanced_unparseable(":nth-child(2n/**/-/**/-/**/2)"); 1.584 + test_balanced_unparseable(":nth-child(2n+/**/+/**/2)"); 1.585 + test_balanced_unparseable(":nth-child(2n+/**/-/**/2)"); 1.586 + test_balanced_unparseable(":nth-child(2n-/**/+/**/2)"); 1.587 + test_balanced_unparseable(":nth-child(2n-/**/-/**/2)"); 1.588 + test_parseable(":nth-child(+/**/n+2)"); 1.589 + test_parseable(":nth-child(+n/**/+2)"); 1.590 + test_parseable(":nth-child(+n/**/+2)"); 1.591 + test_parseable(":nth-child(+n+/**/2)"); 1.592 + test_parseable(":nth-child(+n+2/**/)"); 1.593 + test_parseable(":nth-child(+1/**/n+2)"); 1.594 + test_parseable(":nth-child(+1n/**/+2)"); 1.595 + test_parseable(":nth-child(+1n/**/+2)"); 1.596 + test_parseable(":nth-child(+1n+/**/2)"); 1.597 + test_parseable(":nth-child(+1n+2/**/)"); 1.598 + test_parseable(":nth-child(-/**/n+2)"); 1.599 + test_parseable(":nth-child(-n/**/+2)"); 1.600 + test_parseable(":nth-child(-n/**/+2)"); 1.601 + test_parseable(":nth-child(-n+/**/2)"); 1.602 + test_parseable(":nth-child(-n+2/**/)"); 1.603 + test_parseable(":nth-child(-1/**/n+2)"); 1.604 + test_parseable(":nth-child(-1n/**/+2)"); 1.605 + test_parseable(":nth-child(-1n/**/+2)"); 1.606 + test_parseable(":nth-child(-1n+/**/2)"); 1.607 + test_parseable(":nth-child(-1n+2/**/)"); 1.608 + test_balanced_unparseable(":nth-child(-/**/ n+2)"); 1.609 + test_balanced_unparseable(":nth-child(- /**/n+2)"); 1.610 + test_balanced_unparseable(":nth-child(+/**/ n+2)"); 1.611 + test_balanced_unparseable(":nth-child(+ /**/n+2)"); 1.612 + test_parseable(":nth-child(+/**/n-2)"); 1.613 + test_parseable(":nth-child(+n/**/-2)"); 1.614 + test_parseable(":nth-child(+n/**/-2)"); 1.615 + test_parseable(":nth-child(+n-/**/2)"); 1.616 + test_parseable(":nth-child(+n-2/**/)"); 1.617 + test_parseable(":nth-child(+1/**/n-2)"); 1.618 + test_parseable(":nth-child(+1n/**/-2)"); 1.619 + test_parseable(":nth-child(+1n/**/-2)"); 1.620 + test_parseable(":nth-child(+1n-/**/2)"); 1.621 + test_parseable(":nth-child(+1n-2/**/)"); 1.622 + test_parseable(":nth-child(-/**/n-2)"); 1.623 + test_parseable(":nth-child(-n/**/-2)"); 1.624 + test_parseable(":nth-child(-n/**/-2)"); 1.625 + test_parseable(":nth-child(-n-/**/2)"); 1.626 + test_parseable(":nth-child(-n-2/**/)"); 1.627 + test_parseable(":nth-child(-1/**/n-2)"); 1.628 + test_parseable(":nth-child(-1n/**/-2)"); 1.629 + test_parseable(":nth-child(-1n/**/-2)"); 1.630 + test_parseable(":nth-child(-1n-/**/2)"); 1.631 + test_parseable(":nth-child(-1n-2/**/)"); 1.632 + test_balanced_unparseable(":nth-child(-/**/ n-2)"); 1.633 + test_balanced_unparseable(":nth-child(- /**/n-2)"); 1.634 + test_balanced_unparseable(":nth-child(+/**/ n-2)"); 1.635 + test_balanced_unparseable(":nth-child(+ /**/n-2)"); 1.636 + test_parseable(":nth-child( +n + 1 )"); 1.637 + test_parseable(":nth-child( +/**/n + 1 )"); 1.638 + test_parseable(":nth-child( -/**/2/**/n/**/+/**/4 )"); 1.639 + test_balanced_unparseable(":nth-child( -/**/ 2/**/n/**/+/**/4 )"); 1.640 + test_balanced_unparseable(":nth-child( -/**/2 /**/n/**/+/**/4 )"); 1.641 + test_balanced_unparseable(":nth-child( -/**/2/**/ n/**/+/**/4 )"); 1.642 + test_parseable(":nth-child( -/**/2/**/n /**/+/**/4 )"); 1.643 + test_parseable(":nth-child( -/**/2/**/n/**/ +/**/4 )"); 1.644 + test_parseable(":nth-child(+1/**/n-1)"); 1.645 + test_parseable(":nth-child(1/**/n-1)"); 1.646 + // bug 876570 1.647 + test_balanced_unparseable(":nth-child(+2n-)"); 1.648 + test_balanced_unparseable(":nth-child(+n-)"); 1.649 + test_balanced_unparseable(":nth-child(-2n-)"); 1.650 + test_balanced_unparseable(":nth-child(-n-)"); 1.651 + test_balanced_unparseable(":nth-child(2n-)"); 1.652 + test_balanced_unparseable(":nth-child(n-)"); 1.653 + test_balanced_unparseable(":nth-child(+2n+)"); 1.654 + test_balanced_unparseable(":nth-child(+n+)"); 1.655 + test_balanced_unparseable(":nth-child(-2n+)"); 1.656 + test_balanced_unparseable(":nth-child(-n+)"); 1.657 + test_balanced_unparseable(":nth-child(2n+)"); 1.658 + test_balanced_unparseable(":nth-child(n+)"); 1.659 + 1.660 + // exercise the an+b matching logic particularly hard for 1.661 + // :nth-child() (since we know we use the same code for all 4) 1.662 + var seven_ps = "<p></p><p></p><p></p><p></p><p></p><p></p><p></p>"; 1.663 + function pset(indices) { // takes an array of 1-based indices 1.664 + return function pset_filter(doc) { 1.665 + var a = doc.getElementsByTagName("p"); 1.666 + var result = []; 1.667 + for (var i in indices) 1.668 + result.push(a[indices[i] - 1]); 1.669 + return result; 1.670 + } 1.671 + } 1.672 + test_selector_in_html(":nth-child(0)", seven_ps, 1.673 + pset([]), pset([1, 2, 3, 4, 5, 6, 7])); 1.674 + test_selector_in_html(":nth-child(-3)", seven_ps, 1.675 + pset([]), pset([1, 2, 3, 4, 5, 6, 7])); 1.676 + test_selector_in_html(":nth-child(3)", seven_ps, 1.677 + pset([3]), pset([1, 2, 4, 5, 6, 7])); 1.678 + test_selector_in_html(":nth-child(0n+3)", seven_ps, 1.679 + pset([3]), pset([1, 2, 4, 5, 6, 7])); 1.680 + test_selector_in_html(":nth-child(-0n+3)", seven_ps, 1.681 + pset([3]), pset([1, 2, 4, 5, 6, 7])); 1.682 + test_selector_in_html(":nth-child(8)", seven_ps, 1.683 + pset([]), pset([1, 2, 3, 4, 5, 6, 7])); 1.684 + test_selector_in_html(":nth-child(odd)", seven_ps, 1.685 + pset([1, 3, 5, 7]), pset([2, 4, 6])); 1.686 + test_selector_in_html(":nth-child(even)", seven_ps, 1.687 + pset([2, 4, 6]), pset([1, 3, 5, 7])); 1.688 + test_selector_in_html(":nth-child(2n-1)", seven_ps, 1.689 + pset([1, 3, 5, 7]), pset([2, 4, 6])); 1.690 + test_selector_in_html(":nth-child( 2n - 1 )", seven_ps, 1.691 + pset([1, 3, 5, 7]), pset([2, 4, 6])); 1.692 + test_selector_in_html(":nth-child(2n+1)", seven_ps, 1.693 + pset([1, 3, 5, 7]), pset([2, 4, 6])); 1.694 + test_selector_in_html(":nth-child( 2n + 1 )", seven_ps, 1.695 + pset([1, 3, 5, 7]), pset([2, 4, 6])); 1.696 + test_selector_in_html(":nth-child(2n+0)", seven_ps, 1.697 + pset([2, 4, 6]), pset([1, 3, 5, 7])); 1.698 + test_selector_in_html(":nth-child(2n-0)", seven_ps, 1.699 + pset([2, 4, 6]), pset([1, 3, 5, 7])); 1.700 + test_selector_in_html(":nth-child(-n+3)", seven_ps, 1.701 + pset([1, 2, 3]), pset([4, 5, 6, 7])); 1.702 + test_selector_in_html(":nth-child(-n-3)", seven_ps, 1.703 + pset([]), pset([1, 2, 3, 4, 5, 6, 7])); 1.704 + test_selector_in_html(":nth-child(n)", seven_ps, 1.705 + pset([1, 2, 3, 4, 5, 6, 7]), pset([])); 1.706 + test_selector_in_html(":nth-child(n-3)", seven_ps, 1.707 + pset([1, 2, 3, 4, 5, 6, 7]), pset([])); 1.708 + test_selector_in_html(":nth-child(n+3)", seven_ps, 1.709 + pset([3, 4, 5, 6, 7]), pset([1, 2])); 1.710 + test_selector_in_html(":nth-child(2n+3)", seven_ps, 1.711 + pset([3, 5, 7]), pset([1, 2, 4, 6])); 1.712 + test_selector_in_html(":nth-child(2n)", seven_ps, 1.713 + pset([2, 4, 6]), pset([1, 3, 5, 7])); 1.714 + test_selector_in_html(":nth-child(2n-3)", seven_ps, 1.715 + pset([1, 3, 5, 7]), pset([2, 4, 6])); 1.716 + test_selector_in_html(":nth-child(-1n+3)", seven_ps, 1.717 + pset([1, 2, 3]), pset([4, 5, 6, 7])); 1.718 + test_selector_in_html(":nth-child(-2n+3)", seven_ps, 1.719 + pset([1, 3]), pset([2, 4, 5, 6, 7])); 1.720 + // And a few spot-checks for the other :nth-* selectors 1.721 + test_selector_in_html(":nth-child(4n+1)", seven_ps, 1.722 + pset([1, 5]), pset([2, 3, 4, 6, 7])); 1.723 + test_selector_in_html(":nth-last-child(4n+1)", seven_ps, 1.724 + pset([3, 7]), pset([1, 2, 4, 5, 6])); 1.725 + test_selector_in_html(":nth-of-type(4n+1)", seven_ps, 1.726 + pset([1, 5]), pset([2, 3, 4, 6, 7])); 1.727 + test_selector_in_html(":nth-last-of-type(4n+1)", seven_ps, 1.728 + pset([3, 7]), pset([1, 2, 4, 5, 6])); 1.729 + test_selector_in_html(":nth-child(6)", seven_ps, 1.730 + pset([6]), pset([1, 2, 3, 4, 5, 7])); 1.731 + test_selector_in_html(":nth-last-child(6)", seven_ps, 1.732 + pset([2]), pset([1, 3, 4, 5, 6, 7])); 1.733 + test_selector_in_html(":nth-of-type(6)", seven_ps, 1.734 + pset([6]), pset([1, 2, 3, 4, 5, 7])); 1.735 + test_selector_in_html(":nth-last-of-type(6)", seven_ps, 1.736 + pset([2]), pset([1, 3, 4, 5, 6, 7])); 1.737 + 1.738 + // Test [first|last|only]-[child|node|of-type] 1.739 + 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> <!---->"; 1.740 + function idset(ids) { // takes an array of ids 1.741 + return function idset_filter(doc) { 1.742 + var result = []; 1.743 + for (var id of ids) 1.744 + result.push(doc.getElementById(id)); 1.745 + return result; 1.746 + } 1.747 + } 1.748 + function classset(classes) { // takes an array of classes 1.749 + return function classset_filter(doc) { 1.750 + var i, j, els; 1.751 + var result = []; 1.752 + for (i = 0; i < classes.length; i++) { 1.753 + els = doc.getElementsByClassName(classes[i]); 1.754 + for (j = 0; j < els.length; j++) { 1.755 + result.push(els[j]); 1.756 + } 1.757 + } 1.758 + return result; 1.759 + } 1.760 + } 1.761 + function emptyset(doc) { return []; } 1.762 + test_parseable(":first-child"); 1.763 + test_parseable(":last-child"); 1.764 + test_parseable(":only-child"); 1.765 + test_parseable(":-moz-first-node"); 1.766 + test_parseable(":-moz-last-node"); 1.767 + test_parseable(":first-of-type"); 1.768 + test_parseable(":last-of-type"); 1.769 + test_parseable(":only-of-type"); 1.770 + test_selector_in_html(":first-child", seven_ps, 1.771 + pset([1]), pset([2, 3, 4, 5, 6, 7])); 1.772 + test_selector_in_html(":first-child", interesting_doc, 1.773 + idset(["p1", "s1", "s3", "s5"]), 1.774 + idset(["s2", "p2", "s4", "p3"])); 1.775 + test_selector_in_html(":-moz-first-node", interesting_doc, 1.776 + idset(["p1", "s3", "s5"]), 1.777 + idset(["s1", "s2", "p2", "s4", "p3"])); 1.778 + test_selector_in_html(":last-child", seven_ps, 1.779 + pset([7]), pset([1, 2, 3, 4, 5, 6])); 1.780 + test_selector_in_html(":last-child", interesting_doc, 1.781 + idset(["s2", "s4", "p3", "s5"]), 1.782 + idset(["p1", "s1", "p2", "s3"])); 1.783 + test_selector_in_html(":-moz-last-node", interesting_doc, 1.784 + idset(["s2", "p3", "s5"]), 1.785 + idset(["p1", "s1", "p2", "s3", "s4"])); 1.786 + test_selector_in_html(":only-child", seven_ps, 1.787 + pset([]), pset([1, 2, 3, 4, 5, 6, 7])); 1.788 + test_selector_in_html(":only-child", interesting_doc, 1.789 + idset(["s5"]), 1.790 + idset(["p1", "s1", "s2", "p2", "s3", "s4", "p3"])); 1.791 + test_selector_in_html(":first-of-type", seven_ps, 1.792 + pset([1]), pset([2, 3, 4, 5, 6, 7])); 1.793 + test_selector_in_html(":first-of-type", interesting_doc, 1.794 + idset(["p1", "s1", "p2", "s3", "s5"]), 1.795 + idset(["s2", "s4", "p3"])); 1.796 + test_selector_in_html(":last-of-type", seven_ps, 1.797 + pset([7]), pset([1, 2, 3, 4, 5, 6])); 1.798 + test_selector_in_html(":last-of-type", interesting_doc, 1.799 + idset(["s2", "p2", "s4", "p3", "s5"]), 1.800 + idset(["p1", "s1", "s3"])); 1.801 + test_selector_in_html(":only-of-type", seven_ps, 1.802 + pset([]), pset([1, 2, 3, 4, 5, 6, 7])); 1.803 + test_selector_in_html(":only-of-type", interesting_doc, 1.804 + idset(["p2", "s5"]), 1.805 + idset(["p1", "s1", "s2", "s3", "s4", "p3"])); 1.806 + 1.807 + // And a bunch of tests for the of-type aspect of :nth-of-type() and 1.808 + // :nth-last-of-type(). Note that the last div here contains two 1.809 + // children. 1.810 + var mixed_elements="<p></p><p></p><div></div><p></p><div><p></p><address></address></div><address></address>"; 1.811 + function pdaset(ps, divs, addresses) { // takes an array of 1-based indices 1.812 + var l = { p: ps, div: divs, address: addresses }; 1.813 + return function pdaset_filter(doc) { 1.814 + var result = []; 1.815 + for (var tag in l) { 1.816 + var a = doc.getElementsByTagName(tag); 1.817 + var indices = l[tag]; 1.818 + for (var i in indices) 1.819 + result.push(a[indices[i] - 1]); 1.820 + } 1.821 + return result; 1.822 + } 1.823 + } 1.824 + test_selector_in_html(":nth-of-type(odd)", mixed_elements, 1.825 + pdaset([1, 3, 4], [1], [1, 2]), 1.826 + pdaset([2], [2], [])); 1.827 + test_selector_in_html(":nth-of-type(2n-0)", mixed_elements, 1.828 + pdaset([2], [2], []), 1.829 + pdaset([1, 3, 4], [1], [1, 2])); 1.830 + test_selector_in_html(":nth-last-of-type(even)", mixed_elements, 1.831 + pdaset([2], [1], []), 1.832 + pdaset([1, 3, 4], [2], [1, 2])); 1.833 + 1.834 + // Test greediness of descendant combinators. 1.835 + var four_children="<div id='a'><div id='b'><div id='c'><div id='d'><\/div><\/div><\/div><\/div>"; 1.836 + test_selector_in_html("#a > div div", four_children, 1.837 + idset(["c", "d"]), idset(["a", "b"])); 1.838 + test_selector_in_html("#a > #b div", four_children, 1.839 + idset(["c", "d"]), idset(["a", "b"])); 1.840 + test_selector_in_html("#a div > div", four_children, 1.841 + idset(["c", "d"]), idset(["a", "b"])); 1.842 + test_selector_in_html("#a #b > div", four_children, 1.843 + idset(["c"]), idset(["a", "b", "d"])); 1.844 + test_selector_in_html("#a > #b div", four_children, 1.845 + idset(["c", "d"]), idset(["a", "b"])); 1.846 + test_selector_in_html("#a #c > div", four_children, 1.847 + idset(["d"]), idset(["a", "b", "c"])); 1.848 + test_selector_in_html("#a > #c div", four_children, 1.849 + idset([]), idset(["a", "b", "c", "d"])); 1.850 + 1.851 + // More descendant combinator greediness (bug 511147) 1.852 + test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div></div>', 1.853 + classset(["match"]), classset(["a", "b"])); 1.854 + test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="x"></div><div class="match"></div></div>', 1.855 + classset(["match"]), classset(["a", "b", "x"])); 1.856 + 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>', 1.857 + classset(["match"]), classset(["a", "b", "x"])); 1.858 + 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>', 1.859 + classset(["match"]), classset(["a", "b", "x"])); 1.860 + test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div><div class="match"></div></div>', 1.861 + classset(["match"]), classset(["a", "b"])); 1.862 + 1.863 + test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div></div>', 1.864 + emptyset, classset(["a", "b", "nomatch"])); 1.865 + 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>', 1.866 + emptyset, classset(["a", "b", "nomatch"])); 1.867 + test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div><div><div class="nomatch"></div></div><div></div></div>', 1.868 + emptyset, classset(["a", "b", "nomatch"])); 1.869 + test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div></div><div class="nomatch"></div>', 1.870 + emptyset, classset(["a", "b", "nomatch"])); 1.871 + 1.872 + // Test serialization of pseudo-elements. 1.873 + should_serialize_to("p:first-letter", "p:first-letter"); 1.874 + should_serialize_to("div>p:first-letter", "div > p:first-letter"); 1.875 + should_serialize_to("span +div:first-line", "span + div:first-line"); 1.876 + 1.877 + // Test default namespaces, including inside :not(). 1.878 + var html_default_ns = "@namespace url(http://www.w3.org/1999/xhtml);"; 1.879 + var html_ns = "@namespace html url(http://www.w3.org/1999/xhtml);"; 1.880 + var xul_default_ns = "@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);"; 1.881 + var single_a = "<a id='a' href='data:text/plain,this_better_be_unvisited'></a>"; 1.882 + var set_single = idset(['a']); 1.883 + var empty_set = idset([]); 1.884 + test_selector_in_html("a", single_a, set_single, empty_set, 1.885 + html_default_ns); 1.886 + test_selector_in_html("a", single_a, empty_set, set_single, 1.887 + xul_default_ns); 1.888 + test_selector_in_html("*|a", single_a, set_single, empty_set, 1.889 + xul_default_ns); 1.890 + test_selector_in_html("html|a", single_a, set_single, empty_set, 1.891 + xul_default_ns + html_ns); 1.892 + // Type selectors inside :not() bring in default namespaces, but 1.893 + // non-type selectors don't. 1.894 + test_selector_in_html("*|a:not(*)", single_a, set_single, empty_set, 1.895 + xul_default_ns); 1.896 + test_selector_in_html("*|a:not(a)", single_a, set_single, empty_set, 1.897 + xul_default_ns); 1.898 + test_selector_in_html("*|a:not(*|*)", single_a, empty_set, set_single, 1.899 + xul_default_ns); 1.900 + test_selector_in_html("*|a:not(*|a)", single_a, empty_set, set_single, 1.901 + xul_default_ns); 1.902 + test_selector_in_html("*|a:not(:link)", single_a + "<a id='b'></a>", 1.903 + idset(["b"]), set_single, 1.904 + xul_default_ns); 1.905 + test_selector_in_html("*|a:not(:visited)", single_a + "<a id='b'></a>", 1.906 + idset(["a", "b"]), empty_set, 1.907 + xul_default_ns); 1.908 + test_selector_in_html("*|a:not(html|*)", single_a, empty_set, set_single, 1.909 + xul_default_ns + html_ns); 1.910 + test_selector_in_html("*|a:not(html|a)", single_a, empty_set, set_single, 1.911 + xul_default_ns + html_ns); 1.912 + test_selector_in_html("*|a:not(|*)", single_a, set_single, empty_set, 1.913 + xul_default_ns + html_ns); 1.914 + test_selector_in_html("*|a:not(|a)", single_a, set_single, empty_set, 1.915 + xul_default_ns + html_ns); 1.916 + test_selector_in_html("html|a:not(|*)", single_a, set_single, empty_set, 1.917 + xul_default_ns + html_ns); 1.918 + test_selector_in_html("html|a:not(|a)", single_a, set_single, empty_set, 1.919 + xul_default_ns + html_ns); 1.920 + test_selector_in_html("html|a:not(*|*)", single_a, empty_set, set_single, 1.921 + xul_default_ns + html_ns); 1.922 + test_selector_in_html("html|a:not(*|a)", single_a, empty_set, set_single, 1.923 + xul_default_ns + html_ns); 1.924 + 1.925 + // Test -moz-locale-dir 1.926 + test_parseable(":-moz-locale-dir(ltr)"); 1.927 + test_parseable(":-moz-locale-dir(rtl)"); 1.928 + test_parseable(":-moz-locale-dir(rTl)"); 1.929 + test_parseable(":-moz-locale-dir(LTR)"); 1.930 + if (document.body.mozMatchesSelector(":-moz-locale-dir(ltr)")) { 1.931 + test_selector_in_html("a:-moz-locale-dir(LTr)", single_a, 1.932 + set_single, empty_set); 1.933 + test_selector_in_html("a:-moz-locale-dir(ltR)", single_a, 1.934 + set_single, empty_set); 1.935 + test_selector_in_html("a:-moz-locale-dir(LTR)", single_a, 1.936 + set_single, empty_set); 1.937 + test_selector_in_html("a:-moz-locale-dir(RTl)", single_a, 1.938 + empty_set, set_single); 1.939 + } else { 1.940 + test_selector_in_html("a:-moz-locale-dir(RTl)", single_a, 1.941 + set_single, empty_set); 1.942 + test_selector_in_html("a:-moz-locale-dir(rtL)", single_a, 1.943 + set_single, empty_set); 1.944 + test_selector_in_html("a:-moz-locale-dir(RTL)", single_a, 1.945 + set_single, empty_set); 1.946 + test_selector_in_html("a:-moz-locale-dir(LTr)", single_a, 1.947 + empty_set, set_single); 1.948 + } 1.949 + 1.950 + test_balanced_unparseable(":-moz-locale-dir(other)"); 1.951 + test_balanced_unparseable(":-moz-locale-dir()"); 1.952 + test_balanced_unparseable(":-moz-locale-dir(())"); 1.953 + test_balanced_unparseable(":-moz-locale-dir(3())"); 1.954 + test_balanced_unparseable(":-moz-locale-dir(f{})"); 1.955 + test_balanced_unparseable(":-moz-locale-dir('ltr')"); 1.956 + test_balanced_unparseable(":-moz-locale-dir(ltr, other)"); 1.957 + test_balanced_unparseable(":-moz-locale-dir"); 1.958 + 1.959 + // Test :-moz-dir() 1.960 + test_parseable(":-moz-dir(ltr)"); 1.961 + test_parseable(":-moz-dir(rtl)"); 1.962 + test_parseable(":-moz-dir(rTl)"); 1.963 + test_parseable(":-moz-dir(LTR)"); 1.964 + if (document.body.mozMatchesSelector(":-moz-dir(ltr)")) { 1.965 + test_selector_in_html("a:-moz-dir(LTr)", single_a, 1.966 + set_single, empty_set); 1.967 + test_selector_in_html("a:-moz-dir(ltR)", single_a, 1.968 + set_single, empty_set); 1.969 + test_selector_in_html("a:-moz-dir(LTR)", single_a, 1.970 + set_single, empty_set); 1.971 + test_selector_in_html("a:-moz-dir(RTl)", single_a, 1.972 + empty_set, set_single); 1.973 + } else { 1.974 + test_selector_in_html("a:-moz-dir(RTl)", single_a, 1.975 + set_single, empty_set); 1.976 + test_selector_in_html("a:-moz-dir(rtL)", single_a, 1.977 + set_single, empty_set); 1.978 + test_selector_in_html("a:-moz-dir(RTL)", single_a, 1.979 + set_single, empty_set); 1.980 + test_selector_in_html("a:-moz-dir(LTr)", single_a, 1.981 + empty_set, set_single); 1.982 + } 1.983 + 1.984 + test_balanced_unparseable(":-moz-dir(other)"); 1.985 + test_balanced_unparseable(":-moz-dir()"); 1.986 + test_balanced_unparseable(":-moz-dir(())"); 1.987 + test_balanced_unparseable(":-moz-dir(3())"); 1.988 + test_balanced_unparseable(":-moz-dir(f{})"); 1.989 + test_balanced_unparseable(":-moz-dir('ltr')"); 1.990 + test_balanced_unparseable(":-moz-dir(ltr, other)"); 1.991 + test_balanced_unparseable(":-moz-dir"); 1.992 + 1.993 + // Test -moz-lwtheme and -moz-lwtheme-[darktext|brighttext] 1.994 + test_parseable(":-moz-lwtheme"); 1.995 + test_parseable(":-moz-lwtheme-brighttext"); 1.996 + test_parseable(":-moz-lwtheme-darktext"); 1.997 + 1.998 + test_parseable(":-moz-tree-row(selected)"); 1.999 + test_parseable("::-moz-tree-row(selected)"); 1.1000 + test_parseable(":-moz-tree-row(selected focus)"); 1.1001 + test_parseable(":-moz-tree-row(selected , focus)"); 1.1002 + test_parseable("::-moz-tree-row(selected ,focus)"); 1.1003 + test_parseable(":-moz-tree-row(selected, focus)"); 1.1004 + test_parseable("::-moz-tree-row(selected,focus)"); 1.1005 + test_parseable(":-moz-tree-row(selected focus)"); 1.1006 + test_parseable("::-moz-tree-row(selected , focus)"); 1.1007 + test_parseable("::-moz-tree-twisty( hover open )"); 1.1008 + test_balanced_unparseable("::-moz-tree-row(selected {[]} )"); 1.1009 + test_balanced_unparseable(":-moz-tree-twisty(open())"); 1.1010 + test_balanced_unparseable("::-moz-tree-twisty(hover ())"); 1.1011 + 1.1012 + test_parseable(":-moz-window-inactive"); 1.1013 + test_parseable("div p:-moz-window-inactive:hover span"); 1.1014 + 1.1015 + // Plugin pseudoclasses 1.1016 + test_parseable(":-moz-type-unsupported"); 1.1017 + test_parseable(":-moz-handler-disabled"); 1.1018 + test_parseable(":-moz-handler-blocked"); 1.1019 + test_parseable(":-moz-handler-crashed"); 1.1020 + 1.1021 + // Case sensitivity of tag selectors 1.1022 + function setup_cased_spans(body) { 1.1023 + var data = [ 1.1024 + { tag: "span" }, 1.1025 + { tag: "sPaN" }, 1.1026 + { tag: "Span" }, 1.1027 + { tag: "SPAN" }, 1.1028 + { ns: "http://www.w3.org/1999/xhtml", tag: "span" }, 1.1029 + { ns: "http://www.w3.org/1999/xhtml", tag: "sPaN" }, 1.1030 + { ns: "http://www.w3.org/1999/xhtml", tag: "Span" }, 1.1031 + { ns: "http://www.w3.org/1999/xhtml", tag: "SPAN" }, 1.1032 + { ns: "http://example.com/useless", tag: "span" }, 1.1033 + { ns: "http://example.com/useless", tag: "sPaN" }, 1.1034 + { ns: "http://example.com/useless", tag: "Span" }, 1.1035 + { ns: "http://example.com/useless", tag: "SPAN" }, 1.1036 + ] 1.1037 + for (var i in data) { 1.1038 + var ent = data[i]; 1.1039 + var elem; 1.1040 + if ("ns" in ent) { 1.1041 + elem = body.ownerDocument.createElementNS(ent.ns, ent.tag); 1.1042 + } else { 1.1043 + elem = body.ownerDocument.createElement(ent.tag); 1.1044 + } 1.1045 + body.appendChild(elem); 1.1046 + } 1.1047 + } 1.1048 + function bodychildset(indices) { 1.1049 + return function bodychildset_filter(doc) { 1.1050 + var body = doc.body; 1.1051 + var result = []; 1.1052 + for (var i in indices) { 1.1053 + result.push(body.childNodes[indices[i]]); 1.1054 + } 1.1055 + return result; 1.1056 + } 1.1057 + } 1.1058 + test_selector_in_html("span", setup_cased_spans, 1.1059 + bodychildset([0, 1, 2, 3, 4, 8]), 1.1060 + bodychildset([5, 6, 7, 9, 10, 11])); 1.1061 + test_selector_in_html("sPaN", setup_cased_spans, 1.1062 + bodychildset([0, 1, 2, 3, 4, 9]), 1.1063 + bodychildset([5, 6, 7, 8, 10, 11])); 1.1064 + test_selector_in_html("Span", setup_cased_spans, 1.1065 + bodychildset([0, 1, 2, 3, 4, 10]), 1.1066 + bodychildset([5, 6, 7, 8, 9, 11])); 1.1067 + test_selector_in_html("SPAN", setup_cased_spans, 1.1068 + bodychildset([0, 1, 2, 3, 4, 11]), 1.1069 + bodychildset([5, 6, 7, 8, 9, 10])); 1.1070 + 1.1071 + // bug 528096 (tree pseudos) 1.1072 + test_unbalanced_unparseable(":-moz-tree-column((){} a"); 1.1073 + test_unbalanced_unparseable(":-moz-tree-column(x(){} a"); 1.1074 + test_unbalanced_unparseable(":-moz-tree-column(a b (){} a"); 1.1075 + test_unbalanced_unparseable(":-moz-tree-column(a, b (){} a"); 1.1076 + 1.1077 + // Bug 543428 (escaping) 1.1078 + test_selector_in_html("\\32|a", single_a, set_single, empty_set, 1.1079 + "@namespace \\32 url(http://www.w3.org/1999/xhtml);"); 1.1080 + test_selector_in_html("-\\32|a", single_a, set_single, empty_set, 1.1081 + "@namespace -\\32 url(http://www.w3.org/1999/xhtml);"); 1.1082 + test_selector_in_html("\\2|a", single_a, set_single, empty_set, 1.1083 + "@namespace \\0002 url(http://www.w3.org/1999/xhtml);"); 1.1084 + test_selector_in_html("-\\2|a", single_a, set_single, empty_set, 1.1085 + "@namespace -\\000002 url(http://www.w3.org/1999/xhtml);"); 1.1086 + var spans = "<span class='2'></span><span class=''></span>" + 1.1087 + "<span id='2'></span><span id=''></span>" 1.1088 + test_selector_in_html(".\\32", spans, 1.1089 + bodychildset([0]), bodychildset([1, 2, 3])); 1.1090 + test_selector_in_html("[class=\\32]", spans, 1.1091 + bodychildset([0]), bodychildset([1, 2, 3])); 1.1092 + test_selector_in_html(".\\2", spans, 1.1093 + bodychildset([1]), bodychildset([0, 2, 3])); 1.1094 + test_selector_in_html("[class=\\2]", spans, 1.1095 + bodychildset([1]), bodychildset([0, 2, 3])); 1.1096 + test_selector_in_html("#\\32", spans, 1.1097 + bodychildset([2]), bodychildset([0, 1, 3])); 1.1098 + test_selector_in_html("[id=\\32]", spans, 1.1099 + bodychildset([2]), bodychildset([0, 1, 3])); 1.1100 + test_selector_in_html("#\\2", spans, 1.1101 + bodychildset([3]), bodychildset([0, 1, 2])); 1.1102 + test_selector_in_html("[id=\\2]", spans, 1.1103 + bodychildset([3]), bodychildset([0, 1, 2])); 1.1104 + test_balanced_unparseable("#2"); 1.1105 + 1.1106 + // Bug 553805: :not() containing nothing is forbidden 1.1107 + test_balanced_unparseable(":not()"); 1.1108 + test_balanced_unparseable(":not( )"); 1.1109 + test_balanced_unparseable(":not( \t\n )"); 1.1110 + test_balanced_unparseable(":not(/*comment*/)"); 1.1111 + test_balanced_unparseable(":not( /*comment*/ /* comment */ )"); 1.1112 + test_balanced_unparseable("p :not()"); 1.1113 + test_balanced_unparseable("p :not( )"); 1.1114 + test_balanced_unparseable("p :not( \t\n )"); 1.1115 + test_balanced_unparseable("p :not(/*comment*/)"); 1.1116 + test_balanced_unparseable("p :not( /*comment*/ /* comment */ )"); 1.1117 + test_balanced_unparseable("p:not()"); 1.1118 + test_balanced_unparseable("p:not( )"); 1.1119 + test_balanced_unparseable("p:not( \t\n )"); 1.1120 + test_balanced_unparseable("p:not(/*comment*/)"); 1.1121 + test_balanced_unparseable("p:not( /*comment*/ /* comment */ )"); 1.1122 + 1.1123 + test_balanced_unparseable(":not(:nth-child(2k))"); 1.1124 + test_balanced_unparseable(":not(:nth-child(()))"); 1.1125 + 1.1126 + // :-moz-any() 1.1127 + test_balanced_unparseable(":-moz-any()"); 1.1128 + test_balanced_unparseable(":-moz-any(div p)"); 1.1129 + test_balanced_unparseable(":-moz-any(div ~ p)"); 1.1130 + test_balanced_unparseable(":-moz-any(div~p)"); 1.1131 + test_balanced_unparseable(":-moz-any(div + p)"); 1.1132 + test_balanced_unparseable(":-moz-any(div+p)"); 1.1133 + test_balanced_unparseable(":-moz-any(div > p)"); 1.1134 + test_balanced_unparseable(":-moz-any(div>p)"); 1.1135 + test_parseable(":-moz-any(div, p)"); 1.1136 + test_parseable(":-moz-any( div , p )"); 1.1137 + test_parseable(":-moz-any(div,p)"); 1.1138 + test_parseable(":-moz-any(div)"); 1.1139 + test_parseable(":-moz-any(div,p,:link,span:focus)"); 1.1140 + test_parseable(":-moz-any(:active,:focus)"); 1.1141 + test_parseable(":-moz-any(:active,:link:focus)"); 1.1142 + test_balanced_unparseable(":-moz-any(div,:nonexistentpseudo)"); 1.1143 + var any_elts = "<input type='text'><a href='http://www.example.com/'></a><div></div><a name='foo'>"; 1.1144 + test_selector_in_html(":-moz-any(a,input)", any_elts, 1.1145 + bodychildset([0, 1, 3]), bodychildset([2])); 1.1146 + test_selector_in_html(":-moz-any(:link,:not(a))", any_elts, 1.1147 + bodychildset([0, 1, 2]), bodychildset([3])); 1.1148 + test_selector_in_html(":-moz-any([href],input[type],input[name])", any_elts, 1.1149 + bodychildset([0, 1]), bodychildset([2, 3])); 1.1150 + test_selector_in_html(":-moz-any(div,a):-moz-any([type],[href],[name])", 1.1151 + any_elts, 1.1152 + bodychildset([1, 3]), bodychildset([0, 2])); 1.1153 + 1.1154 + test_selector_in_html(":-moz-table-border-nonzero", 1.1155 + "<p></p>" + 1.1156 + "<p border='2'></p>" + 1.1157 + "<table border='2'></table>" + 1.1158 + "<table border></table>" + 1.1159 + "<table></table>" + 1.1160 + "<table frame='border'></table>" + 1.1161 + "<table border='0'></table>" + 1.1162 + "<table border='0pt'></table>" + 1.1163 + "<table border='3pt'></table>", 1.1164 + bodychildset([2, 3, 8]), 1.1165 + bodychildset([0, 1, 4, 5, 6, 7])); 1.1166 + 1.1167 + // Test that we don't tokenize an empty HASH. 1.1168 + test_balanced_unparseable("#"); 1.1169 + test_balanced_unparseable("# "); 1.1170 + test_balanced_unparseable("#, p"); 1.1171 + test_balanced_unparseable("# , p"); 1.1172 + test_balanced_unparseable("p #"); 1.1173 + test_balanced_unparseable("p # "); 1.1174 + test_balanced_unparseable("p #, p"); 1.1175 + test_balanced_unparseable("p # , p"); 1.1176 + 1.1177 + // Test that a backslash alone at EOF outside of a string is treated 1.1178 + // as U+FFFD. 1.1179 + test_parseable_via_api("#a\\"); 1.1180 + test_parseable_via_api("#\\"); 1.1181 + test_parseable_via_api("\\"); 1.1182 + 1.1183 + // Test that newline escapes are only supported in strings. 1.1184 + test_balanced_unparseable("di\\\nv"); 1.1185 + test_balanced_unparseable("div \\\n p"); 1.1186 + test_balanced_unparseable("div\\\n p"); 1.1187 + test_balanced_unparseable("div \\\np"); 1.1188 + test_balanced_unparseable("div\\\np"); 1.1189 + 1.1190 + // Test that :-moz-placeholder is parsable. 1.1191 + test_parseable(":-moz-placeholder"); 1.1192 + 1.1193 + run_deferred_tests(); 1.1194 +} 1.1195 + 1.1196 +var deferred_tests = []; 1.1197 + 1.1198 +function defer_clonedoc_tests(docurl, onloadfunc) 1.1199 +{ 1.1200 + deferred_tests.push( { docurl: docurl, onloadfunc: onloadfunc } ); 1.1201 +} 1.1202 + 1.1203 +function run_deferred_tests() 1.1204 +{ 1.1205 + if (deferred_tests.length == 0) { 1.1206 + SimpleTest.finish(); 1.1207 + return; 1.1208 + } 1.1209 + 1.1210 + cloneiframe.onload = deferred_tests_onload; 1.1211 + cloneiframe.src = deferred_tests[0].docurl; 1.1212 +} 1.1213 + 1.1214 +function deferred_tests_onload(event) 1.1215 +{ 1.1216 + if (event.target != cloneiframe) 1.1217 + return; 1.1218 + 1.1219 + deferred_tests[0].onloadfunc(); 1.1220 + deferred_tests.shift(); 1.1221 + 1.1222 + run_deferred_tests(); 1.1223 +} 1.1224 + 1.1225 +</script> 1.1226 +</pre> 1.1227 +</body> 1.1228 +</html>