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

Side by Side Diff: LayoutTests/media/track/opera/resources/idlharness.js

Issue 441383002: Remove a few unused resources from Opera <track> tests (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 4 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 /*
2 Distributed under both the W3C Test Suite License [1] and the W3C
3 3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
4 policies and contribution forms [3].
5
6 [1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
7 [2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
8 [3] http://www.w3.org/2004/10/27-testcases
9 */
10
11 /*
12 * This file automatically generates browser tests for WebIDL interfaces, using
13 * the testharness.js framework. To use, first include the following:
14 *
15 * <script src=/resources/testharness.js></script>
16 * <script src=/resources/testharnessreport.js></script>
17 * <script src=/resources/WebIDLParser.js></script>
18 * <script src=/resources/idlharness.js></script>
19 *
20 * Then you'll need some type of IDLs. Here's some script that can be run on a
21 * spec written in HTML, which will grab all the elements with class="idl",
22 * concatenate them, and replace the body so you can copy-paste:
23 *
24 var s = "";
25 [].forEach.call(document.getElementsByClassName("idl"), function(idl) {
26 //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
27 if (!idl.classList.contains("extract"))
28 {
29 s += idl.textContent + "\n\n";
30 }
31 });
32 document.body.innerHTML = '<pre></pre>';
33 document.body.firstChild.textContent = s;
34 *
35 * (TODO: write this in Python or something so that it can be done from the
36 * command line instead.)
37 *
38 * Once you have that, put it in your script somehow. The easiest way is to
39 * embed it literally in an HTML file with <script type=text/plain> or similar,
40 * so that you don't have to do any escaping. Another possibility is to put it
41 * in a separate .idl file that's fetched via XHR or similar. Sample usage:
42 *
43 * var idl_array = new IdlArray();
44 * idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
45 * idl_array.add_idls("interface Document : Node { readonly attribute DOMStrin g URL; };");
46 * idl_array.add_objects({Document: ["document"]});
47 * idl_array.test();
48 *
49 * This tests that window.Document exists and meets all the requirements of
50 * WebIDL. It also tests that window.document (the result of evaluating the
51 * string "document") has URL and nodeName properties that behave as they
52 * should, and otherwise meets WebIDL's requirements for an object whose
53 * primary interface is Document. It does not test that window.Node exists,
54 * which is what you want if the Node interface is already tested in some other
55 * specification's suite and your specification only extends or refers to it.
56 * Of course, each IDL string can define many different things, and calls to
57 * add_objects() can register many different objects for different interfaces:
58 * this is a very simple example.
59 *
60 * TODO: Write assert_writable, assert_enumerable, assert_configurable and
61 * their inverses, and use those instead of just checking
62 * getOwnPropertyDescriptor.
63 *
64 * == Public methods of IdlArray ==
65 *
66 * IdlArray objects can be obtained with new IdlArray(). Anything not
67 * documented in this section should be considered an implementation detail,
68 * and outside callers should not use it.
69 *
70 * add_idls(idl_string):
71 * Parses idl_string (throwing on parse error) and adds the results to the
72 * IdlArray. All the definitions will be tested when you run test(). If
73 * some of the definitions refer to other definitions, those must be present
74 * too. For instance, if idl_string says that Document inherits from Node,
75 * the Node interface must also have been provided in some call to add_idls()
76 * or add_untested_idls().
77 *
78 * add_untested_idls(idl_string):
79 * Like add_idls(), but the definitions will not be tested. If an untested
80 * interface is added and then extended with a tested partial interface, the
81 * members of the partial interface will still be tested. Also, all the
82 * members will still be tested for objects added with add_objects(), because
83 * you probably want to test that (for instance) window.document has all the
84 * properties from Node, not just Document, even if the Node interface itself
85 * is tested in a different test suite.
86 *
87 * add_objects(dict):
88 * dict should be an object whose keys are the names of interfaces or
89 * exceptions, and whose values are arrays of strings. When an interface or
90 * exception is tested, every string registered for it with add_objects()
91 * will be evaluated, and tests will be run on the result to verify that it
92 * correctly implements that interface or exception. This is the only way to
93 * test anything about [NoInterfaceObject] interfaces, and there are many
94 * tests that can't be run on any interface without an object to fiddle with.
95 *
96 * The interface has to be the *primary* interface of all the objects
97 * provided. For example, don't pass {Node: ["document"]}, but rather
98 * {Document: ["document"]}. Assuming the Document interface was declared to
99 * inherit from Node, this will automatically test that document implements
100 * the Node interface too.
101 *
102 * Warning: methods will be called on any provided objects, in a manner that
103 * WebIDL requires be safe. For instance, if a method has mandatory
104 * arguments, the test suite will try calling it with too few arguments to
105 * see if it throws an exception. If an implementation incorrectly runs the
106 * function instead of throwing, this might have side effects, possibly even
107 * preventing the test suite from running correctly.
108 *
109 * prevent_multiple_testing(name):
110 * This is a niche method for use in case you're testing many objects that
111 * implement the same interfaces, and don't want to retest the same
112 * interfaces every single time. For instance, HTML defines many interfaces
113 * that all inherit from HTMLElement, so the HTML test suite has something
114 * like
115 * .add_objects({
116 * HTMLHtmlElement: ['document.documentElement'],
117 * HTMLHeadElement: ['document.head'],
118 * HTMLBodyElement: ['document.body'],
119 * ...
120 * })
121 * and so on for dozens of element types. This would mean that it would
122 * retest that each and every one of those elements implements HTMLElement,
123 * Element, and Node, which would be thousands of basically redundant tests.
124 * The test suite therefore calls prevent_multiple_testing("HTMLElement").
125 * This means that once one object has been tested to implement HTMLElement
126 * and its ancestors, no other object will be. Thus in the example code
127 * above, the harness would test that document.documentElement correctly
128 * implements HTMLHtmlElement, HTMLElement, Element, and Node; but
129 * document.head would only be tested for HTMLHeadElement, and so on for
130 * further objects.
131 *
132 * test():
133 * Run all tests. This should be called after you've called all other
134 * methods to add IDLs and objects.
135 */
136
137 /**
138 * Notes for people who want to edit this file (not just use it as a library):
139 *
140 * Most of the interesting stuff happens in the derived classes of IdlObject,
141 * especially IdlInterface. The entry point for all IdlObjects is .test(),
142 * which is called by IdlArray.test(). An IdlObject is conceptually just
143 * "thing we want to run tests on", and an IdlArray is an array of IdlObjects
144 * with some additional data thrown in.
145 *
146 * The object model is based on what WebIDLParser.js produces, which is in turn
147 * based on its pegjs grammar. If you want to figure out what properties an
148 * object will have from WebIDLParser.js, the best way is to look at the
149 * grammar:
150 *
151 * https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg
152 *
153 * So for instance:
154 *
155 * // interface definition
156 * interface
157 * = extAttrs:extendedAttributeList? S? "interface" S name:identifier w herit:ifInheritance? w "{" w mem:ifMember* w "}" w ";" w
158 * { return { type: "interface", name: name, inheritance: herit, membe rs: mem, extAttrs: extAttrs }; }
159 *
160 * This means that an "interface" object will have a .type property equal to
161 * the string "interface", a .name property equal to the identifier that the
162 * parser found, an .inheritance property equal to either null or the result of
163 * the "ifInheritance" production found elsewhere in the grammar, and so on.
164 * After each grammatical production is a JavaScript function in curly braces
165 * that gets called with suitable arguments and returns some JavaScript value.
166 *
167 * (Note that the version of WebIDLParser.js we use might sometimes be
168 * out-of-date or forked.)
169 *
170 * The members and methods of the classes defined by this file are all at least
171 * briefly documented, hopefully.
172 */
173 (function(){
174 "use strict";
175 /// Helpers ///
176 function constValue (cnt) {
177 if (cnt.type === "null") return null;
178 if (cnt.type === "NaN") return NaN;
179 if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity;
180 return cnt.value;
181 }
182
183 /// IdlArray ///
184 // Entry point
185 window.IdlArray = function()
186 //@{
187 {
188 /**
189 * A map from strings to the corresponding named IdlObject, such as
190 * IdlInterface or IdlException. These are the things that test() will run
191 * tests on.
192 */
193 this.members = {};
194
195 /**
196 * A map from strings to arrays of strings. The keys are interface or
197 * exception names, and are expected to also exist as keys in this.members
198 * (otherwise they'll be ignored). This is populated by add_objects() --
199 * see documentation at the start of the file. The actual tests will be
200 * run by calling this.members[name].test_object(obj) for each obj in
201 * this.objects[name]. obj is a string that will be eval'd to produce a
202 * JavaScript value, which is supposed to be an object implementing the
203 * given IdlObject (interface, exception, etc.).
204 */
205 this.objects = {};
206
207 /**
208 * When adding multiple collections of IDLs one at a time, an earlier one
209 * might contain a partial interface or implements statement that depends
210 * on a later one. Save these up and handle them right before we run
211 * tests.
212 *
213 * .partials is simply an array of objects from WebIDLParser.js'
214 * "partialinterface" production. .implements maps strings to arrays of
215 * strings, such that
216 *
217 * A implements B;
218 * A implements C;
219 * D implements E;
220 *
221 * results in { A: ["B", "C"], D: ["E"] }.
222 */
223 this.partials = [];
224 this["implements"] = {};
225 };
226
227 //@}
228 IdlArray.prototype.add_idls = function(raw_idls)
229 //@{
230 {
231 /** Entry point. See documentation at beginning of file. */
232 this.internal_add_idls(WebIDL2.parse(raw_idls));
233 };
234
235 //@}
236 IdlArray.prototype.add_untested_idls = function(raw_idls)
237 //@{
238 {
239 /** Entry point. See documentation at beginning of file. */
240 var parsed_idls = WebIDL2.parse(raw_idls);
241 for (var i = 0; i < parsed_idls.length; i++)
242 {
243 parsed_idls[i].untested = true;
244 if ("members" in parsed_idls[i])
245 {
246 for (var j = 0; j < parsed_idls[i].members.length; j++)
247 {
248 parsed_idls[i].members[j].untested = true;
249 }
250 }
251 }
252 this.internal_add_idls(parsed_idls);
253 };
254
255 //@}
256 IdlArray.prototype.internal_add_idls = function(parsed_idls)
257 //@{
258 {
259 /**
260 * Internal helper called by add_idls() and add_untested_idls().
261 * parsed_idls is an array of objects that come from WebIDLParser.js's
262 * "definitions" production. The add_untested_idls() entry point
263 * additionally sets an .untested property on each object (and its
264 * .members) so that they'll be skipped by test() -- they'll only be
265 * used for base interfaces of tested interfaces, return types, etc.
266 */
267 parsed_idls.forEach(function(parsed_idl)
268 {
269 if (parsed_idl.type == "interface" && parsed_idl.partial)
270 {
271 this.partials.push(parsed_idl);
272 return;
273 }
274
275 if (parsed_idl.type == "implements")
276 {
277 if (!(parsed_idl.target in this["implements"]))
278 {
279 this["implements"][parsed_idl.target] = [];
280 }
281 this["implements"][parsed_idl.target].push(parsed_idl["implements"]) ;
282 return;
283 }
284
285 parsed_idl.array = this;
286 if (parsed_idl.name in this.members)
287 {
288 throw "Duplicate identifier " + parsed_idl.name;
289 }
290 switch(parsed_idl.type)
291 {
292 case "interface":
293 this.members[parsed_idl.name] = new IdlInterface(parsed_idl);
294 break;
295
296 case "exception":
297 this.members[parsed_idl.name] = new IdlException(parsed_idl);
298 break;
299
300 case "dictionary":
301 // Nothing to test, but we need the dictionary info around for type
302 // checks
303 this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);
304 break;
305
306 case "typedef":
307 this.members[parsed_idl.name] = new IdlTypedef(parsed_idl);
308 break;
309
310 case "callback":
311 // TODO
312 console.log("callback not yet supported");
313 break;
314
315 case "enum":
316 this.members[parsed_idl.name] = new IdlEnum(parsed_idl);
317 break;
318
319 case "callback interface":
320 // TODO
321 console.log("callback interface not yet supported");
322 break;
323
324 default:
325 throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported ";
326 }
327 }.bind(this));
328 };
329
330 //@}
331 IdlArray.prototype.add_objects = function(dict)
332 //@{
333 {
334 /** Entry point. See documentation at beginning of file. */
335 for (var k in dict)
336 {
337 if (k in this.objects)
338 {
339 this.objects[k] = this.objects[k].concat(dict[k]);
340 }
341 else
342 {
343 this.objects[k] = dict[k];
344 }
345 }
346 };
347
348 //@}
349 IdlArray.prototype.prevent_multiple_testing = function(name)
350 //@{
351 {
352 /** Entry point. See documentation at beginning of file. */
353 this.members[name].prevent_multiple_testing = true;
354 };
355
356 //@}
357 IdlArray.prototype.recursively_get_implements = function(interface_name)
358 //@{
359 {
360 /**
361 * Helper function for test(). Returns an array of things that implement
362 * interface_name, so if the IDL contains
363 *
364 * A implements B;
365 * B implements C;
366 * B implements D;
367 *
368 * then recursively_get_implements("A") should return ["B", "C", "D"].
369 */
370 var ret = this["implements"][interface_name];
371 if (ret === undefined)
372 {
373 return [];
374 }
375 for (var i = 0; i < this["implements"][interface_name].length; i++)
376 {
377 ret = ret.concat(this.recursively_get_implements(ret[i]));
378 if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i]))
379 {
380 throw "Circular implements statements involving " + ret[i];
381 }
382 }
383 return ret;
384 };
385
386 //@}
387 IdlArray.prototype.test = function()
388 //@{
389 {
390 /** Entry point. See documentation at beginning of file. */
391
392 // First merge in all the partial interfaces and implements statements we
393 // encountered.
394 this.partials.forEach(function(parsed_idl)
395 {
396 if (!(parsed_idl.name in this.members)
397 || !(this.members[parsed_idl.name] instanceof IdlInterface))
398 {
399 throw "Partial interface " + parsed_idl.name + " with no original in terface";
400 }
401 if (parsed_idl.extAttrs)
402 {
403 parsed_idl.extAttrs.forEach(function(extAttr)
404 {
405 this.members[parsed_idl.name].extAttrs.push(extAttr);
406 }.bind(this));
407 }
408 parsed_idl.members.forEach(function(member)
409 {
410 this.members[parsed_idl.name].members.push(new IdlInterfaceMember(me mber));
411 }.bind(this));
412 }.bind(this));
413 this.partials = [];
414
415 for (var lhs in this["implements"])
416 {
417 this.recursively_get_implements(lhs).forEach(function(rhs)
418 {
419 var errStr = lhs + " implements " + rhs + ", but ";
420 if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";
421 if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface.";
422 if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";
423 if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";
424 this.members[rhs].members.forEach(function(member)
425 {
426 this.members[lhs].members.push(new IdlInterfaceMember(member));
427 }.bind(this));
428 }.bind(this));
429 }
430 this["implements"] = {};
431
432 // Now run test() on every member, and test_object() for every object.
433 for (var name in this.members)
434 {
435 this.members[name].test();
436 if (name in this.objects)
437 {
438 this.objects[name].forEach(function(str)
439 {
440 this.members[name].test_object(str);
441 }.bind(this));
442 }
443 }
444 };
445
446 //@}
447 IdlArray.prototype.assert_type_is = function(value, type)
448 //@{
449 {
450 /**
451 * Helper function that tests that value is an instance of type according
452 * to the rules of WebIDL. value is any JavaScript value, and type is an
453 * object produced by WebIDLParser.js' "type" production. That production
454 * is fairly elaborate due to the complexity of WebIDL's types, so it's
455 * best to look at the grammar to figure out what properties it might have.
456 */
457 if (type.idlType == "any")
458 {
459 // No assertions to make
460 return;
461 }
462
463 if (type.nullable && value === null)
464 {
465 // This is fine
466 return;
467 }
468
469 if (type.array)
470 {
471 // TODO: not supported yet
472 return;
473 }
474
475 if (type.sequence)
476 {
477 assert_true(Array.isArray(value), "is not array");
478 if (!value.length)
479 {
480 // Nothing we can do.
481 return;
482 }
483 this.assert_type_is(value[0], type.idlType.idlType);
484 return;
485 }
486
487 type = type.idlType;
488
489 switch(type)
490 {
491 case "void":
492 assert_equals(value, undefined);
493 return;
494
495 case "boolean":
496 assert_equals(typeof value, "boolean");
497 return;
498
499 case "byte":
500 assert_equals(typeof value, "number");
501 assert_equals(value, Math.floor(value), "not an integer");
502 assert_true(-128 <= value && value <= 127, "byte " + value + " not i n range [-128, 127]");
503 return;
504
505 case "octet":
506 assert_equals(typeof value, "number");
507 assert_equals(value, Math.floor(value), "not an integer");
508 assert_true(0 <= value && value <= 255, "octet " + value + " not in range [0, 255]");
509 return;
510
511 case "short":
512 assert_equals(typeof value, "number");
513 assert_equals(value, Math.floor(value), "not an integer");
514 assert_true(-32768 <= value && value <= 32767, "short " + value + " not in range [-32768, 32767]");
515 return;
516
517 case "unsigned short":
518 assert_equals(typeof value, "number");
519 assert_equals(value, Math.floor(value), "not an integer");
520 assert_true(0 <= value && value <= 65535, "unsigned short " + value + " not in range [0, 65535]");
521 return;
522
523 case "long":
524 assert_equals(typeof value, "number");
525 assert_equals(value, Math.floor(value), "not an integer");
526 assert_true(-2147483648 <= value && value <= 2147483647, "long " + v alue + " not in range [-2147483648, 2147483647]");
527 return;
528
529 case "unsigned long":
530 assert_equals(typeof value, "number");
531 assert_equals(value, Math.floor(value), "not an integer");
532 assert_true(0 <= value && value <= 4294967295, "unsigned long " + va lue + " not in range [0, 4294967295]");
533 return;
534
535 case "long long":
536 assert_equals(typeof value, "number");
537 return;
538
539 case "unsigned long long":
540 assert_equals(typeof value, "number");
541 assert_true(0 <= value, "unsigned long long is negative");
542 return;
543
544 case "float":
545 case "double":
546 case "unrestricted float":
547 case "unrestricted double":
548 // TODO: distinguish these cases
549 assert_equals(typeof value, "number");
550 return;
551
552 case "DOMString":
553 assert_equals(typeof value, "string");
554 return;
555
556 case "object":
557 assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function");
558 return;
559 }
560
561 if (!(type in this.members))
562 {
563 throw "Unrecognized type " + type;
564 }
565
566 if (this.members[type] instanceof IdlInterface)
567 {
568 // We don't want to run the full
569 // IdlInterface.prototype.test_instance_of, because that could result
570 // in an infinite loop. TODO: This means we don't have tests for
571 // NoInterfaceObject interfaces, and we also can't test objects that
572 // come from another window.
573 assert_true(typeof value == "object" || typeof value == "function", "wro ng type: not object or function");
574 if (value instanceof Object
575 && !this.members[type].has_extended_attribute("NoInterfaceObject")
576 && type in window)
577 {
578 assert_true(value instanceof window[type], "not instanceof " + type) ;
579 }
580 }
581 else if (this.members[type] instanceof IdlEnum)
582 {
583 assert_equals(typeof value, "string");
584 }
585 else if (this.members[type] instanceof IdlDictionary)
586 {
587 // TODO: Test when we actually have something to test this on
588 }
589 else if (this.members[type] instanceof IdlTypedef)
590 {
591 // TODO: Test when we actually have something to test this on
592 }
593 else
594 {
595 throw "Type " + type + " isn't an interface or dictionary";
596 }
597 };
598 //@}
599
600 /// IdlObject ///
601 function IdlObject() {}
602 IdlObject.prototype.test = function()
603 //@{
604 {
605 /**
606 * By default, this does nothing, so no actual tests are run for IdlObjects
607 * that don't define any (e.g., IdlDictionary at the time of this writing).
608 */
609 };
610
611 //@}
612 IdlObject.prototype.has_extended_attribute = function(name)
613 //@{
614 {
615 /**
616 * This is only meaningful for things that support extended attributes,
617 * such as interfaces, exceptions, and members.
618 */
619 return this.extAttrs.some(function(o)
620 {
621 return o.name == name;
622 });
623 };
624
625 //@}
626
627 /// IdlDictionary ///
628 // Used for IdlArray.prototype.assert_type_is
629 function IdlDictionary(obj)
630 //@{
631 {
632 /**
633 * obj is an object produced by the WebIDLParser.js "dictionary"
634 * production.
635 */
636
637 /** Self-explanatory. */
638 this.name = obj.name;
639
640 /** An array of objects produced by the "dictionaryMember" production. */
641 this.members = obj.members;
642
643 /**
644 * The name (as a string) of the dictionary type we inherit from, or null
645 * if there is none.
646 */
647 this.base = obj.inheritance;
648 }
649
650 //@}
651 IdlDictionary.prototype = Object.create(IdlObject.prototype);
652
653 /// IdlExceptionOrInterface ///
654 // Code sharing!
655 function IdlExceptionOrInterface(obj)
656 //@{
657 {
658 /**
659 * obj is an object produced by the WebIDLParser.js "exception" or
660 * "interface" production, as appropriate.
661 */
662
663 /** Self-explanatory. */
664 this.name = obj.name;
665
666 /** A back-reference to our IdlArray. */
667 this.array = obj.array;
668
669 /**
670 * An indicator of whether we should run tests on the (exception) interface
671 * object and (exception) interface prototype object. Tests on members are
672 * controlled by .untested on each member, not this.
673 */
674 this.untested = obj.untested;
675
676 /** An array of objects produced by the "ExtAttr" production. */
677 this.extAttrs = obj.extAttrs;
678
679 /** An array of IdlInterfaceMembers. */
680 this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); });
681
682 /**
683 * The name (as a string) of the type we inherit from, or null if there is
684 * none.
685 */
686 this.base = obj.inheritance;
687 }
688
689 //@}
690 IdlExceptionOrInterface.prototype = Object.create(IdlObject.prototype);
691 IdlExceptionOrInterface.prototype.test = function()
692 //@{
693 {
694 if (this.has_extended_attribute("NoInterfaceObject"))
695 {
696 // No tests to do without an instance. TODO: We should still be able
697 // to run tests on the prototype object, if we obtain one through some
698 // other means.
699 return;
700 }
701
702 if (!this.untested)
703 {
704 // First test things to do with the exception/interface object and
705 // exception/interface prototype object.
706 this.test_self();
707 }
708 // Then test things to do with its members (constants, fields, attributes,
709 // operations, . . .). These are run even if .untested is true, because
710 // members might themselves be marked as .untested. This might happen to
711 // interfaces if the interface itself is untested but a partial interface
712 // that extends it is tested -- then the interface itself and its initial
713 // members will be marked as untested, but the members added by the partial
714 // interface are still tested.
715 this.test_members();
716 };
717
718 //@}
719
720 /// IdlException ///
721 function IdlException(obj) { IdlExceptionOrInterface.call(this, obj); }
722 IdlException.prototype = Object.create(IdlExceptionOrInterface.prototype);
723 IdlException.prototype.test_self = function()
724 //@{
725 {
726 test(function()
727 {
728 // "For every exception that is not declared with the
729 // [NoInterfaceObject] extended attribute, a corresponding property
730 // must exist on the exception’s relevant namespace object. The name of
731 // the property is the identifier of the exception, and its value is an
732 // object called the exception interface object, which provides access
733 // to any constants that have been associated with the exception. The
734 // property has the attributes { [[Writable]]: true, [[Enumerable]]:
735 // false, [[Configurable]]: true }."
736 assert_own_property(window, this.name,
737 "window does not have own property " + format_value( this.name));
738 var desc = Object.getOwnPropertyDescriptor(window, this.name);
739 assert_false("get" in desc, "window's property " + format_value(this.nam e) + " has getter");
740 assert_false("set" in desc, "window's property " + format_value(this.nam e) + " has setter");
741 assert_true(desc.writable, "window's property " + format_value(this.name ) + " is not writable");
742 assert_false(desc.enumerable, "window's property " + format_value(this.n ame) + " is enumerable");
743 assert_true(desc.configurable, "window's property " + format_value(this. name) + " is not configurable");
744
745 // "The exception interface object for a given exception must be a
746 // function object."
747 // "If an object is defined to be a function object, then it has
748 // characteristics as follows:"
749 // "Its [[Prototype]] internal property is the Function prototype
750 // object."
751 // Note: This doesn't match browsers as of December 2011, see
752 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14813
753 assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototy pe,
754 "prototype of window's property " + format_value(this.name ) + " is not Function.prototype");
755 // "Its [[Get]] internal property is set as described in ECMA-262
756 // section 15.3.5.4."
757 // Not much to test for this.
758 // "Its [[Construct]] internal property is set as described in ECMA-262
759 // section 13.2.2."
760 // Tested below.
761 // "Its [[HasInstance]] internal property is set as described in
762 // ECMA-262 section 15.3.5.3, unless otherwise specified."
763 // TODO
764 // "Its [[Class]] internal property is “Function”."
765 // String() returns something implementation-dependent, because it
766 // calls Function#toString.
767 assert_class_string(window[this.name], "Function",
768 "class string of " + this.name);
769
770 // TODO: Test 4.9.1.1. Exception interface object [[Call]] method
771 // (which does not match browsers:
772 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14885)
773 }.bind(this), this.name + " exception: existence and properties of exception interface object");
774
775 test(function()
776 {
777 assert_own_property(window, this.name,
778 "window does not have own property " + format_value( this.name));
779
780 // "The exception interface object must also have a property named
781 // “prototype” with attributes { [[Writable]]: false, [[Enumerable]]:
782 // false, [[Configurable]]: false } whose value is an object called the
783 // exception interface prototype object. This object also provides
784 // access to the constants that are declared on the exception."
785 assert_own_property(window[this.name], "prototype",
786 'exception "' + this.name + '" does not have own pro perty "prototype"');
787 var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype ");
788 assert_false("get" in desc, this.name + ".prototype has getter");
789 assert_false("set" in desc, this.name + ".prototype has setter");
790 assert_false(desc.writable, this.name + ".prototype is writable");
791 assert_false(desc.enumerable, this.name + ".prototype is enumerable");
792 assert_false(desc.configurable, this.name + ".prototype is configurable" );
793
794 // "The exception interface prototype object for a given exception must
795 // have an internal [[Prototype]] property whose value is as follows:
796 //
797 // "If the exception is declared to inherit from another exception,
798 // then the value of the internal [[Prototype]] property is the
799 // exception interface prototype object for the inherited exception.
800 // "Otherwise, the exception is not declared to inherit from another
801 // exception. The value of the internal [[Prototype]] property is the
802 // Error prototype object ([ECMA-262], section 15.11.3.1)."
803 //
804 // Note: This doesn't match browsers as of December 2011, see
805 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14887.
806 var inherit_exception = this.base ? this.base : "Error";
807 assert_own_property(window, inherit_exception,
808 'should inherit from ' + inherit_exception + ', but window has no such property');
809 assert_own_property(window[inherit_exception], "prototype",
810 'should inherit from ' + inherit_exception + ', but that object has no "prototype" property');
811 assert_equals(Object.getPrototypeOf(window[this.name].prototype),
812 window[inherit_exception].prototype,
813 'prototype of ' + this.name + '.prototype is not ' + inher it_exception + '.prototype');
814
815 // "The class string of an exception interface prototype object is the
816 // concatenation of the exception’s identifier and the string
817 // “Prototype”."
818 assert_class_string(window[this.name].prototype, this.name + "Prototype" ,
819 "class string of " + this.name + ".prototype");
820 // TODO: Test String(), based on ES definition of
821 // Error.prototype.toString?
822 }.bind(this), this.name + " exception: existence and properties of exception interface prototype object");
823
824 test(function()
825 {
826 assert_own_property(window, this.name,
827 "window does not have own property " + format_value( this.name));
828 assert_own_property(window[this.name], "prototype",
829 'interface "' + this.name + '" does not have own pro perty "prototype"');
830
831 // "There must be a property named “name” on the exception interface
832 // prototype object with attributes { [[Writable]]: true,
833 // [[Enumerable]]: false, [[Configurable]]: true } and whose value is
834 // the identifier of the exception."
835 assert_own_property(window[this.name].prototype, "name",
836 'prototype object does not have own property "name"');
837 var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "name");
838 assert_false("get" in desc, this.name + ".prototype.name has getter");
839 assert_false("set" in desc, this.name + ".prototype.name has setter");
840 assert_true(desc.writable, this.name + ".prototype.name is not writable" );
841 assert_false(desc.enumerable, this.name + ".prototype.name is enumerable ");
842 assert_true(desc.configurable, this.name + ".prototype.name is not confi gurable");
843 assert_equals(desc.value, this.name, this.name + ".prototype.name has in correct value");
844 }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"name\" property");
845
846 test(function()
847 {
848 assert_own_property(window, this.name,
849 "window does not have own property " + format_value( this.name));
850 assert_own_property(window[this.name], "prototype",
851 'interface "' + this.name + '" does not have own pro perty "prototype"');
852
853 // "If the [NoInterfaceObject] extended attribute was not specified on
854 // the exception, then there must also be a property named
855 // “constructor” on the exception interface prototype object with
856 // attributes { [[Writable]]: true, [[Enumerable]]: false,
857 // [[Configurable]]: true } and whose value is a reference to the
858 // exception interface object for the exception."
859 assert_own_property(window[this.name].prototype, "constructor",
860 this.name + '.prototype does not have own property " constructor"');
861 var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor");
862 assert_false("get" in desc, this.name + ".prototype.constructor has gett er");
863 assert_false("set" in desc, this.name + ".prototype.constructor has sett er");
864 assert_true(desc.writable, this.name + ".prototype.constructor is not wr itable");
865 assert_false(desc.enumerable, this.name + ".prototype.constructor is enu merable");
866 assert_true(desc.configurable, this.name + ".prototype.constructor in no t configurable");
867 assert_equals(window[this.name].prototype.constructor, window[this.name] ,
868 this.name + '.prototype.constructor is not the same object as ' + this.name);
869 }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"constructor\" property");
870 };
871
872 //@}
873 IdlException.prototype.test_members = function()
874 //@{
875 {
876 for (var i = 0; i < this.members.length; i++)
877 {
878 var member = this.members[i];
879 if (member.untested)
880 {
881 continue;
882 }
883 if (member.type == "const" && member.name != "prototype")
884 {
885 test(function()
886 {
887 assert_own_property(window, this.name,
888 "window does not have own property " + forma t_value(this.name));
889
890 // "For each constant defined on the exception, there must be a
891 // corresponding property on the exception interface object, if
892 // it exists, if the identifier of the constant is not
893 // “prototype”."
894 assert_own_property(window[this.name], member.name);
895 // "The value of the property is the ECMAScript value that is
896 // equivalent to the constant’s IDL value, according to the
897 // rules in section 4.2 above."
898 assert_equals(window[this.name][member.name], constValue(member. value),
899 "property has wrong value");
900 // "The property has attributes { [[Writable]]: false,
901 // [[Enumerable]]: true, [[Configurable]]: false }."
902 var desc = Object.getOwnPropertyDescriptor(window[this.name], me mber.name);
903 assert_false("get" in desc, "property has getter");
904 assert_false("set" in desc, "property has setter");
905 assert_false(desc.writable, "property is writable");
906 assert_true(desc.enumerable, "property is not enumerable");
907 assert_false(desc.configurable, "property is configurable");
908 }.bind(this), this.name + " exception: constant " + member.name + " on exception interface object");
909 // "In addition, a property with the same characteristics must
910 // exist on the exception interface prototype object."
911 test(function()
912 {
913 assert_own_property(window, this.name,
914 "window does not have own property " + forma t_value(this.name));
915 assert_own_property(window[this.name], "prototype",
916 'exception "' + this.name + '" does not have own property "prototype"');
917
918 assert_own_property(window[this.name].prototype, member.name);
919 assert_equals(window[this.name].prototype[member.name], constVal ue(member.value),
920 "property has wrong value");
921 var desc = Object.getOwnPropertyDescriptor(window[this.name].pro totype, member.name);
922 assert_false("get" in desc, "property has getter");
923 assert_false("set" in desc, "property has setter");
924 assert_false(desc.writable, "property is writable");
925 assert_true(desc.enumerable, "property is not enumerable");
926 assert_false(desc.configurable, "property is configurable");
927 }.bind(this), this.name + " exception: constant " + member.name + " on exception interface prototype object");
928 }
929 else if (member.type == "field")
930 {
931 test(function()
932 {
933 assert_own_property(window, this.name,
934 "window does not have own property " + forma t_value(this.name));
935 assert_own_property(window[this.name], "prototype",
936 'exception "' + this.name + '" does not have own property "prototype"');
937
938 // "For each exception field, there must be a corresponding
939 // property on the exception interface prototype object, whose
940 // characteristics are as follows:
941 // "The name of the property is the identifier of the exception
942 // field."
943 assert_own_property(window[this.name].prototype, member.name);
944 // "The property has attributes { [[Get]]: G, [[Enumerable]]:
945 // true, [[Configurable]]: true }, where G is the exception
946 // field getter, defined below."
947 var desc = Object.getOwnPropertyDescriptor(window[this.name].pro totype, member.name);
948 assert_false("value" in desc, "property descriptor has value but is supposed to be accessor");
949 assert_false("writable" in desc, 'property descriptor has "writa ble" field but is supposed to be accessor');
950 // TODO: ES5 doesn't seem to say whether desc should have a
951 // .set property.
952 assert_true(desc.enumerable, "property is not enumerable");
953 assert_true(desc.configurable, "property is not configurable");
954 // "The exception field getter is a Function object whose
955 // behavior when invoked is as follows:"
956 assert_equals(typeof desc.get, "function", "typeof getter");
957 // "The value of the Function object’s “length” property is the
958 // Number value 0."
959 // This test is before the TypeError tests so that it's easiest
960 // to see that Firefox 11a1 only fails one assert in this test.
961 assert_equals(desc.get.length, 0, "getter length");
962 // "Let O be the result of calling ToObject on the this value.
963 // "If O is not a platform object representing an exception for
964 // the exception on which the exception field was declared,
965 // then throw a TypeError."
966 // TODO: Test on a platform object representing an exception.
967 assert_throws(new TypeError(), function()
968 {
969 window[this.name].prototype[member.name];
970 }.bind(this), "getting property on prototype object must throw T ypeError");
971 assert_throws(new TypeError(), function()
972 {
973 desc.get.call({});
974 }.bind(this), "calling getter on wrong object type must throw Ty peError");
975 }.bind(this), this.name + " exception: field " + member.name + " on exception interface prototype object");
976 }
977 }
978 };
979
980 //@}
981 IdlException.prototype.test_object = function(desc)
982 //@{
983 {
984 var obj, exception = null;
985 try
986 {
987 obj = eval(desc);
988 }
989 catch(e)
990 {
991 exception = e;
992 }
993
994 test(function()
995 {
996 assert_equals(exception, null, "Unexpected exception when evaluating obj ect");
997 assert_equals(typeof obj, "object", "wrong typeof object");
998
999 // We can't easily test that its prototype is correct if there's no
1000 // interface object, or the object is from a different global
1001 // environment (not instanceof Object). TODO: test in this case that
1002 // its prototype at least looks correct, even if we can't test that
1003 // it's actually correct.
1004 if (!this.has_extended_attribute("NoInterfaceObject")
1005 && (typeof obj != "object" || obj instanceof Object))
1006 {
1007 assert_own_property(window, this.name,
1008 "window does not have own property " + format_va lue(this.name));
1009 assert_own_property(window[this.name], "prototype",
1010 'exception "' + this.name + '" does not have own property "prototype"');
1011
1012 // "The value of the internal [[Prototype]] property of the
1013 // exception object must be the exception interface prototype
1014 // object from the global environment the exception object is
1015 // associated with."
1016 assert_equals(Object.getPrototypeOf(obj),
1017 window[this.name].prototype,
1018 desc + "'s prototype is not " + this.name + ".prototyp e");
1019 }
1020
1021 // "The class string of the exception object must be the identifier of
1022 // the exception."
1023 assert_class_string(obj, this.name, "class string of " + desc);
1024 // Stringifier is not defined for DOMExceptions, because message isn't
1025 // defined.
1026 }.bind(this), this.name + " must be represented by " + desc);
1027
1028 for (var i = 0; i < this.members.length; i++)
1029 {
1030 var member = this.members[i];
1031 test(function()
1032 {
1033 assert_equals(exception, null, "Unexpected exception when evaluating object");
1034 assert_equals(typeof obj, "object", "wrong typeof object");
1035 assert_inherits(obj, member.name);
1036 if (member.type == "const")
1037 {
1038 assert_equals(obj[member.name], constValue(member.value));
1039 }
1040 if (member.type == "field")
1041 {
1042 this.array.assert_type_is(obj[member.name], member.idlType);
1043 }
1044 }.bind(this), this.name + " exception: " + desc + ' must inherit propert y "' + member.name + '" with the proper type');
1045 }
1046 };
1047 //@}
1048
1049 /// IdlInterface ///
1050 function IdlInterface(obj) { IdlExceptionOrInterface.call(this, obj); }
1051 IdlInterface.prototype = Object.create(IdlExceptionOrInterface.prototype);
1052 IdlInterface.prototype.is_callback = function()
1053 //@{
1054 {
1055 return this.has_extended_attribute("Callback");
1056 };
1057 //@}
1058
1059 IdlInterface.prototype.has_constants = function()
1060 //@{
1061 {
1062 return this.members.some(function(member) {
1063 return member.type === "const";
1064 });
1065 };
1066 //@}
1067
1068 IdlInterface.prototype.test_self = function()
1069 //@{
1070 {
1071 test(function()
1072 {
1073 // This function tests WebIDL as of 2012-11-28.
1074
1075 // "For every interface that:
1076 // * is a callback interface that has constants declared on it, or
1077 // * is a non-callback interface that is not declared with the
1078 // [NoInterfaceObject] extended attribute,
1079 // a corresponding property MUST exist on the ECMAScript global object.
1080 // The name of the property is the identifier of the interface, and its
1081 // value is an object called the interface object.
1082 // The property has the attributes { [[Writable]]: true,
1083 // [[Enumerable]]: false, [[Configurable]]: true }."
1084 if (this.is_callback() && !this.has_constants()) {
1085 return;
1086 }
1087
1088 // TODO: Should we test here that the property is actually writable
1089 // etc., or trust getOwnPropertyDescriptor?
1090 assert_own_property(window, this.name,
1091 "window does not have own property " + format_value( this.name));
1092 var desc = Object.getOwnPropertyDescriptor(window, this.name);
1093 assert_false("get" in desc, "window's property " + format_value(this.nam e) + " has getter");
1094 assert_false("set" in desc, "window's property " + format_value(this.nam e) + " has setter");
1095 assert_true(desc.writable, "window's property " + format_value(this.name ) + " is not writable");
1096 assert_false(desc.enumerable, "window's property " + format_value(this.n ame) + " is enumerable");
1097 assert_true(desc.configurable, "window's property " + format_value(this. name) + " is not configurable");
1098
1099 if (this.is_callback()) {
1100 // "The internal [[Prototype]] property of an interface object for
1101 // a callback interface MUST be the Object.prototype object."
1102 assert_equals(Object.getPrototypeOf(window[this.name]), Object.proto type,
1103 "prototype of window's property " + format_value(this. name) + " is not Object.prototype");
1104
1105 return;
1106 }
1107
1108 // "The interface object for a given non-callback interface is a
1109 // function object."
1110 // "If an object is defined to be a function object, then it has
1111 // characteristics as follows:"
1112
1113 // "* Its [[Prototype]] internal property is the Function prototype
1114 // object."
1115 assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototy pe,
1116 "prototype of window's property " + format_value(this.name ) + " is not Function.prototype");
1117
1118 // "* Its [[Get]] internal property is set as described in ECMA-262
1119 // section 15.3.5.4."
1120 // Not much to test for this.
1121
1122 // "* Its [[Construct]] internal property is set as described in
1123 // ECMA-262 section 13.2.2."
1124 // Tested below if no constructor is defined. TODO: test constructors
1125 // if defined.
1126
1127 // "* Its [[HasInstance]] internal property is set as described in
1128 // ECMA-262 section 15.3.5.3, unless otherwise specified."
1129 // TODO
1130
1131 // "* Its [[NativeBrand]] internal property is “Function”."
1132 // String() returns something implementation-dependent, because it calls
1133 // Function#toString.
1134 assert_class_string(window[this.name], "Function", "class string of " + this.name);
1135
1136 if (!this.has_extended_attribute("Constructor")) {
1137 // "The internal [[Call]] method of the interface object behaves as
1138 // follows . . .
1139 //
1140 // "If I was not declared with a [Constructor] extended attribute,
1141 // then throw a TypeError."
1142 assert_throws(new TypeError(), function() {
1143 window[this.name]();
1144 }.bind(this), "interface object didn't throw TypeError when called a s a function");
1145 assert_throws(new TypeError(), function() {
1146 new window[this.name]();
1147 }.bind(this), "interface object didn't throw TypeError when called a s a constructor");
1148 }
1149 }.bind(this), this.name + " interface: existence and properties of interface object");
1150
1151 if (!this.is_callback()) {
1152 test(function() {
1153 // This function tests WebIDL as of 2013-08-25.
1154 // http://dev.w3.org/2006/webapi/WebIDL/#es-interface-call
1155
1156 assert_own_property(window, this.name,
1157 "window does not have own property " + format_va lue(this.name));
1158
1159 // "Interface objects for non-callback interfaces MUST have a
1160 // property named “length” with attributes { [[Writable]]: false,
1161 // [[Enumerable]]: false, [[Configurable]]: false } whose value is
1162 // a Number."
1163 assert_own_property(window[this.name], "length");
1164 var desc = Object.getOwnPropertyDescriptor(window[this.name], "lengt h");
1165 assert_false("get" in desc, this.name + ".length has getter");
1166 assert_false("set" in desc, this.name + ".length has setter");
1167 assert_false(desc.writable, this.name + ".length is writable");
1168 assert_false(desc.enumerable, this.name + ".length is enumerable");
1169 assert_false(desc.configurable, this.name + ".length is configurable ");
1170
1171 var constructors = this.extAttrs
1172 .filter(function(attr) { return attr.name == "Constructor"; });
1173 var expected_length;
1174 if (!constructors.length) {
1175 // "If the [Constructor] extended attribute, does not appear on
1176 // the interface definition, then the value is 0."
1177 expected_length = 0;
1178 } else {
1179 // "Otherwise, the value is determined as follows: . . .
1180 // "Return the length of the shortest argument list of the
1181 // entries in S."
1182 expected_length = constructors.map(function(attr) {
1183 return attr.arguments ? attr.arguments.filter(function(arg) {
1184 return !arg.optional;
1185 }).length : 0;
1186 })
1187 .reduce(function(m, n) { return Math.min(m, n); });
1188 }
1189 assert_equals(window[this.name].length, expected_length, "wrong valu e for " + this.name + ".length");
1190 }.bind(this), this.name + " interface object length");
1191 }
1192
1193 // TODO: Test named constructors if I find any interfaces that have them.
1194
1195 test(function()
1196 {
1197 assert_own_property(window, this.name,
1198 "window does not have own property " + format_value( this.name));
1199
1200 if (this.has_extended_attribute("Callback")) {
1201 assert_false("prototype" in window[this.name],
1202 this.name + ' should not have a "prototype" property');
1203 return;
1204 }
1205
1206 // "The interface object must also have a property named “prototype”
1207 // with attributes { [[Writable]]: false, [[Enumerable]]: false,
1208 // [[Configurable]]: false } whose value is an object called the
1209 // interface prototype object. This object has properties that
1210 // correspond to the attributes and operations defined on the
1211 // interface, and is described in more detail in section 4.5.3 below."
1212 assert_own_property(window[this.name], "prototype",
1213 'interface "' + this.name + '" does not have own pro perty "prototype"');
1214 var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype ");
1215 assert_false("get" in desc, this.name + ".prototype has getter");
1216 assert_false("set" in desc, this.name + ".prototype has setter");
1217 assert_false(desc.writable, this.name + ".prototype is writable");
1218 assert_false(desc.enumerable, this.name + ".prototype is enumerable");
1219 assert_false(desc.configurable, this.name + ".prototype is configurable" );
1220
1221 // Next, test that the [[Prototype]] of the interface prototype object
1222 // is correct. (This is made somewhat difficult by the existence of
1223 // [NoInterfaceObject].)
1224 // TODO: Aryeh thinks there's at least other place in this file where
1225 // we try to figure out if an interface prototype object is
1226 // correct. Consolidate that code.
1227
1228 // "The interface prototype object for a given interface A must have an
1229 // internal [[Prototype]] property whose value is as follows:
1230 // "If A is not declared to inherit from another interface, then the
1231 // value of the internal [[Prototype]] property of A is the Array
1232 // prototype object ([ECMA-262], section 15.4.4) if the interface was
1233 // declared with ArrayClass, or the Object prototype object otherwise
1234 // ([ECMA-262], section 15.2.4).
1235 // "Otherwise, A does inherit from another interface. The value of the
1236 // internal [[Prototype]] property of A is the interface prototype
1237 // object for the inherited interface."
1238 var inherit_interface, inherit_interface_has_interface_object;
1239 if (this.base) {
1240 inherit_interface = this.base;
1241 inherit_interface_has_interface_object =
1242 !this.array
1243 .members[inherit_interface]
1244 .has_extended_attribute("NoInterfaceObject");
1245 } else if (this.has_extended_attribute('ArrayClass')) {
1246 inherit_interface = 'Array';
1247 inherit_interface_has_interface_object = true;
1248 } else {
1249 inherit_interface = 'Object';
1250 inherit_interface_has_interface_object = true;
1251 }
1252 if (inherit_interface_has_interface_object) {
1253 assert_own_property(window, inherit_interface,
1254 'should inherit from ' + inherit_interface + ', but window has no such property');
1255 assert_own_property(window[inherit_interface], 'prototype',
1256 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property');
1257 assert_equals(Object.getPrototypeOf(window[this.name].prototype),
1258 window[inherit_interface].prototype,
1259 'prototype of ' + this.name + '.prototype is not ' + i nherit_interface + '.prototype');
1260 } else {
1261 // We can't test that we get the correct object, because this is the
1262 // only way to get our hands on it. We only test that its class
1263 // string, at least, is correct.
1264 assert_class_string(Object.getPrototypeOf(window[this.name].prototyp e),
1265 inherit_interface + 'Prototype',
1266 'Class name for prototype of ' + this.name +
1267 '.prototype is not "' + inherit_interface + 'Pro totype"');
1268 }
1269
1270 // "The class string of an interface prototype object is the
1271 // concatenation of the interface’s identifier and the string
1272 // “Prototype”."
1273 assert_class_string(window[this.name].prototype, this.name + "Prototype" ,
1274 "class string of " + this.name + ".prototype");
1275 // String() should end up calling {}.toString if nothing defines a
1276 // stringifier.
1277 if (!this.has_stringifier()) {
1278 assert_equals(String(window[this.name].prototype), "[object " + this .name + "Prototype]",
1279 "String(" + this.name + ".prototype)");
1280 }
1281 }.bind(this), this.name + " interface: existence and properties of interface prototype object");
1282
1283 test(function()
1284 {
1285 assert_own_property(window, this.name,
1286 "window does not have own property " + format_value( this.name));
1287
1288 if (this.has_extended_attribute("Callback")) {
1289 assert_false("prototype" in window[this.name],
1290 this.name + ' should not have a "prototype" property');
1291 return;
1292 }
1293
1294 assert_own_property(window[this.name], "prototype",
1295 'interface "' + this.name + '" does not have own pro perty "prototype"');
1296
1297 // "If the [NoInterfaceObject] extended attribute was not specified on
1298 // the interface, then the interface prototype object must also have a
1299 // property named “constructor” with attributes { [[Writable]]: true,
1300 // [[Enumerable]]: false, [[Configurable]]: true } whose value is a
1301 // reference to the interface object for the interface."
1302 assert_own_property(window[this.name].prototype, "constructor",
1303 this.name + '.prototype does not have own property " constructor"');
1304 var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor");
1305 assert_false("get" in desc, this.name + ".prototype.constructor has gett er");
1306 assert_false("set" in desc, this.name + ".prototype.constructor has sett er");
1307 assert_true(desc.writable, this.name + ".prototype.constructor is not wr itable");
1308 assert_false(desc.enumerable, this.name + ".prototype.constructor is enu merable");
1309 assert_true(desc.configurable, this.name + ".prototype.constructor in no t configurable");
1310 assert_equals(window[this.name].prototype.constructor, window[this.name] ,
1311 this.name + '.prototype.constructor is not the same object as ' + this.name);
1312 }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');
1313 };
1314
1315 //@}
1316 IdlInterface.prototype.test_members = function()
1317 //@{
1318 {
1319 for (var i = 0; i < this.members.length; i++)
1320 {
1321 var member = this.members[i];
1322 if (member.untested)
1323 {
1324 continue;
1325 }
1326 if (member.type == "const")
1327 {
1328 test(function()
1329 {
1330 assert_own_property(window, this.name,
1331 "window does not have own property " + forma t_value(this.name));
1332
1333 // "For each constant defined on an interface A, there must be
1334 // a corresponding property on the interface object, if it
1335 // exists."
1336 assert_own_property(window[this.name], member.name);
1337 // "The value of the property is that which is obtained by
1338 // converting the constant’s IDL value to an ECMAScript
1339 // value."
1340 assert_equals(window[this.name][member.name], constValue(member. value),
1341 "property has wrong value");
1342 // "The property has attributes { [[Writable]]: false,
1343 // [[Enumerable]]: true, [[Configurable]]: false }."
1344 var desc = Object.getOwnPropertyDescriptor(window[this.name], me mber.name);
1345 assert_false("get" in desc, "property has getter");
1346 assert_false("set" in desc, "property has setter");
1347 assert_false(desc.writable, "property is writable");
1348 assert_true(desc.enumerable, "property is not enumerable");
1349 assert_false(desc.configurable, "property is configurable");
1350 }.bind(this), this.name + " interface: constant " + member.name + " on interface object");
1351 // "In addition, a property with the same characteristics must
1352 // exist on the interface prototype object."
1353 test(function()
1354 {
1355 assert_own_property(window, this.name,
1356 "window does not have own property " + forma t_value(this.name));
1357
1358 if (this.has_extended_attribute("Callback")) {
1359 assert_false("prototype" in window[this.name],
1360 this.name + ' should not have a "prototype" pro perty');
1361 return;
1362 }
1363
1364 assert_own_property(window[this.name], "prototype",
1365 'interface "' + this.name + '" does not have own property "prototype"');
1366
1367 assert_own_property(window[this.name].prototype, member.name);
1368 assert_equals(window[this.name].prototype[member.name], constVal ue(member.value),
1369 "property has wrong value");
1370 var desc = Object.getOwnPropertyDescriptor(window[this.name], me mber.name);
1371 assert_false("get" in desc, "property has getter");
1372 assert_false("set" in desc, "property has setter");
1373 assert_false(desc.writable, "property is writable");
1374 assert_true(desc.enumerable, "property is not enumerable");
1375 assert_false(desc.configurable, "property is configurable");
1376 }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
1377 }
1378 else if (member.type == "attribute")
1379 {
1380 if (member.has_extended_attribute("Unforgeable"))
1381 {
1382 // We do the checks in test_interface_of instead
1383 continue;
1384 }
1385 test(function()
1386 {
1387 assert_own_property(window, this.name,
1388 "window does not have own property " + forma t_value(this.name));
1389 assert_own_property(window[this.name], "prototype",
1390 'interface "' + this.name + '" does not have own property "prototype"');
1391
1392 if (member["static"]) {
1393 assert_own_property(window[this.name], member.name,
1394 "The interface object must have a property " +
1395 format_value(member.name));
1396 }
1397 else
1398 {
1399 assert_true(member.name in window[this.name].prototype,
1400 "The prototype object must have a property " +
1401 format_value(member.name));
1402
1403 // TODO: Needs to test for LenientThis.
1404 assert_throws(new TypeError(), function() {
1405 window[this.name].prototype[member.name];
1406 }.bind(this), "getting property on prototype object must thr ow TypeError");
1407 do_interface_attribute_asserts(window[this.name].prototype, member);
1408 }
1409 }.bind(this), this.name + " interface: attribute " + member.name);
1410 }
1411 else if (member.type == "operation")
1412 {
1413 // TODO: Need to correctly handle multiple operations with the same
1414 // identifier.
1415 if (!member.name)
1416 {
1417 // Unnamed getter or such
1418 continue;
1419 }
1420 test(function()
1421 {
1422 assert_own_property(window, this.name,
1423 "window does not have own property " + forma t_value(this.name));
1424
1425 if (this.has_extended_attribute("Callback")) {
1426 assert_false("prototype" in window[this.name],
1427 this.name + ' should not have a "prototype" pro perty');
1428 return;
1429 }
1430
1431 assert_own_property(window[this.name], "prototype",
1432 'interface "' + this.name + '" does not have own property "prototype"');
1433
1434 // "For each unique identifier of an operation defined on the
1435 // interface, there must be a corresponding property on the
1436 // interface prototype object (if it is a regular operation) or
1437 // the interface object (if it is a static operation), unless
1438 // the effective overload set for that identifier and operation
1439 // and with an argument count of 0 (for the ECMAScript language
1440 // binding) has no entries."
1441 //
1442 var prototypeOrInterfaceObject;
1443 if (member["static"]) {
1444 assert_own_property(window[this.name], member.name,
1445 "interface prototype object missing static operation ");
1446 prototypeOrInterfaceObject = window[this.name];
1447 }
1448 else
1449 {
1450 assert_own_property(window[this.name].prototype, member.name ,
1451 "interface prototype object missing non-static opera tion");
1452 prototypeOrInterfaceObject = window[this.name].prototype;
1453 }
1454
1455 var desc = Object.getOwnPropertyDescriptor(prototypeOrInterfaceO bject, member.name);
1456 // "The property has attributes { [[Writable]]: true,
1457 // [[Enumerable]]: true, [[Configurable]]: true }."
1458 assert_false("get" in desc, "property has getter");
1459 assert_false("set" in desc, "property has setter");
1460 assert_true(desc.writable, "property is not writable");
1461 assert_true(desc.enumerable, "property is not enumerable");
1462 assert_true(desc.configurable, "property is not configurable");
1463 // "The value of the property is a Function object whose
1464 // behavior is as follows . . ."
1465 assert_equals(typeof prototypeOrInterfaceObject[member.name], "f unction",
1466 "property must be a function");
1467 // "The value of the Function object’s “length” property is
1468 // a Number determined as follows:
1469 // ". . .
1470 // "Return the length of the shortest argument list of the
1471 // entries in S."
1472 //
1473 // TODO: Doesn't handle overloading or variadic arguments.
1474 assert_equals(prototypeOrInterfaceObject[member.name].length,
1475 member.arguments.filter(function(arg) {
1476 return !arg.optional;
1477 }).length,
1478 "property has wrong .length");
1479
1480 // Make some suitable arguments
1481 var args = member.arguments.map(function(arg) {
1482 return create_suitable_object(arg.idlType);
1483 });
1484
1485 // "Let O be a value determined as follows:
1486 // ". . .
1487 // "Otherwise, throw a TypeError."
1488 // This should be hit if the operation is not static, there is
1489 // no [ImplicitThis] attribute, and the this value is null.
1490 //
1491 // TODO: We currently ignore the [ImplicitThis] case.
1492 if (!member["static"]) {
1493 assert_throws(new TypeError(), function() {
1494 window[this.name].prototype[member.name].apply(null, arg s);
1495 }, "calling operation with this = null didn't throw TypeErro r");
1496 }
1497
1498 // ". . . If O is not null and is also not a platform object
1499 // that implements interface I, throw a TypeError."
1500 //
1501 // TODO: Test a platform object that implements some other
1502 // interface. (Have to be sure to get inheritance right.)
1503 assert_throws(new TypeError(), function() {
1504 window[this.name].prototype[member.name].apply({}, args);
1505 }, "calling operation with this = {} didn't throw TypeError");
1506 }.bind(this), this.name + " interface: operation " + member.name +
1507 "(" + member.arguments.map(function(m) { return m.idlType.idlType; } ) +
1508 ")");
1509 }
1510 // TODO: check more member types, like stringifier
1511 }
1512 };
1513
1514 //@}
1515 IdlInterface.prototype.test_object = function(desc)
1516 //@{
1517 {
1518 var obj, exception = null;
1519 try
1520 {
1521 obj = eval(desc);
1522 }
1523 catch(e)
1524 {
1525 exception = e;
1526 }
1527
1528 // TODO: WebIDLParser doesn't currently support named legacycallers, so I'm
1529 // not sure what those would look like in the AST
1530 var expected_typeof = this.members.some(function(member)
1531 {
1532 return member.legacycaller
1533 || ("idlType" in member && member.idlType.legacycaller)
1534 || ("idlType" in member && typeof member.idlType == "object"
1535 && "idlType" in member.idlType && member.idlType.idlType == "legacyc aller");
1536 }) ? "function" : "object";
1537
1538 this.test_primary_interface_of(desc, obj, exception, expected_typeof);
1539 var current_interface = this;
1540 while (current_interface)
1541 {
1542 if (!(current_interface.name in this.array.members))
1543 {
1544 throw "Interface " + current_interface.name + " not found (inherited by " + this.name + ")";
1545 }
1546 if (current_interface.prevent_multiple_testing && current_interface.alre ady_tested)
1547 {
1548 return;
1549 }
1550 current_interface.test_interface_of(desc, obj, exception, expected_typeo f);
1551 current_interface = this.array.members[current_interface.base];
1552 }
1553 };
1554
1555 //@}
1556 IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception , expected_typeof)
1557 //@{
1558 {
1559 // We can't easily test that its prototype is correct if there's no
1560 // interface object, or the object is from a different global environment
1561 // (not instanceof Object). TODO: test in this case that its prototype at
1562 // least looks correct, even if we can't test that it's actually correct.
1563 if (!this.has_extended_attribute("NoInterfaceObject")
1564 && (typeof obj != expected_typeof || obj instanceof Object))
1565 {
1566 test(function()
1567 {
1568 assert_equals(exception, null, "Unexpected exception when evaluating object");
1569 assert_equals(typeof obj, expected_typeof, "wrong typeof object");
1570 assert_own_property(window, this.name,
1571 "window does not have own property " + format_va lue(this.name));
1572 assert_own_property(window[this.name], "prototype",
1573 'interface "' + this.name + '" does not have own property "prototype"');
1574
1575 // "The value of the internal [[Prototype]] property of the
1576 // platform object is the interface prototype object of the primary
1577 // interface from the platform object’s associated global
1578 // environment."
1579 assert_equals(Object.getPrototypeOf(obj),
1580 window[this.name].prototype,
1581 desc + "'s prototype is not " + this.name + ".prototyp e");
1582 }.bind(this), this.name + " must be primary interface of " + desc);
1583 }
1584
1585 // "The class string of a platform object that implements one or more
1586 // interfaces must be the identifier of the primary interface of the
1587 // platform object."
1588 test(function()
1589 {
1590 assert_equals(exception, null, "Unexpected exception when evaluating obj ect");
1591 assert_equals(typeof obj, expected_typeof, "wrong typeof object");
1592 assert_class_string(obj, this.name, "class string of " + desc);
1593 if (!this.has_stringifier())
1594 {
1595 assert_equals(String(obj), "[object " + this.name + "]", "String(" + desc + ")");
1596 }
1597 }.bind(this), "Stringification of " + desc);
1598 };
1599
1600 //@}
1601 IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect ed_typeof)
1602 //@{
1603 {
1604 // TODO: Indexed and named properties, more checks on interface members
1605 this.already_tested = true;
1606
1607 for (var i = 0; i < this.members.length; i++)
1608 {
1609 var member = this.members[i];
1610 if (member.has_extended_attribute("Unforgeable"))
1611 {
1612 test(function()
1613 {
1614 assert_equals(exception, null, "Unexpected exception when evalua ting object");
1615 assert_equals(typeof obj, expected_typeof, "wrong typeof object" );
1616 do_interface_attribute_asserts(obj, member);
1617 }.bind(this), this.name + " interface: " + desc + ' must have own pr operty "' + member.name + '"');
1618 }
1619 else if ((member.type == "const"
1620 || member.type == "attribute"
1621 || member.type == "operation")
1622 && member.name)
1623 {
1624 test(function()
1625 {
1626 assert_equals(exception, null, "Unexpected exception when evalua ting object");
1627 assert_equals(typeof obj, expected_typeof, "wrong typeof object" );
1628 if (!member["static"]) {
1629 assert_inherits(obj, member.name);
1630 if (member.type == "const")
1631 {
1632 assert_equals(obj[member.name], constValue(member.value) );
1633 }
1634 if (member.type == "attribute")
1635 {
1636 // Attributes are accessor properties, so they might
1637 // legitimately throw an exception rather than returning
1638 // anything.
1639 var property, thrown = false;
1640 try
1641 {
1642 property = obj[member.name];
1643 }
1644 catch (e)
1645 {
1646 thrown = true;
1647 }
1648 if (!thrown)
1649 {
1650 this.array.assert_type_is(property, member.idlType);
1651 }
1652 }
1653 if (member.type == "operation")
1654 {
1655 assert_equals(typeof obj[member.name], "function");
1656 }
1657 }
1658 }.bind(this), this.name + " interface: " + desc + ' must inherit pro perty "' + member.name + '" with the proper type (' + i + ')');
1659 }
1660 // TODO: This is wrong if there are multiple operations with the same
1661 // identifier.
1662 // TODO: Test passing arguments of the wrong type.
1663 if (member.type == "operation" && member.name && member.arguments.length )
1664 {
1665 test(function()
1666 {
1667 assert_equals(exception, null, "Unexpected exception when evalua ting object");
1668 assert_equals(typeof obj, expected_typeof, "wrong typeof object" );
1669 if (!member["static"]) {
1670 assert_inherits(obj, member.name);
1671 }
1672 else
1673 {
1674 assert_false(member.name in obj);
1675 }
1676 var args = [];
1677 for (var i = 0; i < member.arguments.length; i++)
1678 {
1679 if (member.arguments[i].optional)
1680 {
1681 break;
1682 }
1683 assert_throws(new TypeError(), function()
1684 {
1685 obj[member.name].apply(obj, args);
1686 }.bind(this), "Called with " + i + " arguments");
1687
1688 args.push(create_suitable_object(member.arguments[i].idlType ));
1689 }
1690 }.bind(this), this.name + " interface: calling " + member.name +
1691 "(" + member.arguments.map(function(m) { return m.idlType.idlType; } ) +
1692 ") on " + desc + " with too few arguments must throw TypeError");
1693 }
1694 }
1695 };
1696
1697 //@}
1698 IdlInterface.prototype.has_stringifier = function()
1699 //@{
1700 {
1701 if (this.members.some(function(member) { return member.stringifier; })) {
1702 return true;
1703 }
1704 if (this.base &&
1705 this.array.members[this.base].has_stringifier()) {
1706 return true;
1707 }
1708 return false;
1709 };
1710
1711 //@}
1712 function do_interface_attribute_asserts(obj, member)
1713 //@{
1714 {
1715 // "For each attribute defined on the interface, there must exist a
1716 // corresponding property. If the attribute was declared with the
1717 // [Unforgeable] extended attribute, then the property exists on every
1718 // object that implements the interface. Otherwise, it exists on the
1719 // interface’s interface prototype object."
1720 //
1721 // This is called by test_self() with the prototype as obj, and by
1722 // test_interface_of() with the object as obj.
1723 assert_own_property(obj, member.name);
1724
1725 // "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]:
1726 // true, [[Configurable]]: configurable }, where:
1727 // "configurable is false if the attribute was declared with the
1728 // [Unforgeable] extended attribute and true otherwise;
1729 // "G is the attribute getter, defined below; and
1730 // "S is the attribute setter, also defined below."
1731 var desc = Object.getOwnPropertyDescriptor(obj, member.name);
1732 assert_false("value" in desc, 'property descriptor has value but is supposed to be accessor');
1733 assert_false("writable" in desc, 'property descriptor has "writable" field b ut is supposed to be accessor');
1734 assert_true(desc.enumerable, "property is not enumerable");
1735 if (member.has_extended_attribute("Unforgeable"))
1736 {
1737 assert_false(desc.configurable, "[Unforgeable] property must not be conf igurable");
1738 }
1739 else
1740 {
1741 assert_true(desc.configurable, "property must be configurable");
1742 }
1743
1744 // "The attribute getter is a Function object whose behavior when invoked
1745 // is as follows:
1746 // "...
1747 // "The value of the Function object’s “length” property is the Number
1748 // value 0."
1749 assert_equals(typeof desc.get, "function", "getter must be Function");
1750 assert_equals(desc.get.length, 0, "getter length must be 0");
1751 // TODO: Account for LenientThis
1752 assert_throws(new TypeError(), function()
1753 {
1754 desc.get.call({});
1755 }.bind(this), "calling getter on wrong object type must throw TypeError");
1756
1757 // TODO: Test calling setter on the interface prototype (should throw
1758 // TypeError in most cases).
1759 //
1760 // "The attribute setter is undefined if the attribute is declared readonly
1761 // and has neither a [PutForwards] nor a [Replaceable] extended attribute
1762 // declared on it. Otherwise, it is a Function object whose behavior when
1763 // invoked is as follows:
1764 // "...
1765 // "The value of the Function object’s “length” property is the Number
1766 // value 1."
1767 if (member.readonly
1768 && !member.has_extended_attribute("PutForwards")
1769 && !member.has_extended_attribute("Replaceable"))
1770 {
1771 assert_equals(desc.set, undefined, "setter must be undefined for readonl y attributes");
1772 }
1773 else
1774 {
1775 assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes");
1776 assert_equals(desc.set.length, 1, "setter length must be 1");
1777 }
1778 }
1779 //@}
1780
1781 /// IdlInterfaceMember ///
1782 function IdlInterfaceMember(obj)
1783 //@{
1784 {
1785 /**
1786 * obj is an object produced by the WebIDLParser.js "ifMember" production.
1787 * We just forward all properties to this object without modification,
1788 * except for special extAttrs handling.
1789 */
1790 for (var k in obj)
1791 {
1792 this[k] = obj[k];
1793 }
1794 if (!("extAttrs" in this))
1795 {
1796 this.extAttrs = [];
1797 }
1798 }
1799
1800 //@}
1801 IdlInterfaceMember.prototype = Object.create(IdlObject.prototype);
1802
1803 /// Internal helper functions ///
1804 function create_suitable_object(type)
1805 //@{
1806 {
1807 /**
1808 * type is an object produced by the WebIDLParser.js "type" production. We
1809 * return a JavaScript value that matches the type, if we can figure out
1810 * how.
1811 */
1812 if (type.nullable)
1813 {
1814 return null;
1815 }
1816 switch (type.idlType)
1817 {
1818 case "any":
1819 case "boolean":
1820 return true;
1821
1822 case "byte": case "octet": case "short": case "unsigned short":
1823 case "long": case "unsigned long": case "long long":
1824 case "unsigned long long": case "float": case "double":
1825 case "unrestricted float": case "unrestricted double":
1826 return 7;
1827
1828 case "DOMString":
1829 return "foo";
1830
1831 case "object":
1832 return {a: "b"};
1833
1834 case "Node":
1835 return document.createTextNode("abc");
1836 }
1837 return null;
1838 }
1839 //@}
1840
1841 /// IdlEnum ///
1842 // Used for IdlArray.prototype.assert_type_is
1843 function IdlEnum(obj)
1844 //@{
1845 {
1846 /**
1847 * obj is an object produced by the WebIDLParser.js "dictionary"
1848 * production.
1849 */
1850
1851 /** Self-explanatory. */
1852 this.name = obj.name;
1853
1854 /** An array of values produced by the "enum" production. */
1855 this.values = obj.values;
1856
1857 }
1858 //@}
1859
1860 IdlEnum.prototype = Object.create(IdlObject.prototype);
1861
1862 /// IdlTypedef ///
1863 // Used for IdlArray.prototype.assert_type_is
1864 function IdlTypedef(obj)
1865 //@{
1866 {
1867 /**
1868 * obj is an object produced by the WebIDLParser.js "typedef"
1869 * production.
1870 */
1871
1872 /** Self-explanatory. */
1873 this.name = obj.name;
1874
1875 /** An array of values produced by the "typedef" production. */
1876 this.values = obj.values;
1877
1878 }
1879 //@}
1880
1881 IdlTypedef.prototype = Object.create(IdlObject.prototype);
1882
1883 }());
1884 // vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker:
OLDNEW
« no previous file with comments | « LayoutTests/media/track/opera/resources/WebIDLParser.js ('k') | LayoutTests/media/track/opera/resources/media/sunflower.mp4 » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698