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

Side by Side Diff: third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/reflection.js

Issue 1984023002: Move web-platform-tests to wpt (part 1 of 2) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 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
OLDNEW
(Empty)
1 ReflectionTests = {};
2
3 ReflectionTests.start = new Date().getTime();
4
5 /**
6 * Resolve the given URL to an absolute URL, relative to the current document's
7 * address. There's no API that I know of that exposes this directly, so we
8 * actually just create an <a> element, set its href, and stitch together the
9 * various properties. Seems to work. We don't try to reimplement the
10 * algorithm here, because we're not concerned with its correctness -- we're
11 * only testing HTML reflection, not Web Addresses.
12 *
13 * Return "" if the URL couldn't be resolved, since this is really for
14 * reflected URL attributes, and those are supposed to return "" if the URL
15 * couldn't be resolved.
16 *
17 * It seems like IE9 doesn't implement URL decomposition attributes correctly
18 * for <a>, which causes all these tests to fail. Ideally I'd do this in some
19 * other way, but the failure does stem from an incorrect implementation of
20 * HTML, so I'll leave it alone for now.
21 *
22 * TODO: This relies on reflection to test reflection, so it could mask bugs.
23 * Either get a JS implementation of the "resolve a URL" algorithm, or just
24 * specify expected values manually here. It shouldn't be too hard to write
25 * special cases for all the values we test.
26 */
27 ReflectionTests.resolveUrl = function(url) {
28 var el = document.createElement("a");
29 el.href = String(url);
30 var ret = el.protocol + "//" + el.host + el.pathname + el.search + el.hash;
31 if (ret == "//") {
32 return "";
33 } else {
34 return ret;
35 }
36 };
37
38 /**
39 * Given some input, convert to a multi-URL value for IDL get per the spec.
40 */
41 ReflectionTests.urlsExpected = function(urls) {
42 var expected = "";
43 // TODO: Test other whitespace?
44 urls = urls + "";
45 var split = urls.split(" ");
46 for (var j = 0; j < split.length; j++) {
47 if (split[j] == "") {
48 continue;
49 }
50 var append = ReflectionTests.resolveUrl(split[j]);
51 if (append == "") {
52 continue;
53 }
54 if (expected == "") {
55 expected = append;
56 } else {
57 expected += " " + append;
58 }
59 }
60 return expected;
61 };
62
63 /**
64 * The "rules for parsing non-negative integers" from the HTML spec. They're
65 * mostly used for reflection, so here seems like as good a place to test them
66 * as any. Returns false on error.
67 */
68 ReflectionTests.parseNonneg = function(input) {
69 var value = this.parseInt(input);
70 if (value === false || value < 0) {
71 return false;
72 }
73 return value;
74 };
75
76 /**
77 * The "rules for parsing integers" from the HTML spec. Returns false on
78 * error.
79 */
80 ReflectionTests.parseInt = function(input) {
81 var position = 0;
82 var sign = 1;
83 // Skip whitespace
84 while (input.length > position && /^[ \t\n\f\r]$/.test(input[position])) {
85 position++;
86 }
87 if (position >= input.length) {
88 return false;
89 }
90 if (input[position] == "-") {
91 sign = -1;
92 position++;
93 } else if (input[position] == "+") {
94 position++;
95 }
96 if (position >= input.length) {
97 return false;
98 }
99 if (!/^[0-9]$/.test(input[position])) {
100 return false;
101 }
102 var value = 0;
103 while (input.length > position && /^[0-9]$/.test(input[position])) {
104 value *= 10;
105 // Don't use parseInt even for single-digit strings . . .
106 value += input.charCodeAt(position) - "0".charCodeAt(0);
107 position++;
108 }
109 if (value === 0) {
110 return 0;
111 }
112 return sign * value;
113 };
114
115 // Used in initializing typeMap
116 var binaryString = "\x00\x01\x02\x03\x04\x05\x06\x07 "
117 + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f "
118 + "\x10\x11\x12\x13\x14\x15\x16\x17 "
119 + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ";
120 var maxInt = 2147483647;
121 var minInt = -2147483648;
122 var maxUnsigned = 4294967295;
123
124 /**
125 * Array containing the tests and other information for each type of reflected
126 * attribute. Meaning of keys:
127 *
128 * "jsType": What typeof idlObj[idlName] is supposed to be.
129 * "defaultVal": The default value to be returned if the attribute is not
130 * present and no default is specifically set for this attribute.
131 * "domTests": What values to test with setAttribute().
132 * "domExpected": What values to expect with IDL get after setAttribute().
133 * Defaults to the same as domTests.
134 * "idlTests": What values to test with IDL set. Defaults to domTests.
135 * "idlDomExpected": What to expect from getAttribute() after IDL set.
136 * Defaults to idlTests.
137 * "idlIdlExpected": What to expect from IDL get after IDL set. Defaults to
138 * idlDomExpected.
139 *
140 * Note that all tests/expected values are only baselines, and can be expanded
141 * with additional tests hardcoded into the function for particular types if
142 * necessary. For example, a special codepath is used for enums, and for
143 * IDL setters which throw an exception. null means "defaultVal" is the
144 * expected value. Expected DOM values are cast to strings by adding "".
145 *
146 * TODO: Test strings that aren't valid UTF-16. Desired behavior is not clear
147 * here at the time of writing, see
148 * http://www.w3.org/Bugs/Public/show_bug.cgi?id=12100
149 *
150 * TODO: Test deleting an IDL attribute, and maybe doing other fun stuff to it.
151 *
152 * TODO: Test IDL sets of integer types to out-of-range or other weird values.
153 * WebIDL says to wrap, but I'm not sure offhand if that's what we want.
154 *
155 * TODO: tokenlist, settable tokenlist, limited
156 */
157
158
159 ReflectionTests.typeMap = {
160 /**
161 * "If a reflecting IDL attribute is a DOMString but doesn't fall into any
162 * of the above categories, then the getting and setting must be done in a
163 * transparent, case-preserving manner."
164 *
165 * The data object passed to reflects() can contain an optional key
166 * treatNullAsEmptyString, whose value is ignored. If it does contain the
167 * key, null will be cast to "" instead of "null", per WebIDL
168 * [TreatNullAs=EmptyString].
169 */
170 "string": {
171 "jsType": "string",
172 "defaultVal": "",
173 "domTests": ["", " " + binaryString + " foo ", undefined, 7, 1.5, true,
174 false, {"test": 6}, NaN, +Infinity, -Infinity, "\0", null,
175 {"toString":function(){return "test-toString";}},
176 {"valueOf":function(){return "test-valueOf";}, toString:nul l}
177 ]
178 },
179 /**
180 * "If a reflecting IDL attribute is a DOMString attribute whose content
181 * attribute is defined to contain a URL, then on getting, the IDL
182 * attribute must resolve the value of the content attribute relative to
183 * the element and return the resulting absolute URL if that was
184 * successful, or the empty string otherwise; and on setting, must set the
185 * content attribute to the specified literal value. If the content
186 * attribute is absent, the IDL attribute must return the default value, if
187 * the content attribute has one, or else the empty string."
188 */
189 "url": {
190 "jsType": "string",
191 "defaultVal": "",
192 "domTests": ["", " foo ", "http://site.example/",
193 "//site.example/path???@#l", binaryString, undefined, 7, 1. 5, true,
194 false, {"test": 6}, NaN, +Infinity, -Infinity, "\0", null,
195 {"toString":function(){return "test-toString";}},
196 {"valueOf":function(){return "test-valueOf";}, toString:nul l}],
197 "domExpected": ReflectionTests.resolveUrl,
198 "idlIdlExpected": ReflectionTests.resolveUrl
199 },
200 /**
201 * "If a reflecting IDL attribute is a DOMString attribute whose content
202 * attribute is defined to contain one or more URLs, then on getting, the
203 * IDL attribute must split the content attribute on spaces and return the
204 * concatenation of resolving each token URL to an absolute URL relative to
205 * the element, with a single U+0020 SPACE character between each URL,
206 * ignoring any tokens that did not resolve successfully. If the content
207 * attribute is absent, the IDL attribute must return the default value, if
208 * the content attribute has one, or else the empty string. On setting, the
209 * IDL attribute must set the content attribute to the specified literal
210 * value."
211 *
212 * Seems to only be used for ping.
213 */
214 "urls": {
215 "jsType": "string",
216 "defaultVal": "",
217 "domTests": ["", " foo ", "http://site.example/ foo bar baz",
218 "//site.example/path???@#l", binaryString, undefined, 7, 1. 5, true,
219 false, {"test": 6}, NaN, +Infinity, -Infinity, "\0", null,
220 {"toString":function(){return "test-toString";}},
221 {"valueOf":function(){return "test-valueOf";}, toString:nul l}],
222 "domExpected": ReflectionTests.urlsExpected,
223 "idlIdlExpected": ReflectionTests.urlsExpected
224 },
225 /**
226 * "If a reflecting IDL attribute is a DOMString whose content attribute is
227 * an enumerated attribute, and the IDL attribute is limited to only known
228 * values, then, on getting, the IDL attribute must return the conforming
229 * value associated with the state the attribute is in (in its canonical
230 * case), or the empty string if the attribute is in a state that has no
231 * associated keyword value; and on setting, if the new value is an ASCII
232 * case-insensitive match for one of the keywords given for that attribute,
233 * then the content attribute must be set to the conforming value
234 * associated with the state that the attribute would be in if set to the
235 * given new value, otherwise, if the new value is the empty string, then
236 * the content attribute must be removed, otherwise, the content attribute
237 * must be set to the given new value."
238 *
239 * "Some attributes are defined as taking one of a finite set of keywords.
240 * Such attributes are called enumerated attributes. The keywords are each
241 * defined to map to a particular state (several keywords might map to the
242 * same state, in which case some of the keywords are synonyms of each
243 * other; additionally, some of the keywords can be said to be
244 * non-conforming, and are only in the specification for historical
245 * reasons). In addition, two default states can be given. The first is the
246 * invalid value default, the second is the missing value default.
247 *
248 * . . .
249 *
250 * When the attribute is specified, if its value is an ASCII
251 * case-insensitive match for one of the given keywords then that keyword's
252 * state is the state that the attribute represents. If the attribute value
253 * matches none of the given keywords, but the attribute has an invalid
254 * value default, then the attribute represents that state. Otherwise, if
255 * the attribute value matches none of the keywords but there is a missing
256 * value default state defined, then that is the state represented by the
257 * attribute. Otherwise, there is no default, and invalid values must be
258 * ignored.
259 *
260 * When the attribute is not specified, if there is a missing value default
261 * state defined, then that is the state represented by the (missing)
262 * attribute. Otherwise, the absence of the attribute means that there is
263 * no state represented."
264 *
265 * This is only used for enums that are limited to known values, not other
266 * enums (those are treated as generic strings by the spec). The data
267 * object passed to reflects() can contain these keys:
268 *
269 * "defaultVal": missing value default (defaults to "")
270 * "invalidVal": invalid value default (defaults to defaultVal)
271 * "keywords": array of keywords as given by the spec (required)
272 * "nonCanon": dictionary mapping non-canonical values to their
273 * canonical equivalents (defaults to {})
274 * "isNullable": Indicates if attribute is nullable (defaults to false)
275 *
276 * Tests are mostly hardcoded into reflects(), since they depend on the
277 * keywords. All expected values are computed in reflects() using a helper
278 * function.
279 */
280 "enum": {
281 "jsType": "string",
282 "defaultVal": "",
283 "domTests": ["", " " + binaryString + " foo ", undefined, 7, 1.5, true,
284 false, {"test": 6}, NaN, +Infinity, -Infinity, "\0", null,
285 {"toString":function(){return "test-toString";}},
286 {"valueOf":function(){return "test-valueOf";}, toString:null}]
287 },
288 /**
289 * "If a reflecting IDL attribute is a boolean attribute, then on getting
290 * the IDL attribute must return true if the content attribute is set, and
291 * false if it is absent. On setting, the content attribute must be removed
292 * if the IDL attribute is set to false, and must be set to the empty
293 * string if the IDL attribute is set to true. (This corresponds to the
294 * rules for boolean content attributes.)"
295 */
296 "boolean": {
297 "jsType": "boolean",
298 "defaultVal": false,
299 "domTests": ["", " foo ", undefined, null, 7, 1.5, true, false,
300 {"test": 6}, NaN, +Infinity, -Infinity, "\0",
301 {"toString":function(){return "test-toString";}},
302 {"valueOf":function(){return "test-valueOf";}, toString:nul l}],
303 "domExpected": function(val) {
304 return true;
305 }
306 },
307 /**
308 * "If a reflecting IDL attribute is a signed integer type (long) then, on
309 * getting, the content attribute must be parsed according to the rules for
310 * parsing signed integers, and if that is successful, and the value is in
311 * the range of the IDL attribute's type, the resulting value must be
312 * returned. If, on the other hand, it fails or returns an out of range
313 * value, or if the attribute is absent, then the default value must be
314 * returned instead, or 0 if there is no default value. On setting, the
315 * given value must be converted to the shortest possible string
316 * representing the number as a valid integer and then that string must be
317 * used as the new content attribute value."
318 */
319 "long": {
320 "jsType": "number",
321 "defaultVal": 0,
322 "domTests": [-36, -1, 0, 1, maxInt, minInt, maxInt + 1, minInt - 1,
323 maxUnsigned, maxUnsigned + 1, "", "-1", "-0", "0", "1",
324 " " + binaryString + " foo ",
325 // Test various different whitespace. Only 20, 9, A, C,
326 // and D are whitespace.
327 "\u00097", "\u000B7", "\u000C7", "\u00207", "\u00A07", "\uF EFF7",
328 "\u000A7", "\u000D7", "\u20287", "\u20297", "\u16807", "\u1 80E7",
329 "\u20007", "\u20017", "\u20027", "\u20037", "\u20047", "\u2 0057",
330 "\u20067", "\u20077", "\u20087", "\u20097", "\u200A7", "\u2 02F7",
331 "\u30007",
332 undefined, 1.5, true, false, {"test": 6}, NaN, +Infinity,
333 -Infinity, "\0",
334 {toString:function() {return 2;}, valueOf: null},
335 {valueOf:function() {return 3;}}],
336 "domExpected": function(val) {
337 var parsed = ReflectionTests.parseInt(String(val));
338 if (parsed === false || parsed > maxInt || parsed < minInt) {
339 return null;
340 }
341 return parsed;
342 },
343 "idlTests": [-36, -1, 0, 1, 2147483647, -2147483648],
344 "idlDomExpected": [-36, -1, 0, 1, 2147483647, -2147483648]
345 },
346 /**
347 * "If a reflecting IDL attribute is a signed integer type (long) that is
348 * limited to only non-negative numbers then, on getting, the content
349 * attribute must be parsed according to the rules for parsing non-negative
350 * integers, and if that is successful, and the value is in the range of
351 * the IDL attribute's type, the resulting value must be returned. If, on
352 * the other hand, it fails or returns an out of range value, or if the
353 * attribute is absent, the default value must be returned instead, or −1
354 * if there is no default value. On setting, if the value is negative, the
355 * user agent must fire an INDEX_SIZE_ERR exception. Otherwise, the given
356 * value must be converted to the shortest possible string representing the
357 * number as a valid non-negative integer and then that string must be used
358 * as the new content attribute value."
359 */
360 "limited long": {
361 "jsType": "number",
362 "defaultVal": -1,
363 "domTests": [minInt - 1, minInt, -36, -1, -0, 0, 1, maxInt, maxInt + 1,
364 maxUnsigned, maxUnsigned + 1, "", "-1", "-0", "0", "1",
365 " " + binaryString + " foo ",
366 "\u00097", "\u000B7", "\u000C7", "\u00207", "\u00A07", "\uF EFF7",
367 "\u000A7", "\u000D7", "\u20287", "\u20297", "\u16807", "\u1 80E7",
368 "\u20007", "\u20017", "\u20027", "\u20037", "\u20047", "\u2 0057",
369 "\u20067", "\u20077", "\u20087", "\u20097", "\u200A7", "\u2 02F7",
370 "\u30007",
371 undefined, 1.5, true, false, {"test": 6}, NaN, +Infinity,
372 -Infinity, "\0",
373 {toString:function() {return 2;}, valueOf: null},
374 {valueOf:function() {return 3;}}],
375 "domExpected": function(val) {
376 var parsed = ReflectionTests.parseNonneg(String(val));
377 if (parsed === false || parsed > maxInt || parsed < minInt) {
378 return null;
379 }
380 return parsed;
381 },
382 "idlTests": [minInt, -36, -1, 0, 1, maxInt],
383 "idlDomExpected": [null/*exception*/, null/*exception*/, null/*exception */, 0, 1, maxInt]
384 },
385 /**
386 * "If a reflecting IDL attribute is an unsigned integer type (unsigned
387 * long) then, on getting, the content attribute must be parsed according
388 * to the rules for parsing non-negative integers, and if that is
389 * successful, and the value is in the range 0 to 2147483647 inclusive, the
390 * resulting value must be returned. If, on the other hand, it fails or
391 * returns an out of range value, or if the attribute is absent, the
392 * default value must be returned instead, or 0 if there is no default
393 * value. On setting, the given value must be converted to the shortest
394 * possible string representing the number as a valid non-negative integer
395 * and then that string must be used as the new content attribute value."
396 */
397 "unsigned long": {
398 "jsType": "number",
399 "defaultVal": 0,
400 "domTests": [minInt - 1, minInt, -36, -1, 0, 1, 257, maxInt,
401 maxInt + 1, maxUnsigned, maxUnsigned + 1, "", "-1", "-0", " 0", "1",
402 "\u00097", "\u000B7", "\u000C7", "\u00207", "\u00A07", "\uF EFF7",
403 "\u000A7", "\u000D7", "\u20287", "\u20297", "\u16807", "\u1 80E7",
404 "\u20007", "\u20017", "\u20027", "\u20037", "\u20047", "\u2 0057",
405 "\u20067", "\u20077", "\u20087", "\u20097", "\u200A7", "\u2 02F7",
406 "\u30007",
407 " " + binaryString + " foo ", undefined, 1.5, true, false,
408 {"test": 6}, NaN, +Infinity, -Infinity, "\0",
409 {toString:function() {return 2;}, valueOf: null},
410 {valueOf:function() {return 3;}}],
411 "domExpected": function(val) {
412 var parsed = ReflectionTests.parseNonneg(String(val));
413 // Note maxInt, not maxUnsigned.
414 if (parsed === false || parsed < 0 || parsed > maxInt) {
415 return null;
416 }
417 return parsed;
418 },
419 "idlTests": [0, 1, 257, maxInt, "-0", maxInt + 1, maxUnsigned],
420 "idlIdlExpected": [0, 1, 257, maxInt, 0, null, null],
421 "idlDomExpected": [0, 1, 257, maxInt, 0, null, null],
422 },
423 /**
424 * "If a reflecting IDL attribute is an unsigned integer type (unsigned
425 * long) that is limited to only non-negative numbers greater than zero,
426 * then the behavior is similar to the previous case, but zero is not
427 * allowed. On getting, the content attribute must first be parsed
428 * according to the rules for parsing non-negative integers, and if that is
429 * successful, and the value is in the range 1 to 2147483647 inclusive, the
430 * resulting value must be returned. If, on the other hand, it fails or
431 * returns an out of range value, or if the attribute is absent, the
432 * default value must be returned instead, or 1 if there is no default
433 * value. On setting, if the value is zero, the user agent must fire an
434 * INDEX_SIZE_ERR exception. Otherwise, the given value must be converted
435 * to the shortest possible string representing the number as a valid
436 * non-negative integer and then that string must be used as the new
437 * content attribute value."
438 */
439 "limited unsigned long": {
440 "jsType": "number",
441 "defaultVal": 1,
442 "domTests": [minInt - 1, minInt, -36, -1, 0, 1, maxInt,
443 maxInt + 1, maxUnsigned, maxUnsigned + 1, "", "-1", "-0", " 0", "1",
444 "\u00097", "\u000B7", "\u000C7", "\u00207", "\u00A07", "\uF EFF7",
445 "\u000A7", "\u000D7", "\u20287", "\u20297", "\u16807", "\u1 80E7",
446 "\u20007", "\u20017", "\u20027", "\u20037", "\u20047", "\u2 0057",
447 "\u20067", "\u20077", "\u20087", "\u20097", "\u200A7", "\u2 02F7",
448 "\u30007",
449 " " + binaryString + " foo ", undefined, 1.5, true, false,
450 {"test": 6}, NaN, +Infinity, -Infinity, "\0",
451 {toString:function() {return 2;}, valueOf: null},
452 {valueOf:function() {return 3;}}],
453 "domExpected": function(val) {
454 var parsed = ReflectionTests.parseNonneg(String(val));
455 // Note maxInt, not maxUnsigned.
456 if (parsed === false || parsed < 1 || parsed > maxInt) {
457 return null;
458 }
459 return parsed;
460 },
461 "idlTests": [0, 1, maxInt, maxInt + 1, maxUnsigned],
462 "idlDomExpected": [null/*exception*/, 1, maxInt, null, null]
463 },
464 /**
465 * "If a reflecting IDL attribute is a floating point number type (double),
466 * then, on getting, the content attribute must be parsed according to the
467 * rules for parsing floating point number values, and if that is
468 * successful, the resulting value must be returned. If, on the other hand,
469 * it fails, or if the attribute is absent, the default value must be
470 * returned instead, or 0.0 if there is no default value. On setting, the
471 * given value must be converted to the best representation of the number
472 * as a floating point number and then that string must be used as the new
473 * content attribute value."
474 *
475 * TODO: Check this:
476 *
477 * "Except where otherwise specified, if an IDL attribute that is a
478 * floating point number type (double) is assigned an Infinity or
479 * Not-a-Number (NaN) value, a NOT_SUPPORTED_ERR exception must be raised."
480 *
481 * TODO: Implement the actual algorithm so we can run lots more tests. For
482 * now we're stuck with manually setting up expected values. Of course,
483 * a lot of care has to be taken in checking equality for floats . . .
484 * maybe we should have some tolerance for comparing them. I'm not even
485 * sure whether setting the content attribute to 0 should return 0.0 or
486 * -0.0 (the former, I hope).
487 */
488 "double": {
489 "jsType": "number",
490 "defaultVal": 0.0,
491 "domTests": [minInt - 1, minInt, -36, -1, 0, 1, maxInt,
492 maxInt + 1, maxUnsigned, maxUnsigned + 1, "",
493 "\u00097", "\u000B7", "\u000C7", "\u00207", "\u00A07", "\uFEFF7",
494 "\u000A7", "\u000D7", "\u20287", "\u20297", "\u16807", "\u180E7",
495 "\u20007", "\u20017", "\u20027", "\u20037", "\u20047", "\u20057",
496 "\u20067", "\u20077", "\u20087", "\u20097", "\u200A7", "\u202F7",
497 "\u30007",
498 " " + binaryString + " foo ", undefined, 1.5, true, false,
499 {"test": 6}, NaN, +Infinity, -Infinity, "\0",
500 {toString:function() {return 2;}, valueOf: null},
501 {valueOf:function() {return 3;}}],
502 "domExpected": [minInt - 1, minInt, -36, -1, 0, 1, maxInt,
503 maxInt + 1, maxUnsigned, maxUnsigned + 1, null,
504 // Leading whitespace tests
505 7, null, 7, 7, null, null,
506 7, 7, null, null, null, null,
507 null, null, null, null, null, null,
508 null, null, null, null, null, null,
509 null,
510 // End leading whitespace tests
511 null, null, 1.5, null, null,
512 null, null, null, null, null,
513 2, 3],
514 // I checked that ES ToString is well-defined for all of these (I
515 // think). Yes, String(-0) == "0".
516 "idlTests": [ -10000000000, -1, -0, 0, 1, 10000000000],
517 "idlDomExpected": ["-10000000000", "-1", "0", "0", "1", "10000000000"],
518 "idlIdlExpected": [ -10000000000, -1, -0, 0, 1, 10000000000]
519 }
520 };
521
522 for (var type in ReflectionTests.typeMap) {
523 var props = ReflectionTests.typeMap[type];
524 var cast = window[props.jsType[0].toUpperCase() + props.jsType.slice(1)];
525 if (props.domExpected === undefined) {
526 props.domExpected = props.domTests.map(cast);
527 } else if (typeof props.domExpected == "function") {
528 props.domExpected = props.domTests.map(props.domExpected);
529 }
530 if (props.idlTests === undefined) {
531 props.idlTests = props.domTests;
532 }
533 if (props.idlDomExpected === undefined) {
534 props.idlDomExpected = props.idlTests.map(cast);
535 } else if (typeof props.idlDomExpected == "function") {
536 props.idlDomExpected = props.idlTests.map(props.idlDomExpected);
537 }
538 if (props.idlIdlExpected === undefined) {
539 props.idlIdlExpected = props.idlDomExpected;
540 } else if (typeof props.idlIdlExpected == "function") {
541 props.idlIdlExpected = props.idlTests.map(props.idlIdlExpected);
542 }
543 }
544
545 /**
546 * Tests that the JavaScript attribute named idlName on the object idlObj
547 * reflects the DOM attribute named domName on domObj. The data argument is an
548 * object that must contain at least one key, "type", which contains the
549 * expected type of the IDL attribute ("string", "enum", etc.). The "comment"
550 * key will add a parenthesized comment in the type info if there's a test
551 * failure, to indicate that there's something special about the element you're
552 * testing (like it has an attribute set to some value). Other keys in the
553 * data object are type-specific, e.g., "defaultVal" for numeric types. If the
554 * data object is a string, it's converted to {"type": data}. If idlObj is a
555 * string, we set idlObj = domObj = document.createElement(idlObj).
556 */
557 ReflectionTests.reflects = function(data, idlName, idlObj, domName, domObj) {
558 // Do some setup first so that getTypeDescription() works in testWrapper()
559 if (typeof data == "string") {
560 data = {type: data};
561 }
562 if (domName === undefined) {
563 domName = idlName;
564 }
565 if (typeof idlObj == "string") {
566 idlObj = document.createElement(idlObj);
567 }
568 if (domObj === undefined) {
569 domObj = idlObj;
570 }
571
572 // Note: probably a hack? This kind of assumes that the variables here
573 // won't change over the course of the tests, which is wrong, but it's
574 // probably safe enough. Just don't read stuff that will change.
575 ReflectionHarness.currentTestInfo = {data: data, idlName: idlName, idlObj: i dlObj, domName: domName, domObj: domObj};
576
577 ReflectionHarness.testWrapper(function() {
578 ReflectionTests.doReflects(data, idlName, idlObj, domName, domObj);
579 });
580 };
581
582 /**
583 * Actual implementation of the above.
584 */
585 ReflectionTests.doReflects = function(data, idlName, idlObj, domName, domObj) {
586 // If we don't recognize the type, testing is impossible.
587 if (this.typeMap[data.type] === undefined) {
588 if (unimplemented.indexOf(data.type) == -1) {
589 unimplemented.push(data.type);
590 }
591 return;
592 }
593
594 var typeInfo = this.typeMap[data.type];
595
596 if (typeof data.isNullable == "undefined") {
597 data.isNullable = false;
598 }
599
600 // Test that typeof idlObj[idlName] is correct. If not, further tests are
601 // probably pointless, so bail out.
602 var isDefaultValueNull = data.isNullable && data.defaultVal === null;
603 if (!ReflectionHarness.test(typeof idlObj[idlName], isDefaultValueNull ? "ob ject" : typeInfo.jsType, "typeof IDL attribute")) {
604 return;
605 }
606
607 // Test default
608 var defaultVal = data.defaultVal;
609 if (defaultVal === undefined) {
610 defaultVal = typeInfo.defaultVal;
611 }
612 if (defaultVal !== null || data.isNullable) {
613 ReflectionHarness.test(idlObj[idlName], defaultVal, "IDL get with DOM at tribute unset");
614 }
615
616 var domTests = typeInfo.domTests.slice(0);
617 var domExpected = typeInfo.domExpected.map(function(val) { return val === nu ll ? defaultVal : val; });
618 var idlTests = typeInfo.idlTests.slice(0);
619 var idlDomExpected = typeInfo.idlDomExpected.map(function(val) { return val === null ? defaultVal : val; });
620 var idlIdlExpected = typeInfo.idlIdlExpected.map(function(val) { return val === null ? defaultVal : val; });
621 switch (data.type) {
622 // Extra tests and other special-casing
623 case "boolean":
624 domTests.push(domName);
625 domExpected.push(true);
626 break;
627
628 case "enum":
629 // Whee, enum is complicated.
630 if (typeof data.invalidVal == "undefined") {
631 data.invalidVal = defaultVal;
632 }
633 if (typeof data.nonCanon == "undefined") {
634 data.nonCanon = {};
635 }
636 for (var i = 0; i < data.keywords.length; i++) {
637 if (data.keywords[i] != "") {
638 domTests.push(data.keywords[i], "x" + data.keywords[i], data.key words[i] + "\0");
639 idlTests.push(data.keywords[i], "x" + data.keywords[i], data.key words[i] + "\0");
640 }
641
642 if (data.keywords[i].length > 1) {
643 domTests.push(data.keywords[i].slice(1));
644 idlTests.push(data.keywords[i].slice(1));
645 }
646
647 if (data.keywords[i] != data.keywords[i].toLowerCase()) {
648 domTests.push(data.keywords[i].toLowerCase());
649 idlTests.push(data.keywords[i].toLowerCase());
650 }
651 if (data.keywords[i] != data.keywords[i].toUpperCase()) {
652 domTests.push(data.keywords[i].toUpperCase());
653 idlTests.push(data.keywords[i].toUpperCase());
654 }
655 }
656
657 // Per spec, the expected DOM values are the same as the value we set
658 // it to.
659 if (!data.isNullable) {
660 idlDomExpected = idlTests.slice(0);
661 } else {
662 idlDomExpected = [];
663 for (var i = 0; i < idlTests.length; i++) {
664 idlDomExpected.push((idlTests[i] === null || idlTests[i] === und efined) ? null : idlTests[i]);
665 }
666 }
667
668 // Now we have the fun of calculating what the expected IDL values are.
669 domExpected = [];
670 idlIdlExpected = [];
671 for (var i = 0; i < domTests.length; i++) {
672 domExpected.push(this.enumExpected(data.keywords, data.nonCanon, dat a.invalidVal, domTests[i]));
673 }
674 for (var i = 0; i < idlTests.length; i++) {
675 if (data.isNullable && (idlTests[i] === null || idlTests[i] === unde fined)) {
676 idlIdlExpected.push(null);
677 } else {
678 idlIdlExpected.push(this.enumExpected(data.keywords, data.nonCan on, data.invalidVal, idlTests[i]));
679 }
680 }
681 break;
682
683 case "string":
684 if ("treatNullAsEmptyString" in data) {
685 for (var i = 0; i < idlTests.length; i++) {
686 if (idlTests[i] === null) {
687 idlDomExpected[i] = idlIdlExpected[i] = "";
688 }
689 }
690 }
691 break;
692 }
693 if (domObj.tagName.toLowerCase() == "canvas" && (domName == "width" || domNa me == "height")) {
694 // Opera tries to allocate a canvas with the given width and height, so
695 // it OOMs when given excessive sizes. This is permissible under the
696 // hardware-limitations clause, so cut out those checks. TODO: Must be
697 // a way to make this more succinct.
698 domTests = domTests.filter(function(element, index, array) { return domE xpected[index] < 1000; });
699 domExpected = domExpected.filter(function(element, index, array) { retur n element < 1000; });
700 idlTests = idlTests.filter(function(element, index, array) { return idlI dlExpected[index] < 1000; });
701 idlDomExpected = idlDomExpected.filter(function(element, index, array) { return idlIdlExpected[index] < 1000; });
702 idlIdlExpected = idlIdlExpected.filter(function(element, index, array) { return idlIdlExpected[index] < 1000; });
703 }
704
705 if (!data.customGetter) {
706 for (var i = 0; i < domTests.length; i++) {
707 if (domExpected[i] === null && !data.isNullable) {
708 // If you follow all the complicated logic here, you'll find tha t
709 // this will only happen if there's no expected value at all (li ke
710 // for tabIndex, where the default is too complicated). So skip
711 // the test.
712 continue;
713 }
714 try {
715 domObj.setAttribute(domName, domTests[i]);
716 ReflectionHarness.test(domObj.getAttribute(domName), String(domT ests[i]), "setAttribute() to " + ReflectionHarness.stringRep(domTests[i]) + " fo llowed by getAttribute()");
717 ReflectionHarness.test(idlObj[idlName], domExpected[i], "setAttr ibute() to " + ReflectionHarness.stringRep(domTests[i]) + " followed by IDL get" );
718 if (ReflectionHarness.catchUnexpectedExceptions) {
719 ReflectionHarness.success();
720 }
721 } catch (err) {
722 if (ReflectionHarness.catchUnexpectedExceptions) {
723 ReflectionHarness.failure("Exception thrown during tests wit h setAttribute() to " + ReflectionHarness.stringRep(domTests[i]));
724 } else {
725 throw err;
726 }
727 }
728 }
729 }
730
731 for (var i = 0; i < idlTests.length; i++) {
732 if ((data.type == "limited long" && idlTests[i] < 0) ||
733 (data.type == "limited unsigned long" && idlTests[i] == 0)) {
734 ReflectionHarness.testException("INDEX_SIZE_ERR", function() {
735 idlObj[idlName] = idlTests[i];
736 }, "IDL set to " + ReflectionHarness.stringRep(idlTests[i]) + " must throw INDEX_SIZE_ERR");
737 } else {
738 ReflectionHarness.run(function() {
739 idlObj[idlName] = idlTests[i];
740 if (data.type == "boolean") {
741 // Special case yay
742 ReflectionHarness.test(domObj.hasAttribute(domName), Boolean (idlTests[i]), "IDL set to " + ReflectionHarness.stringRep(idlTests[i]) + " foll owed by hasAttribute()");
743 } else if (idlDomExpected[i] !== null || data.isNullable) {
744 var expected = idlDomExpected[i] + "";
745 if (data.isNullable && idlDomExpected[i] === null) {
746 expected = null;
747 }
748 ReflectionHarness.test(domObj.getAttribute(domName), expecte d, "IDL set to " + ReflectionHarness.stringRep(idlTests[i]) + " followed by getA ttribute()");
749 }
750 if (idlIdlExpected[i] !== null || data.isNullable) {
751 ReflectionHarness.test(idlObj[idlName], idlIdlExpected[i], " IDL set to " + ReflectionHarness.stringRep(idlTests[i]) + " followed by IDL get" );
752 }
753 if (ReflectionHarness.catchUnexpectedExceptions) {
754 ReflectionHarness.success();
755 }
756 }, "IDL set to " + ReflectionHarness.stringRep(idlTests[i]) + " shou ld not throw");
757 }
758 }
759 };
760
761 /**
762 * If we have an enumerated attribute limited to the array of values in
763 * keywords, with nonCanon being a map of non-canonical values to their
764 * canonical equivalents, and invalidVal being the invalid value default (or ""
765 * for none), then what would we expect from an IDL get if the content
766 * attribute is equal to contentVal?
767 */
768 ReflectionTests.enumExpected = function(keywords, nonCanon, invalidVal, contentV al) {
769 var ret = invalidVal;
770 for (var i = 0; i < keywords.length; i++) {
771 if (String(contentVal).toLowerCase() == keywords[i].toLowerCase()) {
772 ret = keywords[i];
773 break;
774 }
775 }
776 if (typeof nonCanon[ret] != "undefined") {
777 return nonCanon[ret];
778 }
779 return ret;
780 };
781
782 /**
783 * Now we have the data structures that tell us which elements have which
784 * attributes.
785 *
786 * The elements object (which must have been defined in earlier files) is a map
787 * from element name to an object whose keys are IDL attribute names and whose
788 * values are types. A type is of the same format as
789 * ReflectionTests.reflects() accepts, except that there's an extra optional
790 * domAttrName key that gets passed as the fourth argument to reflects() if
791 * it's provided. (TODO: drop the fourth and fifth reflects() arguments and
792 * make it take them from the dictionary instead?)
793 */
794
795 // Now we actually run all the tests.
796 var unimplemented = [];
797 for (var element in elements) {
798 ReflectionTests.reflects("string", "title", element);
799 ReflectionTests.reflects("string", "lang", element);
800 ReflectionTests.reflects({type: "enum", keywords: ["ltr", "rtl", "auto"]}, " dir", element);
801 ReflectionTests.reflects("string", "className", element, "class");
802 ReflectionTests.reflects("tokenlist", "classList", element, "class");
803 ReflectionTests.reflects("boolean", "hidden", element);
804 ReflectionTests.reflects("string", "accessKey", element);
805 // Don't try to test the defaultVal -- it should be either 0 or -1, but the
806 // rules are complicated, and a lot of them are SHOULDs.
807 ReflectionTests.reflects({type: "long", defaultVal: null}, "tabIndex", eleme nt);
808 // TODO: classList, contextMenu, itemProp, itemRef, dropzone (require
809 // tokenlist support)
810
811 for (var idlAttrName in elements[element]) {
812 var type = elements[element][idlAttrName];
813 ReflectionTests.reflects(type, idlAttrName, element,
814 typeof type == "object" && "domAttrName" in type ? type.domAttrName : idlAttrName);
815 }
816 }
817
818 for (var i = 0; i < extraTests.length; i++) {
819 extraTests[i]();
820 }
821
822 var time = document.getElementById("time");
823 if (time) {
824 time.innerHTML = (new Date().getTime() - ReflectionTests.start)/1000;
825 }
826
827 if (unimplemented.length) {
828 var p = document.createElement("p");
829 p.textContent = "(Note: missing tests for types " + unimplemented.join(", ") + ".)";
830 document.body.appendChild(p);
831 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698