test_selectors.html 58 KB

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