Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / layout / style / test / test_selectors.html
blob9fa16d6973e6300b3a308862cf2833296175cee4
1 <!DOCTYPE HTML>
2 <html>
3 <head>
4 <title>Test for CSS Selectors</title>
5 <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
6 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
8 </head>
9 <body onload="run()">
10 <p id="display"><iframe id="iframe" src="about:blank"></iframe></p>
11 <pre id="test">
12 <script class="testbody" type="text/javascript">
14 SimpleTest.waitForExplicitFinish();
16 function run() {
18 var iframe = document.getElementById("iframe");
19 var ifwin = iframe.contentWindow;
20 var ifdoc = iframe.contentDocument;
22 function setup_style() {
23 var style_elem = ifdoc.createElement("style");
24 style_elem.setAttribute("type", "text/css");
25 ifdoc.getElementsByTagName("head")[0].appendChild(style_elem);
26 var style_text = ifdoc.createTextNode("");
27 style_elem.appendChild(style_text);
28 return style_text;
31 var style_text = setup_style();
33 var gCounter = 0;
36 * selector: the selector to test
37 * body_contents: what to set the body's innerHTML to
38 * match_fn: a function that, given the document object into which
39 * body_contents has been inserted, produces an array of nodes that
40 * should match selector
41 * notmatch_fn: likewise, but for nodes that should not match
43 function test_selector_in_html(selector, body_contents, match_fn, notmatch_fn)
45 var zi = ++gCounter;
46 if (typeof(body_contents) == "string") {
47 ifdoc.body.innerHTML = body_contents;
48 } else {
49 // It's a function.
50 ifdoc.body.innerHTML = "";
51 body_contents(ifdoc.body);
53 style_text.data = selector + "{ z-index: " + zi + " }";
54 var should_match = match_fn(ifdoc);
55 var should_not_match = notmatch_fn(ifdoc);
56 if (should_match.length + should_not_match.length == 0) {
57 ok(false, "nothing to check");
60 for (var i = 0; i < should_match.length; ++i) {
61 var e = should_match[i];
62 is(ifwin.getComputedStyle(e, "").zIndex, zi,
63 "element in " + body_contents + " matched " + selector);
65 for (var i = 0; i < should_not_match.length; ++i) {
66 var e = should_not_match[i];
67 is(ifwin.getComputedStyle(e, "").zIndex, "auto",
68 "element in " + body_contents + " did not match " + selector);
71 // Now, since we're here, may as well make sure serialization
72 // works correctly. It need not produce the exact same text,
73 // but it should produce a selector that matches the same
74 // elements.
75 zi = ++gCounter;
76 var ser1 = style_text.parentNode.sheet.cssRules[0].selectorText;
77 style_text.data = ser1 + "{ z-index: " + zi + " }";
78 for (var i = 0; i < should_match.length; ++i) {
79 var e = should_match[i];
80 is(ifwin.getComputedStyle(e, "").zIndex, zi,
81 "element in " + body_contents + " matched " + ser1 +
82 " which is the reserialization of " + selector);
84 for (var i = 0; i < should_not_match.length; ++i) {
85 var e = should_not_match[i];
86 is(ifwin.getComputedStyle(e, "").zIndex, "auto",
87 "element in " + body_contents + " did not match " + ser1 +
88 " which is the reserialization of " + selector);
91 // But when we serialize the serialized result, we should get
92 // the same text.
93 var ser2 = style_text.parentNode.sheet.cssRules[0].selectorText;
94 is(ser2, ser1, "parse+serialize of selector \"" + selector +
95 "\" is idempotent");
97 ifdoc.body.innerHTML = "";
98 style_text.data = "";
101 function test_parseable(selector)
103 var zi = ++gCounter;
104 ifdoc.body.innerHTML = "<p></p>";
105 style_text.data = "p, " + selector + "{ z-index: " + zi + " }";
106 var should_match = ifdoc.getElementsByTagName("p")[0];
107 is(ifwin.getComputedStyle(should_match, "").zIndex, zi,
108 "selector " + selector + " was parsed");
109 ifdoc.body.innerHTML = "";
110 style_text.data = "";
113 function test_balanced_unparseable(selector)
115 var zi1 = ++gCounter;
116 var zi2 = ++gCounter;
117 ifdoc.body.innerHTML = "<p></p><div></div>";
118 style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" +
119 "div { z-index: " + zi2 + " }";
120 var should_not_match = ifdoc.getElementsByTagName("p")[0];
121 var should_match = ifdoc.getElementsByTagName("div")[0];
122 is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
123 "selector " + selector + " was a parser error");
124 is(ifwin.getComputedStyle(should_match, "").zIndex, zi2,
125 "selector " + selector + " error was recovered from");
126 ifdoc.body.innerHTML = "";
127 style_text.data = "";
130 // [attr= ] selector
131 test_parseable("[attr=\"x\"]");
132 test_parseable("[attr='x']");
133 test_parseable("[attr=x]");
134 test_parseable("[attr=\"\"]");
135 test_parseable("[attr='']");
136 test_parseable("[attr=\"foo bar\"]");
138 test_balanced_unparseable("[attr=]");
139 test_balanced_unparseable("[attr=foo bar]");
141 test_selector_in_html(
142 '[title=""]',
143 '<p title=""></p>'
144 + '<div lang=" "></div><div lang="\t"></div><div lang="\n"></div>',
145 function(doc) { return doc.getElementsByTagName("p"); },
146 function(doc) { return doc.getElementsByTagName("div"); }
149 // [attr~= ] selector
150 test_parseable("[attr~=\"x\"]");
151 test_parseable("[attr~='x']");
152 test_parseable("[attr~=x]");
153 test_parseable("[attr~=\"\"]");
154 test_parseable("[attr~='']");
155 test_parseable("[attr~=\"foo bar\"]");
157 test_balanced_unparseable("[attr~=]");
158 test_balanced_unparseable("[attr~=foo bar]");
160 test_selector_in_html(
161 '[class~="x x"]',
162 '<div class="x x"></div><div class="x"></div><div class="x\tx"></div>div class="x\nx"></div>',
163 function(doc) { return []; },
164 function(doc) { return doc.getElementsByTagName("div"); }
167 // [attr|="x"]
168 test_parseable('[attr|="x"]');
169 test_parseable("[attr|='x']");
170 test_parseable('[attr|=x]');
172 test_parseable('[attr|=""]');
173 test_parseable("[attr|='']");
174 test_balanced_unparseable('[attr|=]');
176 test_selector_in_html(
177 '[lang|=""]',
178 '<p lang=""></p><p lang="-"></p><p lang="-GB"></p>'
179 + '<div lang="en-GB"></div><div lang="en-"></div>',
180 function(doc) { return doc.getElementsByTagName("p"); },
181 function(doc) { return doc.getElementsByTagName("div"); }
184 // [attr$= ] selector
185 test_parseable("[attr$=\"x\"]");
186 test_parseable("[attr$='x']");
187 test_parseable("[attr$=x]");
188 test_parseable("[attr$=\"\"]");
189 test_parseable("[attr$='']");
190 test_parseable("[attr$=\"foo bar\"]");
192 test_balanced_unparseable("[attr$=]");
193 test_balanced_unparseable("[attr$=foo bar]");
195 // [attr^= ] selector
196 test_parseable("[attr^=\"x\"]");
197 test_parseable("[attr^='x']");
198 test_parseable("[attr^=x]");
199 test_parseable("[attr^=\"\"]");
200 test_parseable("[attr^='']");
201 test_parseable("[attr^=\"foo bar\"]");
203 test_balanced_unparseable("[attr^=]");
204 test_balanced_unparseable("[attr^=foo bar]");
206 // attr[*= ] selector
207 test_parseable("[attr*=\"x\"]");
208 test_parseable("[attr*='x']");
209 test_parseable("[attr*=x]");
210 test_parseable("[attr*=\"\"]");
211 test_parseable("[attr*='']");
212 test_parseable("[attr*=\"foo bar\"]");
214 test_balanced_unparseable("[attr*=]");
215 test_balanced_unparseable("[attr*=foo bar]");
218 // Bug 420814
219 test_selector_in_html(
220 "div ~ div p",
221 "<div></div><div><div><p>match</p></div></div>",
222 function(doc) { return doc.getElementsByTagName("p"); },
223 function(doc) { return []; }
226 // Bug 420245
227 test_selector_in_html(
228 "p[attr$=\"\"]",
229 "<p attr=\"foo\">This should not match</p>",
230 function(doc) { return []; },
231 function(doc) { return doc.getElementsByTagName("p"); }
233 test_selector_in_html(
234 "div + p[attr~=\"\"]",
235 "<div>Dummy</div><p attr=\"foo\">This should not match</p>",
236 function(doc) { return []; },
237 function(doc) { return doc.getElementsByTagName("p"); }
239 test_selector_in_html(
240 "div[attr^=\"\"]",
241 "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
242 function(doc) { return []; },
243 function(doc) { return doc.getElementsByTagName("div"); }
245 test_selector_in_html(
246 "div[attr*=\"\"]",
247 "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
248 function(doc) { return []; },
249 function(doc) { return doc.getElementsByTagName("div"); }
252 // :nth-child(), etc.
253 // Follow the whitespace rules as proposed in
254 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
255 test_balanced_unparseable(":nth-child()");
256 test_balanced_unparseable(":nth-of-type( )");
257 test_parseable(":nth-last-child( odd)");
258 test_parseable(":nth-last-of-type(even )");
259 test_parseable(":nth-child(n )");
260 test_parseable(":nth-of-type( 2n)");
261 test_parseable(":nth-last-child( -n)");
262 test_parseable(":nth-last-of-type(-2n )");
263 test_balanced_unparseable(":nth-child(- n)");
264 test_balanced_unparseable(":nth-of-type(-2 n)");
265 test_balanced_unparseable(":nth-last-of-type(2n1)");
266 test_balanced_unparseable(":nth-child(2n++1)");
267 test_balanced_unparseable(":nth-of-type(2n-+1)");
268 test_balanced_unparseable(":nth-last-child(2n+-1)");
269 test_balanced_unparseable(":nth-last-of-type(2n--1)");
270 test_parseable(":nth-child( 3n + 1 )");
271 test_parseable(":nth-child( +3n - 2 )");
272 test_parseable(":nth-child( -n+ 6)");
273 test_parseable(":nth-child( +6 )");
274 test_balanced_unparseable(":nth-child(3 n)");
275 test_balanced_unparseable(":nth-child(+ 2n)");
276 test_balanced_unparseable(":nth-child(+ 2)");
277 test_parseable(":nth-child(3)");
278 test_parseable(":nth-of-type(-3)");
279 test_parseable(":nth-last-child(+3)");
280 test_parseable(":nth-last-of-type(0)");
281 test_parseable(":nth-child(-0)");
282 test_parseable(":nth-of-type(3n)");
283 test_parseable(":nth-last-child(-3n)");
284 test_parseable(":nth-last-of-type(+3n)");
285 test_parseable(":nth-last-of-type(0n)");
286 test_parseable(":nth-child(-0n)");
287 test_parseable(":nth-of-type(n)");
288 test_parseable(":nth-last-child(-n)");
289 test_parseable(":nth-last-of-type(2n+1)");
290 test_parseable(":nth-child(2n-1)");
291 test_parseable(":nth-of-type(2n+0)");
292 test_parseable(":nth-last-child(2n-0)");
293 test_parseable(":nth-child(-0n+0)");
294 test_parseable(":nth-of-type(n+1)");
295 test_parseable(":nth-last-child(n-1)");
296 test_parseable(":nth-last-of-type(-n+1)");
297 test_parseable(":nth-child(-n-1)");
298 test_balanced_unparseable(":nth-child(2-n)");
299 test_balanced_unparseable(":nth-child(2-n-1)");
300 test_balanced_unparseable(":nth-child(n-2-1)");
302 // exercise the an+b matching logic particularly hard for
303 // :nth-child() (since we know we use the same code for all 4)
304 var seven_ps = "<p></p><p></p><p></p><p></p><p></p><p></p><p></p>";
305 function pset(indices) { // takes an array of 1-based indices
306 return function pset_filter(doc) {
307 var a = doc.getElementsByTagName("p");
308 var result = [];
309 for (var i in indices)
310 result.push(a[indices[i] - 1]);
311 return result;
314 test_selector_in_html(":nth-child(0)", seven_ps,
315 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
316 test_selector_in_html(":nth-child(-3)", seven_ps,
317 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
318 test_selector_in_html(":nth-child(3)", seven_ps,
319 pset([3]), pset([1, 2, 4, 5, 6, 7]));
320 test_selector_in_html(":nth-child(0n+3)", seven_ps,
321 pset([3]), pset([1, 2, 4, 5, 6, 7]));
322 test_selector_in_html(":nth-child(-0n+3)", seven_ps,
323 pset([3]), pset([1, 2, 4, 5, 6, 7]));
324 test_selector_in_html(":nth-child(8)", seven_ps,
325 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
326 test_selector_in_html(":nth-child(odd)", seven_ps,
327 pset([1, 3, 5, 7]), pset([2, 4, 6]));
328 test_selector_in_html(":nth-child(even)", seven_ps,
329 pset([2, 4, 6]), pset([1, 3, 5, 7]));
330 test_selector_in_html(":nth-child(2n-1)", seven_ps,
331 pset([1, 3, 5, 7]), pset([2, 4, 6]));
332 test_selector_in_html(":nth-child( 2n - 1 )", seven_ps,
333 pset([1, 3, 5, 7]), pset([2, 4, 6]));
334 test_selector_in_html(":nth-child(2n+1)", seven_ps,
335 pset([1, 3, 5, 7]), pset([2, 4, 6]));
336 test_selector_in_html(":nth-child( 2n + 1 )", seven_ps,
337 pset([1, 3, 5, 7]), pset([2, 4, 6]));
338 test_selector_in_html(":nth-child(2n+0)", seven_ps,
339 pset([2, 4, 6]), pset([1, 3, 5, 7]));
340 test_selector_in_html(":nth-child(2n-0)", seven_ps,
341 pset([2, 4, 6]), pset([1, 3, 5, 7]));
342 test_selector_in_html(":nth-child(-n+3)", seven_ps,
343 pset([1, 2, 3]), pset([4, 5, 6, 7]));
344 test_selector_in_html(":nth-child(-n-3)", seven_ps,
345 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
346 test_selector_in_html(":nth-child(n)", seven_ps,
347 pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
348 test_selector_in_html(":nth-child(n-3)", seven_ps,
349 pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
350 test_selector_in_html(":nth-child(n+3)", seven_ps,
351 pset([3, 4, 5, 6, 7]), pset([1, 2]));
352 test_selector_in_html(":nth-child(2n+3)", seven_ps,
353 pset([3, 5, 7]), pset([1, 2, 4, 6]));
354 test_selector_in_html(":nth-child(2n)", seven_ps,
355 pset([2, 4, 6]), pset([1, 3, 5, 7]));
356 test_selector_in_html(":nth-child(2n-3)", seven_ps,
357 pset([1, 3, 5, 7]), pset([2, 4, 6]));
358 test_selector_in_html(":nth-child(-1n+3)", seven_ps,
359 pset([1, 2, 3]), pset([4, 5, 6, 7]));
360 test_selector_in_html(":nth-child(-2n+3)", seven_ps,
361 pset([1, 3]), pset([2, 4, 5, 6, 7]));
362 // And a few spot-checks for the other :nth-* selectors
363 test_selector_in_html(":nth-child(4n+1)", seven_ps,
364 pset([1, 5]), pset([2, 3, 4, 6, 7]));
365 test_selector_in_html(":nth-last-child(4n+1)", seven_ps,
366 pset([3, 7]), pset([1, 2, 4, 5, 6]));
367 test_selector_in_html(":nth-of-type(4n+1)", seven_ps,
368 pset([1, 5]), pset([2, 3, 4, 6, 7]));
369 test_selector_in_html(":nth-last-of-type(4n+1)", seven_ps,
370 pset([3, 7]), pset([1, 2, 4, 5, 6]));
371 test_selector_in_html(":nth-child(6)", seven_ps,
372 pset([6]), pset([1, 2, 3, 4, 5, 7]));
373 test_selector_in_html(":nth-last-child(6)", seven_ps,
374 pset([2]), pset([1, 3, 4, 5, 6, 7]));
375 test_selector_in_html(":nth-of-type(6)", seven_ps,
376 pset([6]), pset([1, 2, 3, 4, 5, 7]));
377 test_selector_in_html(":nth-last-of-type(6)", seven_ps,
378 pset([2]), pset([1, 3, 4, 5, 6, 7]));
380 // Test [first|last|only]-[child|node|of-type]
381 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> <!---->";
382 function idset(ids) { // takes an array of ids
383 return function idset_filter(doc) {
384 var result = [];
385 for each (var id in ids)
386 result.push(doc.getElementById(id));
387 return result;
390 test_parseable(":first-child");
391 test_parseable(":last-child");
392 test_parseable(":only-child");
393 test_parseable(":-moz-first-node");
394 test_parseable(":-moz-last-node");
395 test_parseable(":first-of-type");
396 test_parseable(":last-of-type");
397 test_parseable(":only-of-type");
398 test_selector_in_html(":first-child", seven_ps,
399 pset([1]), pset([2, 3, 4, 5, 6, 7]));
400 test_selector_in_html(":first-child", interesting_doc,
401 idset(["p1", "s1", "s3", "s5"]),
402 idset(["s2", "p2", "s4", "p3"]));
403 test_selector_in_html(":-moz-first-node", interesting_doc,
404 idset(["p1", "s3", "s5"]),
405 idset(["s1", "s2", "p2", "s4", "p3"]));
406 test_selector_in_html(":last-child", seven_ps,
407 pset([7]), pset([1, 2, 3, 4, 5, 6]));
408 test_selector_in_html(":last-child", interesting_doc,
409 idset(["s2", "s4", "p3", "s5"]),
410 idset(["p1", "s1", "p2", "s3"]));
411 test_selector_in_html(":-moz-last-node", interesting_doc,
412 idset(["s2", "p3", "s5"]),
413 idset(["p1", "s1", "p2", "s3", "s4"]));
414 test_selector_in_html(":only-child", seven_ps,
415 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
416 test_selector_in_html(":only-child", interesting_doc,
417 idset(["s5"]),
418 idset(["p1", "s1", "s2", "p2", "s3", "s4", "p3"]));
419 test_selector_in_html(":first-of-type", seven_ps,
420 pset([1]), pset([2, 3, 4, 5, 6, 7]));
421 test_selector_in_html(":first-of-type", interesting_doc,
422 idset(["p1", "s1", "p2", "s3", "s5"]),
423 idset(["s2", "s4", "p3"]));
424 test_selector_in_html(":last-of-type", seven_ps,
425 pset([7]), pset([1, 2, 3, 4, 5, 6]));
426 test_selector_in_html(":last-of-type", interesting_doc,
427 idset(["s2", "p2", "s4", "p3", "s5"]),
428 idset(["p1", "s1", "s3"]));
429 test_selector_in_html(":only-of-type", seven_ps,
430 pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
431 test_selector_in_html(":only-of-type", interesting_doc,
432 idset(["p2", "s5"]),
433 idset(["p1", "s1", "s2", "s3", "s4", "p3"]));
435 // And a bunch of tests for the of-type aspect of :nth-of-type() and
436 // :nth-last-of-type(). Note that the last div here contains two
437 // children.
438 var mixed_elements="<p></p><p></p><div></div><p></p><div><p></p><address></address></div><address></address>";
439 function pdaset(ps, divs, addresses) { // takes an array of 1-based indices
440 var l = { p: ps, div: divs, address: addresses };
441 return function pdaset_filter(doc) {
442 var result = [];
443 for (var tag in l) {
444 var a = doc.getElementsByTagName(tag);
445 var indices = l[tag];
446 for (var i in indices)
447 result.push(a[indices[i] - 1]);
449 return result;
452 test_selector_in_html(":nth-of-type(odd)", mixed_elements,
453 pdaset([1, 3, 4], [1], [1, 2]),
454 pdaset([2], [2], []));
455 test_selector_in_html(":nth-of-type(2n-0)", mixed_elements,
456 pdaset([2], [2], []),
457 pdaset([1, 3, 4], [1], [1, 2]));
458 test_selector_in_html(":nth-last-of-type(even)", mixed_elements,
459 pdaset([2], [1], []),
460 pdaset([1, 3, 4], [2], [1, 2]));
462 SimpleTest.finish();
465 </script>
466 </pre>
467 </body>
468 </html>