Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: page_cycler/acid3/acid3.acidtests.org/index.html

Issue 151051: Add Acid3-based page cycler.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/
Patch Set: Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/st rict.dtd">
2 <html>
3 <title>The Acid3 Test</title>
4 <script type="text/javascript">
5 var startTime = new Date();
6 </script>
7 <style type="text/css">
8
9 /* set some basic styles so that we can get reliably exact results */
10 * { margin: 0; border: 1px blue; padding: 0; border-spacing: 0; font: inherit; line-height: 1.2; color: inherit; background: transparent; }
11 :link, :visited { color: blue; }
12
13 /* header and general layout */
14 html { font: 20px Arial, sans-serif; border: 2cm solid gray; width: 32em; marg in: 1em; }
15 :root { background: silver; color: black; border-width: 0 0.2em 0.2em 0; } /* left and top content edges: 1*20px = 20px */
16 body { padding: 2em 2em 0; background: url(data:image/gif;base64,iVBORw0KGgoAA AANSUhEUgAAABQAAAAUCAIAAAAC64paAAAABGdBTUEAAK%2FINwWK6QAAAAlwSFlzAAAASAAAAEgARsl rPgAAABtJREFUOMtj%2FM9APmCiQO%2Bo5lHNo5pHNVNBMwAinAEnIWw89gAAACJ6VFh0U29mdHdhcmU AAHjac0zJT0pV8MxNTE8NSk1MqQQAL5wF1K4MqU0AAAAASUVORK5CYII%3D) no-repeat 99.839228 3% 1px white; border: solid 1px black; margin: -0.2em 0 0 -0.2em; } /* left and top content edges: 20px-0.2*20px+1px+2*20px = 57px */
17 h1:first-child { cursor: help; font-size: 5em; font-weight: bolder; margin-bot tom: -0.4em; text-shadow: rgba(192, 192, 192, 1.0) 3px 3px; } /* (left:57px, top :57px) */
18 #result { font-weight: bolder; width: 5.68em; text-align: right; }
19 #result { font-size: 5em; margin: -2.19em 0 0; } /* (right:57px+5.2*5*20px = 5 77px, top:57px+1.2*5*20px-0.4*5*20px+1px+1*40px+1*40px+1px+2*40px+150px-2.19*5*2 0px = 230px) */
20 .hidden { visibility: hidden; }
21 #slash { color: red; color: hsla(0, 0%, 0%, 1.0); }
22 #instructions { margin-top: 0; font-size: 0.8em; color: gray; color: -acid3-bo gus; height: 6.125em; } /* (left:57px, top:230px+1.2*5*20+0 = 350px) */
23 #instructions { margin-right: -20px; padding-right: 20px; background: url(data :image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAABGdBTUEAAK%2FI NwWK6QAAAAlwSFlzAAAASAAAAEgARslrPgAAABtJREFUOMtj%2FM9APmCiQO%2Bo5lHNo5pHNVNBMwAi nAEnIWw89gAAACJ6VFh0U29mdHdhcmUAAHjac0zJT0pV8MxNTE8NSk1MqQQAL5wF1K4MqU0AAAAASUVO RK5CYII%3D) no-repeat top right; }
24 #instructions span { float: right; width: 20px; margin-right: -20px; backgroun d: white; height: 20px; }
25 @font-face { font-family: "AcidAhemTest"; src: url(font.ttf); }
26 map::after { position: absolute; top: 18px; left: 638px; content: "X"; backgro und: fuchsia; color: white; font: 20px/1 AcidAhemTest; }
27 iframe { float: left; height: 0; width: 0; } /* hide iframes but don't make th em display: none */
28 object { position: fixed; left: 130.5px; top: 84.3px; background: transparent; } /* show objects if they have content */
29 .removed { position: absolute; top: 80px; left: 380px; height: 100px; width: 1 00px; opacity: 0; }
30
31 /* set the line height of the line of coloured boxes so we can add them withou t the layout changing height */
32 .buckets { font: 0/0 Arial, sans-serif; }
33 .buckets { padding: 0 0 150px 3px; }
34
35 /* the next two rules give the six coloured blocks their default styles (they match the same elements); the third hides them */
36 :first-child + * .buckets p { display: inline-block; vertical-align: 2em; bord er: 2em dotted red; padding: 1.0em 0 1.0em 2em; }
37 * + * > * > p { margin: 0; border: 1px solid ! important; }
38 .z { visibility: hidden; } /* only matches the buckets with no score */
39
40 /* sizes for the six buckets */
41 #bucket1 { font-size: 20px; margin-left: 0.2em; padding-left: 1.3em; padding-r ight: 1.3em; margin-right: 0.0001px; }
42 #bucket2 { font-size: 24px; margin-left: 0.375em; padding-left: 30px; padding- right: 32px; margin-right: 2px; }
43 #bucket3 { font-size: 28px; margin-left: 8.9999px; padding-left: 17px; padding -right: 55px; margin-right: 12px; }
44 #bucket4 { font-size: 32px; margin-left: 0; padding-left: 84px; padding-right: 0; margin-right: 0; }
45 #bucket5 { font-size: 36px; margin-left: 13px; padding-left: 0; padding-right: 94px; margin-right: 25px; }
46 #bucket6 { font-size: 40px; margin-left: -10px; padding-left: 104px; padding-r ight: -10px; }
47
48 /* colours for them */
49 .z, .zP, .zPP, .zPPP, .zPPPP, .zPPPPP { background: black; }
50 .zPPPPPP, .zPPPPPPP, .zPPPPPPPP, .zPPPPPPPP, .zPPPPPPPPP,
51 .zPPPPPPPPPP { background: grey; }
52 .zPPPPPPPPPPP, .zPPPPPPPPPPPP, .zPPPPPPPPPPPPP,
53 .zPPPPPPPPPPPPPP, .zPPPPPPPPPPPPPPP { background: silver; }
54 #bucket1.zPPPPPPPPPPPPPPPP { background: red; }
55 #bucket2.zPPPPPPPPPPPPPPPP { background: orange; }
56 #bucket3.zPPPPPPPPPPPPPPPP { background: yellow; }
57 #bucket4.zPPPPPPPPPPPPPPPP { background: lime; }
58 #bucket5.zPPPPPPPPPPPPPPPP { background: blue; }
59 #bucket6.zPPPPPPPPPPPPPPPP { background: purple; }
60
61 /* The line-height for the .bucket div is worked out as follows:
62 *
63 * The div.bucket element has a line box with a few
64 * inline-blocks. Each inline-block consists of:
65 *
66 * 2.0em vertical-align from baseline to bottom of inline-block
67 * 1px bottom border
68 * 1.0em bottom padding
69 * 1.0em top padding
70 * 1px top border
71 *
72 * The biggest inline-block has font-size: 40px.
73 *
74 * Thus the distance from the baseline to the top of the biggest
75 * inline-block is (2em+1em+1em)*2em*20px+2px = 162px.
76 *
77 * The line box itself has no other contents, and its strut has zero
78 * height and there is no half-leading, so the height of the
79 * div.bucket is 162px.
80 *
81 * (Why use line-height:0 and font-size:0? Well:
82 *
83 * The div.bucket line box would have a height that is the maximum
84 * of the following two sums:
85 *
86 * 1: half-leading + font descent at 1em + font ascent at 1em + half-leading
87 * 2: half-leading + font descent at 1em + 162px
88 *
89 * Now the half-leading is (line-height - (font-ascent + font-descent))/2, so that is really:
90 *
91 * 1: (line-height - (font-ascent + font-descent))/2 + font descent + font as cent + (line-height - (font-ascent + font-descent))/2
92 * 2: (line-height - (font-ascent + font-descent))/2 + font descent + 162px
93 *
94 * Which simplify to:
95 *
96 * 1: line-height
97 * 2: line-height/2 + (font descent - font-ascent)/2 + 162px
98 *
99 * So if the following expression is true:
100 *
101 * line-height > line-height/2 + (font descent - font-ascent)/2 + 162px
102 *
103 * That is, if this is true:
104 *
105 * line-height > font descent - font-ascent + 324px
106 *
107 * ...then the line-height matters, otherwise the font does. Note
108 * that font descent - font-ascent will be in the region of
109 * 10px-30px (with Ahem, exactly 12px). However, if we make the
110 * line-height big, then the _positioning_ of the inline-blocks will
111 * depend on the font descent, since that is what will decide the
112 * distance from the bottom of the line box to the baseline of the
113 * block (since the baseline is set by the strut).
114 *
115 * However, in Acid2 a dependency on the font metrics was introduced
116 * and this caused all kinds of problems. And we can't require Ahem
117 * in the Acid tests, since it's unlikely most people will have it
118 * installed.
119 *
120 * What we want is for the font to not matter, and the baseline to
121 * be as high as possible. We can do that by saying that the font
122 * and the line-height are zero.
123 *
124 * One word of warning. If your browser has a minimum font size feature
125 * that forces font sizes up even when there is no text, you will need
126 * to disable it before running this test.
127 *
128 */
129
130 /* rules specific to the tests below */
131 #instructions:last-child { white-space: pre-wrap; white-space: x-bogus; }
132 #linktest:link { display: block; color: red; text-align: center; text-decorati on: none; }
133 #linktest.pending, #linktest:visited { display: none; }
134 #\ { color: transparent; color: hsla(0, 0, 0, 1); position: fixed; top: 10px; left: 10px; font: 40px Arial, sans-serif; }
135 #\ #result, #\ #score { position: fixed; top: 10%; left: 10%; width: 4em; z- index: 1; color: yellow; font-size: 50px; background: fuchsia; border: solid 1em purple; }
136 </style>
137
138 <!-- part of the HTTP tests -->
139 <link rel="stylesheet" href="empty.css"><!-- text/html file (should be ignored, <h1> will go red if it isn't) -->
140
141 <!-- the next five script blocks are part of one of the tests -->
142 <script type="text/javascript">
143 var d1 = "fail";
144 var d2 = "fail";
145 var d3 = "fail";
146 var d4 = "fail";
147 var d5 = "fail";
148 </script>
149 <script type="text/javascript" src="data:text/javascript,d1%20%3D%20'one'%3B">< /script>
150 <script type="text/javascript" src="data:text/javascript;base64,ZDIgPSAndHdvJzs %3D"></script>
151 <script type="text/javascript" src="data:text/javascript;base64,%5a%44%4d%67%50 %53%41%6e%64%47%68%79%5a%57%55%6e%4f%77%3D%3D"></script>
152 <script type="text/javascript" src="data:text/javascript;base64,%20ZD%20Qg%0D%0 APS%20An%20Zm91cic%0D%0A%207%20"></script>
153 <script type="text/javascript" src="data:text/javascript,d5%20%3D%20'five%5Cu00 27s'%3B"></script>
154
155 <!-- part of the JS regexp and \0 value tests test -->
156 <script type="text/javascript">
157 var nullInRegexpArgumentResult = 0 < /script/.test('\0script') ? "passed" : "f ailed";
158 </script>
159
160 <!-- main test body -->
161 <script type="text/javascript">
162 var notifications = {};
163 function notify(file) {
164 // used in cross-file tests
165 notifications[file] = 1;
166 }
167 function fail(message) {
168 throw { message: message };
169 }
170 function assert(condition, message) {
171 if (!condition)
172 fail(message);
173 }
174 function assertEquals(expression, value, message) {
175 if (expression != value) {
176 expression = (""+expression).replace(/[\r\n]+/g, "\\n");
177 value = (""+value).replace(/\r?\n/g, "\\n");
178 fail("expected '" + value + "' but got '" + expression + "' - " + message) ;
179 }
180 }
181 function getTestDocument() {
182 var iframe = document.getElementById("selectors");
183 var doc = iframe.contentDocument;
184 //alert(doc);
185 for (var i = doc.documentElement.childNodes.length-1; i >= 0; i -= 1) {
186 doc.documentElement.removeChild(doc.documentElement.childNodes[i]);
187 }
188 doc.documentElement.appendChild(doc.createElement('head'));
189 doc.documentElement.firstChild.appendChild(doc.createElement('title'));
190 doc.documentElement.appendChild(doc.createElement('body'));
191 return doc;
192 }
193 function selectorTest(tester) {
194 var doc = getTestDocument();
195 var style = doc.createElement('style');
196 style.appendChild(doc.createTextNode("* { z-index: 0; position: absolute; }\ n"));
197 doc.documentElement.firstChild.appendChild(style);
198 var ruleCount = 0;
199 tester(doc, function (selector) {
200 ruleCount += 1;
201 style.appendChild(doc.createTextNode(selector + " { z-index: " + ruleCou nt + "; }\n"));
202 return ruleCount;
203 }, function(node, rule, message) {
204 var value = doc.defaultView.getComputedStyle(node, "").zIndex;
205 assert(value != 'auto', "underlying problems prevent this test from runn ing properly");
206 assertEquals(value, rule, message);
207 });
208 }
209 var kungFuDeathGrip = null; // used to hold things from test to test
210 var tests = [
211
212 // there are 6 buckets with 16 tests each, plus four special tests (0, 97, 9 8, and 99).
213
214 // Remove the "JS required" message and the <script> element in the <body>
215 function () {
216 // test 0: whether removing an element that is the last child correctly re computes styles for the new last child
217 // also tests support for getComputedStyle, :last-child, pre-wrap, removin g a <script> element
218 // removing script:
219 var scripts = document.getElementsByTagName('script');
220 document.body.removeChild(scripts[scripts.length-1]);
221 // removing last child:
222 var last = document.getElementById('remove-last-child-test');
223 var penultimate = last.previousSibling; // this should be the whitespace n ode
224 penultimate = penultimate.previousSibling; // this should now be the actua l penultimate element
225 last.parentNode.removeChild(last);
226 assertEquals(document.defaultView.getComputedStyle(penultimate, '').whiteS pace, 'pre-wrap', "found unexpected computed style");
227 return 7;
228 },
229
230 // bucket 1: DOM Traversal, DOM Range, HTTP
231 // DOM Traversal
232 function () {
233 // test 1: NodeFilters and Exceptions
234 var doc = getTestDocument(); // looks like <!DOCTYPE><html><head><title/>< \head><body/><\html> (the '\'s are to avoid validation errors)
235 var iteration = 0;
236 var exception = "Roses";
237 var test = function(node) {
238 iteration += 1;
239 switch (iteration) {
240 case 1: case 3: case 4: case 6: case 7: case 8: case 9: case 14: case 15: throw exception;
241 case 2: case 5: case 10: case 11: case 12: case 13: return true; // To Number(true) => 1
242 default: throw 0;
243 };
244 };
245 var check = function(o, method) {
246 var ok = false;
247 try {
248 o[method]();
249 } catch (e) {
250 if (e === exception)
251 ok = true;
252 }
253 assert(ok, "method " + o + "." + method + "() didn't forward exception") ;
254 };
255 var i = doc.createNodeIterator(doc.documentElement, 0xFFFFFFFF, test, true );
256 check(i, "nextNode"); // 1
257 assertEquals(i.nextNode(), doc.documentElement, "i.nextNode() didn't retur n the right node"); // 2
258 check(i, "previousNode"); // 3
259 var w = document.createTreeWalker(doc.documentElement, 0xFFFFFFFF, test, t rue);
260 check(w, "nextNode"); // 4
261 assertEquals(w.nextNode(), doc.documentElement.firstChild, "w.nextNode() d idn't return the right node"); // 5
262 check(w, "previousNode"); // 6
263 check(w, "firstChild"); // 7
264 check(w, "lastChild"); // 8
265 check(w, "nextSibling"); // 9
266 assertEquals(iteration, 9, "iterations went wrong");
267 assertEquals(w.previousSibling(), null, "w.previousSibling() didn't return the right node"); // doesn't call filter
268 assertEquals(iteration, 9, "filter called incorrectly for previousSibling( )");
269 assertEquals(w.lastChild(), doc.getElementsByTagName('title')[0], "w.lastC hild() didn't return the right node"); // 10
270 assertEquals(w.nextSibling(), null, "w.nextSibling() didn't return the rig ht node"); // 11 (filter called on parent, to see if it's included, otherwise it could skip that and find a nextsibling elsewhere)
271 assertEquals(iteration, 11, "filter called incorrectly for nextSibling()") ;
272 assertEquals(w.parentNode(), doc.documentElement.firstChild, "w.parentNode () didn't return the right node"); // 12
273 assertEquals(w.nextSibling(), doc.documentElement.lastChild, "w.nextSiblin g() didn't return the right node"); // 13
274 check(w, "previousSibling"); // 14
275 check(w, "parentNode"); // 15
276 return 1;
277 },
278 function () {
279 // test 2: Removing nodes during iteration
280 var count = 0;
281 var expect = function(n, node1, node2) {
282 count += 1;
283 assert(n == count, "reached expectation " + n + " when expecting expecta tion " + count);
284 assertEquals(node1, node2, "expectation " + count + " failed");
285 };
286 var doc = getTestDocument();
287 var t1 = doc.body.appendChild(doc.createElement('t1'));
288 var t2 = doc.body.appendChild(doc.createElement('t2'));
289 var t3 = doc.body.appendChild(doc.createElement('t3'));
290 var t4 = doc.body.appendChild(doc.createElement('t4'));
291 var callCount = 0;
292 var filterFunctions = [
293 function (node) { expect(1, node, doc.body); return true; }, // filter 0
294 function (node) { expect(3, node, t1); return true; }, // filter 1
295 function (node) { expect(5, node, t2); return true; }, // filter 2
296 function (node) { expect(7, node, t3); doc.body.removeChild(t4); return true; }, // filter 3
297 function (node) { expect(9, node, t4); return true; }, // filter 4
298 function (node) { expect(11, node, t4); doc.body.removeChild(t4); return 2 /* REJECT */; }, // filter 5
299 function (node) { expect(12, node, t3); return true; }, // filter 6
300 function (node) { expect(14, node, t2); doc.body.removeChild(t2); return true; }, // filter 7
301 function (node) { expect(16, node, t1); return true; }, // filter 8
302 ];
303 var i = doc.createNodeIterator(doc.documentElement.lastChild, 0xFFFFFFFF, function (node) { return filterFunctions[callCount++](node); }, true);
304 // * B 1 2 3 4
305 expect(2, i.nextNode(), doc.body); // filter 0
306 // [B] * 1 2 3 4
307 expect(4, i.nextNode(), t1); // filter 1
308 // B [1] * 2 3 4
309 expect(6, i.nextNode(), t2); // filter 2
310 // B 1 [2] * 3 4
311 expect(8, i.nextNode(), t3); // filter 3
312 // B 1 2 [3] *
313 doc.body.appendChild(t4);
314 // B 1 2 [3] * 4
315 expect(10, i.nextNode(), t4); // filter 4
316 // B 1 2 3 [4] *
317 expect(13, i.previousNode(), t3); // filters 5, 6
318 // B 1 2 3 * (4) // filter 5
319 // B 1 2 [3] * // between 5 and 6
320 // B 1 2 * (3) // filter 6
321 // B 1 2 * [3]
322 expect(15, i.previousNode(), t2); // filter 7
323 // B 1 * (2) [3]
324 // -- spec says "For instance, if a NodeFilter removes a node
325 // from a document, it can still accept the node, which
326 // means that the node may be returned by the NodeIterator
327 // or TreeWalker even though it is no longer in the subtree
328 // being traversed."
329 // -- but it also says "If changes to the iterated list do not
330 // remove the reference node, they do not affect the state
331 // of the NodeIterator."
332 // B 1 * [3]
333 expect(17, i.previousNode(), t1); // filter 8
334 // B [1] * 3
335 return 1;
336 },
337 function () {
338 // test 3: the infinite iterator
339 var doc = getTestDocument();
340 for (var i = 0; i < 5; i += 1) {
341 doc.body.appendChild(doc.createElement('section'));
342 doc.body.lastChild.title = i;
343 }
344 var count = 0;
345 var test = function() {
346 if (count > 3 && count < 12)
347 doc.body.appendChild(doc.body.firstChild);
348 count += 1;
349 return (count % 2 == 0) ? 1 : 2;
350 };
351 var i = doc.createNodeIterator(doc.body, 0xFFFFFFFF, test, true);
352 assertEquals(i.nextNode().title, "0", "failure 1");
353 assertEquals(i.nextNode().title, "2", "failure 2");
354 assertEquals(i.nextNode().title, "4", "failure 3");
355 assertEquals(i.nextNode().title, "1", "failure 4");
356 assertEquals(i.nextNode().title, "3", "failure 5");
357 assertEquals(i.nextNode().title, "0", "failure 6");
358 assertEquals(i.nextNode().title, "2", "failure 7");
359 assertEquals(i.nextNode(), null, "failure 8");
360 return 1;
361 },
362 function () {
363 // test 4: ignoring whitespace text nodes with node iterators
364 var count = 0;
365 var expect = function(node1, node2) {
366 count += 1;
367 assertEquals(node1, node2, "expectation " + count + " failed");
368 };
369 var allButWS = function (node) {
370 if (node.nodeType == 3 && node.data.match(/^\s*$/))
371 return 2;
372 return 1;
373 };
374 var i = document.createNodeIterator(document.body, 0x01 | 0x04 | 0x08 | 0x 10 | 0x20, allButWS, true);
375 // now walk the document body and make sure everything is in the right pla ce
376 expect(i.nextNode(), document.body); // 1
377 expect(i.nextNode(), document.getElementsByTagName('h1')[0]);
378 expect(i.nextNode(), document.getElementsByTagName('h1')[0].firstChild);
379 expect(i.nextNode(), document.getElementsByTagName('div')[0]);
380 expect(i.nextNode(), document.getElementById('bucket1'));
381 expect(i.nextNode(), document.getElementById('bucket2'));
382 expect(i.nextNode(), document.getElementById('bucket3'));
383 expect(i.nextNode(), document.getElementById('bucket4'));
384 expect(i.nextNode(), document.getElementById('bucket5'));
385 expect(i.nextNode(), document.getElementById('bucket6')); // 10
386 expect(i.nextNode(), document.getElementById('result'));
387 expect(i.nextNode(), document.getElementById('score'));
388 expect(i.nextNode(), document.getElementById('score').firstChild);
389 expect(i.nextNode(), document.getElementById('slash'));
390 expect(i.nextNode(), document.getElementById('slash').firstChild);
391 expect(i.nextNode(), document.getElementById('slash').nextSibling);
392 expect(i.nextNode(), document.getElementById('slash').nextSibling.firstChi ld);
393 expect(i.nextNode(), document.getElementsByTagName('map')[0]);
394 expect(i.nextNode(), document.getElementsByTagName('area')[0]);
395 expect(i.nextNode(), document.getElementsByTagName('iframe')[0]); // 20
396 expect(i.nextNode(), document.getElementsByTagName('iframe')[0].firstChild );
397 expect(i.nextNode(), document.getElementsByTagName('iframe')[1]);
398 expect(i.nextNode(), document.getElementsByTagName('iframe')[1].firstChild );
399 expect(i.nextNode(), document.getElementsByTagName('iframe')[2]);
400 expect(i.nextNode(), document.forms[0]);
401 expect(i.nextNode(), document.forms.form.elements[0]);
402 expect(i.nextNode(), document.getElementsByTagName('table')[0]);
403 expect(i.nextNode(), document.getElementsByTagName('tbody')[0]);
404 expect(i.nextNode(), document.getElementsByTagName('tr')[0]);
405 expect(i.nextNode(), document.getElementsByTagName('td')[0]);
406 expect(i.nextNode(), document.getElementsByTagName('td')[0].getElementsByT agName('p')[0]);
407 expect(i.nextNode(), document.getElementById('instructions'));
408 expect(i.nextNode(), document.getElementById('instructions').firstChild);
409 expect(i.nextNode().nodeName, "SPAN");
410 expect(i.nextNode().nodeName, "#text");
411 expect(i.nextNode(), document.links[1]);
412 expect(i.nextNode(), document.links[1].firstChild);
413 expect(i.nextNode(), document.getElementById('instructions').lastChild);
414 expect(i.nextNode(), null);
415 // walk it backwards for good measure
416 expect(i.previousNode(), document.getElementById('instructions').lastChild );
417 expect(i.previousNode(), document.links[1].firstChild);
418 expect(i.previousNode(), document.links[1]);
419 expect(i.previousNode().nodeName, "#text");
420 expect(i.previousNode().nodeName, "SPAN");
421 expect(i.previousNode(), document.getElementById('instructions').firstChil d);
422 expect(i.previousNode(), document.getElementById('instructions'));
423 expect(i.previousNode(), document.getElementsByTagName('td')[0].getElement sByTagName('p')[0]);
424 expect(i.previousNode(), document.getElementsByTagName('td')[0]);
425 expect(i.previousNode(), document.getElementsByTagName('tr')[0]);
426 expect(i.previousNode(), document.getElementsByTagName('tbody')[0]);
427 expect(i.previousNode(), document.getElementsByTagName('table')[0]);
428 expect(i.previousNode(), document.forms.form.elements[0]);
429 expect(i.previousNode(), document.forms[0]);
430 expect(i.previousNode(), document.getElementsByTagName('iframe')[2]);
431 expect(i.previousNode(), document.getElementsByTagName('iframe')[1].firstC hild);
432 expect(i.previousNode(), document.getElementsByTagName('iframe')[1]);
433 expect(i.previousNode(), document.getElementsByTagName('iframe')[0].firstC hild);
434 expect(i.previousNode(), document.getElementsByTagName('iframe')[0]); // 2 0
435 expect(i.previousNode(), document.getElementsByTagName('area')[0]);
436 expect(i.previousNode(), document.getElementsByTagName('map')[0]);
437 expect(i.previousNode(), document.getElementById('slash').nextSibling.firs tChild);
438 expect(i.previousNode(), document.getElementById('slash').nextSibling);
439 expect(i.previousNode(), document.getElementById('slash').firstChild);
440 expect(i.previousNode(), document.getElementById('slash'));
441 expect(i.previousNode(), document.getElementById('score').firstChild);
442 expect(i.previousNode(), document.getElementById('score'));
443 expect(i.previousNode(), document.getElementById('result'));
444 expect(i.previousNode(), document.getElementById('bucket6'));
445 expect(i.previousNode(), document.getElementById('bucket5'));
446 expect(i.previousNode(), document.getElementById('bucket4'));
447 expect(i.previousNode(), document.getElementById('bucket3'));
448 expect(i.previousNode(), document.getElementById('bucket2'));
449 expect(i.previousNode(), document.getElementById('bucket1'));
450 expect(i.previousNode(), document.getElementsByTagName('div')[0]);
451 expect(i.previousNode(), document.getElementsByTagName('h1')[0].firstChild );
452 expect(i.previousNode(), document.getElementsByTagName('h1')[0]);
453 expect(i.previousNode(), document.body);
454 expect(i.previousNode(), null);
455 return 1;
456 },
457 function () {
458 // test 5: ignoring whitespace text nodes with tree walkers
459 var count = 0;
460 var expect = function(node1, node2) {
461 count += 1;
462 assertEquals(node1, node2, "expectation " + count + " failed");
463 };
464 var allButWS = function (node) {
465 if (node.nodeType == 3 && node.data.match(/^\s*$/))
466 return 3;
467 return 1;
468 };
469 var w = document.createTreeWalker(document.body, 0x01 | 0x04 | 0x08 | 0x10 | 0x20, allButWS, true);
470 expect(w.currentNode, document.body);
471 expect(w.parentNode(), null);
472 expect(w.currentNode, document.body);
473 expect(w.firstChild(), document.getElementsByTagName('h1')[0]);
474 expect(w.firstChild().nodeType, 3);
475 expect(w.parentNode(), document.getElementsByTagName('h1')[0]);
476 expect(w.nextSibling().previousSibling.nodeType, 3);
477 expect(w.nextSibling(), document.getElementsByTagName('p')[6]);
478 expect(w.nextSibling(), document.getElementsByTagName('map')[0]);
479 expect(w.lastChild(), document.getElementsByTagName('table')[0]);
480 expect(w.lastChild(), document.getElementsByTagName('tbody')[0]);
481 expect(w.nextNode(), document.getElementsByTagName('tr')[0]);
482 expect(w.nextNode(), document.getElementsByTagName('td')[0]);
483 expect(w.nextNode(), document.getElementsByTagName('p')[7]);
484 expect(w.nextNode(), document.getElementsByTagName('p')[8]); // instructio ns.inc paragraph
485 expect(w.previousSibling(), document.getElementsByTagName('map')[0]);
486 expect(w.previousNode().data, "100");
487 expect(w.parentNode().tagName, "SPAN");
488 expect(w.parentNode(), document.getElementById('result'));
489 expect(w.parentNode(), document.body);
490 expect(w.lastChild().id, "instructions");
491 expect(w.lastChild().data.substr(0,1), ".");
492 expect(w.previousNode(), document.links[1].firstChild);
493 return 1;
494 },
495 function () {
496 // test 6: walking outside a tree
497 var doc = getTestDocument();
498 var p = doc.createElement('p');
499 doc.body.appendChild(p);
500 var b = doc.body;
501 var w = document.createTreeWalker(b, 0xFFFFFFFF, null, true);
502 assertEquals(w.currentNode, b, "basic use of TreeWalker failed: currentNod e");
503 assertEquals(w.lastChild(), p, "basic use of TreeWalker failed: lastChild( )");
504 assertEquals(w.previousNode(), b, "basic use of TreeWalker failed: previou sNode()");
505 doc.documentElement.removeChild(b);
506 assertEquals(w.lastChild(), p, "TreeWalker failed after removing the curre nt node from the tree");
507 assertEquals(w.nextNode(), null, "failed to walk into the end of a subtree ");
508 doc.documentElement.appendChild(p);
509 assertEquals(w.previousNode(), doc.getElementsByTagName('title')[0], "fail ed to handle regrafting correctly");
510 p.appendChild(b);
511 assertEquals(w.nextNode(), p, "couldn't retrace steps");
512 assertEquals(w.nextNode(), b, "couldn't step back into root");
513 assertEquals(w.previousNode(), null, "root didn't retake its rootish posit ion");
514 return 1;
515 },
516
517 // DOM Range
518 function () {
519 // test 7: basic ranges tests
520 var r = document.createRange();
521 assert(r, "range not created");
522 assert(r.collapsed, "new range wasn't collapsed");
523 assertEquals(r.commonAncestorContainer, document, "new range's common ance stor wasn't the document");
524 assertEquals(r.startContainer, document, "new range's start container wasn 't the document");
525 assertEquals(r.startOffset, 0, "new range's start offset wasn't zero");
526 assertEquals(r.endContainer, document, "new range's end container wasn't t he document");
527 assertEquals(r.endOffset, 0, "new range's end offset wasn't zero");
528 assert(r.cloneContents(), "cloneContents() didn't return an object");
529 assertEquals(r.cloneContents().childNodes.length, 0, "nothing cloned was m ore than nothing");
530 assertEquals(r.cloneRange().toString(), "", "nothing cloned stringifed to more than nothing");
531 r.collapse(true); // no effect
532 assertEquals(r.compareBoundaryPoints(r.START_TO_END, r.cloneRange()), 0, " starting boundary point of range wasn't the same as the end boundary point of th e clone range");
533 r.deleteContents(); // no effect
534 assertEquals(r.extractContents().childNodes.length, 0, "nothing removed wa s more than nothing");
535 var endOffset = r.endOffset;
536 r.insertNode(document.createComment("commented inserted to test ranges"));
537 r.setEnd(r.endContainer, endOffset + 1); // added to work around spec bug that smaug is blocking the errata for
538 try {
539 assert(!r.collapsed, "range with inserted comment is collapsed");
540 assertEquals(r.commonAncestorContainer, document, "range with inserted c omment has common ancestor that isn't the document");
541 assertEquals(r.startContainer, document, "range with inserted comment ha s start container that isn't the document");
542 assertEquals(r.startOffset, 0, "range with inserted comment has start of fset that isn't zero");
543 assertEquals(r.endContainer, document, "range with inserted comment has end container that isn't the document");
544 assertEquals(r.endOffset, 1, "range with inserted comment has end offset that isn't after the comment");
545 } finally {
546 document.removeChild(document.firstChild);
547 }
548 return 1;
549 },
550 function () {
551 // test 8: moving boundary points
552 var doc = document.implementation.createDocument(null, null, null);
553 var root = doc.createElement("root");
554 doc.appendChild(root);
555 var e1 = doc.createElement("e");
556 root.appendChild(e1);
557 var e2 = doc.createElement("e");
558 root.appendChild(e2);
559 var e3 = doc.createElement("e");
560 root.appendChild(e3);
561 var r = doc.createRange();
562 r.setStart(e2, 0);
563 r.setEnd(e3, 0);
564 assert(!r.collapsed, "non-empty range claims to be collapsed");
565 r.setEnd(e1, 0);
566 assert(r.collapsed, "setEnd() didn't collapse the range");
567 assertEquals(r.startContainer, e1, "startContainer is wrong after setEnd() ");
568 assertEquals(r.startOffset, 0, "startOffset is wrong after setEnd()");
569 assertEquals(r.endContainer, e1, "endContainer is wrong after setEnd()");
570 assertEquals(r.endOffset, 0, "endOffset is wrong after setEnd()");
571 r.setStartBefore(e3);
572 assert(r.collapsed, "setStartBefore() didn't collapse the range");
573 assertEquals(r.startContainer, root, "startContainer is wrong after setSta rtBefore()");
574 assertEquals(r.startOffset, 2, "startOffset is wrong after setStartBefore( )");
575 assertEquals(r.endContainer, root, "endContainer is wrong after setStartBe fore()");
576 assertEquals(r.endOffset, 2, "endOffset is wrong after setStartBefore()");
577 r.setEndAfter(root);
578 assert(!r.collapsed, "setEndAfter() didn't uncollapse the range");
579 assertEquals(r.startContainer, root, "startContainer is wrong after setEnd After()");
580 assertEquals(r.startOffset, 2, "startOffset is wrong after setEndAfter()") ;
581 assertEquals(r.endContainer, doc, "endContainer is wrong after setEndAfter ()");
582 assertEquals(r.endOffset, 1, "endOffset is wrong after setEndAfter()");
583 r.setStartAfter(e2);
584 assert(!r.collapsed, "setStartAfter() collapsed the range");
585 assertEquals(r.startContainer, root, "startContainer is wrong after setSta rtAfter()");
586 assertEquals(r.startOffset, 2, "startOffset is wrong after setStartAfter() ");
587 assertEquals(r.endContainer, doc, "endContainer is wrong after setStartAft er()");
588 assertEquals(r.endOffset, 1, "endOffset is wrong after setStartAfter()");
589 var msg = '';
590 try {
591 r.setEndBefore(doc);
592 msg = "no exception thrown for setEndBefore() the document itself";
593 } catch (e) {
594 if (e.BAD_BOUNDARYPOINTS_ERR != 1)
595 msg = 'not a RangeException';
596 else if (e.INVALID_NODE_TYPE_ERR != 2)
597 msg = 'RangeException has no INVALID_NODE_TYPE_ERR';
598 else if ("INVALID_ACCESS_ERR" in e)
599 msg = 'RangeException has DOMException constants';
600 else if (e.code != e.INVALID_NODE_TYPE_ERR)
601 msg = 'wrong exception raised from setEndBefore()';
602 }
603 assert(msg == "", msg);
604 assert(!r.collapsed, "setEndBefore() collapsed the range");
605 assertEquals(r.startContainer, root, "startContainer is wrong after setEnd Before()");
606 assertEquals(r.startOffset, 2, "startOffset is wrong after setEndBefore()" );
607 assertEquals(r.endContainer, doc, "endContainer is wrong after setEndBefor e()");
608 assertEquals(r.endOffset, 1, "endOffset is wrong after setEndBefore()");
609 r.collapse(false);
610 assert(r.collapsed, "collapse() collapsed the range");
611 assertEquals(r.startContainer, doc, "startContainer is wrong after collaps e()");
612 assertEquals(r.startOffset, 1, "startOffset is wrong after collapse()");
613 assertEquals(r.endContainer, doc, "endContainer is wrong after collapse()" );
614 assertEquals(r.endOffset, 1, "endOffset is wrong after collapse()");
615 r.selectNodeContents(root);
616 assert(!r.collapsed, "collapsed is wrong after selectNodeContents()");
617 assertEquals(r.startContainer, root, "startContainer is wrong after select NodeContents()");
618 assertEquals(r.startOffset, 0, "startOffset is wrong after selectNodeConte nts()");
619 assertEquals(r.endContainer, root, "endContainer is wrong after selectNode Contents()");
620 assertEquals(r.endOffset, 3, "endOffset is wrong after selectNodeContents( )");
621 r.selectNode(e2);
622 assert(!r.collapsed, "collapsed is wrong after selectNode()");
623 assertEquals(r.startContainer, root, "startContainer is wrong after select Node()");
624 assertEquals(r.startOffset, 1, "startOffset is wrong after selectNode()");
625 assertEquals(r.endContainer, root, "endContainer is wrong after selectNode ()");
626 assertEquals(r.endOffset, 2, "endOffset is wrong after selectNode()");
627 return 1;
628 },
629 function () {
630 // test 9: extractContents() in a Document
631 var doc = getTestDocument();
632 var h1 = doc.createElement('h1');
633 var t1 = doc.createTextNode('Hello ');
634 h1.appendChild(t1);
635 var em = doc.createElement('em');
636 var t2 = doc.createTextNode('Wonderful');
637 em.appendChild(t2);
638 h1.appendChild(em);
639 var t3 = doc.createTextNode(' Kitty');
640 h1.appendChild(t3);
641 doc.body.appendChild(h1);
642 var p = doc.createElement('p');
643 var t4 = doc.createTextNode('How are you?');
644 p.appendChild(t4);
645 doc.body.appendChild(p);
646 var r = doc.createRange();
647 r.selectNodeContents(doc);
648 assertEquals(r.toString(), "Hello Wonderful KittyHow are you?", "toString( ) on range selecting Document gave wrong output");
649 r.setStart(t2, 6);
650 r.setEnd(p, 0);
651 // <body><h1>Hello <em>Wonder ful<\em> Kitty<\h1><p> How are you?<\p><\bod y> (the '\'s are to avoid validation errors)
652 // ^----------------------^
653 assertEquals(r.toString(), "ful Kitty", "toString() on range crossing text nodes gave wrong output");
654 var f = r.extractContents();
655 // <h1><em>ful<\em> Kitty<\h1><p><\p>
656 // ccccccccccccccccMMMMMMcccccccccccc
657 assertEquals(f.nodeType, 11, "failure 1");
658 assert(f.childNodes.length == 2, "expected two children in the result, got " + f.childNodes.length);
659 assertEquals(f.childNodes[0].tagName, "H1", "failure 3");
660 assert(f.childNodes[0] != h1, "failure 4");
661 assertEquals(f.childNodes[0].childNodes.length, 2, "failure 5");
662 assertEquals(f.childNodes[0].childNodes[0].tagName, "EM", "failure 6");
663 assert(f.childNodes[0].childNodes[0] != em, "failure 7");
664 assertEquals(f.childNodes[0].childNodes[0].childNodes.length, 1, "failure 8");
665 assertEquals(f.childNodes[0].childNodes[0].childNodes[0].data, "ful", "fai lure 9");
666 assert(f.childNodes[0].childNodes[0].childNodes[0] != t2, "failure 10");
667 assertEquals(f.childNodes[0].childNodes[1], t3, "failure 11");
668 assert(f.childNodes[0].childNodes[1] != em, "failure 12");
669 assertEquals(f.childNodes[1].tagName, "P", "failure 13");
670 assertEquals(f.childNodes[1].childNodes.length, 0, "failure 14");
671 assert(f.childNodes[1] != p, "failure 15");
672 return 1;
673 },
674 function () {
675 // test 10: Ranges and Attribute Nodes
676 var e = document.getElementById('result');
677 if (!e.getAttributeNode)
678 return 1; // support for attribute nodes is optional in Acid3, because a ttribute nodes might be removed from DOM Core in the future.
679 // however, if they're supported, they'd better work:
680 var a = e.getAttributeNode('id');
681 var r = document.createRange();
682 r.selectNodeContents(a);
683 assertEquals(r.toString(), "result", "toString() didn't work for attribute node");
684 var t = a.firstChild;
685 var f = r.extractContents();
686 assertEquals(f.childNodes.length, 1, "extracted contents were the wrong le ngth");
687 assertEquals(f.childNodes[0], t, "extracted contents were the wrong node") ;
688 assertEquals(t.textContent, 'result', "extracted contents didn't match old attribute value");
689 assertEquals(r.toString(), '', "extracting contents didn't empty attribute value; instead equals '" + r.toString() + "'");
690 assertEquals(e.getAttribute('id'), '', "extracting contents didn't change 'id' attribute to empty string");
691 e.id = 'result';
692 return 1;
693 },
694 function () {
695 // test 11: Ranges and Comments
696 var msg;
697 var doc = getTestDocument();
698 var c1 = doc.createComment("11111");
699 doc.appendChild(c1);
700 var r = doc.createRange();
701 r.selectNode(c1);
702 msg = 'wrong exception raised';
703 try {
704 r.surroundContents(doc.createElement('a'));
705 msg = 'no exception raised';
706 } catch (e) {
707 if ('code' in e)
708 msg += '; code = ' + e.code;
709 if (e.code == 3)
710 msg = '';
711 }
712 assert(msg == '', "when inserting <a> into Document with another child: " + msg);
713 var c2 = doc.createComment("22222");
714 doc.body.appendChild(c2);
715 var c3 = doc.createComment("33333");
716 doc.body.appendChild(c3);
717 r.setStart(c2, 2);
718 r.setEnd(c3, 3);
719 var msg = 'wrong exception raised';
720 try {
721 r.surroundContents(doc.createElement('a'));
722 msg = 'no exception raised';
723 } catch (e) {
724 if ('code' in e)
725 msg += '; code = ' + e.code;
726 if (e.code == 1)
727 msg = '';
728 }
729 assert(msg == '', "when trying to surround two halves of comment: " + msg) ;
730 assertEquals(r.toString(), "", "comments returned text");
731 return 1;
732 },
733 function () {
734 // test 12: Ranges under mutations: insertion into text nodes
735 var doc = getTestDocument();
736 var p = doc.createElement('p');
737 var t1 = doc.createTextNode('12345');
738 p.appendChild(t1);
739 var t2 = doc.createTextNode('ABCDE');
740 p.appendChild(t2);
741 doc.body.appendChild(p);
742 var r = doc.createRange();
743 r.setStart(p.firstChild, 2);
744 r.setEnd(p.firstChild, 3);
745 assert(!r.collapsed, "collapsed is wrong at start");
746 assertEquals(r.commonAncestorContainer, p.firstChild, "commonAncestorConta iner is wrong at start");
747 assertEquals(r.startContainer, p.firstChild, "startContainer is wrong at s tart");
748 assertEquals(r.startOffset, 2, "startOffset is wrong at start");
749 assertEquals(r.endContainer, p.firstChild, "endContainer is wrong at start ");
750 assertEquals(r.endOffset, 3, "endOffset is wrong at start");
751 assertEquals(r.toString(), "3", "range in text node stringification failed ");
752 r.insertNode(p.lastChild);
753 assertEquals(p.childNodes.length, 3, "insertion of node made wrong number of child nodes");
754 assertEquals(p.childNodes[0], t1, "unexpected first text node");
755 assertEquals(p.childNodes[0].data, "12", "unexpected first text node conte nts");
756 assertEquals(p.childNodes[1], t2, "unexpected second text node");
757 assertEquals(p.childNodes[1].data, "ABCDE", "unexpected second text node") ;
758 assertEquals(p.childNodes[2].data, "345", "unexpected third text node cont ents");
759 // The spec is very vague about what exactly should be in the range afterw ards:
760 // the insertion results in a splitText(), which it says is equivalent to a truncation
761 // followed by an insertion, but it doesn't say what to do when you have a truncation,
762 // so we don't know where either the start or the end boundary points end up.
763 // The spec really should be clarified for how to handle splitText() and
764 // text node truncation in general
765 // The only thing that seems very clear is that the inserted text node sho uld
766 // be in the range, and it has to be at the start, since insertion always puts it at
767 // the start.
768 assert(!r.collapsed, "collapsed is wrong after insertion");
769 assert(r.toString().match(/^ABCDE/), "range didn't start with the expected text; range stringified to '" + r.toString() + "'");
770 return 1;
771 },
772 function () {
773 // test 13: Ranges under mutations: deletion
774 var doc = getTestDocument();
775 var p = doc.createElement('p');
776 p.appendChild(doc.createTextNode("12345"));
777 doc.body.appendChild(p);
778 var r = doc.createRange();
779 r.setEnd(doc.body, 1);
780 r.setStart(p.firstChild, 2);
781 assert(!r.collapsed, "collapsed is wrong at start");
782 assertEquals(r.commonAncestorContainer, doc.body, "commonAncestorContainer is wrong at start");
783 assertEquals(r.startContainer, p.firstChild, "startContainer is wrong at s tart");
784 assertEquals(r.startOffset, 2, "startOffset is wrong at start");
785 assertEquals(r.endContainer, doc.body, "endContainer is wrong at start");
786 assertEquals(r.endOffset, 1, "endOffset is wrong at start");
787 doc.body.removeChild(p);
788 assert(r.collapsed, "collapsed is wrong after deletion");
789 assertEquals(r.commonAncestorContainer, doc.body, "commonAncestorContainer is wrong after deletion");
790 assertEquals(r.startContainer, doc.body, "startContainer is wrong after de letion");
791 assertEquals(r.startOffset, 0, "startOffset is wrong after deletion");
792 assertEquals(r.endContainer, doc.body, "endContainer is wrong after deleti on");
793 assertEquals(r.endOffset, 0, "endOffset is wrong after deletion");
794 return 1;
795 },
796
797 // HTTP
798 function () {
799 // test 14: HTTP - Content-Type: image/png
800 assert(!notifications['empty.png'], "privilege escalation security bug: PN G ran script");
801 var iframe = document.getElementsByTagName('iframe')[0];
802 assert(iframe, "no <iframe> support");
803 if (iframe && iframe.contentDocument) {
804 var ps = iframe.contentDocument.getElementsByTagName('p');
805 if (ps.length > 0) {
806 if (ps[0].firstChild && ps[0].firstChild.data && ps[0].firstChild.data == 'FAIL')
807 fail("PNG was parsed as HTML.");
808 }
809 }
810 return 1;
811 },
812 function () {
813 // test 15: HTTP - Content-Type: text/plain
814 assert(!notifications['empty.txt'], "privilege escalation security bug: te xt file ran script");
815 var iframe = document.getElementsByTagName('iframe')[1];
816 assert(iframe, "no <iframe> support");
817 if (iframe && iframe.contentDocument) {
818 var ps = iframe.contentDocument.getElementsByTagName('p');
819 if (ps.length > 0) {
820 if (ps[0].firstChild && ps[0].firstChild.data && ps[0].firstChild.data == 'FAIL')
821 fail("text/plain file was parsed as HTML");
822 }
823 }
824 return 1;
825 },
826 function () {
827 // test 16: <object> handling and HTTP status codes
828 var oC = document.createElement('object');
829 //oC.appendChild(document.createTextNode("FAIL"));
830 var oB = document.createElement('object');
831 var oA = document.createElement('object');
832 oA.data = "support-a.png";
833 oB.data = "support-b.png";
834 oB.appendChild(oC);
835 oC.data = "support-c.png";
836 oA.appendChild(oB);
837 document.getElementsByTagName("map")[0].appendChild(oA);
838 // assuming the above didn't raise any exceptions, this test has passed
839 // (the real test is whether the rendering is correct)
840 return 1;
841 },
842
843 // bucket 2: DOM2 Core and DOM2 Events
844 // Core
845 function () {
846 // test 17: hasAttribute
847 // missing attribute
848 assert(!document.getElementsByTagName('map')[0].hasAttribute('id'), "hasAt tribute failure for 'id' on map");
849 // implied attribute
850 assert(!document.getElementsByTagName('form')[0].hasAttribute('method'), " hasAttribute failure for 'method' on form");
851 // actually present attribute
852 assert(document.getElementsByTagName('form')[0].hasAttribute('action'), "h asAttribute failure for 'action' on form");
853 assertEquals(document.getElementsByTagName('form')[0].getAttribute('action '), '', "attribute 'action' on form has wrong value");
854 return 2;
855 },
856 function () {
857 // test 18: nodeType (this test also relies on accurate parsing of the doc ument)
858 assertEquals(document.nodeType, 9, "document nodeType wrong");
859 assertEquals(document.documentElement.nodeType, 1, "element nodeType wrong ");
860 if (document.createAttribute) // support for attribute nodes is optional i n Acid3, because attribute nodes might be removed from DOM Core in the future.
861 assertEquals(document.createAttribute('test').nodeType, 2, "attribute no deType wrong"); // however, if they're supported, they'd better work
862 assertEquals(document.getElementById('score').firstChild.nodeType, 3, "tex t node nodeType wrong");
863 assertEquals(document.firstChild.nodeType, 10, "DOCTYPE nodeType wrong");
864 return 2;
865 },
866 function () {
867 // test 19: value of constants
868 var e = null;
869 try {
870 document.body.appendChild(document.documentElement);
871 // raises a HIERARCHY_REQUEST_ERR
872 } catch (err) {
873 e = err;
874 }
875 assertEquals(document.DOCUMENT_FRAGMENT_NODE, 11, "document DOCUMENT_FRAGM ENT_NODE constant missing or wrong");
876 assertEquals(document.body.COMMENT_NODE, 8, "element COMMENT_NODE constant missing or wrong");
877 assertEquals(document.createTextNode('').ELEMENT_NODE, 1, "text node ELEME NT_NODE constant missing or wrong");
878 assert(e.HIERARCHY_REQUEST_ERR == 3, "exception HIERARCHY_REQUEST_ERR cons tant missing or wrong")
879 assertEquals(e.code, 3, "incorrect exception raised from appendChild()");
880 return 2;
881 },
882 function () {
883 // test 20: nulls bytes in various places
884 assert(!document.getElementById('bucket1\0error'), "null in getElementById () probably terminated string");
885 var ok = true;
886 try {
887 document.createElement('form\0div');
888 ok = false;
889 } catch (e) {
890 if (e.code != 5)
891 ok = false;
892 }
893 assert(ok, "didn't raise the right exception for null byte in createElemen t()");
894 return 2;
895 },
896 function () {
897 // test 21: basic namespace stuff
898 var element = document.createElementNS('http://ns.example.com/', 'prefix:l ocalname');
899 assertEquals(element.tagName, 'prefix:localname', "wrong tagName");
900 assertEquals(element.nodeName, 'prefix:localname', "wrong nodeName");
901 assertEquals(element.prefix, 'prefix', "wrong prefix");
902 assertEquals(element.localName, 'localname', "wrong localName");
903 assertEquals(element.namespaceURI, 'http://ns.example.com/', "wrong namesp aceURI");
904 return 2;
905 },
906 function () {
907 // test 22: createElement() with invalid tag names
908 var test = function (name) {
909 var result;
910 try {
911 var div = document.createElement(name);
912 } catch (e) {
913 result = e;
914 }
915 assert(result, "no exception for createElement('" + name + "')");
916 assertEquals(result.code, 5, "wrong exception for createElement('" + nam e + "')"); // INVALID_CHARACTER_ERR
917 }
918 test('<div>');
919 test('0div');
920 test('di v');
921 test('di<v');
922 test('-div');
923 test('.div');
924 return 2;
925 },
926 function () {
927 // test 23: createElementNS() with invalid tag names
928 var test = function (name, ns, code) {
929 var result;
930 try {
931 var div = document.createElementNS(ns, name);
932 } catch (e) {
933 result = e;
934 }
935 assert(result, "no exception for createElementNS('" + ns + "', '" + name + "')");
936 assertEquals(result.code, code, "wrong exception for createElementNS('" + ns + "', '" + name + "')");
937 }
938 test('<div>', null, 5);
939 test('0div', null, 5);
940 test('di v', null, 5);
941 test('di<v', null, 5);
942 test('-div', null, 5);
943 test('.div', null, 5);
944 test('<div>', "http://example.com/", 5);
945 test('0div', "http://example.com/", 5);
946 test('di<v', "http://example.com/", 5);
947 test('-div', "http://example.com/", 5);
948 test('.div', "http://example.com/", 5);
949 test(':div', null, 14);
950 test(':div', "http://example.com/", 14);
951 test('d:iv', null, 14);
952 test('xml:test', "http://example.com/", 14);
953 test('xmlns:test', "http://example.com/", 14); // (technically a DOM3 Core test)
954 test('x:test', "http://www.w3.org/2000/xmlns/", 14); // (technically a DOM 3 Core test)
955 document.createElementNS("http://www.w3.org/2000/xmlns/", 'xmlns:test'); / / (technically a DOM3 Core test)
956 return 2;
957 },
958 function () {
959 // test 24: event handler attributes
960 assertEquals(document.body.getAttribute('onload'), "update() /* this attr ibute's value is tested in one of the tests */ ", "onload value wrong");
961 return 2;
962 },
963 function () {
964 // test 25: test namespace checking in createDocumentType, and
965 // check that exceptions that are thrown are DOMException objects
966 var message = "";
967 try {
968 document.implementation.createDocumentType('a:', '', ''); /* doesn't con tain an illegal character; is malformed */
969 message = "failed to raise exception";
970 } catch (e) {
971 if (e.code != e.NAMESPACE_ERR)
972 message = "wrong exception";
973 else if (e.INVALID_ACCESS_ERR != 15)
974 message = "exceptions don't have all the constants";
975 }
976 if (message)
977 fail(message);
978 return 2;
979 },
980 function () {
981 // test 26: check that document tree survives while still accessible
982 var d;
983 // e1 - an element that's in a document
984 d = document.implementation.createDocument(null, null, null);
985 var e1 = d.createElement('test');
986 d.appendChild(d.createElement('root'));
987 d.documentElement.appendChild(e1);
988 assert(e1.parentNode, "e1 - parent element doesn't exist");
989 assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist");
990 // e2 - an element that's not in a document
991 d = document.implementation.createDocument(null, null, null);
992 var e2 = d.createElement('test');
993 d.createElement('root').appendChild(e2);
994 assert(e2.parentNode, "e2 - parent element doesn't exist");
995 assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist");
996 // now try to decouple them
997 d = null;
998 kungFuDeathGrip = [e1, e2];
999 assert(e1.parentNode, "e1 - parent element doesn't exist after dropping re ference to document");
1000 assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist after dro pping reference to document");
1001 assert(e2.parentNode, "e2 - parent element doesn't exist after dropping re ference to document");
1002 assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist after dro pping reference to document");
1003 var loops = new Date().valueOf() * 2.813435e-9 - 2412; // increases linear ly over time
1004 for (var i = 0; i < loops; i += 1) {
1005 // we want to force a GC here, so we use up lots of memory
1006 // we take the opportunity to sneak in a perf test to make DOM and JS st uff faster...
1007 d = new Date();
1008 d = new (function (x) { return { toString: function () { return x.toStri ng() } } })(d.valueOf());
1009 d = document.createTextNode("iteration " + i + " at " + d);
1010 document.createElement('a').appendChild(d);
1011 d = d.parentNode;
1012 document.body.insertBefore(d, document.getElementById('bucket1').parentN ode);
1013 assert(document.getElementById('bucket2').nextSibling.parentNode.previou sSibling.firstChild.data.match(/AT\W/i), "iteration " + i + " failed");
1014 d.setAttribute('class', d.textContent);
1015 document.body.removeChild(d);
1016 }
1017 assert(e1.parentNode, "e1 - parent element doesn't exist after looping");
1018 assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist after loo ping");
1019 assertEquals(e1.parentNode.ownerDocument.nodeType, 9, "e1 - document node type has wrong node type");
1020 assert(e2.parentNode, "e2 - parent element doesn't exist after looping");
1021 assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist after loo ping");
1022 assertEquals(e2.parentNode.ownerDocument.nodeType, 9, "e2 - document node type has wrong node type");
1023 return 2;
1024 },
1025 function () {
1026 // test 27: a continuation of the previous test
1027 var e1 = kungFuDeathGrip[0];
1028 var e2 = kungFuDeathGrip[1];
1029 kungFuDeathGrip = null;
1030 assert(e1, "e1 - element itself didn't survive across tests");
1031 assert(e1.parentNode, "e1 - parent element doesn't exist after waiting");
1032 assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist after wai ting");
1033 assertEquals(e1.parentNode.ownerDocument.nodeType, 9, "e1 - document node type has wrong node type after waiting");
1034 assert(e2, "e2 - element itself didn't survive across tests");
1035 assert(e2.parentNode, "e2 - parent element doesn't exist after waiting");
1036 assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist after wai ting");
1037 assertEquals(e2.parentNode.ownerDocument.nodeType, 9, "e2 - document node type has wrong node type after waiting");
1038 return 2;
1039 },
1040 function () {
1041 // test 28: getElementById()
1042 // ...and name=""
1043 assert(document.getElementById('form') !== document.getElementsByTagName(' form')[0], "getElementById() searched on 'name'");
1044 // ...and a space character as the ID
1045 var div = document.createElement('div');
1046 div.appendChild(document.createTextNode('FAIL'));
1047 div.id = " ";
1048 document.body.appendChild(div); // it's hidden by CSS
1049 assert(div === document.getElementById(" "), "getElementById() didn't retu rn the right element");
1050 return 2;
1051 },
1052 function () {
1053 // test 29: check that whitespace survives cloning
1054 var t1 = document.getElementsByTagName('table')[0];
1055 var t2 = t1.cloneNode(true);
1056 assertEquals(t2.tBodies[0].rows[0].cells[0].firstChild.tagName, 'P', "<p> didn't clone right");
1057 assertEquals(t2.tBodies[0].rows[0].cells[0].firstChild.childNodes.length, 0, "<p> got child nodes after cloning");
1058 assertEquals(t2.childNodes.length, 2, "cloned table had wrong number of ch ildren");
1059 assertEquals(t2.lastChild.data, " ", "cloned table lost whitespace text no de");
1060 return 2;
1061 },
1062
1063 // Events
1064 function () {
1065 // test 30: dispatchEvent()
1066 var count = 0;
1067 var ok = true;
1068 var test = function (event) {
1069 if (event.detail != 6)
1070 ok = false;
1071 count++;
1072 };
1073 // test event listener addition
1074 document.getElementById('result').addEventListener('test', test, false);
1075 // test event creation
1076 var event = document.createEvent('UIEvents');
1077 event.initUIEvent('test', true, false, null, 6);
1078 // test event dispatch on elements and text nodes
1079 assert(document.getElementById('score').dispatchEvent(event), "dispatchEve nt #1 failed");
1080 assert(document.getElementById('score').nextSibling.dispatchEvent(event), "dispatchEvent #2 failed");
1081 // test event listener removal
1082 document.getElementById('result').removeEventListener('test', test, false) ;
1083 assert(document.getElementById('score').dispatchEvent(event), "dispatchEve nt #3 failed");
1084 assertEquals(count, 2, "unexpected number of events handled");
1085 assert(ok, "unexpected events handled");
1086 return 2;
1087 },
1088 function () {
1089 // test 31: event.stopPropagation() and capture
1090 // we're going to use an input element because we can cause events to bubb le from it
1091 var input = document.createElement('input');
1092 var div = document.createElement('div');
1093 div.appendChild(input);
1094 document.body.appendChild(div);
1095 // the test will consist of two event handlers:
1096 var ok = true;
1097 var captureCount = 0;
1098 var testCapture = function (event) {
1099 ok = ok &&
1100 (event.type == 'click') &&
1101 (event.target == input) &&
1102 (event.currentTarget == div) &&
1103 (event.eventPhase == 1) &&
1104 (event.bubbles) &&
1105 (event.cancelable);
1106 captureCount++;
1107 event.stopPropagation(); // this shouldn't stop it from firing both time s on the div element
1108 };
1109 var testBubble = function (event) {
1110 ok = false;
1111 };
1112 // one of which is added twice:
1113 div.addEventListener('click', function (event) { testCapture(event) }, tru e);
1114 div.addEventListener('click', function (event) { testCapture(event) }, tru e);
1115 div.addEventListener('click', testBubble, false);
1116 // we cause an event to bubble like this:
1117 input.type = 'reset';
1118 input.click();
1119 // cleanup afterwards
1120 document.body.removeChild(div);
1121 // capture handler should have been called twice
1122 assertEquals(captureCount, 2, "capture handler called the wrong number of times");
1123 assert(ok, "capture handler called incorrectly");
1124 return 2;
1125 },
1126 function () {
1127 // test 32: events bubbling through Document node
1128 // event handler:
1129 var ok = true;
1130 var count = 0;
1131 var test = function (event) {
1132 count += 1;
1133 if (event.eventPhase != 3)
1134 ok = false;
1135 }
1136 // register event handler
1137 document.body.addEventListener('click', test, false);
1138 // create an element that bubbles an event, and bubble it
1139 var input = document.createElement('input');
1140 var div = document.createElement('div');
1141 div.appendChild(input);
1142 document.body.appendChild(div);
1143 input.type = 'reset';
1144 input.click();
1145 // unregister event handler
1146 document.body.removeEventListener('click', test, false);
1147 // check that it's removed for good
1148 input.click();
1149 // remove the newly added elements
1150 document.body.removeChild(div);
1151 assertEquals(count, 1, "capture handler called the wrong number of times") ;
1152 assert(ok, "capture handler called incorrectly");
1153 return 2;
1154 },
1155
1156 // bucket 3: DOM2 Views, DOM2 Style, and Selectors
1157 function () {
1158 // test 33: basic tests for selectors - classes, attributes
1159 var p;
1160 var builder = function(doc) {
1161 p = doc.createElement("p");
1162 doc.body.appendChild(p);
1163 };
1164 selectorTest(function (doc, add, expect) {
1165 builder(doc);
1166 p.className = "selectorPingTest";
1167 var good = add(".selectorPingTest");
1168 add(".SelectorPingTest");
1169 add(".selectorpingtest");
1170 expect(doc.body, 0, "failure 1");
1171 expect(p, good, "failure 2");
1172 });
1173 selectorTest(function (doc, add, expect) {
1174 builder(doc);
1175 p.className = 'a\u0020b\u0009c\u000Ad\u000De\u000Cf\u2003g\u3000h';
1176 var good = add(".a.b.c.d.e.f\\2003g\\3000h");
1177 expect(p, good, "whitespace error in class processing");
1178 });
1179 selectorTest(function (doc, add, expect) {
1180 builder(doc);
1181 p.className = "selectorPingTest";
1182 var good = add("[class=selectorPingTest]");
1183 add("[class=SelectorPingTest]");
1184 add("[class=selectorpingtest]");
1185 expect(doc.body, 0, "failure 3");
1186 expect(p, good, "class attribute matching failed");
1187 });
1188 selectorTest(function (doc, add, expect) {
1189 builder(doc);
1190 p.className = "selectorPingTest";
1191 var good = add("[title=selectorPingTest]");
1192 add("[title=SelectorPingTest]");
1193 add("[title=selectorpingtest]");
1194 expect(doc.body, 0, "failure 4");
1195 expect(p, 0, "failure 5");
1196 p.title = "selectorPingTest";
1197 expect(doc.body, 0, "failure 6");
1198 expect(p, good, "failure 7");
1199 });
1200 selectorTest(function (doc, add, expect) {
1201 builder(doc);
1202 p.setAttribute('align', 'right and left');
1203 var good = add("[align=\"right and left\"]");
1204 add("[align=left]");
1205 add("[align=right]");
1206 expect(p, good, "align attribute mismatch");
1207 });
1208 return 3;
1209 },
1210 function () {
1211 // test 34: :lang() and [|=]
1212 var div1;
1213 var div2;
1214 var p;
1215 var builder = function(doc) {
1216 div1 = doc.createElement('div');
1217 div1.setAttribute("lang", "english");
1218 div1.setAttribute("class", "widget-tree");
1219 doc.body.appendChild(div1);
1220 div2 = doc.createElement('div');
1221 div2.setAttribute("lang", "en-GB");
1222 div2.setAttribute("class", "WIDGET");
1223 doc.body.appendChild(div2);
1224 p = doc.createElement('p');
1225 div2.appendChild(p);
1226 };
1227 selectorTest(function (doc, add, expect) {
1228 builder(doc);
1229 var lang_en = add(":lang(en)");
1230 expect(div1, 0, "lang=english should not be matched by :lang(en)");
1231 expect(div2, lang_en, "lang=en-GB should be matched by :lang(en)");
1232 expect(p, lang_en, "descendants inheriting lang=en-GB should be matched by :lang(en)");
1233 });
1234 selectorTest(function (doc, add, expect) {
1235 builder(doc);
1236 var class_widget = add("[class|=widget]");
1237 expect(div1, class_widget, "class attribute should be supported by |= at tribute selectors");
1238 expect(div2, 0, "class attribute is case-sensitive");
1239 });
1240 return 3;
1241 },
1242 function () {
1243 // test 35: :first-child
1244 selectorTest(function (doc, add, expect) {
1245 var notFirst = 0;
1246 var first = add(":first-child");
1247 var p1 = doc.createElement("p");
1248 doc.body.appendChild(doc.createTextNode(" TEST "));
1249 doc.body.appendChild(p1);
1250 expect(doc.documentElement, notFirst, "root element, with no parent node , claims to be a :first-child");
1251 expect(doc.documentElement.firstChild, first, "first child of root node didn't match :first-child");
1252 expect(doc.documentElement.firstChild.firstChild, first, "failure 3");
1253 expect(doc.body, notFirst, "failure 4");
1254 expect(p1, first, "failure 5");
1255 var p2 = doc.createElement("p");
1256 doc.body.appendChild(p2);
1257 expect(doc.body, notFirst, "failure 6");
1258 expect(p1, first, "failure 7");
1259 expect(p2, notFirst, "failure 8");
1260 var p0 = doc.createElement("p");
1261 doc.body.insertBefore(p0, p1);
1262 expect(doc.body, notFirst, "failure 9");
1263 expect(p0, first, "failure 10");
1264 expect(p1, notFirst, ":first-child still applies to element that was pre viously a first child");
1265 expect(p2, notFirst, "failure 12");
1266 doc.body.insertBefore(p0, p2);
1267 expect(doc.body, notFirst, "failure 13");
1268 expect(p1, first, "failure 14");
1269 expect(p0, notFirst, "failure 15");
1270 expect(p2, notFirst, "failure 16");
1271 });
1272 return 3;
1273 },
1274 function () {
1275 // test 36: :last-child
1276 var p1;
1277 var p2;
1278 var builder = function(doc) {
1279 p1 = doc.createElement('p');
1280 p2 = doc.createElement('p');
1281 doc.body.appendChild(p1);
1282 doc.body.appendChild(p2);
1283 };
1284 selectorTest(function (doc, add, expect) {
1285 builder(doc);
1286 var last = add(":last-child");
1287 expect(p1, 0, "control test for :last-child failed");
1288 expect(p2, last, "last child did not match :last-child");
1289 doc.body.appendChild(p1);
1290 expect(p2, 0, ":last-child matched element with a following sibling");
1291 expect(p1, last, "failure 4");
1292 p1.appendChild(p2);
1293 expect(p2, last, "failure 5");
1294 expect(p1, last, "failure 6");
1295 });
1296 selectorTest(function (doc, add, expect) {
1297 builder(doc);
1298 var last = add(":last-child");
1299 expect(p1, 0, "failure 7");
1300 expect(p2, last, "failure 8");
1301 doc.body.insertBefore(p2, p1);
1302 expect(p2, 0, "failure 9");
1303 expect(p1, last, "failure 10");
1304 });
1305 selectorTest(function (doc, add, expect) {
1306 builder(doc);
1307 var last = add(":last-child");
1308 expect(p1, 0, "failure 11");
1309 expect(p2, last, "failure 12");
1310 doc.body.removeChild(p2);
1311 expect(p1, last, "failure 13");
1312 assertEquals(p1.nextSibling, null, "failure 14");
1313 assertEquals(p2.parentNode, null, "failure 15");
1314 });
1315 return 3;
1316 },
1317 function () {
1318 // test 37: :only-child
1319 var p1;
1320 var p2;
1321 var builder = function(doc) {
1322 p1 = doc.createElement('p');
1323 p2 = doc.createElement('p');
1324 doc.body.appendChild(p1);
1325 doc.body.appendChild(p2);
1326 };
1327 selectorTest(function (doc, add, expect) {
1328 builder(doc);
1329 var only = add(":only-child");
1330 expect(p1, 0, "control test for :only-child failed");
1331 expect(p2, 0, "failure 2");
1332 doc.body.removeChild(p2);
1333 expect(p1, only, ":only-child did not match only child");
1334 p1.appendChild(p2);
1335 expect(p2, only, "failure 4");
1336 expect(p1, only, "failure 5");
1337 });
1338 selectorTest(function (doc, add, expect) {
1339 builder(doc);
1340 var only = add(":only-child");
1341 expect(p1, 0, "failure 6");
1342 expect(p2, 0, "failure 7");
1343 doc.body.removeChild(p1);
1344 expect(p2, only, "failure 8");
1345 p2.appendChild(p1);
1346 expect(p2, only, "failure 9");
1347 expect(p1, only, "failure 10");
1348 });
1349 selectorTest(function (doc, add, expect) {
1350 builder(doc);
1351 var only = add(":only-child");
1352 expect(p1, 0, "failure 11");
1353 expect(p2, 0, "failure 12");
1354 var span1 = doc.createElement('span');
1355 p1.appendChild(span1);
1356 expect(p1, 0, "failure 13");
1357 expect(p2, 0, "failure 14");
1358 expect(span1, only, "failure 15");
1359 var span2 = doc.createElement('span');
1360 p1.appendChild(span2);
1361 expect(p1, 0, "failure 16");
1362 expect(p2, 0, "failure 17");
1363 expect(span1, 0, "failure 18");
1364 expect(span2, 0, "failure 19");
1365 });
1366 selectorTest(function (doc, add, expect) {
1367 builder(doc);
1368 var only = add(":only-child");
1369 expect(p1, 0, "failure 20");
1370 expect(p2, 0, "failure 21");
1371 var span1 = doc.createElement('span');
1372 p2.appendChild(span1);
1373 expect(p1, 0, "failure 22");
1374 expect(p2, 0, "failure 23");
1375 expect(span1, only, "failure 24");
1376 var span2 = doc.createElement('span');
1377 p2.insertBefore(span2, span1);
1378 expect(p1, 0, "failure 25");
1379 expect(p2, 0, "failure 26");
1380 expect(span1, 0, "failure 27");
1381 expect(span2, 0, "failure 28");
1382 });
1383 return 3;
1384 },
1385 function () {
1386 // test 38: :empty
1387 selectorTest(function (doc, add, expect) {
1388 var empty = add(":empty");
1389 var p = doc.createElement('p');
1390 doc.body.appendChild(p);
1391 expect(p, empty, "empty p element didn't match :empty");
1392 var span = doc.createElement('span');
1393 p.appendChild(span);
1394 expect(p, 0, "adding children didn't stop the element matching :empty");
1395 expect(span, empty, "empty span element didn't match :empty");
1396 p.removeChild(span);
1397 expect(p, empty, "removing all children didn't make the element match :e mpty");
1398 p.appendChild(doc.createComment("c"));
1399 p.appendChild(doc.createTextNode(""));
1400 expect(p, empty, "element with a comment node and an empty text node did n't match :empty");
1401 p.appendChild(doc.createTextNode(""));
1402 expect(p, empty, "element with a comment node and two empty text nodes d idn't match :empty");
1403 p.lastChild.data = " ";
1404 expect(p, 0, "adding text to a text node didn't make the element non-:em pty");
1405 assertEquals(p.childNodes.length, 3, "text nodes may have merged");
1406 p.childNodes[1].replaceWholeText("");
1407 assertEquals(p.childNodes.length, 1, "replaceWholeText('') didn't remove text nodes");
1408 expect(p, empty, "element with a comment node only didn't match :empty") ;
1409 p.appendChild(doc.createElementNS("http://example.com/", "test"));
1410 expect(p, 0, "adding an element in a namespace didn't make the element n on-:empty");
1411 });
1412 return 3;
1413 },
1414 function () {
1415 // test 39: :nth-child, :nth-last-child
1416 var ps;
1417 var builder = function(doc) {
1418 ps = [
1419 doc.createElement('p'),
1420 doc.createElement('p'),
1421 doc.createElement('p'),
1422 doc.createElement('p'),
1423 doc.createElement('p'),
1424 doc.createElement('p'),
1425 doc.createElement('p'),
1426 doc.createElement('p'),
1427 doc.createElement('p'),
1428 doc.createElement('p'),
1429 doc.createElement('p'),
1430 doc.createElement('p'),
1431 doc.createElement('p')
1432 ];
1433 for (var i = 0; i < ps.length; i += 1)
1434 doc.body.appendChild(ps[i]);
1435 };
1436 selectorTest(function (doc, add, expect) {
1437 builder(doc);
1438 var match = add(":nth-child(odd)");
1439 for (var i = 0; i < ps.length; i += 1)
1440 expect(ps[i], i % 2 ? 0 : match, ":nth-child(odd) failed with child " + i);
1441 });
1442 selectorTest(function (doc, add, expect) {
1443 builder(doc);
1444 var match = add(":nth-child(even)");
1445 for (var i = 0; i < ps.length; i += 1)
1446 expect(ps[i], i % 2 ? match : 0 , ":nth-child(even) failed with child " + i);
1447 });
1448 selectorTest(function (doc, add, expect) {
1449 builder(doc);
1450 var match = add(":nth-child(odd)");
1451 doc.body.removeChild(ps[5]);
1452 for (var i = 0; i < 5; i += 1)
1453 expect(ps[i], i % 2 ? 0 : match, ":nth-child(odd) failed after removal with child " + i);
1454 for (var i = 6; i < ps.length; i += 1)
1455 expect(ps[i], i % 2 ? match : 0, ":nth-child(odd) failed after removal with child " + i);
1456 });
1457 selectorTest(function (doc, add, expect) {
1458 builder(doc);
1459 var match = add(":nth-child(even)");
1460 doc.body.removeChild(ps[5]);
1461 for (var i = 0; i < 5; i += 1)
1462 expect(ps[i], i % 2 ? match : 0, ":nth-child(even) failed after remova l with child " + i);
1463 for (var i = 6; i < ps.length; i += 1)
1464 expect(ps[i], i % 2 ? 0 : match, ":nth-child(even) failed after remova l with child " + i);
1465 });
1466 selectorTest(function (doc, add, expect) {
1467 builder(doc);
1468 var match = add(":nth-child(-n+3)");
1469 for (var i = 0; i < 3; i += 1)
1470 expect(ps[i], match, ":nth-child(-n+3) failed with child " + i);
1471 for (var i = 3; i < ps.length; i += 1)
1472 expect(ps[i], 0, ":nth-child(-n+3) failed with child " + i);
1473 });
1474 return 3;
1475 },
1476 function () {
1477 // test 40: :first-of-type, :last-of-type, :only-of-type, :nth-of-type, :n th-last-of-type
1478 var elements;
1479 var builder = function(doc) {
1480 elements = [
1481 doc.createElement('p'),
1482 doc.createElement('div'),
1483 doc.createElement('div'),
1484 doc.createElement('p'),
1485 doc.createElement('p'),
1486 doc.createElement('p'),
1487 doc.createElement('div'),
1488 doc.createElement('address'),
1489 doc.createElement('div'),
1490 doc.createElement('div'),
1491 doc.createElement('div'),
1492 doc.createElement('p'),
1493 doc.createElement('div'),
1494 doc.createElement('p')
1495 ];
1496 for (var i = 0; i < elements.length; i += 1)
1497 doc.body.appendChild(elements[i]);
1498 };
1499 selectorTest(function (doc, add, expect) {
1500 builder(doc);
1501 var match = add(":first-of-type");
1502 var values = [1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0];
1503 for (var i = 0; i < elements.length; i += 1)
1504 expect(elements[i], values[i] ? match : 0, "part 1:" + i);
1505 });
1506 selectorTest(function (doc, add, expect) {
1507 builder(doc);
1508 var match = add(":last-of-type");
1509 var values = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1];
1510 for (var i = 0; i < elements.length; i += 1)
1511 expect(elements[i], values[i] ? match : 0, "part 2:" + i);
1512 });
1513 selectorTest(function (doc, add, expect) {
1514 builder(doc);
1515 var match = add(":only-of-type");
1516 var values = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0];
1517 for (var i = 0; i < elements.length; i += 1)
1518 expect(elements[i], values[i] ? match : 0, "part 3:" + i);
1519 });
1520 selectorTest(function (doc, add, expect) {
1521 builder(doc);
1522 var match = add(":nth-of-type(3n-1)");
1523 var values = [0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0];
1524 for (var i = 0; i < elements.length; i += 1)
1525 expect(elements[i], values[i] ? match : 0, "part 4:" + i);
1526 });
1527 selectorTest(function (doc, add, expect) {
1528 builder(doc);
1529 var match = add(":nth-of-type(3n+1)");
1530 var values = [1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0];
1531 for (var i = 0; i < elements.length; i += 1)
1532 expect(elements[i], values[i] ? match : 0, "part 5:" + i);
1533 });
1534 selectorTest(function (doc, add, expect) {
1535 builder(doc);
1536 var match = add(":nth-last-of-type(2n)");
1537 var values = [1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0];
1538 for (var i = 0; i < elements.length; i += 1)
1539 expect(elements[i], values[i] ? match : 0, "part 6:" + i);
1540 });
1541 selectorTest(function (doc, add, expect) {
1542 builder(doc);
1543 var match = add(":nth-last-of-type(-5n+3)");
1544 var values;
1545 values = [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0];
1546 for (var i = 0; i < elements.length; i += 1)
1547 expect(elements[i], values[i] ? match : 0, "part 7:" + i);
1548 doc.body.appendChild(doc.createElement('blockquote'));
1549 values = [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0];
1550 for (var i = 0; i < elements.length; i += 1)
1551 expect(elements[i], values[i] ? match : 0, "part 8:" + i);
1552 doc.body.appendChild(doc.createElement('div'));
1553 values = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0];
1554 for (var i = 0; i < elements.length; i += 1)
1555 expect(elements[i], values[i] ? match : 0, "part 9:" + i);
1556 });
1557 return 3;
1558 },
1559 function () {
1560 // test 41: :root, :not()
1561 selectorTest(function (doc, add, expect) {
1562 var match = add(":not(:root)");
1563 var p = doc.createElement('p');
1564 doc.body.appendChild(p);
1565 expect(doc.documentElement, 0, "root was :not(:root)");
1566 expect(doc.documentElement.childNodes[0], match,"head was not :not(:root )");
1567 expect(doc.documentElement.childNodes[1], match,"body was not :not(:root )");
1568 expect(doc.documentElement.childNodes[0].firstChild, match,"title was no t :not(:root)");
1569 expect(p, match,"p was not :not(:root)");
1570 });
1571 return 3;
1572 },
1573 function () {
1574 // test 42: +, ~, >, and ' ' in dynamic situations
1575 selectorTest(function (doc, add, expect) {
1576 var div1 = doc.createElement('div');
1577 div1.id = "div1";
1578 doc.body.appendChild(div1);
1579 var div2 = doc.createElement('div');
1580 doc.body.appendChild(div2);
1581 var div3 = doc.createElement('div');
1582 doc.body.appendChild(div3);
1583 var div31 = doc.createElement('div');
1584 div3.appendChild(div31);
1585 var div311 = doc.createElement('div');
1586 div31.appendChild(div311);
1587 var div3111 = doc.createElement('div');
1588 div311.appendChild(div3111);
1589 var match = add("#div1 ~ div div + div > div");
1590 expect(div1, 0, "failure 1");
1591 expect(div2, 0, "failure 2");
1592 expect(div3, 0, "failure 3");
1593 expect(div31, 0, "failure 4");
1594 expect(div311, 0, "failure 5");
1595 expect(div3111, 0, "failure 6");
1596 var div310 = doc.createElement('div');
1597 div31.insertBefore(div310, div311);
1598 expect(div1, 0, "failure 7");
1599 expect(div2, 0, "failure 8");
1600 expect(div3, 0, "failure 9");
1601 expect(div31, 0, "failure 10");
1602 expect(div310, 0, "failure 11");
1603 expect(div311, 0, "failure 12");
1604 expect(div3111, match, "rule did not start matching after change");
1605 });
1606 selectorTest(function (doc, add, expect) {
1607 var div1 = doc.createElement('div');
1608 div1.id = "div1";
1609 doc.body.appendChild(div1);
1610 var div2 = doc.createElement('div');
1611 div1.appendChild(div2);
1612 var div3 = doc.createElement('div');
1613 div2.appendChild(div3);
1614 var div4 = doc.createElement('div');
1615 div3.appendChild(div4);
1616 var div5 = doc.createElement('div');
1617 div4.appendChild(div5);
1618 var div6 = doc.createElement('div');
1619 div5.appendChild(div6);
1620 var match = add("#div1 > div div > div");
1621 expect(div1, 0, "failure 14");
1622 expect(div2, 0, "failure 15");
1623 expect(div3, 0, "failure 16");
1624 expect(div4, match, "failure 17");
1625 expect(div5, match, "failure 18");
1626 expect(div6, match, "failure 19");
1627 var p34 = doc.createElement('p');
1628 div3.insertBefore(p34, div4);
1629 p34.insertBefore(div4, null);
1630 expect(div1, 0, "failure 20");
1631 expect(div2, 0, "failure 21");
1632 expect(div3, 0, "failure 22");
1633 expect(p34, 0, "failure 23");
1634 expect(div4, 0, "failure 24");
1635 expect(div5, match, "failure 25");
1636 expect(div6, match, "failure 26");
1637 });
1638 selectorTest(function (doc, add, expect) {
1639 var div1 = doc.createElement('div');
1640 div1.id = "div1";
1641 doc.body.appendChild(div1);
1642 var div2 = doc.createElement('div');
1643 div1.appendChild(div2);
1644 var div3 = doc.createElement('div');
1645 div2.appendChild(div3);
1646 var div4 = doc.createElement('div');
1647 div3.appendChild(div4);
1648 var div5 = doc.createElement('div');
1649 div4.appendChild(div5);
1650 var div6 = doc.createElement('div');
1651 div5.appendChild(div6);
1652 var match = add("#div1 > div div > div");
1653 expect(div1, 0, "failure 27");
1654 expect(div2, 0, "failure 28");
1655 expect(div3, 0, "failure 29");
1656 expect(div4, match, "failure 30");
1657 expect(div5, match, "failure 31");
1658 expect(div6, match, "failure 32");
1659 var p23 = doc.createElement('p');
1660 div2.insertBefore(p23, div3);
1661 p23.insertBefore(div3, null);
1662 expect(div1, 0, "failure 33");
1663 expect(div2, 0, "failure 34");
1664 expect(div3, 0, "failure 35");
1665 expect(p23, 0, "failure 36");
1666 expect(div4, match, "failure 37");
1667 expect(div5, match, "failure 38");
1668 expect(div6, match, "failure 39");
1669 });
1670 return 3;
1671 },
1672 function () {
1673 // test 43: :enabled, :disabled, :checked, etc
1674 selectorTest(function (doc, add, expect) {
1675 var input = doc.createElement('input');
1676 input.type = 'checkbox';
1677 doc.body.appendChild(input);
1678 var neither = 0;
1679 var both = add(":checked:enabled");
1680 var checked = add(":checked");
1681 var enabled = add(":enabled");
1682 expect(doc.body, neither, "control failure");
1683 expect(input, enabled, "input element didn't match :enabled");
1684 input.click();
1685 expect(input, both, "input element didn't match :checked");
1686 input.disabled = true;
1687 expect(input, checked, "failure 3");
1688 input.checked = false;
1689 expect(input, neither, "failure 4");
1690 expect(doc.body, neither, "failure 5");
1691 });
1692 selectorTest(function (doc, add, expect) {
1693 var input1 = doc.createElement('input');
1694 input1.type = 'radio';
1695 input1.name = 'radio';
1696 doc.body.appendChild(input1);
1697 var input2 = doc.createElement('input');
1698 input2.type = 'radio';
1699 input2.name = 'radio';
1700 doc.body.appendChild(input2);
1701 var checked = add(":checked");
1702 expect(input1, 0, "failure 6");
1703 expect(input2, 0, "failure 7");
1704 input2.click();
1705 expect(input1, 0, "failure 6");
1706 expect(input2, checked, "failure 7");
1707 input1.checked = true;
1708 expect(input1, checked, "failure 8");
1709 expect(input2, 0, "failure 9");
1710 input2.setAttribute("checked", "checked"); // sets defaultChecked, doesn 't change actual state
1711 expect(input1, checked, "failure 10");
1712 expect(input2, 0, "failure 11");
1713 input1.type = "text";
1714 expect(input1, 0, "text field matched :checked");
1715 });
1716 selectorTest(function (doc, add, expect) {
1717 var input = doc.createElement('input');
1718 input.type = 'button';
1719 doc.body.appendChild(input);
1720 var neither = 0;
1721 var enabled = add(":enabled");
1722 var disabled = add(":disabled");
1723 add(":enabled:disabled");
1724 expect(input, enabled, "failure 12");
1725 input.disabled = true;
1726 expect(input, disabled, "failure 13");
1727 input.removeAttribute("disabled");
1728 expect(input, enabled, "failure 14");
1729 expect(doc.body, neither, "failure 15");
1730 });
1731 return 3;
1732 },
1733 function () {
1734 // test 44: selectors without spaces before a "*"
1735 selectorTest(function (doc, add, expect) {
1736 doc.body.className = "test";
1737 var p = doc.createElement('p');
1738 p.className = "test";
1739 doc.body.appendChild(p);
1740 add("html*.test");
1741 expect(doc.body, 0, "misparsed selectors");
1742 expect(p, 0, "really misparsed selectors");
1743 });
1744 return 3;
1745 },
1746 function () {
1747 // test 45: cssFloat and the style attribute
1748 assert(!document.body.style.cssFloat, "body has floatation");
1749 document.body.setAttribute("style", "float: right");
1750 assertEquals(document.body.style.cssFloat, "right", "body doesn't have flo atation");
1751 document.body.setAttribute("style", "float: none");
1752 assertEquals(document.body.style.cssFloat, "none", "body didn't lose float ation");
1753 return 3;
1754 },
1755 function () {
1756 // test 46: media queries
1757 var doc = getTestDocument();
1758 var style = doc.createElement('style');
1759 style.setAttribute('type', 'text/css');
1760 style.appendChild(doc.createTextNode('@media all and (min-color: 0) { #a { text-transform: uppercase; } }')); // matches
1761 style.appendChild(doc.createTextNode('@media not all and (min-color: 0) { #b { text-transform: uppercase; } }'));
1762 style.appendChild(doc.createTextNode('@media only all and (min-color: 0) { #c { text-transform: uppercase; } }')); // matches
1763 style.appendChild(doc.createTextNode('@media (bogus) { #d { text-transform : uppercase; } }'));
1764 style.appendChild(doc.createTextNode('@media all and (bogus) { #e { text-t ransform: uppercase; } }'));
1765 style.appendChild(doc.createTextNode('@media not all and (bogus) { #f { te xt-transform: uppercase; } }')); // commentd out but sho uld not match
1766 style.appendChild(doc.createTextNode('@media only all and (bogus) { #g { t ext-transform: uppercase; } }'));
1767 style.appendChild(doc.createTextNode('@media (bogus), all { #h { text-tran sform: uppercase; } }')); // matches
1768 style.appendChild(doc.createTextNode('@media all and (bogus), all { #i { t ext-transform: uppercase; } }')); // matches
1769 style.appendChild(doc.createTextNode('@media not all and (bogus), all { #j { text-transform: uppercase; } }')); // matches
1770 style.appendChild(doc.createTextNode('@media only all and (bogus), all { # k { text-transform: uppercase; } }')); // matches
1771 style.appendChild(doc.createTextNode('@media all, (bogus) { #l { text-tran sform: uppercase; } }')); // matches
1772 style.appendChild(doc.createTextNode('@media all, all and (bogus) { #m { t ext-transform: uppercase; } }')); // matches
1773 style.appendChild(doc.createTextNode('@media all, not all and (bogus) { #n { text-transform: uppercase; } }')); // matches
1774 style.appendChild(doc.createTextNode('@media all, only all and (bogus) { # o { text-transform: uppercase; } }')); // matches
1775 style.appendChild(doc.createTextNode('@media all and color { #p { text-tra nsform: uppercase; } }'));
1776 style.appendChild(doc.createTextNode('@media all and min-color: 0 { #q { t ext-transform: uppercase; } }'));
1777 style.appendChild(doc.createTextNode('@media all, all and color { #r { tex t-transform: uppercase; } }')); // commented out but sh ould match
1778 style.appendChild(doc.createTextNode('@media all, all and min-color: 0 { # s { text-transform: uppercase; } }')); // commented out but sh ould match
1779 style.appendChild(doc.createTextNode('@media all and min-color: 0, all { # t { text-transform: uppercase; } }')); // commented out but sh ould match
1780 style.appendChild(doc.createTextNode('@media (max-color: 0) and (max-monoc hrome: 0) { #u { text-transform: uppercase; } }'));
1781 style.appendChild(doc.createTextNode('@media (min-color: 1), (min-monochro me: 1) { #v { text-transform: uppercase; } }')); // matches
1782 style.appendChild(doc.createTextNode('@media all and (min-color: 0) and (m in-monochrome: 0) { #w { text-transform: uppercase; } }')); // matches
1783 style.appendChild(doc.createTextNode('@media not all and (min-color: 1), n ot all and (min-monochrome: 1) { #x { text-transform: uppercase; } }')); // matc hes
1784 style.appendChild(doc.createTextNode('@media all and (min-height: 1em) and (min-width: 1em) { #y1 { text-transform: uppercase; } }'));
1785 style.appendChild(doc.createTextNode('@media all and (max-height: 1em) and (min-width: 1em) { #y2 { text-transform: uppercase; } }'));
1786 style.appendChild(doc.createTextNode('@media all and (min-height: 1em) and (max-width: 1em) { #y3 { text-transform: uppercase; } }'));
1787 style.appendChild(doc.createTextNode('@media all and (max-height: 1em) and (max-width: 1em) { #y4 { text-transform: uppercase; } }')); // matches
1788 doc.getElementsByTagName('head')[0].appendChild(style);
1789 var names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', ' m', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y1', 'y2', 'y3', 'y4 '];
1790 for (var i in names) {
1791 var p = doc.createElement('p');
1792 p.id = names[i];
1793 doc.body.appendChild(p);
1794 }
1795 var count = 0;
1796 var check = function (c, e) {
1797 count += 1;
1798 var p = doc.getElementById(c);
1799 assertEquals(doc.defaultView.getComputedStyle(p, '').textTransform, e ? 'uppercase' : 'none', "case " + c + " failed (index " + count + ")");
1800 }
1801 check('a', true); // 1
1802 check('b', false);
1803 check('c', true);
1804 check('d', false);
1805 check('e', false);
1806 /* COMMENTED OUT BECAUSE THE CSSWG KEEP CHANGING THE RIGHT ANSWER FOR THIS CASE
1807 * check('f', false);
1808 */
1809 check('g', false);
1810 check('h', true);
1811 check('i', true);
1812 check('j', true); // 10
1813 check('k', true);
1814 check('l', true);
1815 check('m', true);
1816 check('n', true);
1817 check('o', true);
1818 check('p', false);
1819 check('q', false);
1820 /* COMMENTED OUT BECAUSE THE CSSWG KEEP CHANGING THE RIGHT ANSWER FOR THESE TOO APPARENTLY
1821 * check('r', true);
1822 * check('s', true);
1823 * check('t', true); // 20
1824 */
1825 check('u', false);
1826 check('v', true);
1827 check('w', true);
1828 check('x', true);
1829 // here the viewport is 0x0
1830 check('y1', false); // 25
1831 check('y2', false);
1832 check('y3', false);
1833 check('y4', true);
1834 document.getElementById("selectors").setAttribute("style", "height: 100px; width: 100px");
1835 // now the viewport is more than 1em by 1em
1836 check('y1', true); // 29
1837 check('y2', false);
1838 check('y3', false);
1839 check('y4', false);
1840 document.getElementById("selectors").removeAttribute("style");
1841 // here the viewport is 0x0 again
1842 check('y1', false); // 33
1843 check('y2', false);
1844 check('y3', false);
1845 check('y4', true);
1846 return 3;
1847 },
1848 function () {
1849 // test 47: 'cursor' and CSS3 values
1850 var doc = getTestDocument();
1851 var style = doc.createElement('style');
1852 style.setAttribute('type', 'text/css');
1853 var cursors = ['auto', 'default', 'none', 'context-menu', 'help', 'pointer ', 'progress', 'wait', 'cell', 'crosshair', 'text', 'vertical-text', 'alias', 'c opy', 'move', 'no-drop', 'not-allowed', 'e-resize', 'n-resize', 'ne-resize', 'nw -resize', 's-resize', 'se-resize', 'sw-resize', 'w-resize', 'ew-resize', 'ns-res ize', 'nesw-resize', 'nwse-resize', 'col-resize', 'row-resize', 'all-scroll'];
1854 for (var i in cursors) {
1855 var c = cursors[i];
1856 style.appendChild(doc.createTextNode('#' + c + ' { cursor: ' + c + '; }' ));
1857 }
1858 style.appendChild(doc.createTextNode('#bogus { cursor: bogus; }'));
1859 doc.body.previousSibling.appendChild(style);
1860 doc.body.id = "bogus";
1861 assertEquals(doc.defaultView.getComputedStyle(doc.body, '').cursor, "auto" , "control failed");
1862 for (var i in cursors) {
1863 var c = cursors[i];
1864 doc.body.id = c;
1865 assertEquals(doc.defaultView.getComputedStyle(doc.body, '').cursor, c, " cursor " + c + " not supported");
1866 }
1867 return 3;
1868 },
1869 function () {
1870 // test 48: :link and :visited
1871 var iframe = document.getElementById("selectors");
1872 var number = (new Date()).valueOf();
1873 var a = document.createElement('a');
1874 a.appendChild(document.createTextNode('LINKTEST FAILED'));
1875 a.setAttribute('id', 'linktest');
1876 a.setAttribute('class', 'pending');
1877 a.setAttribute('href', iframe.getAttribute('src') + "?" + number);
1878 document.getElementsByTagName('map')[0].appendChild(a);
1879 iframe.setAttribute("onload", "document.getElementById('linktest').removeA ttribute('class')");
1880 iframe.src = a.getAttribute("href");
1881 return 3;
1882 },
1883
1884 // bucket 4: HTML and the DOM
1885 // Tables
1886 function () {
1887 // test 49: basic table accessor ping test create*, delete*, and *
1888 // where * is caption, tHead, tFoot.
1889 var table = document.createElement('table');
1890 assert(!table.caption, "initially: caption");
1891 assert(table.tBodies, "initially: tBodies");
1892 assertEquals(table.tBodies.length, 0, "initially: tBodies.length");
1893 assert(table.rows, "initially: rows");
1894 assertEquals(table.rows.length, 0, "initially: rows.length");
1895 assert(!table.tFoot, "initially: tFoot");
1896 assert(!table.tHead, "initially: tHead");
1897 var caption = table.createCaption();
1898 var thead = table.createTHead();
1899 var tfoot = table.createTFoot();
1900 assertEquals(table.caption, caption, "after creation: caption");
1901 assert(table.tBodies, "after creation: tBodies");
1902 assertEquals(table.tBodies.length, 0, "after creation: tBodies.length");
1903 assert(table.rows, "after creation: rows");
1904 assertEquals(table.rows.length, 0, "after creation: rows.length");
1905 assertEquals(table.tFoot, tfoot, "after creation: tFoot");
1906 assertEquals(table.tHead, thead, "after creation: tHead");
1907 assertEquals(table.childNodes.length, 3, "after creation: childNodes.lengt h");
1908 table.caption = caption; // no-op
1909 table.tHead = thead; // no-op
1910 table.tFoot = tfoot; // no-op
1911 assertEquals(table.caption, caption, "after setting: caption");
1912 assert(table.tBodies, "after setting: tBodies");
1913 assertEquals(table.tBodies.length, 0, "after setting: tBodies.length");
1914 assert(table.rows, "after setting: rows");
1915 assertEquals(table.rows.length, 0, "after setting: rows.length");
1916 assertEquals(table.tFoot, tfoot, "after setting: tFoot");
1917 assertEquals(table.tHead, thead, "after setting: tHead");
1918 assertEquals(table.childNodes.length, 3, "after setting: childNodes.length ");
1919 table.deleteCaption();
1920 table.deleteTHead();
1921 table.deleteTFoot();
1922 assert(!table.caption, "after deletion: caption");
1923 assert(table.tBodies, "after deletion: tBodies");
1924 assertEquals(table.tBodies.length, 0, "after deletion: tBodies.length");
1925 assert(table.rows, "after deletion: rows");
1926 assertEquals(table.rows.length, 0, "after deletion: rows.length");
1927 assert(!table.tFoot, "after deletion: tFoot");
1928 assert(!table.tHead, "after deletion: tHead");
1929 assert(!table.hasChildNodes(), "after deletion: hasChildNodes()");
1930 assertEquals(table.childNodes.length, 0, "after deletion: childNodes.lengt h");
1931 return 4;
1932 },
1933 function () {
1934 // test 50: construct a table, and see if the table is as expected
1935 var table = document.createElement('table');
1936 table.appendChild(document.createElement('tbody'));
1937 var tr1 = document.createElement('tr');
1938 table.appendChild(tr1);
1939 table.appendChild(document.createElement('caption'));
1940 table.appendChild(document.createElement('thead'));
1941 // <table><tbody/><tr/><caption/><thead/>
1942 table.insertBefore(table.firstChild.nextSibling, null); // move the <tr/> to the end
1943 // <table><tbody/><caption/><thead/><tr/>
1944 table.replaceChild(table.firstChild, table.lastChild); // move the <tbody/ > to the end and remove the <tr>
1945 // <table><caption/><thead/><tbody/>
1946 var tr2 = table.tBodies[0].insertRow(0);
1947 // <table><caption/><thead/><tbody><tr/><\tbody> (the '\' is to avoid validation errors)
1948 assertEquals(table.tBodies[0].rows[0].rowIndex, 0, "rowIndex broken");
1949 assertEquals(table.tBodies[0].rows[0].sectionRowIndex, 0, "sectionRowIndex broken");
1950 assertEquals(table.childNodes.length, 3, "wrong number of children");
1951 assert(table.caption, "caption broken");
1952 assert(table.tHead, "tHead broken");
1953 assert(!table.tFoot, "tFoot broken");
1954 assertEquals(table.tBodies.length, 1, "wrong number of tBodies");
1955 assertEquals(table.rows.length, 1, "wrong number of rows");
1956 assert(!tr1.parentNode, "orphan row has unexpected parent");
1957 assertEquals(table.caption, table.createCaption(), "caption creation faile d");
1958 assertEquals(table.tFoot, null, "table has unexpected footer");
1959 assertEquals(table.tHead, table.createTHead(), "header creation failed");
1960 assertEquals(table.createTFoot(), table.tFoot, "footer creation failed");
1961 // either: <table><caption/><thead/><tbody><tr/><\tbody><tfoot/>
1962 // or: <table><caption/><thead/><tfoot/><tbody><tr/><\tbody>
1963 table.tHead.appendChild(tr1);
1964 // either: <table><caption/><thead><tr/><\thead><tbody><tr/><\tbody><tfoot />
1965 // or: <table><caption/><thead><tr/><\thead><tfoot/><tbody><tr/><\tbod y>
1966 assertEquals(table.rows[0], table.tHead.firstChild, "top row not in expect ed position");
1967 assertEquals(table.rows.length, 2, "wrong number of rows after appending o ne");
1968 assertEquals(table.rows[1], table.tBodies[0].firstChild, "second row not i n expected position");
1969 return 4;
1970 },
1971 function () {
1972 // test 51: test the ordering and creation of rows
1973 var table = document.createElement('table');
1974 var rows = [
1975 document.createElement('tr'), // 0: ends up first child of the tfoot
1976 document.createElement('tr'), // 1: goes at the end of the table
1977 document.createElement('tr'), // 2: becomes second child of thead
1978 document.createElement('tr'), // 3: becomes third child of the thead
1979 document.createElement('tr'), // 4: not in the table
1980 table.insertRow(0), // 5: not in the table
1981 table.createTFoot().insertRow(0) // 6: ends up second in the tfoot
1982 ];
1983 rows[6].parentNode.appendChild(rows[0]);
1984 table.appendChild(rows[1]);
1985 table.insertBefore(document.createElement('thead'), table.firstChild);
1986 table.firstChild.appendChild(rows[2]);
1987 rows[2].parentNode.appendChild(rows[3]);
1988 rows[4].appendChild(rows[5].parentNode);
1989 table.insertRow(0);
1990 table.tFoot.appendChild(rows[6]);
1991 assertEquals(table.rows.length, 6, "wrong number of rows");
1992 assertEquals(table.getElementsByTagName('tr').length, 6, "wrong number of tr elements");
1993 assertEquals(table.childNodes.length, 3, "table has wrong number of childr en");
1994 assertEquals(table.childNodes[0], table.tHead, "tHead isn't first");
1995 assertEquals(table.getElementsByTagName('tr')[0], table.tHead.childNodes[0 ], "first tr isn't in tHead correctly");
1996 assertEquals(table.getElementsByTagName('tr')[1], table.tHead.childNodes[1 ], "second tr isn't in tHead correctly");
1997 assertEquals(table.getElementsByTagName('tr')[1], rows[2], "second tr is t he wrong row");
1998 assertEquals(table.getElementsByTagName('tr')[2], table.tHead.childNodes[2 ], "third tr isn't in tHead correctly");
1999 assertEquals(table.getElementsByTagName('tr')[2], rows[3], "third tr is th e wrong row");
2000 assertEquals(table.childNodes[1], table.tFoot, "tFoot isn't second");
2001 assertEquals(table.getElementsByTagName('tr')[3], table.tFoot.childNodes[0 ], "fourth tr isn't in tFoot correctly");
2002 assertEquals(table.getElementsByTagName('tr')[3], rows[0], "fourth tr is t he wrong row");
2003 assertEquals(table.getElementsByTagName('tr')[4], table.tFoot.childNodes[1 ], "fifth tr isn't in tFoot correctly");
2004 assertEquals(table.getElementsByTagName('tr')[4], rows[6], "fifth tr is th e wrong row");
2005 assertEquals(table.getElementsByTagName('tr')[5], table.childNodes[2], "si xth tr isn't in tFoot correctly");
2006 assertEquals(table.getElementsByTagName('tr')[5], rows[1], "sixth tr is th e wrong row");
2007 assertEquals(table.tBodies.length, 0, "non-zero number of tBodies");
2008 return 4;
2009 },
2010
2011 // Forms
2012 function () {
2013 // test 52: <form> and .elements
2014 test = document.getElementsByTagName('form')[0];
2015 assert(test.elements !== test, "form.elements === form");
2016 assert(test.elements !== test.getAttribute('elements'), "form element has an elements content attribute");
2017 assertEquals(test.elements.length, 1, "form element has unexpected number of controls");
2018 assertEquals(test.elements.length, test.length, "form element has inconsis tent numbers of controls");
2019 return 4;
2020 },
2021 function () {
2022 // test 53: changing an <input> dynamically
2023 var f = document.createElement('form');
2024 var i = document.createElement('input');
2025 i.name = 'first';
2026 i.type = 'text';
2027 i.value = 'test';
2028 f.appendChild(i);
2029 assertEquals(i.getAttribute('name'), 'first', "name attribute wrong");
2030 assertEquals(i.name, 'first', "name property wrong");
2031 assertEquals(i.getAttribute('type'), 'text', "type attribute wrong");
2032 assertEquals(i.type, 'text', "type property wrong");
2033 assert(!i.hasAttribute('value'), "value attribute wrong");
2034 assertEquals(i.value, 'test', "value property wrong");
2035 assertEquals(f.elements.length, 1, "form's elements array has wrong size") ;
2036 assertEquals(f.elements[0], i, "form's element array doesn't have input co ntrol by index");
2037 assertEquals(f.elements.first, i, "form's element array doesn't have input control by name");
2038 assertEquals(f.elements.second, null, "form's element array has unexpected controls by name");
2039 i.name = 'second';
2040 i.type = 'password';
2041 i.value = 'TEST';
2042 assertEquals(i.getAttribute('name'), 'second', "name attribute wrong after change");
2043 assertEquals(i.name, 'second', "name property wrong after change");
2044 assertEquals(i.getAttribute('type'), 'password', "type attribute wrong aft er change");
2045 assertEquals(i.type, 'password', "type property wrong after change");
2046 assert(!i.hasAttribute('value'), "value attribute wrong after change");
2047 assertEquals(i.value, 'TEST', "value property wrong after change");
2048 assertEquals(f.elements.length, 1, "form's elements array has wrong size a fter change");
2049 assertEquals(f.elements[0], i, "form's element array doesn't have input co ntrol by index after change");
2050 assertEquals(f.elements.second, i, "form's element array doesn't have inpu t control by name after change");
2051 assertEquals(f.elements.first, null, "form's element array has unexpected controls by name after change");
2052 return 4;
2053 },
2054 function () {
2055 // test 54: changing a parsed <input>
2056 var i = document.getElementsByTagName('input')[0];
2057 // initial values
2058 assertEquals(i.getAttribute('type'), 'HIDDEN', "input control's type conte nt attribute was wrong");
2059 assertEquals(i.type, 'hidden', "input control's type DOM attribute was wro ng");
2060 // change values
2061 i.name = 'test';
2062 assertEquals(i.parentNode.elements.test, i, "input control's form didn't u pdate");
2063 // check event handlers
2064 i.parentNode.action = 'javascript:';
2065 var called = false;
2066 i.parentNode.onsubmit = function (arg) {
2067 arg.preventDefault();
2068 called = true;
2069 };
2070 i.type = 'submit';
2071 i.click(); // synchronously dispatches a click event to the submit button, which submits the form, which calls onsubmit
2072 assert(called, "click handler didn't dispatch properly");
2073 i.type = 'hIdDeN';
2074 // check numeric attributes
2075 i.setAttribute('maxLength', '2');
2076 var s = i.getAttribute('maxLength');
2077 assert(s.match, "attribute is not a String");
2078 assert(!s.MIN_VALUE, "attribute is a Number");
2079 return 4;
2080 },
2081 function () {
2082 // test 55: moved checkboxes should keep their state
2083 var container = document.getElementsByTagName("iframe")[0];
2084 var input1 = document.createElement('input');
2085 container.appendChild(input1);
2086 input1.type = "checkbox";
2087 input1.checked = true;
2088 assert(input1.checked, "checkbox not checked after being checked (inserted first)");
2089 var input2 = document.createElement('input');
2090 input2.type = "checkbox";
2091 container.appendChild(input2);
2092 input2.checked = true;
2093 assert(input2.checked, "checkbox not checked after being checked (inserted after type set)");
2094 var input3 = document.createElement('input');
2095 input3.type = "checkbox";
2096 input3.checked = true;
2097 container.appendChild(input3);
2098 assert(input3.checked, "checkbox not checked after being checked (inserted after being checked)");
2099 var target = document.getElementsByTagName("iframe")[1];
2100 target.appendChild(input1);
2101 target.appendChild(input2);
2102 target.appendChild(input3);
2103 assert(input1.checked, "checkbox 1 not checked after being moved");
2104 assert(input2.checked, "checkbox 2 not checked after being moved");
2105 assert(input3.checked, "checkbox 3 not checked after being moved");
2106 return 4;
2107 },
2108 function () {
2109 // test 56: cloned radio buttons should keep their state
2110 var form = document.getElementsByTagName("form")[0];
2111 var input1 = document.createElement('input');
2112 input1.type = "radio";
2113 input1.name = "radioGroup1";
2114 form.appendChild(input1);
2115 var input2 = input1.cloneNode(true);
2116 input1.parentNode.appendChild(input2);
2117 input1.checked = true;
2118 assert(form.elements.radioGroup1, "radio group absent");
2119 assert(input1.checked, "first radio button not checked");
2120 assert(!input2.checked, "second radio button checked");
2121 input2.checked = true;
2122 assert(!input1.checked, "first radio button checked");
2123 assert(input2.checked, "second radio button not checked");
2124 var input3 = document.createElement('input');
2125 input3.type = "radio";
2126 input3.name = "radioGroup2";
2127 form.appendChild(input3);
2128 assert(!input3.checked, "third radio button checked");
2129 input3.checked = true;
2130 assert(!input1.checked, "first radio button newly checked");
2131 assert(input2.checked, "second radio button newly not checked");
2132 assert(input3.checked, "third radio button not checked");
2133 input1.checked = true;
2134 assert(input1.checked, "first radio button ended up not checked");
2135 assert(!input2.checked, "second radio button ended up checked");
2136 assert(input3.checked, "third radio button ended up not checked");
2137 input1.parentNode.removeChild(input1);
2138 input2.parentNode.removeChild(input2);
2139 input3.parentNode.removeChild(input3);
2140 return 4;
2141 },
2142 function () {
2143 // test 57: HTMLSelectElement.add()
2144 var s = document.createElement('select');
2145 var o = document.createElement('option');
2146 s.add(o, null);
2147 assert(s.firstChild === o, "add() didn't add to firstChild");
2148 assertEquals(s.childNodes.length, 1, "add() didn't add to childNodes");
2149 assert(s.childNodes[0] === o, "add() didn't add to childNodes correctly");
2150 assertEquals(s.options.length, 1, "add() didn't add to options");
2151 assert(s.options[0] === o, "add() didn't add to options correctly");
2152 return 4;
2153 },
2154 function () {
2155 // test 58: HTMLOptionElement.defaultSelected
2156 var s = document.createElement('select');
2157 var o1 = document.createElement('option');
2158 var o2 = document.createElement('option');
2159 o2.defaultSelected = true;
2160 var o3 = document.createElement('option');
2161 s.appendChild(o1);
2162 s.appendChild(o2);
2163 s.appendChild(o3);
2164 assert(s.options[s.selectedIndex] === o2, "defaultSelected didn't take");
2165 return 4;
2166 },
2167 function () {
2168 // test 59: attributes of <button> elements
2169 var button = document.createElement('button');
2170 assertEquals(button.type, "submit", "<button> doesn't have type=submit");
2171 button.setAttribute("type", "button");
2172 assertEquals(button.type, "button", "<button type=button> doesn't have typ e=button");
2173 button.removeAttribute("type");
2174 assertEquals(button.type, "submit", "<button> doesn't have type=submit bac k");
2175 button.setAttribute('value', 'apple');
2176 button.appendChild(document.createTextNode('banana'));
2177 assertEquals(button.value, 'apple', "wrong button value");
2178 return 4;
2179 },
2180
2181 // Misc DOM2 HTML
2182 function () {
2183 // test 60: className vs "class" vs attribute nodes
2184 var span = document.getElementsByTagName('span')[0];
2185 span.setAttribute('class', 'kittens');
2186 if (!span.getAttributeNode)
2187 return 4; // support for attribute nodes is optional in Acid3, because a ttribute nodes might be removed from DOM Core in the future.
2188 var attr = span.getAttributeNode('class');
2189 // however, if they're supported, they'd better work:
2190 assert(attr.specified, "attribute not specified");
2191 assertEquals(attr.value, 'kittens', "attribute value wrong");
2192 assertEquals(attr.name, 'class', "attribute name wrong");
2193 attr.value = 'ocelots';
2194 assertEquals(attr.value, 'ocelots', "attribute value wrong");
2195 assertEquals(span.className, 'ocelots', "setting attribute value failed to be reflected in className");
2196 span.className = 'cats';
2197 assertEquals(attr.ownerElement.getAttribute('class'), 'cats', "setting att ribute value failed to be reflected in getAttribute()");
2198 span.removeAttributeNode(attr);
2199 assert(attr.specified, "attribute not specified after removal");
2200 assert(!attr.ownerElement, "attribute still owned after removal");
2201 assert(!span.className, "element had class after removal");
2202 return 4;
2203 },
2204 function () {
2205 // test 61: className and the class attribute: space preservation
2206 var p = document.createElement('p');
2207 assert(!p.hasAttribute('class'), "element had attribute on creation");
2208 p.setAttribute('class', ' te st ');
2209 assert(p.hasAttribute('class'), "element did not have attribute after sett ing");
2210 assertEquals(p.getAttribute('class'), ' te st ', "class attribute's value was wrong");
2211 assertEquals(p.className, ' te st ', "className was wrong");
2212 p.className = p.className.replace(/ /g, '\n');
2213 assert(p.hasAttribute('class'), "element did not have attribute after repl acement");
2214 assertEquals(p.getAttribute('class'), '\nte\n\nst\n', "class attribute's v alue was wrong after replacement");
2215 assertEquals(p.className, '\nte\n\nst\n', "className was wrong after repla cement");
2216 p.className = '';
2217 assert(p.hasAttribute('class'), "element lost attribute after being set to empty string");
2218 assertEquals(p.getAttribute('class'), '', "class attribute's value was wro ng after being emptied");
2219 assertEquals(p.className, '', "className was wrong after being emptied");
2220 return 4;
2221 },
2222 function () {
2223 // test 62: check that DOM attributes and content attributes aren't equiva lent
2224 var test;
2225 // <div class="">
2226 test = document.getElementsByTagName('div')[0];
2227 assertEquals(test.className, 'buckets', "buckets: className wrong");
2228 assertEquals(test.getAttribute('class'), 'buckets', "buckets: class wrong" );
2229 assert(!test.hasAttribute('className'), "buckets: element has className at tribute");
2230 assert(test.className != test.getAttribute('className'), "buckets: classNa me attribute equals className property");
2231 assert(!('class' in test), "buckets: element has class property")
2232 test['class'] = "oil";
2233 assert(test.className != "oil", "buckets: class property affected classNam e");
2234 // <label for="">
2235 test = document.createElement('label');
2236 test.htmlFor = 'jars';
2237 assertEquals(test.htmlFor, 'jars', "jars: htmlFor wrong");
2238 assertEquals(test.getAttribute('for'), 'jars', "jars: for wrong");
2239 assert(!test.hasAttribute('htmlFor'), "jars: element has htmlFor attribute ");
2240 assert(test.htmlFor != test.getAttribute('htmlFor'), "jars: htmlFor attrib ute equals htmlFor property");
2241 test = document.createElement('label');
2242 test.setAttribute('for', 'pots');
2243 assertEquals(test.htmlFor, 'pots', "pots: htmlFor wrong");
2244 assertEquals(test.getAttribute('for'), 'pots', "pots: for wrong");
2245 assert(!test.hasAttribute('htmlFor'), "pots: element has htmlFor attribute ");
2246 assert(test.htmlFor != test.getAttribute('htmlFor'), "pots: htmlFor attrib ute equals htmlFor property");
2247 assert(!('for' in test), "pots: element has for property");
2248 test['for'] = "oil";
2249 assert(test.htmlFor != "oil", "pots: for property affected htmlFor");
2250 // <meta http-equiv="">
2251 test = document.createElement('meta');
2252 test.setAttribute('http-equiv', 'boxes');
2253 assertEquals(test.httpEquiv, 'boxes', "boxes: httpEquiv wrong");
2254 assertEquals(test.getAttribute('http-equiv'), 'boxes', "boxes: http-equiv wrong");
2255 assert(!test.hasAttribute('httpEquiv'), "boxes: element has httpEquiv attr ibute");
2256 assert(test.httpEquiv != test.getAttribute('httpEquiv'), "boxes: httpEquiv attribute equals httpEquiv property");
2257 test = document.createElement('meta');
2258 test.httpEquiv = 'cans';
2259 assertEquals(test.httpEquiv, 'cans', "cans: httpEquiv wrong");
2260 assertEquals(test.getAttribute('http-equiv'), 'cans', "cans: http-equiv wr ong");
2261 assert(!test.hasAttribute('httpEquiv'), "cans: element has httpEquiv attri bute");
2262 assert(test.httpEquiv != test.getAttribute('httpEquiv'), "cans: httpEquiv attribute equals httpEquiv property");
2263 assert(!('http-equiv' in test), "cans: element has http-equiv property");
2264 test['http-equiv'] = "oil";
2265 assert(test.httpEquiv != "oil", "cans: http-equiv property affected httpEq uiv");
2266 return 4;
2267 },
2268 function () {
2269 // test 63: attributes of the <area> element
2270 var area = document.getElementsByTagName('area')[0];
2271 assertEquals(area.getAttribute('href'), '', "wrong value for href=''");
2272 assertEquals(area.getAttribute('shape'), 'rect', "wrong value for shape='' ");
2273 assertEquals(area.getAttribute('coords'), '2,2,4,4', "wrong value for coor ds=''");
2274 assertEquals(area.getAttribute('alt'), '<\'>', "wrong value for alt=''");
2275 return 4;
2276 },
2277 function () {
2278 // test 64: more attribute tests
2279 // attributes of the <object> element
2280 var obj1 = document.createElement('object');
2281 obj1.setAttribute('data', 'test.html');
2282 var obj2 = document.createElement('object');
2283 obj2.setAttribute('data', './test.html');
2284 assertEquals(obj1.data, obj2.data, "object elements didn't resolve URIs co rrectly");
2285 assert(obj1.data.match(/^file:/), "object.data isn't absolute"); // change d by chase from /^http:/
2286 obj1.appendChild(document.createElement('param'));
2287 assertEquals(obj1.getElementsByTagName('param').length, 1, "object is miss ing its only child");
2288 // non-existent attributes
2289 var test = document.createElement('p');
2290 assert(!('TWVvdywgbWV3Li4u' in test), "TWVvdywgbWV3Li4u unexpectedly found ");
2291 assertEquals(test.TWVvdywgbWV3Li4u, undefined, ".TWVvdywgbWV3Li4u wasn't u ndefined");
2292 assertEquals(test['TWVvdywgbWV3Li4u'], undefined, "['TWVvdywgbWV3Li4u'] wa sn't undefined");
2293 test.setAttribute('TWVvdywgbWV3Li4u', 'woof');
2294 assert(!('TWVvdywgbWV3Li4u' in test), "TWVvdywgbWV3Li4u unexpectedly found after setting");
2295 assertEquals(test.TWVvdywgbWV3Li4u, undefined, ".TWVvdywgbWV3Li4u wasn't u ndefined after setting");
2296 assertEquals(test['TWVvdywgbWV3Li4u'], undefined, "['TWVvdywgbWV3Li4u'] wa sn't undefined after setting");
2297 assertEquals(test.getAttribute('TWVvdywgbWV3Li4u'), 'woof', "TWVvdywgbWV3L i4u has wrong value after setting");
2298 return 4;
2299 },
2300
2301 // bucket 5: Tests from the Acid3 Competition
2302 function () {
2303 // test 65: bring in a couple of SVG files and some HTML files dynamically - preparation for later tests in this bucket
2304 kungFuDeathGrip = document.createElement('p');
2305 kungFuDeathGrip.className = 'removed';
2306 var iframe, object;
2307 // svg iframe
2308 iframe = document.createElement('iframe');
2309 iframe.onload = function () { kungFuDeathGrip.title += '1' };
2310 iframe.src = "svg.svg"; // changed by chase from 'svg.xml'
2311 kungFuDeathGrip.appendChild(iframe);
2312 // object iframe
2313 object = document.createElement('object');
2314 object.onload = function () { kungFuDeathGrip.title += '2' };
2315 object.data = "svg.svg"; // changed by chase from 'svg.xml'
2316 kungFuDeathGrip.appendChild(object);
2317 // xml iframe
2318 iframe = document.createElement('iframe');
2319 iframe.onload = function () { kungFuDeathGrip.title += '3' };
2320 iframe.src = "empty.xml";
2321 kungFuDeathGrip.appendChild(iframe);
2322 // html iframe
2323 iframe = document.createElement('iframe');
2324 iframe.onload = function () { kungFuDeathGrip.title += '4' };
2325 iframe.src = "empty.html";
2326 kungFuDeathGrip.appendChild(iframe);
2327 // html iframe
2328 iframe = document.createElement('iframe');
2329 iframe.onload = function () { kungFuDeathGrip.title += '5' };
2330 iframe.src = "xhtml.1.xhtml"; // changed by chase from 'xhtml.1'
2331 kungFuDeathGrip.appendChild(iframe);
2332 // html iframe
2333 iframe = document.createElement('iframe');
2334 iframe.onload = function () { kungFuDeathGrip.title += '6' };
2335 iframe.src = "xhtml.2.xhtml"; // changed by chase from 'xhtml.2'
2336 kungFuDeathGrip.appendChild(iframe);
2337 // html iframe
2338 iframe = document.createElement('iframe');
2339 iframe.onload = function () { kungFuDeathGrip.title += '7' };
2340 iframe.src = "xhtml.3.xhtml"; // changed by chase from 'xhtml.3'
2341 kungFuDeathGrip.appendChild(iframe);
2342 // add the lot to the document
2343 document.getElementsByTagName('map')[0].appendChild(kungFuDeathGrip);
2344 return 5;
2345 },
2346 function () {
2347 // test 66: localName on text nodes (and now other things), from Sylvain P asche
2348 assertEquals(document.createTextNode("test").localName, null, 'wrong local Name for text node');
2349 assertEquals(document.createComment("test").localName, null, 'wrong localN ame for comment node');
2350 assertEquals(document.localName, null, 'wrong localName for document node' );
2351 return 5;
2352 },
2353 function () {
2354 // test 67: removedNamedItemNS on missing attributes, from Sylvain Pasche
2355 var p = document.createElement("p");
2356 var msg = 'wrong exception raised';
2357 try {
2358 p.attributes.removeNamedItemNS("http://www.example.com/", "absent");
2359 msg = 'no exception raised';
2360 } catch (e) {
2361 if ('code' in e) {
2362 if (e.code == 8)
2363 msg = '';
2364 else
2365 msg += '; code = ' + e.code;
2366 }
2367 }
2368 assert(msg == '', "when calling removeNamedItemNS in a non existent attrib ute: " + msg);
2369 return 5;
2370 },
2371 function () {
2372 // test 68: UTF-16 surrogate pairs, from David Chan
2373 //
2374 // In The Unicode Standard 5.0, it is explicitly permitted to
2375 // allow malformed UTF-16, that is, to leave the string alone.
2376 // (http://www.unicode.org/versions/Unicode5.0.0):
2377 //
2378 // section 2.7: "...strings in ... ECMAScript are Unicode 16-bit
2379 // strings, but are not necessarily well-formed UTF-16
2380 // sequences. In normal processing, it can be far more
2381 // efficient to allow such strings to contain code unit
2382 // sequences that are not well-formed UTF-16 -- that is,
2383 // isolated surrogates"
2384 //
2385 // On the other hand, if the application wishes to ensure
2386 // well-formed character sequences, it may not permit the
2387 // malformed sequence and it must regard the first codepoint as
2388 // an error:
2389 //
2390 // Section 3.2: "C10. When a process interprets a code sequence
2391 // which purports to be in a Unicode character encoding form, it
2392 // shall treat ill-formed code unit sequences as an error
2393 // condition and shall not interpret such sequences as
2394 // characters.
2395 // [...]
2396 // For example, in UTF-8 every code unit of the form 110....2
2397 // must be followed by a code unit of the form 10......2. A
2398 // sequence such as 110.....2 0.......2 is ill-formed and must
2399 // never be generated. When faced with this ill-formed code unit
2400 // sequence while transforming or interpreting text, a
2401 // conformant process must treat the first code unit 110.....2
2402 // as an illegally terminated code unit sequence~Wfor example,
2403 // by signaling an error, filtering the code unit out, or
2404 // representing the code unit with a marker such as U+FFFD
2405 // replacement character."
2406 //
2407 // So it would be permitted to do any of the following:
2408 // 1) Leave the string alone
2409 // 2) Remove the unpaired surrogate
2410 // 3) Replace the unpaired surrogate with U+FFFD
2411 // 4) Throw an exception
2412
2413 try {
2414 var unpaired = String.fromCharCode(0xd863); // half a surrogate pair
2415 var before = unpaired + "text";
2416 var elt = document.createElement("input");
2417 elt.value = before;
2418 var after = elt.value;
2419 }
2420 catch(ex) {
2421 return 5; // Unpaired surrogate caused an exception - ok
2422 }
2423 if (after == before && before.length == 5)
2424 return 5; // Unpaired surrogate kept - ok
2425 if (after == "text")
2426 return 5; // Unpaired surrogate removed - ok
2427 var replacement = String.fromCharCode(0xfffd);
2428 if (after == replacement + "text")
2429 return 5; // Unpaired surrogate replaced - ok
2430 fail("Unpaired surrogate handled wrongly (input was '" + before + "', outp ut was '" + after + "')");
2431 },
2432 function () {
2433 // test 69: check that the support files loaded -- preparation for the res t of the tests in this bucket
2434 assert(!(kungFuDeathGrip == null), "kungFuDeathGrip was null");
2435 assert(!(kungFuDeathGrip.title == null), "kungFuDeathGrip.title was null") ;
2436 if (kungFuDeathGrip.title.length < 7)
2437 return "retry";
2438 assert(!(kungFuDeathGrip.firstChild == null), "kungFuDeathGrip.firstChild was null");
2439 assert(!(kungFuDeathGrip.firstChild.contentDocument == null), "kungFuDeath Grip.firstChild.contentDocument was null");
2440 assert(!(kungFuDeathGrip.firstChild.contentDocument.getElementsByTagName = = null), "kungFuDeathGrip.firstChild.contentDocument.getElementsByTagName was nu ll");
2441 var t = kungFuDeathGrip.firstChild.contentDocument.getElementsByTagName('t ext')[0];
2442 assert(!(t == null), "t was null");
2443 assert(!(t.parentNode == null), "t.parentNode was null");
2444 assert(!(t.parentNode.removeChild == null), "t.parentNode.removeChild was null");
2445 t.parentNode.removeChild(t);
2446 return 5;
2447 },
2448 function () {
2449 // test 70: XML encoding test
2450 // the third child in kungFuDeathGrip is an ISO-8859-1 document sent as UT F-8.
2451 // q.v. XML 1.0, section 4.3.3 Character Encoding in Entities
2452 // this only tests one of a large number of conditions that should cause f atal errors
2453 var doc = kungFuDeathGrip.childNodes[2].contentDocument;
2454 if (!doc)
2455 return 5;
2456 if (doc.documentElement.tagName != "root")
2457 return 5;
2458 if (doc.documentElement.getElementsByTagName('test').length < 1)
2459 return 5;
2460 fail("UTF-8 encoded XML document with invalid character did not have a wel l-formedness error");
2461 },
2462 function () {
2463 // test 71: HTML parsing, from Simon Pieters and Anne van Kesteren
2464 var doc = kungFuDeathGrip.childNodes[3].contentDocument;
2465 assert(doc, "missing document for test");
2466 try {
2467 // siblings
2468 doc.open();
2469 doc.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN \"><title><\/title><span><\/span><script type=\"text/javascript\"><\/script>");
2470 doc.close();
2471 assertEquals(doc.childNodes.length, 2, "wrong number of children in #doc ument (first test)");
2472 assertEquals(doc.firstChild.name, "HTML", "name wrong (first test)");
2473 assertEquals(doc.firstChild.publicId, "-//W3C//DTD HTML 4.0 Transitional //EN", "publicId wrong (first test)");
2474 if ((doc.firstChild.systemId != null) && (doc.firstChild.systemId != "") )
2475 fail("systemId wrong (first test)");
2476 if (('internalSubset' in doc.firstChild) || doc.firstChild.internalSubse t)
2477 assertEquals(doc.firstChild.internalSubset, null, "internalSubset wron g (first test)");
2478 assertEquals(doc.documentElement.childNodes.length, 2, "wrong number of children in HTML (first test)");
2479 assertEquals(doc.documentElement.firstChild.nodeName, "HEAD", "misplaced HEAD element (first test)");
2480 assertEquals(doc.documentElement.firstChild.childNodes.length, 1, "wrong number of children in HEAD (first test)");
2481 assertEquals(doc.documentElement.firstChild.firstChild.tagName, "TITLE", "misplaced TITLE element (first test)");
2482 assertEquals(doc.documentElement.lastChild.nodeName, "BODY", "misplaced BODY element (first test)");
2483 assertEquals(doc.documentElement.lastChild.childNodes.length, 2, "wrong number of children in BODY (first test)");
2484 assertEquals(doc.documentElement.lastChild.firstChild.tagName, "SPAN", " misplaced SPAN element (first test)");
2485 assertEquals(doc.documentElement.lastChild.lastChild.tagName, "SCRIPT", "misplaced SCRIPT element (first test)");
2486 // parent/child
2487 doc.open();
2488 doc.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//E N\" \"http://www.w3.org/TR/html4/loose.dtd\"><title><\/title><span><script type= \"text/javascript\"><\/script><\/span>");
2489 doc.close();
2490 assertEquals(doc.childNodes.length, 2, "wrong number of children in #doc ument (first test)");
2491 assertEquals(doc.firstChild.name, "HTML", "name wrong (second test)");
2492 assertEquals(doc.firstChild.publicId, "-//W3C//DTD HTML 4.01 Transitiona l//EN", "publicId wrong (second test)");
2493 assertEquals(doc.firstChild.systemId, "http://www.w3.org/TR/html4/loose. dtd", "systemId wrong (second test)");
2494 if (('internalSubset' in doc.firstChild) || doc.firstChild.internalSubse t)
2495 assertEquals(doc.firstChild.internalSubset, null, "internalSubset wron g (second test)");
2496 assertEquals(doc.documentElement.childNodes.length, 2, "wrong number of children in HTML (second test)");
2497 assertEquals(doc.documentElement.firstChild.nodeName, "HEAD", "misplaced HEAD element (second test)");
2498 assertEquals(doc.documentElement.firstChild.childNodes.length, 1, "wrong number of children in HEAD (second test)");
2499 assertEquals(doc.documentElement.firstChild.firstChild.tagName, "TITLE", "misplaced TITLE element (second test)");
2500 assertEquals(doc.documentElement.lastChild.nodeName, "BODY", "misplaced BODY element (second test)");
2501 assertEquals(doc.documentElement.lastChild.childNodes.length, 1, "wrong number of children in BODY (second test)");
2502 assertEquals(doc.documentElement.lastChild.firstChild.tagName, "SPAN", " misplaced SPAN element (second test)");
2503 assertEquals(doc.documentElement.lastChild.firstChild.firstChild.tagName , "SCRIPT", "misplaced SCRIPT element (second test)");
2504 } finally {
2505 // prepare the file for the next test
2506 doc.open();
2507 doc.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"><head><ti tle><\/title><style type=\"text/css\">img { height: 10px; }<\/style><body><p><im g src=\"data:image/gif;base64,R0lGODlhAQABAID%2FAMDAwAAAACH5BAEAAAAALAAAAAABAAEA AAICRAEAOw%3D%3D\" alt=\"\">");
2508 doc.close();
2509 }
2510 return 5;
2511 },
2512 function () {
2513 // test 72: dynamic modification of <style> blocks' text nodes, from Jonas Sicking and Garret Smith
2514 var doc = kungFuDeathGrip.childNodes[3].contentDocument;
2515 assert(doc, "missing document for test");
2516 assert(doc.images[0], "prerequisite failed: no image");
2517 assertEquals(doc.images[0].height, 10, "prerequisite failed: style didn't affect image");
2518 doc.styleSheets[0].ownerNode.firstChild.data = "img { height: 20px; }";
2519 assertEquals(doc.images[0].height, 20, "change failed to take effect");
2520 doc.styleSheets[0].ownerNode.appendChild(doc.createTextNode("img { height: 30px; }"));
2521 assertEquals(doc.images[0].height, 30, "append failed to take effect");
2522 var rules = doc.styleSheets[0].cssRules; // "All CSS objects in the DOM ar e "live"" says section 2.1, Overview of the DOM Level 2 CSS Interfaces
2523 doc.styleSheets[0].insertRule("img { height: 40px; }", 2);
2524 assertEquals(doc.images[0].height, 40, "insertRule failed to take effect") ;
2525 assertEquals(doc.styleSheets[0].cssRules.length, 3, "count of rules is wro ng");
2526 assertEquals(rules.length, 3, "cssRules isn't live");
2527 // while we're at it, check some other things on doc.styleSheets:
2528 assert(doc.styleSheets[0].href === null, "internal stylesheet had a URI: " + doc.styleSheets[0].href);
2529 assert(document.styleSheets[0].href === null, "internal acid3 stylesheet h ad a URI: " + document.styleSheets[0].href);
2530 return 5;
2531 },
2532 function () {
2533 // test 73: nested events, from Jonas Sicking
2534 var doc = kungFuDeathGrip.childNodes[3].contentDocument;
2535 // implied events
2536 var up = 0;
2537 var down = 0;
2538 var button = doc.createElement("button");
2539 button.type = "button";
2540 button.onclick = function () { up += 1; if (up < 10) button.click(); down += up; }; // not called
2541 button.addEventListener('test', function () { up += 1; var e = doc.createE vent("HTMLEvents"); e.initEvent('test', false, false); if (up < 20) button.dispa tchEvent(e); down += up; }, false);
2542 var evt = doc.createEvent("HTMLEvents");
2543 evt.initEvent('test', false, false);
2544 button.dispatchEvent(evt);
2545 assertEquals(up, 20, "test event handler called the wrong number of times" );
2546 assertEquals(down, 400, "test event handler called in the wrong order");
2547 return 5;
2548 },
2549 function () {
2550 // test 74: check getSVGDocument(), from Erik Dahlstrom
2551 // GetSVGDocument[6]: "In the case where an SVG document is
2552 // embedded by reference, such as when an XHTML document has an
2553 // 'object' element whose href (or equivalent) attribute
2554 // references an SVG document (i.e., a document whose MIME type
2555 // is "image/svg+xml" and whose root element is thus an 'svg'
2556 // element), the SVG user agent is required to implement the
2557 // GetSVGDocument interface for the element which references the
2558 // SVG document (e.g., the HTML 'object' or comparable
2559 // referencing elements)."
2560 //
2561 // [6] http://www.w3.org/TR/SVG11/struct.html#InterfaceGetSVGDocument
2562 //
2563 // iframe
2564 var iframe = kungFuDeathGrip.childNodes[0];
2565 assert(iframe, "Failed finding svg iframe.");
2566 assert(iframe.contentDocument, "contentDocument failed for <iframe> refere ncing an svg document.");
2567 if (!iframe.getSVGDocument)
2568 fail("getSVGDocument missing on <iframe> element.");
2569 assert(iframe.getSVGDocument(), "getSVGDocument failed for <iframe> refere ncing an svg document.");
2570 assert(iframe.getSVGDocument() == iframe.contentDocument, "Mismatch betwee n getSVGDocument and contentDocument #1.");
2571 // object
2572 var object = kungFuDeathGrip.childNodes[1];
2573 assert(object, "Failed finding svg object.");
2574 assert(object.contentDocument, "contentDocument failed for <object> refere ncing an svg document.");
2575 if (!object.getSVGDocument)
2576 fail("getSVGDocument missing on <object> element.");
2577 assert(object.getSVGDocument(), "getSVGDocument failed for <object> refere ncing an svg document.");
2578 assert(object.getSVGDocument() == object.contentDocument, "Mismatch betwee n getSVGDocument and contentDocument #2.");
2579 return 5;
2580 },
2581 function () {
2582 // test 75: SMIL in SVG, from Erik Dahlstrom
2583 //
2584 // The test begins by creating a few elements, among those is a
2585 // <set> element. This element is prevented from running by
2586 // setting begin="indefinite", which means that the animation
2587 // doesn't start until the 'beginElement' DOM method is called
2588 // on the <set> element. The animation is a simple animation
2589 // that sets the value of the width attribute to 0. The duration
2590 // of the animation is 'indefinite' which means that the value
2591 // will stay 0 indefinitely. The target of the animation is the
2592 // 'width' attribute of the <rect> element that is the parent of
2593 // the <set> element. When 'width' is 0 the rect is not rendered
2594 // according to the spec[7].
2595 //
2596 // Some properties of the SVGAnimatedLength[2] and SVGLength[8]
2597 // are also inspected. Before the animation starts both baseVal
2598 // and animVal contain the same values[2]. Then the animation is
2599 // started by calling the beginElement method[9]. To make sure
2600 // that time passes between the triggering of the animation and
2601 // the time that the values are read out (in test #66), the
2602 // current time is set to 1000 seconds using the setCurrentTime
2603 // method[10].
2604 //
2605 // [2] http://www.w3.org/TR/SVG11/types.html#InterfaceSVGAnimatedLength
2606 // [7] http://www.w3.org/TR/SVG11/shapes.html#RectElement
2607 // [8] http://www.w3.org/TR/SVG11/types.html#InterfaceSVGLength
2608 // [9] http://www.w3.org/TR/SVG11/animate.html#DOMInterfaces
2609 // [10] http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement
2610
2611 var svgns = "http://www.w3.org/2000/svg";
2612 var svgdoc = kungFuDeathGrip.firstChild.contentDocument;
2613 assert(svgdoc, "contentDocument failed on <iframe> for svg document.");
2614 var svg = svgdoc.documentElement;
2615 var rect = svgdoc.createElementNS(svgns, "rect");
2616 rect.setAttribute("fill", "red");
2617 rect.setAttribute("width", "100");
2618 rect.setAttribute("height", "100");
2619 rect.setAttribute("id", "rect");
2620 var anim = svgdoc.createElementNS(svgns, "set");
2621 anim.setAttribute("begin", "indefinite");
2622 anim.setAttribute("to", "0");
2623 anim.setAttribute("attributeName", "width");
2624 anim.setAttribute("dur", "indefinite");
2625 anim.setAttribute("fill", "freeze");
2626 rect.appendChild(anim);
2627 svg.appendChild(rect);
2628 assert(rect.width, "SVG DOM interface SVGRectElement not supported.");
2629 assert(rect.width.baseVal, "SVG DOM base type SVGAnimatedLength not suppor ted.");
2630 assert(rect.width.animVal, "SVG DOM base type SVGAnimatedLength not suppor ted.");
2631 assertEquals(SVGLength.SVG_LENGTHTYPE_NUMBER, 1, "Incorrect SVGLength.SVG_ LENGTHTYPE_NUMBER constant value.");
2632 assertEquals(rect.width.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER, "Incorrect unitType on width attribute.");
2633 assertEquals(rect.getAttribute("width"), "100", "Incorrect value from getA ttribute.");
2634 assertEquals(rect.width.baseVal.valueInSpecifiedUnits, 100, "Incorrect val ueInSpecifiedUnits value.");
2635 assertEquals(rect.width.baseVal.value, 100, "Incorrect baseVal value befor e animation.");
2636 assertEquals(rect.width.animVal.value, 100, "Incorrect animVal value befor e animation.");
2637 anim.beginElement();
2638 assertEquals(rect.width.baseVal.value, 100, "Incorrect baseVal value after starting animation.");
2639 svg.setCurrentTime(1000); // setting 1 second to make sure that time != 0s when we check the animVal value
2640 // the animation is then tested in the next test
2641 return 5;
2642 },
2643 function () {
2644 // test 76: SMIL in SVG, part 2, from Erik Dahlstrom
2645 //
2646 // About animVal[2]: "If the given attribute or property is
2647 // being animated, contains the current animated value of the
2648 // attribute or property, and both the object itself and its
2649 // contents are readonly. If the given attribute or property is
2650 // not currently being animated, contains the same value as
2651 // 'baseVal'."
2652 //
2653 // Since the duration of the animation is indefinite the value
2654 // is still being animated at the time it's queried. Now since
2655 // the 'width' attribute was animated from its original value of
2656 // "100" to the new value of "0" the animVal property must
2657 // contain the value 0.
2658 //
2659 // [2] http://www.w3.org/TR/SVG11/types.html#InterfaceSVGAnimatedLength
2660
2661 var svgdoc = kungFuDeathGrip.firstChild.contentDocument;
2662 assert(svgdoc, "contentDocument failed on <object> for svg document.");
2663 var rect = svgdoc.getElementById("rect");
2664 assert(rect, "Failed to find <rect> element in svg document.");
2665 assertEquals(rect.width.animVal.value, 0, "Incorrect animVal value after s vg animation.");
2666 return 5;
2667 },
2668 function () {
2669 // test 77: external SVG fonts, from Erik Dahlstrom
2670 //
2671 // SVGFonts are described here[3], and the relevant DOM methods
2672 // used in the test are defined here[4].
2673 //
2674 // Note that in order to be more predictable the svg should be
2675 // visible, so that clause "For non-rendering environments, the
2676 // user agent shall make reasonable assumptions about glyph
2677 // metrics." doesn't influence the results. We use 'opacity:0'
2678 // to hide the SVG, but arguably it's still a "rendering
2679 // environment".
2680 //
2681 // The font-size 4000 was chosen because that matches the
2682 // unitsPerEm value in the svgfont, which makes it easy to check
2683 // the glyph advances since they will then be exactly what was
2684 // specified in the svgfont.
2685 //
2686 // [3] http://www.w3.org/TR/SVG11/fonts.html
2687 // [4] http://www.w3.org/TR/SVG11/text.html#InterfaceSVGTextContentElement
2688
2689 var svgns = "http://www.w3.org/2000/svg";
2690 var xlinkns = "http://www.w3.org/1999/xlink";
2691 var svgdoc = kungFuDeathGrip.firstChild.contentDocument;
2692 assert(svgdoc, "contentDocument failed on <object> for svg document.");
2693 var svg = svgdoc.documentElement;
2694 var text = svgdoc.createElementNS(svgns, "text");
2695 text.setAttribute("y", "1em");
2696 text.setAttribute("font-size", "4000");
2697 text.setAttribute("font-family", "ACID3svgfont");
2698 var textContent = svgdoc.createTextNode("abc");
2699 text.appendChild(textContent);
2700 svg.appendChild(text);
2701 // The font-size 4000 was chosen because that matches the unitsPerEm value in the svgfont,
2702 // which makes it easy to check the glyph advances since they will then be exactly what was specified in the svgfont.
2703 assert(text.getNumberOfChars, "SVGTextContentElement.getNumberOfChars() no t supported.");
2704 assertEquals(text.getNumberOfChars(), 3, "getNumberOfChars returned incorr ect string length.");
2705 assertEquals(text.getComputedTextLength(), 4711+42+23, "getComputedTextLen gth failed.");
2706 assertEquals(text.getSubStringLength(0,1), 42, "getSubStringLength #1 fail ed.");
2707 assertEquals(text.getSubStringLength(0,2), 42+23, "getSubStringLength #2 f ailed.");
2708 assertEquals(text.getSubStringLength(1,1), 23, "getSubStringLength #3 fail ed.");
2709 assertEquals(text.getSubStringLength(1,0), 0, "getSubStringLength #4 faile d.");
2710 /* COMMENTED OUT BECAUSE SVGWG KEEPS CHANGING THIS
2711 * var code = -1000;
2712 * try {
2713 * var sl = text.getSubStringLength(1,3);
2714 * } catch(e) {
2715 * code = e.code;
2716 * }
2717 * assertEquals(code, DOMException.INDEX_SIZE_ERR, "getSubStringLength #1 di dn't throw exception.");
2718 * code = -1000;
2719 * try {
2720 * var sl = text.getSubStringLength(0,4);
2721 * } catch(e) {
2722 * code = e.code;
2723 * }
2724 * assertEquals(code, DOMException.INDEX_SIZE_ERR, "getSubStringLength #2 di dn't throw exception.");
2725 * code = -1000;
2726 * try {
2727 * var sl = text.getSubStringLength(3,0);
2728 * } catch(e) {
2729 * code = e.code;
2730 * }
2731 * assertEquals(code, DOMException.INDEX_SIZE_ERR, "getSubStringLength #3 di dn't throw exception.");
2732 */
2733 code = -1000;
2734 try {
2735 var sl = text.getSubStringLength(-17,20);
2736 } catch(e) {
2737 code = 0; // negative values might throw native exception since the api accepts only unsigned values
2738 }
2739 assert(code == 0, "getSubStringLength #4 didn't throw exception.");
2740 assertEquals(text.getStartPositionOfChar(0).x, 0, "getStartPositionOfChar( 0).x returned invalid value.");
2741 assertEquals(text.getStartPositionOfChar(1).x, 42, "getStartPositionOfChar (1).x returned invalid value.");
2742 assertEquals(text.getStartPositionOfChar(2).x, 42+23, "getStartPositionOfC har(2).x returned invalid value.");
2743 assertEquals(text.getStartPositionOfChar(0).y, 4000, "getStartPositionOfCh ar(0).y returned invalid value.");
2744 code = -1000;
2745 try {
2746 var val = text.getStartPositionOfChar(-1);
2747 } catch(e) {
2748 code = 0; // negative values might throw native exception since the api accepts only unsigned values
2749 }
2750 assert(code == 0, "getStartPositionOfChar #1 exception failed.");
2751 code = -1000;
2752 try {
2753 var val = text.getStartPositionOfChar(4);
2754 } catch(e) {
2755 code = e.code;
2756 }
2757 assertEquals(code, DOMException.INDEX_SIZE_ERR, "getStartPositionOfChar #2 exception failed.");
2758 assertEquals(text.getEndPositionOfChar(0).x, 42, "getEndPositionOfChar(0). x returned invalid value.");
2759 assertEquals(text.getEndPositionOfChar(1).x, 42+23, "getEndPositionOfChar( 1).x returned invalid value.");
2760 assertEquals(text.getEndPositionOfChar(2).x, 42+23+4711, "getEndPositionOf Char(2).x returned invalid value.");
2761 code = -1000;
2762 try {
2763 var val = text.getEndPositionOfChar(-17);
2764 } catch(e) {
2765 code = 0; // negative values might throw native exception since the api accepts only unsigned values
2766 }
2767 assert(code == 0, "getEndPositionOfChar #1 exception failed.");
2768 code = -1000;
2769 try {
2770 var val = text.getEndPositionOfChar(4);
2771 } catch(e) {
2772 code = e.code;
2773 }
2774 assertEquals(code, DOMException.INDEX_SIZE_ERR, "getEndPositionOfChar #2 e xception failed.");
2775 return 5;
2776 },
2777 function () {
2778 // test 78: SVG textPath and getRotationOfChar(), from Erik Dahlstrom
2779 //
2780 // The getRotationOfChar[4] method fetches the midpoint rotation
2781 // of a glyph defined by a character (in this testcase there is
2782 // a simple 1:1 correspondence between the two). The path is
2783 // defined in the svg.xml file, and consists of first a line
2784 // going down, then followed by a line that has a 45 degree
2785 // slope and then followed by a horizontal line. The length of
2786 // each path segment have been paired with the advance of each
2787 // glyph, so that each glyph will be on each of the three
2788 // different path segments (see text on a path layout rules[5]).
2789 // Thus the rotation of the first glyph is 90 degrees, the
2790 // second 45 degrees and the third 0 degrees.
2791 //
2792 // [4] http://www.w3.org/TR/SVG11/text.html#InterfaceSVGTextContentElement
2793 // [5] http://www.w3.org/TR/SVG11/text.html#TextpathLayoutRules
2794
2795 var svgns = "http://www.w3.org/2000/svg";
2796 var xlinkns = "http://www.w3.org/1999/xlink";
2797 var svgdoc = kungFuDeathGrip.firstChild.contentDocument;
2798 assert(svgdoc, "contentDocument failed on <object> for svg document.");
2799 var svg = svgdoc.documentElement;
2800 var text = svgdoc.createElementNS(svgns, "text");
2801 text.setAttribute("font-size", "4000");
2802 text.setAttribute("font-family", "ACID3svgfont");
2803 var textpath = svgdoc.createElementNS(svgns, "textPath");
2804 textpath.setAttributeNS(xlinkns, "xlink:href", "#path");
2805 var textContent = svgdoc.createTextNode("abc");
2806 textpath.appendChild(textContent);
2807 text.appendChild(textpath);
2808 svg.appendChild(text);
2809 assertEquals(text.getRotationOfChar(0), 90, "getRotationOfChar(0) failed." );
2810 assertEquals(text.getRotationOfChar(1), 45, "getRotationOfChar(1) failed." );
2811 assertEquals(text.getRotationOfChar(2), 0, "getRotationOfChar(2) failed.") ;
2812 var code = -1000;
2813 try {
2814 var val = text.getRotationOfChar(-1)
2815 } catch(e) {
2816 code = e.code;
2817 }
2818 assertEquals(code, DOMException.INDEX_SIZE_ERR, "getRotationOfChar #1 exce ption failed.");
2819 code = -1000;
2820 try {
2821 var val = text.getRotationOfChar(4)
2822 } catch(e) {
2823 code = e.code;
2824 }
2825 assertEquals(code, DOMException.INDEX_SIZE_ERR, "getRotationOfChar #2 exce ption failed.");
2826 return 5;
2827 },
2828 function () {
2829 // test 79: a giant test for <svg:font>, from Cameron McCormack
2830 // This tests various features of SVG fonts from SVG 1.1. It consists of
2831 // a <text> element with 33 characters, styled using an SVG font that has
2832 // different advance values for each glyph. The script uses
2833 // SVGTextElementContent.getStartPositionOfChar() to determine where the
2834 // glyph corresponding to each character was placed, and thus to work out
2835 // whether the SVG font was used correctly.
2836 //
2837 // The font uses 100 units per em, and the text is set in 100px. Since
2838 // font-size gives the size of the em box
2839 // (http://www.w3.org/TR/SVG11/text.html#DOMInterfaces), the scale of the
2840 // coordinate system for the glyphs is the same as the SVG document.
2841 //
2842 // The expectedAdvances array holds the expected advance value for each
2843 // character, and expectedKerning holds the (negative) kerning for each
2844 // character. getPositionOfChar() returns the actual x coordinate for the
2845 // glyph, corresponding to the given character, and if multiple characters
2846 // correspond to the same glyph, the same position value is returned for
2847 // each of those characters.
2848 //
2849 // Here are the reasonings for the advance/kerning values. Note that for
2850 // a given character at index i, the expected position is
2851 // sum(expectedAdvances[0:i-1] + expectedKerning[0:i-1]).
2852 //
2853 // char advance kerning reasoning
2854 // ------- ------- ------- -------------------------------------------- ------
2855 // A 10000 0 Normal character mapping to a single glyph.
2856 // B 0 0 First character of a two character glyph, so the
2857 // current position isn't advanced until the se cond
2858 // character.
2859 // C 200 0 Second character of a two character glyph, s o now
2860 // the position is advanced.
2861 // B 300 0 Although there is a glyph for "BC" in the fo nt,
2862 // it appears after the glyph for "B", so the s ingle
2863 // character glyph for "B" should be chosen ins tead.
2864 // D 1100 0 Normal character mapping to a single glyph.
2865 // A 10000 200 Kerning of -200 is specified in the font bet ween
2866 // the "A" and "EE" glyphs.
2867 // E 0 0 The first character of a two character glyph "EE".
2868 // E 1300 0 The second character of a two character glyp h.
2869 // U 0 0 This is a glyph for the six characters "U+00 46",
2870 // which happen to look like a valid unicode ra nge.
2871 // This tests that the <glyph unicode=""> in th e
2872 // font matches exact strings rather than a ran ge,
2873 // as used in the kerning elements.
2874 // + 0 0 Second character of six character glyph.
2875 // 0 0 0 Third character of six character glyph.
2876 // 0 0 0 Fourth character of six character glyph.
2877 // 4 0 0 Fifth character of six character glyph.
2878 // 6 1700 0 Sixth character of six character glyph.
2879 // U 0 0 The same six character glyph that looks like a
2880 // Unicode range. One of the kerning elements has
2881 // u1="U+0046" u2="U+0046", which shouldn't mat ch
2882 // this, because those attributes are interpret ed
2883 // as Unicode ranges if they are, and normal
2884 // strings otherwise. Thus there should be no
2885 // kerning between these two glyphs.
2886 // G 2300 200 Kerning is between this character and the ne xt
2887 // "G", since there is an <hkern> element that
2888 // uses a Unicode range on its u1="" attribute
2889 // and a glyph name on its g2="" attribute whic h
2890 // both match "G".
2891 // G 2300 0 Normal character with kerning before it.
2892 // H 3100 0 A glyph with graphical content describing th e
2893 // glyph, rather than a d="" attribute.
2894 // I 4300 0 Glyphs are checked in document order for one
2895 // that matches, but the first glyph with
2896 // unicode="I" also has lang="zh", which disqua lifies
2897 // it. Thus the second glyph with unicode="I"
2898 // is chosen.
2899 // I 4100 0 Since this I has xml:lang="zh" on it in the text,
2900 // the first glyph with lang="zh" matches.
2901 // J 4700 -4700 A normal glyph with kerning between the "J" and the
2902 // next glyph "A" equal to the advance of the " J"
2903 // glyph, so the position should stay the same.
2904 // A 10000 0 Normal glyph with kerning before it.
2905 // K 5900 0 The first glyph with unicode="K" does not ma tch,
2906 // since it has orientation="v", so the second
2907 // glyph with unicode="K" is chosen.
2908 // <spc> 6100 0 The space character should select the glyph with
2909 // unicode=" ", despite it having a misleading
2910 // glyph-name="L".
2911 // L 6700 0 The "L" character should select the glyph wi th
2912 // unicode=" ", despite it having a misleading
2913 // glyph-name="spacev".
2914 // A 2900 0 An <altGlyph> element is used to select the
2915 // glyph for U+10085 instead of the one for "A" .
2916 // U+10085 2900 0 Tests glyph selection with a non-plane-0
2917 // character.
2918 // A 10000 0 A final normal character.
2919 //
2920 // In addition, the script tests the value returned by
2921 // SVGTextContentElement.getNumberOfChars(), which in this case should be 34.
2922 // If it returned 33, then it incorrectly counted Unicode characters inste ad
2923 // of UTF-16 codepoints (probably).
2924 //
2925 // See http://www.w3.org/TR/SVG11/fonts.html for a description of the glyp h
2926 // matching rules, and http://www.w3.org/TR/SVG11/text.html#DOMInterfaces
2927 // for a description of getStartPositionOfChar() and getNumberOfChars().
2928 //
2929 // Note also that the test uses DOMImplementation.createDocument() to crea te
2930 // the SVG document. This seems to cause browsers trouble for the SVG DOM
2931 // interfaces, since the document isn't being "rendered" as it might be
2932 // if it were in an <iframe>. Changing the test to use an <iframe> will
2933 // at least let you see the main part of the test running.
2934
2935 var NS = {
2936 svg: 'http://www.w3.org/2000/svg',
2937 xml: 'http://www.w3.org/XML/1998/namespace',
2938 xlink: 'http://www.w3.org/1999/xlink'
2939 };
2940
2941 var doc = kungFuDeathGrip.childNodes[1].contentDocument;
2942 while (doc.hasChildNodes())
2943 doc.removeChild(doc.firstChild);
2944 doc.appendChild(doc.createElementNS(NS.svg, "svg:svg"));
2945
2946 var e = function (n, as, cs) {
2947 var elt = doc.createElementNS(NS.svg, n);
2948 if (as) {
2949 for (var an in as) {
2950 var idx = an.indexOf(':');
2951 var ns = null;
2952 if (idx != -1)
2953 ns = NS[an.substring(0, idx)];
2954 elt.setAttributeNS(ns, an, as[an]);
2955 }
2956 }
2957 if (cs) {
2958 for (var i in cs) {
2959 var c = cs[i];
2960 elt.appendChild(typeof c == 'string' ? doc.createTextNode(c) : c);
2961 }
2962 }
2963 return elt;
2964 }
2965
2966 doc.documentElement.appendChild(e('font', { 'horiz-adv-x': '10000'}, [e('f ont-face', { 'font-family': 'HCl', 'units-per-em': '100', 'ascent': '1000', 'des cent': '500'}), e('missing-glyph', null, [e('path', { 'd': 'M100,0 h800 v-100 h- 800 z'})]), e('glyph', { 'unicode': 'A', 'd': 'M100,0 h100 v-100 h-100 z'}), e(' glyph', { 'unicode': 'BC', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '200 '}), e('glyph', { 'unicode': 'B', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x ': '300'}), e('glyph', { 'unicode': 'C', 'd': 'M100,0 h100 v-100 h-100 z', 'hori z-adv-x': '500'}), e('glyph', { 'unicode': 'BD', 'd': 'M100,0 h100 v-100 h-100 z ', 'horiz-adv-x': '700'}), e('glyph', { 'unicode': 'D', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '1100'}), e('glyph', { 'unicode': 'EE', 'd': 'M100,0 h1 00 v-100 h-100 z', 'horiz-adv-x': '1300', 'glyph-name': 'grapefruit'}), e('glyp h', { 'unicode': 'U+0046', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '170 0'}), e('glyph', { 'unicode': 'F', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv- x': '1900'}), e('glyph', { 'unicode': 'G', 'd': 'M100,0 h100 v-100 h-100 z', 'ho riz-adv-x': '2300', 'glyph-name': 'gee'}), e('glyph', { 'unicode': '\uD800\uDC85 ', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '2900', 'id': 'astral'}), e( 'glyph', { 'unicode': 'H', 'horiz-adv-x': '3100'}, [e('path', { 'd': 'M100,0 h10 0 v-100 h-100 z'})]), e('glyph', { 'unicode': 'I', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '4100', 'lang': 'zh'}), e('glyph', { 'unicode': 'I', 'd': 'M 100,0 h100 v-100 h-100 z', 'horiz-adv-x': '4300'}), e('glyph', { 'unicode': 'J', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '4700'}), e('glyph', { 'unicod e': 'K', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-adv-x': '5300', 'orientation': 'v'}), e('glyph', { 'unicode': 'K', 'd': 'M100,0 h100 v-100 h-100 z', 'horiz-ad v-x': '5900'}), e('glyph', { 'unicode': ' ', 'd': 'M100,0 h100 v-100 h-100 z', ' horiz-adv-x': '6100', 'glyph-name': 'L'}), e('glyph', { 'unicode': 'L', 'd': 'M1 00,0 h100 v-100 h-100 z', 'horiz-adv-x': '6700', 'glyph-name': 'space'}), e('hke rn', { 'u1': 'A', 'u2': 'EE', 'k': '1000'}), e('hkern', { 'u1': 'A', 'g2': 'grap efruit', 'k': '-200'}), e('hkern', { 'u1': 'U+0046', 'u2': 'U+0046', 'k': '-200' }), e('hkern', { 'u1': 'U+0047-0047', 'g2': 'gee', 'k': '-200'}), e('hkern', { ' u1': 'J', 'u2': 'A', 'k': '4700'})]));
2967 doc.documentElement.appendChild(e('text', { 'y': '100', 'font-family': 'HC l', 'font-size': '100px', 'letter-spacing': '0px', 'word-spacing': '0px'}, ['ABC BDAEEU+0046U+0046GGHI', e('tspan', { 'xml:lang': 'zh'}, ['I']), 'JAK L', e('altG lyph', { 'xlink:href': '#astral'}, ['A']), '\uD800\uDC85A']));
2968
2969 var t = doc.documentElement.lastChild;
2970
2971 var characterDescriptions = [
2972 "a normal character",
2973 "the first character of a two-character glyph",
2974 "the second character of a two-character glyph",
2975 "a normal character, which shouldn't be the first character of a two-cha racter glyph",
2976 "a normal character, which shouldn't be the second character of a two-ch aracter glyph",
2977 "a normal character, which has some kerning after it",
2978 "the first character of a two-character glyph, which has some kerning be fore it",
2979 "the second character of a two-character glyph, which has some kerning b efore it",
2980 "the first character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning after it, but thi s glyph does not",
2981 "the second character of a six-character glyph, which happens to look li ke a Unicode range, where the range-specified glyph has kerning after it, but th is glyph does not",
2982 "the third character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning after it, but thi s glyph does not",
2983 "the fourth character of a six-character glyph, which happens to look li ke a Unicode range, where the range-specified glyph has kerning after it, but th is glyph does not",
2984 "the fifth character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning after it, but thi s glyph does not",
2985 "the sixth character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning after it, but thi s glyph does not",
2986 "the first character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning before it, but th is glyph does not",
2987 "the second character of a six-character glyph, which happens to look li ke a Unicode range, where the range-specified glyph has kerning before it, but t his glyph does not",
2988 "the third character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning before it, but th is glyph does not",
2989 "the fourth character of a six-character glyph, which happens to look li ke a Unicode range, where the range-specified glyph has kerning before it, but t his glyph does not",
2990 "the fifth character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning before it, but th is glyph does not",
2991 "the sixth character of a six-character glyph, which happens to look lik e a Unicode range, where the range-specified glyph has kerning before it, but th is glyph does not",
2992 "a normal character, which has some kerning after it that is specified b y glyph name",
2993 "a normal character, which has some kerning before it that is specified by glyph name",
2994 "a normal character, whose glyph is given by child graphical content of the <glyph> element",
2995 "a normal character, whose glyph should not match the one with a lang=\" \" attribute on it",
2996 "a normal character, whose glyph should match the one with a lang=\"\" a ttribute on it",
2997 "a normal character, which has some kerning after it that is equal to th e advance of the character",
2998 "a normal character, which has some kerning before it that is equal to t he advance of the previous character",
2999 "a normal character, whose glyph should not match the one with an orient ation=\"v\" attribute on it",
3000 "a space character, which has a misleading glyph-name=\"\" attribute",
3001 "a normal character, which has a misleading glyph-name=\"\" attribute",
3002 "a normal character, whose glyph is chosen to be another by using <altGl yph>",
3003 "a character not in Plane 0 (high surrogate pair)",
3004 "a character not in Plane 0 (low surrogate pair)",
3005 "a normal character",
3006 ];
3007
3008 var expectedAdvances = [
3009 10000, // A
3010 0, // BC [0]
3011 200, // BC [1]
3012 300, // B
3013 1100, // D
3014 10000, // A
3015 0, // EE [0]
3016 1300, // EE [1]
3017 0, // U+0046 [0]
3018 0, // U+0046 [1]
3019 0, // U+0046 [2]
3020 0, // U+0046 [3]
3021 0, // U+0046 [4]
3022 1700, // U+0046 [5]
3023 0, // U+0046 [0]
3024 0, // U+0046 [1]
3025 0, // U+0046 [2]
3026 0, // U+0046 [3]
3027 0, // U+0046 [4]
3028 1700, // U+0046 [5]
3029 2300, // G
3030 2300, // G
3031 3100, // H
3032 4300, // I
3033 4100, // I (zh)
3034 4700, // J
3035 10000, // A
3036 5900, // K
3037 6100, // <space>
3038 6700, // L
3039 2900, // A (using &#x10085; altGlyph)
3040 0, // &#x10085; high surrogate pair
3041 2900, // &#x10085; low surrogate pair
3042 10000, // A
3043 ];
3044
3045 var expectedKerning = [
3046 0, // A
3047 0, // BC [0]
3048 0, // BC [1]
3049 0, // B
3050 0, // D
3051 200, // A
3052 0, // EE [0]
3053 0, // EE [1]
3054 0, // U+0046 [0]
3055 0, // U+0046 [1]
3056 0, // U+0046 [2]
3057 0, // U+0046 [3]
3058 0, // U+0046 [4]
3059 0, // U+0046 [5]
3060 0, // U+0046 [0]
3061 0, // U+0046 [1]
3062 0, // U+0046 [2]
3063 0, // U+0046 [3]
3064 0, // U+0046 [4]
3065 0, // U+0046 [5]
3066 200, // G
3067 0, // G
3068 0, // H
3069 0, // I
3070 0, // I (zh)
3071 -4700, // J
3072 0, // A
3073 0, // K
3074 0, // <space>
3075 0, // L
3076 0, // A (using &#x10085; altGlyph)
3077 0, // &#x10085; high surrogate pair
3078 0, // &#x10085; low surrogate pair
3079 0, // A
3080 ];
3081
3082 assertEquals(t.getNumberOfChars(), expectedAdvances.length, 'SVGSVGTextEle ment.getNumberOfChars() incorrect');
3083
3084 var expectedPositions = [0];
3085 for (var i = 0; i < expectedAdvances.length; i++)
3086 expectedPositions.push(expectedPositions[i] + expectedAdvances[i] + expe ctedKerning[i]);
3087
3088 var actualPositions = [];
3089 for (var i = 0; i < t.getNumberOfChars(); i++)
3090 actualPositions.push(t.getStartPositionOfChar(i).x);
3091 actualPositions.push(t.getEndPositionOfChar(t.getNumberOfChars() - 1).x);
3092
3093 for (var i = 0; i < expectedPositions.length; i++) {
3094 if (expectedPositions[i] != actualPositions[i]) {
3095 var s = "character position " + i + ", which is ";
3096 if (i == 0) {
3097 s += "before " + characterDescriptions[0];
3098 } else if (i == expectedPositions.length - 1) {
3099 s += "after " + characterDescriptions[characterDescriptions.length - 1];
3100 } else {
3101 s += "between " + characterDescriptions[i - 1] + " and " + character Descriptions[i];
3102 }
3103 s += ", is " + actualPositions[i] + " but should be " + expectedPositi ons[i] + ".";
3104 fail(s);
3105 }
3106 }
3107 return 5;
3108 },
3109 function () {
3110 // test 80: remove the iframes and the object
3111 assert(!(kungFuDeathGrip == null), "kungFuDeathGrip was null");
3112 assert(!(kungFuDeathGrip.parentNode == null), "kungFuDeathGrip.parentNode was null");
3113 kungFuDeathGrip.parentNode.removeChild(kungFuDeathGrip);
3114 kungFuDeathGrip = null;
3115 // check that the xhtml files worked right
3116 assert(notifications['xhtml.1'], "Script in XHTML didn't execute");
3117 assert(!notifications['xhtml.2'], "XML well-formedness error didn't stop s cript from executing");
3118 assert(!notifications['xhtml.3'], "Script executed despite having wrong na mespace");
3119 // while we're at it, check that the linktest is loaded
3120 // since the other iframes have forcibly loaded by now, we assume that
3121 // there's no way this can't have loaded by now
3122 // (probably a safe bet)
3123 var a = document.links[1];
3124 assert(!(a == null), "linktest was null");
3125 assert(a.textContent == "LINKTEST FAILED", "linktest link couldn't be foun d");
3126 if (a.hasAttribute('class'))
3127 return "retry"; // linktest onload didn't fire -- could be a networking issue, check that first
3128 return 5;
3129 },
3130
3131 // bucket 6: ECMAScript
3132 function () {
3133 // test 81: length of arrays with elisions at end
3134 var t1 = [,];
3135 var t2 = [,,];
3136 assertEquals(t1.length, 1, "[,] doesn't have length 1");
3137 assertEquals(t2.length, 2, "[,,] doesn't have length 2");
3138 return 6;
3139 },
3140 function () {
3141 // test 82: length of arrays with elisions in the middle
3142 var t3 = ['a', , 'c'];
3143 assertEquals(t3.length, 3, "['a',,'c'] doesn't have length 3");
3144 assert(0 in t3, "no 0 in t3");
3145 assert(!(1 in t3), "unexpected 1 in t3");
3146 assert(2 in t3, "no 2 in t3");
3147 assertEquals(t3[0], 'a', "t3[0] wrong");
3148 assertEquals(t3[2], 'c', "t3[2] wrong");
3149 return 6;
3150 },
3151 function () {
3152 // test 83: array methods
3153 var x = ['a', 'b', 'c'];
3154 assertEquals(x.unshift('A', 'B', 'C'), 6, "array.unshift() returned the wr ong value");
3155 var s = x.join(undefined);
3156 assertEquals(s, 'A,B,C,a,b,c', "array.join(undefined) used wrong separator "); // qv 15.4.4.5:3
3157 return 6;
3158 },
3159 function () {
3160 // test 84: converting numbers to strings
3161 assertEquals((0.0).toFixed(4), "0.0000", "toFixed(4) wrong for 0");
3162 assertEquals((-0.0).toFixed(4), "0.0000", "toFixed(4) wrong for -0");
3163 assertEquals((0.00006).toFixed(4), "0.0001", "toFixed(4) wrong for 0.00006 ");
3164 assertEquals((-0.00006).toFixed(4), "-0.0001", "toFixed(4) wrong for -0.00 006");
3165 assertEquals((0.0).toExponential(4), "0.0000e+0", "toExponential(4) wrong for 0");
3166 assertEquals((-0.0).toExponential(4), "0.0000e+0", "toExponential(4) wrong for -0");
3167 var x = 7e-4;
3168 assertEquals(x.toPrecision(undefined), x.toString(undefined), "toPrecision (undefined) was wrong");
3169 return 6;
3170 },
3171 function () {
3172 // test 85: strings and string-related operations
3173 // substr() and negative numbers
3174 assertEquals("scathing".substr(-7, 3), "cat", "substr() wrong with negativ e numbers");
3175 return 6;
3176 },
3177 function () {
3178 // test 86: Date tests -- methods passed no arguments
3179 var d = new Date();
3180 assert(isNaN(d.setMilliseconds()), "calling setMilliseconds() with no argu ments didn't result in NaN");
3181 assert(isNaN(d), "date wasn't made NaN");
3182 assert(isNaN(d.getDay()), "date wasn't made NaN");
3183 return 6;
3184 },
3185 function () {
3186 // test 87: Date tests -- years
3187 var d1 = new Date(Date.UTC(99.9, 6));
3188 assertEquals(d1.getUTCFullYear(), 1999, "Date.UTC() didn't do proper 1900 year offsetting");
3189 var d2 = new Date(98.9, 6);
3190 assertEquals(d2.getFullYear(), 1998, "new Date() didn't do proper 1900 yea r offsetting");
3191 return 6;
3192 },
3193 function () {
3194 // test 88: ES3 section 7.6:3 (unicode escapes can't be used to put non-id entifier characters into identifiers)
3195 // and there's no other place for them in the syntax (other than strings, of course)
3196 var ok = false;
3197 try {
3198 eval("var test = { };\ntest.i= 0;\ntest.i\\u002b= 1;\ntest.i;\n");
3199 } catch (e) {
3200 ok = true;
3201 }
3202 assert(ok, "\\u002b was not considered a parse error in script");
3203 return 6;
3204 },
3205 function () {
3206 // test 89: Regular Expressions
3207 var ok = true;
3208 // empty classes in regexps
3209 try {
3210 eval("/TA[])]/.exec('TA]')");
3211 // JS regexps aren't like Perl regexps, if their character
3212 // classes start with a ] that means they're empty. So this
3213 // is a syntax error; if we get here it's a bug.
3214 ok = false;
3215 } catch (e) { }
3216 assert(ok, "orphaned bracket not considered parse error in regular express ion literal");
3217 try {
3218 if (eval("/[]/.exec('')"))
3219 ok = false;
3220 } catch (e) {
3221 ok = false;
3222 }
3223 assert(ok, "/[]/ either failed to parse or matched something");
3224 return 6;
3225 },
3226 function () {
3227 // test 90: Regular Expressions
3228 // not back references.
3229 assert(!(/(1)\0(2)/.test("12")), "NUL in regexp incorrectly ignored");
3230 assert((/(1)\0(2)/.test("1" + "\0" + "2")), "NUL in regexp didn't match co rrectly");
3231 assert(!(/(1)\0(2)/.test("1\02")), "octal 2 unexpectedly matched NUL");
3232 assertEquals(nullInRegexpArgumentResult, "passed", "failed //.test() check "); // nothing to see here, move along now
3233 // back reference to future capture
3234 var x = /(\3)(\1)(a)/.exec('cat'); // the \3 matches the empty string, qv. ES3:15.10.2.9
3235 assert(x, "/(\\3)(\\1)(a)/ failed to match 'cat'");
3236 assertEquals(x.length, 4, "/(\\3)(\\1)(a)/ failed to return four component s");
3237 assertEquals(x[0], "a", "/(\\3)(\\1)(a)/ failed to find 'a' in 'cat'");
3238 assert(x[1] === "", "/(\\3)(\\1)(a)/ failed to find '' in 'cat' as first p art");
3239 assert(x[2] === "", "/(\\3)(\\1)(a)/ failed to find '' in 'cat' as second part");
3240 assertEquals(x[3], "a", "/(\\3)(\\1)(a)/ failed to find 'a' in 'cat' as th ird part");
3241 // negative lookahead
3242 x = /(?!(text))(te.t)/.exec("text testing");
3243 assertEquals(x.length, 3, "negative lookahead test failed to return the ri ght number of bits");
3244 assertEquals(x[0], "test", "negative lookahead test failed to find the rig ht text");
3245 assert(x[1] === undefined, "negative lookahead test failed to return undef ined for negative lookahead capture");
3246 assert(x[2] === "test", "negative lookahead test failed to find the right second capture");
3247 return 6;
3248 },
3249 function () {
3250 // test 91: check that properties are enumerable by default
3251 var test = {
3252 constructor: function() { return 1; },
3253 toString: function() { return 2; },
3254 toLocaleString: function() { return 3; },
3255 valueOf: function() { return 4; },
3256 hasOwnProperty: function() { return 5; },
3257 isPrototypeOf: function() { return 6; },
3258 propertyIsEnumerable: function() { return 7; },
3259 prototype: function() { return 8; },
3260 length: function() { return 9; },
3261 unique: function() { return 10; }
3262 };
3263 var results = [];
3264 for (var property in test)
3265 results.push([test[property](), property]);
3266 results.sort(function(a, b) {
3267 if (a[0] < b[0]) return -1;
3268 if (a[0] > b[0]) return 1;
3269 return 0;
3270 });
3271 assertEquals(results.length, 10, "missing properties");
3272 for (var index = 0; index < 10; index += 1)
3273 assertEquals(results[index][0], index+1, "order wrong at results["+index +"] == ");
3274 var index = 0;
3275 assertEquals(results[index++][1], "constructor", "failed to find construct or in expected position");
3276 assertEquals(results[index++][1], "toString", "failed to find toString in expected position");
3277 assertEquals(results[index++][1], "toLocaleString", "failed to find toLoca leString in expected position");
3278 assertEquals(results[index++][1], "valueOf", "failed to find valueOf in ex pected position");
3279 assertEquals(results[index++][1], "hasOwnProperty", "failed to find hasOwn Property in expected position");
3280 assertEquals(results[index++][1], "isPrototypeOf", "failed to find isProto typeOf in expected position");
3281 assertEquals(results[index++][1], "propertyIsEnumerable", "failed to find propertyIsEnumerable in expected position");
3282 assertEquals(results[index++][1], "prototype", "failed to find prototype i n expected position");
3283 assertEquals(results[index++][1], "length", "failed to find length in expe cted position");
3284 assertEquals(results[index++][1], "unique", "failed to find unique in expe cted position");
3285 return 6;
3286 },
3287 function () {
3288 // test 92: internal properties of Function objects
3289 // constructor is not ReadOnly
3290 var f1 = function () { 1 };
3291 f1.prototype.constructor = "hello world";
3292 var f1i = new f1();
3293 assert(f1i.constructor === "hello world", "Function object's prototype's c onstructor was ReadOnly");
3294 // constructor is DontEnum (indeed, no properties at all on a new Function object)
3295 var f2 = function () { 2 };
3296 var f2i = new f2();
3297 var count = 0;
3298 for (var property in f2i) {
3299 assert(property != "constructor", "Function object's prototype's constru ctor was not DontEnum");
3300 count += 1;
3301 }
3302 assertEquals(count, 0, "Function object had unexpected properties");
3303 // constructor is not DontDelete
3304 var f3 = function (a, b) { 3 };
3305 delete f3.prototype.constructor;
3306 var f3i = new f3();
3307 assertEquals(f3i.constructor, Object.prototype.constructor, "Function obje ct's prototype's constructor was DontDelete (or got magically replaced)");
3308 return 6;
3309 },
3310 function () {
3311 // test 93: FunctionExpression semantics
3312 var functest;
3313 var vartest = 0;
3314 var value = (function functest(arg) {
3315 if (arg)
3316 return 1;
3317 vartest = 1;
3318 functest = function (arg) { return 2; }; // this line does nothing as 'f unctest' is ReadOnly here
3319 return functest(true); // this is therefore tail recursion and returns 1
3320 })(false);
3321 assertEquals(vartest, 1, "rules in 10.1.4 not followed in FunctionBody");
3322 assertEquals(value, 1, "semantics of FunctionExpression: function Identifi er ... not followed");
3323 assert(!functest, "Property in step 4 of FunctionExpression: function Iden tifier ... leaked to parent scope");
3324 return 6;
3325 },
3326 function () {
3327 // test 94: exception scope
3328 var test = 'pass';
3329 try {
3330 throw 'fail';
3331 } catch (test) {
3332 test += 'ing';
3333 }
3334 assertEquals(test, 'pass', 'outer scope poisoned by exception catch{} bloc k');
3335 return 6;
3336 },
3337 function () {
3338 // test 95: types of expressions
3339 var a = []; var s;
3340 s = a.length = "2147483648";
3341 assertEquals(typeof s, "string", "type of |\"2147483648\"| is not string") ;
3342 return 6;
3343 },
3344 function () {
3345 // test 96: encodeURI() and encodeURIComponent() and null bytes
3346 assertEquals(encodeURIComponent(String.fromCharCode(0)), '%00', "encodeURI Component failed to encode U+0000");
3347 assertEquals(encodeURI(String.fromCharCode(0)), '%00', "encodeURI failed t o encode U+0000");
3348 return 6;
3349 },
3350
3351 // URIs
3352 function () {
3353 // test 97: data: URI parsing
3354 assertEquals(d1, "one", "data: failed as escaped");
3355 assertEquals(d2, "two", "data: failed as base64");
3356 assertEquals(d3, "three", "data: failed as base64 escaped");
3357 assertEquals(d4, "four", "data: failed as base64 with spaces");
3358 assertEquals(d5, "five's", "data: failed with backslash");
3359 return 7;
3360 },
3361
3362 // XHTML
3363 function () {
3364 // test 98: XHTML and the DOM
3365 // (special test)
3366 var doctype = document.implementation.createDocumentType("html", "-//W3C// DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
3367 assertEquals(doctype.ownerDocument, null, "doctype's ownerDocument was wro ng after creation");
3368 var doc = document.implementation.createDocument("http://www.w3.org/1999/x html", "html", doctype);
3369 doc.documentElement.appendChild(doc.createElementNS("http://www.w3.org/199 9/xhtml", "head"));
3370 doc.documentElement.appendChild(doc.createElementNS("http://www.w3.org/199 9/xhtml", "body"));
3371 var t = doc.createElementNS("http://www.w3.org/1999/xhtml", "title");
3372 doc.documentElement.firstChild.appendChild(t);
3373 // ok we have a conforming XHTML1 doc in |doc| now.
3374 assertEquals(doctype.ownerDocument, doc, "doctype's ownerDocument didn't c hange when it was assigned to another document");
3375 assertEquals(doc.title, "", "document had unexpected title");
3376 t.textContent = "Sparrow";
3377 assertEquals(doc.title, "Sparrow", "document.title did not update dynamica lly");
3378 doc.body.appendChild(doc.createElementNS("http://www.w3.org/1999/xhtml", " form"));
3379 assertEquals(doc.forms.length, 1, "document.forms not updated after insert ing a form");
3380 return 7;
3381 },
3382
3383 // Sanity
3384 function () {
3385 // test 99: check for the weirdest bug ever
3386 var a = document.createElement('a');
3387 a.setAttribute('href', 'http://www.example.com/');
3388 a.appendChild(document.createTextNode('www.example.com'));
3389 a.href = 'http://hixie.ch/';
3390 assertEquals(a.firstChild.data, "www.example.com", "sanity did not prevail ");
3391 a.href = 'http://damowmow.com/';
3392 assertEquals(a.firstChild.data, "www.example.com", "final test failed");
3393 return 7;
3394 }
3395
3396 ];
3397 var log = '';
3398 var delay = 10;
3399 var score = 0, index = 0, retry = 0, errors = 0;
3400 function update() {
3401 var span = document.getElementById('score'); // not cached by JS
3402 span.nextSibling.removeAttribute('class'); // no-op after first loop
3403 span.nextSibling.nextSibling.firstChild.data = tests.length; // no-op after first loop
3404 if (index < tests.length) {
3405 var zeroPaddedIndex = index < 10 ? '0' + index : index;
3406 try {
3407 var beforeTest = new Date();
3408 var result = tests[index]();
3409 var elapsedTest = new Date() - beforeTest;
3410 if (result == "retry") {
3411 // some tests uses this magical mechanism to wait for support files to load
3412 // we will give this test 500 attempts (5000ms) before aborting
3413 retry += 1;
3414 if (retry < 500) {
3415 setTimeout(update, delay);
3416 return;
3417 }
3418 fail("timeout -- could be a networking issue");
3419 } else if (result) {
3420 var bucket = document.getElementById('bucket' + result);
3421 if (bucket)
3422 bucket.className += 'P';
3423 score += 1;
3424 if (retry > 0) {
3425 errors += 1;
3426 log += "Test " + zeroPaddedIndex + " passed, but took " + retry + " attempts (less than perfect).\n";
3427 } else if (elapsedTest > 33) { // 30fps
3428 errors += 1;
3429 log += "Test " + zeroPaddedIndex + " passed, but took " + elapsedTes t + "ms (less than 30fps)\n";
3430 }
3431 } else {
3432 fail("no error message");
3433 }
3434 } catch (e) {
3435 var s;
3436 if (e.message)
3437 s = e.message.replace(/\s+$/, "");
3438 else
3439 s = e;
3440 errors += 1;
3441 log += "Test " + zeroPaddedIndex + " failed: " + s + "\n";
3442 };
3443 retry = 0;
3444 index += 1;
3445 span.firstChild.data = score;
3446 setTimeout(update, delay);
3447 } else {
3448 var endTime = new Date();
3449 var elapsedTime = ((endTime - startTime) - (delay * tests.length)) / 1000;
3450 log += "Total elapsed time: " + elapsedTime.toFixed(2) + "s";
3451 if (errors == 0)
3452 log += "\nNo JS errors and no timing issues.\nWas the rendering pixel-fo r-pixel perfect too?";
3453 test_complete(tests.length - score, endTime - startTime);
3454 }
3455 }
3456 function running() {
3457 if (index < tests.length) {
3458 return true;
3459 } else {
3460 return false;
3461 }
3462 }
3463 function report(event) {
3464 // for debugging either click the "A" in "Acid3" (to get an alert) or shift- click it (to get a report)
3465 if (event.shiftKey) {
3466 var w = window.open();
3467 w.document.write('<pre>Failed ' + (tests.length - score) + ' of ' + tests. length + ' tests.\n' +
3468 log.replace(/&/g,'&amp;').replace(RegExp('<', 'g'), '&lt; ').replace('\0', '\\0') +
3469 '<\/pre>');
3470 w.document.close();
3471 } else {
3472 alert('Failed ' + (tests.length - score) + ' test' + (score == 1 ? '' : 's ') + '.\n' + log)
3473 }
3474 }
3475 </script>
3476 <script src="head.js"></script>
3477 <body onload="update() /* this attribute's value is tested in one of the tests */ ">
3478 <h1 onclick="report(event)">Acid3</h1>
3479 <div class="buckets"
3480 ><p id="bucket1" class="z"></p
3481 ><p id="bucket2" class="z"></p
3482 ><p id="bucket3" class="z"></p
3483 ><p id="bucket4" class="z"></p
3484 ><p id="bucket5" class="z"></p
3485 ><p id="bucket6" class="z"></p>
3486 </div>
3487 <p id="result"><span id="score">JS</span><span id="slash" class="hidden">/</sp an><span>?</span></p>
3488 <!-- The following line is used in a number of the tests. It is done using doc ument.write() to sidestep complaints of validity. -->
3489 <script type="text/javascript">document.write('<map name=""><area href="" shap e="rect" coords="2,2,4,4" alt="<\'>"><iframe src="empty.png">FAIL<\/iframe><ifra me src="empty.txt">FAIL<\/iframe><iframe src="empty.html" id="selectors"><\/ifra me><form action="" name="form"><input type=HIDDEN><\/form><table><tr><td><p><\/t body> <\/table><\/map>');</script>
3490 <p id="instructions">To pass the test,<span></span> a browser must use its def ault settings, the animation has to be smooth, the score has to end on 100/100, and the final page has to look exactly, pixel for pixel, like <a href="reference .html">this reference rendering</a>.</p>
3491 <p id="remove-last-child-test">Scripting must be enabled to use this test.</p>
3492 </body>
3493 </html>
OLDNEW
« no previous file with comments | « page_cycler/acid3/acid3.acidtests.org/head.js ('k') | page_cycler/acid3/acid3.acidtests.org/reference.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698