| OLD | NEW |
| 1 /* | 1 /* |
| 2 Distributed under both the W3C Test Suite License [1] and the W3C | 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 | 3 3-clause BSD License [2]. To contribute to a W3C Test Suite, see the |
| 4 policies and contribution forms [3]. | 4 policies and contribution forms [3]. |
| 5 | 5 |
| 6 [1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license | 6 [1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license |
| 7 [2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license | 7 [2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license |
| 8 [3] http://www.w3.org/2004/10/27-testcases | 8 [3] http://www.w3.org/2004/10/27-testcases |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 /* | 11 /* For user documentation see docs/idlharness.md */ |
| 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 | 12 |
| 137 /** | 13 /** |
| 138 * Notes for people who want to edit this file (not just use it as a library): | 14 * Notes for people who want to edit this file (not just use it as a library): |
| 139 * | 15 * |
| 140 * Most of the interesting stuff happens in the derived classes of IdlObject, | 16 * Most of the interesting stuff happens in the derived classes of IdlObject, |
| 141 * especially IdlInterface. The entry point for all IdlObjects is .test(), | 17 * especially IdlInterface. The entry point for all IdlObjects is .test(), |
| 142 * which is called by IdlArray.test(). An IdlObject is conceptually just | 18 * 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 | 19 * "thing we want to run tests on", and an IdlArray is an array of IdlObjects |
| 144 * with some additional data thrown in. | 20 * with some additional data thrown in. |
| 145 * | 21 * |
| (...skipping 29 matching lines...) Expand all Loading... |
| 175 /// Helpers /// | 51 /// Helpers /// |
| 176 function constValue (cnt) { | 52 function constValue (cnt) { |
| 177 if (cnt.type === "null") return null; | 53 if (cnt.type === "null") return null; |
| 178 if (cnt.type === "NaN") return NaN; | 54 if (cnt.type === "NaN") return NaN; |
| 179 if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity; | 55 if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity; |
| 180 return cnt.value; | 56 return cnt.value; |
| 181 } | 57 } |
| 182 | 58 |
| 183 /// IdlArray /// | 59 /// IdlArray /// |
| 184 // Entry point | 60 // Entry point |
| 185 window.IdlArray = function() | 61 self.IdlArray = function() |
| 186 //@{ | 62 //@{ |
| 187 { | 63 { |
| 188 /** | 64 /** |
| 189 * A map from strings to the corresponding named IdlObject, such as | 65 * A map from strings to the corresponding named IdlObject, such as |
| 190 * IdlInterface or IdlException. These are the things that test() will run | 66 * IdlInterface or IdlException. These are the things that test() will run |
| 191 * tests on. | 67 * tests on. |
| 192 */ | 68 */ |
| 193 this.members = {}; | 69 this.members = {}; |
| 194 | 70 |
| 195 /** | 71 /** |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 } | 159 } |
| 284 | 160 |
| 285 parsed_idl.array = this; | 161 parsed_idl.array = this; |
| 286 if (parsed_idl.name in this.members) | 162 if (parsed_idl.name in this.members) |
| 287 { | 163 { |
| 288 throw "Duplicate identifier " + parsed_idl.name; | 164 throw "Duplicate identifier " + parsed_idl.name; |
| 289 } | 165 } |
| 290 switch(parsed_idl.type) | 166 switch(parsed_idl.type) |
| 291 { | 167 { |
| 292 case "interface": | 168 case "interface": |
| 293 this.members[parsed_idl.name] = new IdlInterface(parsed_idl); | 169 this.members[parsed_idl.name] = |
| 294 break; | 170 new IdlInterface(parsed_idl, /* is_callback = */ false); |
| 295 | |
| 296 case "exception": | |
| 297 this.members[parsed_idl.name] = new IdlException(parsed_idl); | |
| 298 break; | 171 break; |
| 299 | 172 |
| 300 case "dictionary": | 173 case "dictionary": |
| 301 // Nothing to test, but we need the dictionary info around for type | 174 // Nothing to test, but we need the dictionary info around for type |
| 302 // checks | 175 // checks |
| 303 this.members[parsed_idl.name] = new IdlDictionary(parsed_idl); | 176 this.members[parsed_idl.name] = new IdlDictionary(parsed_idl); |
| 304 break; | 177 break; |
| 305 | 178 |
| 306 case "typedef": | 179 case "typedef": |
| 307 this.members[parsed_idl.name] = new IdlTypedef(parsed_idl); | 180 this.members[parsed_idl.name] = new IdlTypedef(parsed_idl); |
| 308 break; | 181 break; |
| 309 | 182 |
| 310 case "callback": | 183 case "callback": |
| 311 // TODO | 184 // TODO |
| 312 console.log("callback not yet supported"); | 185 console.log("callback not yet supported"); |
| 313 break; | 186 break; |
| 314 | 187 |
| 315 case "enum": | 188 case "enum": |
| 316 this.members[parsed_idl.name] = new IdlEnum(parsed_idl); | 189 this.members[parsed_idl.name] = new IdlEnum(parsed_idl); |
| 317 break; | 190 break; |
| 318 | 191 |
| 319 case "callback interface": | 192 case "callback interface": |
| 320 // TODO | 193 this.members[parsed_idl.name] = |
| 321 console.log("callback interface not yet supported"); | 194 new IdlInterface(parsed_idl, /* is_callback = */ true); |
| 322 break; | 195 break; |
| 323 | 196 |
| 324 default: | 197 default: |
| 325 throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported
"; | 198 throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported
"; |
| 326 } | 199 } |
| 327 }.bind(this)); | 200 }.bind(this)); |
| 328 }; | 201 }; |
| 329 | 202 |
| 330 //@} | 203 //@} |
| 331 IdlArray.prototype.add_objects = function(dict) | 204 IdlArray.prototype.add_objects = function(dict) |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 assert_equals(typeof value, "number"); | 403 assert_equals(typeof value, "number"); |
| 531 assert_equals(value, Math.floor(value), "not an integer"); | 404 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]"); | 405 assert_true(0 <= value && value <= 4294967295, "unsigned long " + va
lue + " not in range [0, 4294967295]"); |
| 533 return; | 406 return; |
| 534 | 407 |
| 535 case "long long": | 408 case "long long": |
| 536 assert_equals(typeof value, "number"); | 409 assert_equals(typeof value, "number"); |
| 537 return; | 410 return; |
| 538 | 411 |
| 539 case "unsigned long long": | 412 case "unsigned long long": |
| 413 case "DOMTimeStamp": |
| 540 assert_equals(typeof value, "number"); | 414 assert_equals(typeof value, "number"); |
| 541 assert_true(0 <= value, "unsigned long long is negative"); | 415 assert_true(0 <= value, "unsigned long long is negative"); |
| 542 return; | 416 return; |
| 543 | 417 |
| 544 case "float": | 418 case "float": |
| 545 case "double": | 419 case "double": |
| 420 case "DOMHighResTimeStamp": |
| 546 case "unrestricted float": | 421 case "unrestricted float": |
| 547 case "unrestricted double": | 422 case "unrestricted double": |
| 548 // TODO: distinguish these cases | 423 // TODO: distinguish these cases |
| 549 assert_equals(typeof value, "number"); | 424 assert_equals(typeof value, "number"); |
| 550 return; | 425 return; |
| 551 | 426 |
| 552 case "DOMString": | 427 case "DOMString": |
| 428 case "ByteString": |
| 429 case "USVString": |
| 430 // TODO: https://github.com/w3c/testharness.js/issues/92 |
| 553 assert_equals(typeof value, "string"); | 431 assert_equals(typeof value, "string"); |
| 554 return; | 432 return; |
| 555 | 433 |
| 556 case "object": | 434 case "object": |
| 557 assert_true(typeof value == "object" || typeof value == "function",
"wrong type: not object or function"); | 435 assert_true(typeof value == "object" || typeof value == "function",
"wrong type: not object or function"); |
| 558 return; | 436 return; |
| 559 } | 437 } |
| 560 | 438 |
| 561 if (!(type in this.members)) | 439 if (!(type in this.members)) |
| 562 { | 440 { |
| 563 throw "Unrecognized type " + type; | 441 throw "Unrecognized type " + type; |
| 564 } | 442 } |
| 565 | 443 |
| 566 if (this.members[type] instanceof IdlInterface) | 444 if (this.members[type] instanceof IdlInterface) |
| 567 { | 445 { |
| 568 // We don't want to run the full | 446 // We don't want to run the full |
| 569 // IdlInterface.prototype.test_instance_of, because that could result | 447 // IdlInterface.prototype.test_instance_of, because that could result |
| 570 // in an infinite loop. TODO: This means we don't have tests for | 448 // in an infinite loop. TODO: This means we don't have tests for |
| 571 // NoInterfaceObject interfaces, and we also can't test objects that | 449 // NoInterfaceObject interfaces, and we also can't test objects that |
| 572 // come from another window. | 450 // come from another self. |
| 573 assert_true(typeof value == "object" || typeof value == "function", "wro
ng type: not object or function"); | 451 assert_true(typeof value == "object" || typeof value == "function", "wro
ng type: not object or function"); |
| 574 if (value instanceof Object | 452 if (value instanceof Object |
| 575 && !this.members[type].has_extended_attribute("NoInterfaceObject") | 453 && !this.members[type].has_extended_attribute("NoInterfaceObject") |
| 576 && type in window) | 454 && type in self) |
| 577 { | 455 { |
| 578 assert_true(value instanceof window[type], "not instanceof " + type)
; | 456 assert_true(value instanceof self[type], "not instanceof " + type); |
| 579 } | 457 } |
| 580 } | 458 } |
| 581 else if (this.members[type] instanceof IdlEnum) | 459 else if (this.members[type] instanceof IdlEnum) |
| 582 { | 460 { |
| 583 assert_equals(typeof value, "string"); | 461 assert_equals(typeof value, "string"); |
| 584 } | 462 } |
| 585 else if (this.members[type] instanceof IdlDictionary) | 463 else if (this.members[type] instanceof IdlDictionary) |
| 586 { | 464 { |
| 587 // TODO: Test when we actually have something to test this on | 465 // TODO: Test when we actually have something to test this on |
| 588 } | 466 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 643 /** | 521 /** |
| 644 * The name (as a string) of the dictionary type we inherit from, or null | 522 * The name (as a string) of the dictionary type we inherit from, or null |
| 645 * if there is none. | 523 * if there is none. |
| 646 */ | 524 */ |
| 647 this.base = obj.inheritance; | 525 this.base = obj.inheritance; |
| 648 } | 526 } |
| 649 | 527 |
| 650 //@} | 528 //@} |
| 651 IdlDictionary.prototype = Object.create(IdlObject.prototype); | 529 IdlDictionary.prototype = Object.create(IdlObject.prototype); |
| 652 | 530 |
| 653 /// IdlExceptionOrInterface /// | 531 /// IdlInterface /// |
| 654 // Code sharing! | 532 function IdlInterface(obj, is_callback) { |
| 655 function IdlExceptionOrInterface(obj) | |
| 656 //@{ | |
| 657 { | |
| 658 /** | 533 /** |
| 659 * obj is an object produced by the WebIDLParser.js "exception" or | 534 * obj is an object produced by the WebIDLParser.js "exception" or |
| 660 * "interface" production, as appropriate. | 535 * "interface" production, as appropriate. |
| 661 */ | 536 */ |
| 662 | 537 |
| 663 /** Self-explanatory. */ | 538 /** Self-explanatory. */ |
| 664 this.name = obj.name; | 539 this.name = obj.name; |
| 665 | 540 |
| 666 /** A back-reference to our IdlArray. */ | 541 /** A back-reference to our IdlArray. */ |
| 667 this.array = obj.array; | 542 this.array = obj.array; |
| 668 | 543 |
| 669 /** | 544 /** |
| 670 * An indicator of whether we should run tests on the (exception) interface | 545 * An indicator of whether we should run tests on the (exception) interface |
| 671 * object and (exception) interface prototype object. Tests on members are | 546 * object and (exception) interface prototype object. Tests on members are |
| 672 * controlled by .untested on each member, not this. | 547 * controlled by .untested on each member, not this. |
| 673 */ | 548 */ |
| 674 this.untested = obj.untested; | 549 this.untested = obj.untested; |
| 675 | 550 |
| 676 /** An array of objects produced by the "ExtAttr" production. */ | 551 /** An array of objects produced by the "ExtAttr" production. */ |
| 677 this.extAttrs = obj.extAttrs; | 552 this.extAttrs = obj.extAttrs; |
| 678 | 553 |
| 679 /** An array of IdlInterfaceMembers. */ | 554 /** An array of IdlInterfaceMembers. */ |
| 680 this.members = obj.members.map(function(m){return new IdlInterfaceMember(m);
}); | 555 this.members = obj.members.map(function(m){return new IdlInterfaceMember(m);
}); |
| 556 if (this.has_extended_attribute("Unforgeable")) { |
| 557 this.members |
| 558 .filter(function(m) { return !m["static"] && (m.type == "attribute"
|| m.type == "operation"); }) |
| 559 .forEach(function(m) { return m.isUnforgeable = true; }); |
| 560 } |
| 681 | 561 |
| 682 /** | 562 /** |
| 683 * The name (as a string) of the type we inherit from, or null if there is | 563 * The name (as a string) of the type we inherit from, or null if there is |
| 684 * none. | 564 * none. |
| 685 */ | 565 */ |
| 686 this.base = obj.inheritance; | 566 this.base = obj.inheritance; |
| 567 |
| 568 this._is_callback = is_callback; |
| 687 } | 569 } |
| 570 IdlInterface.prototype = Object.create(IdlObject.prototype); |
| 571 IdlInterface.prototype.is_callback = function() |
| 572 //@{ |
| 573 { |
| 574 return this._is_callback; |
| 575 }; |
| 576 //@} |
| 688 | 577 |
| 578 IdlInterface.prototype.has_constants = function() |
| 579 //@{ |
| 580 { |
| 581 return this.members.some(function(member) { |
| 582 return member.type === "const"; |
| 583 }); |
| 584 }; |
| 689 //@} | 585 //@} |
| 690 IdlExceptionOrInterface.prototype = Object.create(IdlObject.prototype); | 586 |
| 691 IdlExceptionOrInterface.prototype.test = function() | 587 IdlInterface.prototype.is_global = function() |
| 588 //@{ |
| 589 { |
| 590 return this.extAttrs.some(function(attribute) { |
| 591 return attribute.name === "Global" || |
| 592 attribute.name === "PrimaryGlobal"; |
| 593 }); |
| 594 }; |
| 595 //@} |
| 596 |
| 597 IdlInterface.prototype.test = function() |
| 692 //@{ | 598 //@{ |
| 693 { | 599 { |
| 694 if (this.has_extended_attribute("NoInterfaceObject")) | 600 if (this.has_extended_attribute("NoInterfaceObject")) |
| 695 { | 601 { |
| 696 // No tests to do without an instance. TODO: We should still be able | 602 // 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 | 603 // to run tests on the prototype object, if we obtain one through some |
| 698 // other means. | 604 // other means. |
| 699 return; | 605 return; |
| 700 } | 606 } |
| 701 | 607 |
| 702 if (!this.untested) | 608 if (!this.untested) |
| 703 { | 609 { |
| 704 // First test things to do with the exception/interface object and | 610 // First test things to do with the exception/interface object and |
| 705 // exception/interface prototype object. | 611 // exception/interface prototype object. |
| 706 this.test_self(); | 612 this.test_self(); |
| 707 } | 613 } |
| 708 // Then test things to do with its members (constants, fields, attributes, | 614 // Then test things to do with its members (constants, fields, attributes, |
| 709 // operations, . . .). These are run even if .untested is true, because | 615 // operations, . . .). These are run even if .untested is true, because |
| 710 // members might themselves be marked as .untested. This might happen to | 616 // members might themselves be marked as .untested. This might happen to |
| 711 // interfaces if the interface itself is untested but a partial interface | 617 // interfaces if the interface itself is untested but a partial interface |
| 712 // that extends it is tested -- then the interface itself and its initial | 618 // 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 | 619 // members will be marked as untested, but the members added by the partial |
| 714 // interface are still tested. | 620 // interface are still tested. |
| 715 this.test_members(); | 621 this.test_members(); |
| 716 }; | 622 }; |
| 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 //@} | 623 //@} |
| 1067 | 624 |
| 1068 IdlInterface.prototype.test_self = function() | 625 IdlInterface.prototype.test_self = function() |
| 1069 //@{ | 626 //@{ |
| 1070 { | 627 { |
| 1071 test(function() | 628 test(function() |
| 1072 { | 629 { |
| 1073 // This function tests WebIDL as of 2012-11-28. | 630 // This function tests WebIDL as of 2015-01-13. |
| 631 // TODO: Consider [Exposed]. |
| 1074 | 632 |
| 1075 // "For every interface that: | 633 // "For every interface that is exposed in a given ECMAScript global |
| 634 // environment and: |
| 1076 // * is a callback interface that has constants declared on it, or | 635 // * is a callback interface that has constants declared on it, or |
| 1077 // * is a non-callback interface that is not declared with the | 636 // * is a non-callback interface that is not declared with the |
| 1078 // [NoInterfaceObject] extended attribute, | 637 // [NoInterfaceObject] extended attribute, |
| 1079 // a corresponding property MUST exist on the ECMAScript global object. | 638 // a corresponding property MUST exist on the ECMAScript global object. |
| 1080 // The name of the property is the identifier of the interface, and its | 639 // The name of the property is the identifier of the interface, and its |
| 1081 // value is an object called the interface object. | 640 // value is an object called the interface object. |
| 1082 // The property has the attributes { [[Writable]]: true, | 641 // The property has the attributes { [[Writable]]: true, |
| 1083 // [[Enumerable]]: false, [[Configurable]]: true }." | 642 // [[Enumerable]]: false, [[Configurable]]: true }." |
| 1084 if (this.is_callback() && !this.has_constants()) { | 643 if (this.is_callback() && !this.has_constants()) { |
| 1085 return; | 644 return; |
| 1086 } | 645 } |
| 1087 | 646 |
| 1088 // TODO: Should we test here that the property is actually writable | 647 // TODO: Should we test here that the property is actually writable |
| 1089 // etc., or trust getOwnPropertyDescriptor? | 648 // etc., or trust getOwnPropertyDescriptor? |
| 1090 assert_own_property(window, this.name, | 649 assert_own_property(self, this.name, |
| 1091 "window does not have own property " + format_value(
this.name)); | 650 "self does not have own property " + format_value(th
is.name)); |
| 1092 var desc = Object.getOwnPropertyDescriptor(window, this.name); | 651 var desc = Object.getOwnPropertyDescriptor(self, this.name); |
| 1093 assert_false("get" in desc, "window's property " + format_value(this.nam
e) + " has getter"); | 652 assert_false("get" in desc, "self's property " + format_value(this.name)
+ " has getter"); |
| 1094 assert_false("set" in desc, "window's property " + format_value(this.nam
e) + " has setter"); | 653 assert_false("set" in desc, "self's property " + format_value(this.name)
+ " has setter"); |
| 1095 assert_true(desc.writable, "window's property " + format_value(this.name
) + " is not writable"); | 654 assert_true(desc.writable, "self's property " + format_value(this.name)
+ " is not writable"); |
| 1096 assert_false(desc.enumerable, "window's property " + format_value(this.n
ame) + " is enumerable"); | 655 assert_false(desc.enumerable, "self's property " + format_value(this.nam
e) + " is enumerable"); |
| 1097 assert_true(desc.configurable, "window's property " + format_value(this.
name) + " is not configurable"); | 656 assert_true(desc.configurable, "self's property " + format_value(this.na
me) + " is not configurable"); |
| 1098 | 657 |
| 1099 if (this.is_callback()) { | 658 if (this.is_callback()) { |
| 1100 // "The internal [[Prototype]] property of an interface object for | 659 // "The internal [[Prototype]] property of an interface object for |
| 1101 // a callback interface MUST be the Object.prototype object." | 660 // a callback interface MUST be the Object.prototype object." |
| 1102 assert_equals(Object.getPrototypeOf(window[this.name]), Object.proto
type, | 661 assert_equals(Object.getPrototypeOf(self[this.name]), Object.prototy
pe, |
| 1103 "prototype of window's property " + format_value(this.
name) + " is not Object.prototype"); | 662 "prototype of self's property " + format_value(this.na
me) + " is not Object.prototype"); |
| 1104 | 663 |
| 1105 return; | 664 return; |
| 1106 } | 665 } |
| 1107 | 666 |
| 1108 // "The interface object for a given non-callback interface is a | 667 // "The interface object for a given non-callback interface is a |
| 1109 // function object." | 668 // function object." |
| 1110 // "If an object is defined to be a function object, then it has | 669 // "If an object is defined to be a function object, then it has |
| 1111 // characteristics as follows:" | 670 // characteristics as follows:" |
| 1112 | 671 |
| 1113 // "* Its [[Prototype]] internal property is the Function prototype | 672 // Its [[Prototype]] internal property is otherwise specified (see |
| 1114 // object." | 673 // below). |
| 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 | 674 |
| 1118 // "* Its [[Get]] internal property is set as described in ECMA-262 | 675 // "* Its [[Get]] internal property is set as described in ECMA-262 |
| 1119 // section 15.3.5.4." | 676 // section 9.1.8." |
| 1120 // Not much to test for this. | 677 // Not much to test for this. |
| 1121 | 678 |
| 1122 // "* Its [[Construct]] internal property is set as described in | 679 // "* Its [[Construct]] internal property is set as described in |
| 1123 // ECMA-262 section 13.2.2." | 680 // ECMA-262 section 19.2.2.3." |
| 1124 // Tested below if no constructor is defined. TODO: test constructors | 681 // Tested below if no constructor is defined. TODO: test constructors |
| 1125 // if defined. | 682 // if defined. |
| 1126 | 683 |
| 1127 // "* Its [[HasInstance]] internal property is set as described in | 684 // "* Its @@hasInstance property is set as described in ECMA-262 |
| 1128 // ECMA-262 section 15.3.5.3, unless otherwise specified." | 685 // section 19.2.3.8, unless otherwise specified." |
| 1129 // TODO | 686 // TODO |
| 1130 | 687 |
| 1131 // "* Its [[NativeBrand]] internal property is “Function”." | 688 // ES6 (rev 30) 19.1.3.6: |
| 1132 // String() returns something implementation-dependent, because it calls | 689 // "Else, if O has a [[Call]] internal method, then let builtinTag be |
| 1133 // Function#toString. | 690 // "Function"." |
| 1134 assert_class_string(window[this.name], "Function", "class string of " +
this.name); | 691 assert_class_string(self[this.name], "Function", "class string of " + th
is.name); |
| 692 |
| 693 // "The [[Prototype]] internal property of an interface object for a |
| 694 // non-callback interface is determined as follows:" |
| 695 var prototype = Object.getPrototypeOf(self[this.name]); |
| 696 if (this.base) { |
| 697 // "* If the interface inherits from some other interface, the |
| 698 // value of [[Prototype]] is the interface object for that other |
| 699 // interface." |
| 700 var has_interface_object = |
| 701 !this.array |
| 702 .members[this.base] |
| 703 .has_extended_attribute("NoInterfaceObject"); |
| 704 if (has_interface_object) { |
| 705 assert_own_property(self, this.base, |
| 706 'should inherit from ' + this.base + |
| 707 ', but self has no such property'); |
| 708 assert_equals(prototype, self[this.base], |
| 709 'prototype of ' + this.name + ' is not ' + |
| 710 this.base); |
| 711 } |
| 712 } else { |
| 713 // "If the interface doesn't inherit from any other interface, the |
| 714 // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262], |
| 715 // section 6.1.7.4)." |
| 716 assert_equals(prototype, Function.prototype, |
| 717 "prototype of self's property " + format_value(this.na
me) + " is not Function.prototype"); |
| 718 } |
| 1135 | 719 |
| 1136 if (!this.has_extended_attribute("Constructor")) { | 720 if (!this.has_extended_attribute("Constructor")) { |
| 1137 // "The internal [[Call]] method of the interface object behaves as | 721 // "The internal [[Call]] method of the interface object behaves as |
| 1138 // follows . . . | 722 // follows . . . |
| 1139 // | 723 // |
| 1140 // "If I was not declared with a [Constructor] extended attribute, | 724 // "If I was not declared with a [Constructor] extended attribute, |
| 1141 // then throw a TypeError." | 725 // then throw a TypeError." |
| 1142 assert_throws(new TypeError(), function() { | 726 assert_throws(new TypeError(), function() { |
| 1143 window[this.name](); | 727 self[this.name](); |
| 1144 }.bind(this), "interface object didn't throw TypeError when called a
s a function"); | 728 }.bind(this), "interface object didn't throw TypeError when called a
s a function"); |
| 1145 assert_throws(new TypeError(), function() { | 729 assert_throws(new TypeError(), function() { |
| 1146 new window[this.name](); | 730 new self[this.name](); |
| 1147 }.bind(this), "interface object didn't throw TypeError when called a
s a constructor"); | 731 }.bind(this), "interface object didn't throw TypeError when called a
s a constructor"); |
| 1148 } | 732 } |
| 1149 }.bind(this), this.name + " interface: existence and properties of interface
object"); | 733 }.bind(this), this.name + " interface: existence and properties of interface
object"); |
| 1150 | 734 |
| 1151 if (!this.is_callback()) { | 735 if (!this.is_callback()) { |
| 1152 test(function() { | 736 test(function() { |
| 1153 // This function tests WebIDL as of 2013-08-25. | 737 // This function tests WebIDL as of 2014-10-25. |
| 1154 // http://dev.w3.org/2006/webapi/WebIDL/#es-interface-call | 738 // https://heycam.github.io/webidl/#es-interface-call |
| 1155 | 739 |
| 1156 assert_own_property(window, this.name, | 740 assert_own_property(self, this.name, |
| 1157 "window does not have own property " + format_va
lue(this.name)); | 741 "self does not have own property " + format_valu
e(this.name)); |
| 1158 | 742 |
| 1159 // "Interface objects for non-callback interfaces MUST have a | 743 // "Interface objects for non-callback interfaces MUST have a |
| 1160 // property named “length” with attributes { [[Writable]]: false, | 744 // property named “length” with attributes { [[Writable]]: false, |
| 1161 // [[Enumerable]]: false, [[Configurable]]: false } whose value is | 745 // [[Enumerable]]: false, [[Configurable]]: true } whose value is |
| 1162 // a Number." | 746 // a Number." |
| 1163 assert_own_property(window[this.name], "length"); | 747 assert_own_property(self[this.name], "length"); |
| 1164 var desc = Object.getOwnPropertyDescriptor(window[this.name], "lengt
h"); | 748 var desc = Object.getOwnPropertyDescriptor(self[this.name], "length"
); |
| 1165 assert_false("get" in desc, this.name + ".length has getter"); | 749 assert_false("get" in desc, this.name + ".length has getter"); |
| 1166 assert_false("set" in desc, this.name + ".length has setter"); | 750 assert_false("set" in desc, this.name + ".length has setter"); |
| 1167 assert_false(desc.writable, this.name + ".length is writable"); | 751 assert_false(desc.writable, this.name + ".length is writable"); |
| 1168 assert_false(desc.enumerable, this.name + ".length is enumerable"); | 752 assert_false(desc.enumerable, this.name + ".length is enumerable"); |
| 1169 assert_false(desc.configurable, this.name + ".length is configurable
"); | 753 assert_true(desc.configurable, this.name + ".length is not configura
ble"); |
| 1170 | 754 |
| 1171 var constructors = this.extAttrs | 755 var constructors = this.extAttrs |
| 1172 .filter(function(attr) { return attr.name == "Constructor"; }); | 756 .filter(function(attr) { return attr.name == "Constructor"; }); |
| 1173 var expected_length; | 757 var expected_length; |
| 1174 if (!constructors.length) { | 758 if (!constructors.length) { |
| 1175 // "If the [Constructor] extended attribute, does not appear on | 759 // "If the [Constructor] extended attribute, does not appear on |
| 1176 // the interface definition, then the value is 0." | 760 // the interface definition, then the value is 0." |
| 1177 expected_length = 0; | 761 expected_length = 0; |
| 1178 } else { | 762 } else { |
| 1179 // "Otherwise, the value is determined as follows: . . . | 763 // "Otherwise, the value is determined as follows: . . . |
| 1180 // "Return the length of the shortest argument list of the | 764 // "Return the length of the shortest argument list of the |
| 1181 // entries in S." | 765 // entries in S." |
| 1182 expected_length = constructors.map(function(attr) { | 766 expected_length = constructors.map(function(attr) { |
| 1183 return attr.arguments ? attr.arguments.filter(function(arg)
{ | 767 return attr.arguments ? attr.arguments.filter(function(arg)
{ |
| 1184 return !arg.optional; | 768 return !arg.optional; |
| 1185 }).length : 0; | 769 }).length : 0; |
| 1186 }) | 770 }) |
| 1187 .reduce(function(m, n) { return Math.min(m, n); }); | 771 .reduce(function(m, n) { return Math.min(m, n); }); |
| 1188 } | 772 } |
| 1189 assert_equals(window[this.name].length, expected_length, "wrong valu
e for " + this.name + ".length"); | 773 assert_equals(self[this.name].length, expected_length, "wrong value
for " + this.name + ".length"); |
| 1190 }.bind(this), this.name + " interface object length"); | 774 }.bind(this), this.name + " interface object length"); |
| 1191 } | 775 } |
| 1192 | 776 |
| 1193 // TODO: Test named constructors if I find any interfaces that have them. | 777 // TODO: Test named constructors if I find any interfaces that have them. |
| 1194 | 778 |
| 1195 test(function() | 779 test(function() |
| 1196 { | 780 { |
| 1197 assert_own_property(window, this.name, | 781 // This function tests WebIDL as of 2015-01-21. |
| 1198 "window does not have own property " + format_value(
this.name)); | 782 // https://heycam.github.io/webidl/#interface-object |
| 1199 | 783 |
| 1200 if (this.has_extended_attribute("Callback")) { | 784 if (this.is_callback() && !this.has_constants()) { |
| 1201 assert_false("prototype" in window[this.name], | 785 return; |
| 786 } |
| 787 |
| 788 assert_own_property(self, this.name, |
| 789 "self does not have own property " + format_value(th
is.name)); |
| 790 |
| 791 if (this.is_callback()) { |
| 792 assert_false("prototype" in self[this.name], |
| 1202 this.name + ' should not have a "prototype" property'); | 793 this.name + ' should not have a "prototype" property'); |
| 1203 return; | 794 return; |
| 1204 } | 795 } |
| 1205 | 796 |
| 1206 // "The interface object must also have a property named “prototype” | 797 // "An interface object for a non-callback interface must have a |
| 1207 // with attributes { [[Writable]]: false, [[Enumerable]]: false, | 798 // property named “prototype” with attributes { [[Writable]]: false, |
| 1208 // [[Configurable]]: false } whose value is an object called the | 799 // [[Enumerable]]: false, [[Configurable]]: false } whose value is an |
| 1209 // interface prototype object. This object has properties that | 800 // object called the interface prototype object. This object has |
| 1210 // correspond to the attributes and operations defined on the | 801 // properties that correspond to the regular attributes and regular |
| 1211 // interface, and is described in more detail in section 4.5.3 below." | 802 // operations defined on the interface, and is described in more detail |
| 1212 assert_own_property(window[this.name], "prototype", | 803 // in section 4.5.4 below." |
| 804 assert_own_property(self[this.name], "prototype", |
| 1213 'interface "' + this.name + '" does not have own pro
perty "prototype"'); | 805 'interface "' + this.name + '" does not have own pro
perty "prototype"'); |
| 1214 var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype
"); | 806 var desc = Object.getOwnPropertyDescriptor(self[this.name], "prototype")
; |
| 1215 assert_false("get" in desc, this.name + ".prototype has getter"); | 807 assert_false("get" in desc, this.name + ".prototype has getter"); |
| 1216 assert_false("set" in desc, this.name + ".prototype has setter"); | 808 assert_false("set" in desc, this.name + ".prototype has setter"); |
| 1217 assert_false(desc.writable, this.name + ".prototype is writable"); | 809 assert_false(desc.writable, this.name + ".prototype is writable"); |
| 1218 assert_false(desc.enumerable, this.name + ".prototype is enumerable"); | 810 assert_false(desc.enumerable, this.name + ".prototype is enumerable"); |
| 1219 assert_false(desc.configurable, this.name + ".prototype is configurable"
); | 811 assert_false(desc.configurable, this.name + ".prototype is configurable"
); |
| 1220 | 812 |
| 1221 // Next, test that the [[Prototype]] of the interface prototype object | 813 // Next, test that the [[Prototype]] of the interface prototype object |
| 1222 // is correct. (This is made somewhat difficult by the existence of | 814 // is correct. (This is made somewhat difficult by the existence of |
| 1223 // [NoInterfaceObject].) | 815 // [NoInterfaceObject].) |
| 1224 // TODO: Aryeh thinks there's at least other place in this file where | 816 // 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 | 817 // we try to figure out if an interface prototype object is |
| 1226 // correct. Consolidate that code. | 818 // correct. Consolidate that code. |
| 1227 | 819 |
| 1228 // "The interface prototype object for a given interface A must have an | 820 // "The interface prototype object for a given interface A must have an |
| 1229 // internal [[Prototype]] property whose value is as follows: | 821 // internal [[Prototype]] property whose value is returned from the |
| 1230 // "If A is not declared to inherit from another interface, then the | 822 // following steps: |
| 1231 // value of the internal [[Prototype]] property of A is the Array | 823 // "If A is declared with the [Global] or [PrimaryGlobal] extended |
| 1232 // prototype object ([ECMA-262], section 15.4.4) if the interface was | 824 // attribute, and A supports named properties, then return the named |
| 1233 // declared with ArrayClass, or the Object prototype object otherwise | 825 // properties object for A, as defined in section 4.5.5 below. |
| 826 // "Otherwise, if A is declared to inherit from another interface, then |
| 827 // return the interface prototype object for the inherited interface. |
| 828 // "Otherwise, if A is declared with the [ArrayClass] extended |
| 829 // attribute, then return %ArrayPrototype% ([ECMA-262], section |
| 830 // 6.1.7.4). |
| 831 // "Otherwise, return %ObjectPrototype% ([ECMA-262], section 6.1.7.4). |
| 1234 // ([ECMA-262], section 15.2.4). | 832 // ([ECMA-262], section 15.2.4). |
| 1235 // "Otherwise, A does inherit from another interface. The value of the | 833 if (this.name === "Window") { |
| 1236 // internal [[Prototype]] property of A is the interface prototype | 834 assert_class_string(Object.getPrototypeOf(self[this.name].prototype)
, |
| 1237 // object for the inherited interface." | 835 'WindowProperties', |
| 1238 var inherit_interface, inherit_interface_has_interface_object; | 836 'Class name for prototype of Window' + |
| 1239 if (this.base) { | 837 '.prototype is not "WindowProperties"'); |
| 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 { | 838 } else { |
| 1249 inherit_interface = 'Object'; | 839 var inherit_interface, inherit_interface_has_interface_object; |
| 1250 inherit_interface_has_interface_object = true; | 840 if (this.base) { |
| 1251 } | 841 inherit_interface = this.base; |
| 1252 if (inherit_interface_has_interface_object) { | 842 inherit_interface_has_interface_object = |
| 1253 assert_own_property(window, inherit_interface, | 843 !this.array |
| 1254 'should inherit from ' + inherit_interface + ',
but window has no such property'); | 844 .members[inherit_interface] |
| 1255 assert_own_property(window[inherit_interface], 'prototype', | 845 .has_extended_attribute("NoInterfaceObject"); |
| 1256 'should inherit from ' + inherit_interface + ',
but that object has no "prototype" property'); | 846 } else if (this.has_extended_attribute('ArrayClass')) { |
| 1257 assert_equals(Object.getPrototypeOf(window[this.name].prototype), | 847 inherit_interface = 'Array'; |
| 1258 window[inherit_interface].prototype, | 848 inherit_interface_has_interface_object = true; |
| 1259 'prototype of ' + this.name + '.prototype is not ' + i
nherit_interface + '.prototype'); | 849 } else { |
| 1260 } else { | 850 inherit_interface = 'Object'; |
| 1261 // We can't test that we get the correct object, because this is the | 851 inherit_interface_has_interface_object = true; |
| 1262 // only way to get our hands on it. We only test that its class | 852 } |
| 1263 // string, at least, is correct. | 853 if (inherit_interface_has_interface_object) { |
| 1264 assert_class_string(Object.getPrototypeOf(window[this.name].prototyp
e), | 854 assert_own_property(self, inherit_interface, |
| 1265 inherit_interface + 'Prototype', | 855 'should inherit from ' + inherit_interface +
', but self has no such property'); |
| 1266 'Class name for prototype of ' + this.name + | 856 assert_own_property(self[inherit_interface], 'prototype', |
| 1267 '.prototype is not "' + inherit_interface + 'Pro
totype"'); | 857 'should inherit from ' + inherit_interface +
', but that object has no "prototype" property'); |
| 858 assert_equals(Object.getPrototypeOf(self[this.name].prototype), |
| 859 self[inherit_interface].prototype, |
| 860 'prototype of ' + this.name + '.prototype is not '
+ inherit_interface + '.prototype'); |
| 861 } else { |
| 862 // We can't test that we get the correct object, because this is
the |
| 863 // only way to get our hands on it. We only test that its class |
| 864 // string, at least, is correct. |
| 865 assert_class_string(Object.getPrototypeOf(self[this.name].protot
ype), |
| 866 inherit_interface + 'Prototype', |
| 867 'Class name for prototype of ' + this.name + |
| 868 '.prototype is not "' + inherit_interface +
'Prototype"'); |
| 869 } |
| 1268 } | 870 } |
| 1269 | 871 |
| 1270 // "The class string of an interface prototype object is the | 872 // "The class string of an interface prototype object is the |
| 1271 // concatenation of the interface’s identifier and the string | 873 // concatenation of the interface’s identifier and the string |
| 1272 // “Prototype”." | 874 // “Prototype”." |
| 1273 assert_class_string(window[this.name].prototype, this.name + "Prototype"
, | 875 assert_class_string(self[this.name].prototype, this.name + "Prototype", |
| 1274 "class string of " + this.name + ".prototype"); | 876 "class string of " + this.name + ".prototype"); |
| 1275 // String() should end up calling {}.toString if nothing defines a | 877 // String() should end up calling {}.toString if nothing defines a |
| 1276 // stringifier. | 878 // stringifier. |
| 1277 if (!this.has_stringifier()) { | 879 if (!this.has_stringifier()) { |
| 1278 assert_equals(String(window[this.name].prototype), "[object " + this
.name + "Prototype]", | 880 assert_equals(String(self[this.name].prototype), "[object " + this.n
ame + "Prototype]", |
| 1279 "String(" + this.name + ".prototype)"); | 881 "String(" + this.name + ".prototype)"); |
| 1280 } | 882 } |
| 1281 }.bind(this), this.name + " interface: existence and properties of interface
prototype object"); | 883 }.bind(this), this.name + " interface: existence and properties of interface
prototype object"); |
| 1282 | 884 |
| 1283 test(function() | 885 test(function() |
| 1284 { | 886 { |
| 1285 assert_own_property(window, this.name, | 887 if (this.is_callback() && !this.has_constants()) { |
| 1286 "window does not have own property " + format_value(
this.name)); | 888 return; |
| 889 } |
| 1287 | 890 |
| 1288 if (this.has_extended_attribute("Callback")) { | 891 assert_own_property(self, this.name, |
| 1289 assert_false("prototype" in window[this.name], | 892 "self does not have own property " + format_value(th
is.name)); |
| 893 |
| 894 if (this.is_callback()) { |
| 895 assert_false("prototype" in self[this.name], |
| 1290 this.name + ' should not have a "prototype" property'); | 896 this.name + ' should not have a "prototype" property'); |
| 1291 return; | 897 return; |
| 1292 } | 898 } |
| 1293 | 899 |
| 1294 assert_own_property(window[this.name], "prototype", | 900 assert_own_property(self[this.name], "prototype", |
| 1295 'interface "' + this.name + '" does not have own pro
perty "prototype"'); | 901 'interface "' + this.name + '" does not have own pro
perty "prototype"'); |
| 1296 | 902 |
| 1297 // "If the [NoInterfaceObject] extended attribute was not specified on | 903 // "If the [NoInterfaceObject] extended attribute was not specified on |
| 1298 // the interface, then the interface prototype object must also have a | 904 // the interface, then the interface prototype object must also have a |
| 1299 // property named “constructor” with attributes { [[Writable]]: true, | 905 // property named “constructor” with attributes { [[Writable]]: true, |
| 1300 // [[Enumerable]]: false, [[Configurable]]: true } whose value is a | 906 // [[Enumerable]]: false, [[Configurable]]: true } whose value is a |
| 1301 // reference to the interface object for the interface." | 907 // reference to the interface object for the interface." |
| 1302 assert_own_property(window[this.name].prototype, "constructor", | 908 assert_own_property(self[this.name].prototype, "constructor", |
| 1303 this.name + '.prototype does not have own property "
constructor"'); | 909 this.name + '.prototype does not have own property "
constructor"'); |
| 1304 var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype,
"constructor"); | 910 var desc = Object.getOwnPropertyDescriptor(self[this.name].prototype, "c
onstructor"); |
| 1305 assert_false("get" in desc, this.name + ".prototype.constructor has gett
er"); | 911 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"); | 912 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"); | 913 assert_true(desc.writable, this.name + ".prototype.constructor is not wr
itable"); |
| 1308 assert_false(desc.enumerable, this.name + ".prototype.constructor is enu
merable"); | 914 assert_false(desc.enumerable, this.name + ".prototype.constructor is enu
merable"); |
| 1309 assert_true(desc.configurable, this.name + ".prototype.constructor in no
t configurable"); | 915 assert_true(desc.configurable, this.name + ".prototype.constructor in no
t configurable"); |
| 1310 assert_equals(window[this.name].prototype.constructor, window[this.name]
, | 916 assert_equals(self[this.name].prototype.constructor, self[this.name], |
| 1311 this.name + '.prototype.constructor is not the same object
as ' + this.name); | 917 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'); | 918 }.bind(this), this.name + ' interface: existence and properties of interface
prototype object\'s "constructor" property'); |
| 1313 }; | 919 }; |
| 1314 | 920 |
| 1315 //@} | 921 //@} |
| 922 IdlInterface.prototype.test_member_const = function(member) |
| 923 //@{ |
| 924 { |
| 925 test(function() |
| 926 { |
| 927 if (this.is_callback() && !this.has_constants()) { |
| 928 return; |
| 929 } |
| 930 |
| 931 assert_own_property(self, this.name, |
| 932 "self does not have own property " + format_value(th
is.name)); |
| 933 |
| 934 // "For each constant defined on an interface A, there must be |
| 935 // a corresponding property on the interface object, if it |
| 936 // exists." |
| 937 assert_own_property(self[this.name], member.name); |
| 938 // "The value of the property is that which is obtained by |
| 939 // converting the constant’s IDL value to an ECMAScript |
| 940 // value." |
| 941 assert_equals(self[this.name][member.name], constValue(member.value), |
| 942 "property has wrong value"); |
| 943 // "The property has attributes { [[Writable]]: false, |
| 944 // [[Enumerable]]: true, [[Configurable]]: false }." |
| 945 var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name)
; |
| 946 assert_false("get" in desc, "property has getter"); |
| 947 assert_false("set" in desc, "property has setter"); |
| 948 assert_false(desc.writable, "property is writable"); |
| 949 assert_true(desc.enumerable, "property is not enumerable"); |
| 950 assert_false(desc.configurable, "property is configurable"); |
| 951 }.bind(this), this.name + " interface: constant " + member.name + " on inter
face object"); |
| 952 // "In addition, a property with the same characteristics must |
| 953 // exist on the interface prototype object." |
| 954 test(function() |
| 955 { |
| 956 if (this.is_callback() && !this.has_constants()) { |
| 957 return; |
| 958 } |
| 959 |
| 960 assert_own_property(self, this.name, |
| 961 "self does not have own property " + format_value(th
is.name)); |
| 962 |
| 963 if (this.is_callback()) { |
| 964 assert_false("prototype" in self[this.name], |
| 965 this.name + ' should not have a "prototype" property'); |
| 966 return; |
| 967 } |
| 968 |
| 969 assert_own_property(self[this.name], "prototype", |
| 970 'interface "' + this.name + '" does not have own pro
perty "prototype"'); |
| 971 |
| 972 assert_own_property(self[this.name].prototype, member.name); |
| 973 assert_equals(self[this.name].prototype[member.name], constValue(member.
value), |
| 974 "property has wrong value"); |
| 975 var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name)
; |
| 976 assert_false("get" in desc, "property has getter"); |
| 977 assert_false("set" in desc, "property has setter"); |
| 978 assert_false(desc.writable, "property is writable"); |
| 979 assert_true(desc.enumerable, "property is not enumerable"); |
| 980 assert_false(desc.configurable, "property is configurable"); |
| 981 }.bind(this), this.name + " interface: constant " + member.name + " on inter
face prototype object"); |
| 982 }; |
| 983 |
| 984 |
| 985 //@} |
| 986 IdlInterface.prototype.test_member_attribute = function(member) |
| 987 //@{ |
| 988 { |
| 989 test(function() |
| 990 { |
| 991 if (this.is_callback() && !this.has_constants()) { |
| 992 return; |
| 993 } |
| 994 |
| 995 assert_own_property(self, this.name, |
| 996 "self does not have own property " + format_value(th
is.name)); |
| 997 assert_own_property(self[this.name], "prototype", |
| 998 'interface "' + this.name + '" does not have own pro
perty "prototype"'); |
| 999 |
| 1000 if (member["static"]) { |
| 1001 assert_own_property(self[this.name], member.name, |
| 1002 "The interface object must have a property " + |
| 1003 format_value(member.name)); |
| 1004 } else if (this.is_global()) { |
| 1005 assert_own_property(self, member.name, |
| 1006 "The global object must have a property " + |
| 1007 format_value(member.name)); |
| 1008 assert_false(member.name in self[this.name].prototype, |
| 1009 "The prototype object must not have a property " + |
| 1010 format_value(member.name)); |
| 1011 |
| 1012 // Try/catch around the get here, since it can legitimately throw. |
| 1013 // If it does, we obviously can't check for equality with direct |
| 1014 // invocation of the getter. |
| 1015 var gotValue; |
| 1016 var propVal; |
| 1017 try { |
| 1018 propVal = self[member.name]; |
| 1019 gotValue = true; |
| 1020 } catch (e) { |
| 1021 gotValue = false; |
| 1022 } |
| 1023 if (gotValue) { |
| 1024 var getter = Object.getOwnPropertyDescriptor(self, member.name).
get; |
| 1025 assert_equals(typeof(getter), "function", |
| 1026 format_value(member.name) + " must have a getter")
; |
| 1027 assert_equals(propVal, getter.call(undefined), |
| 1028 "Gets on a global should not require an explicit t
his"); |
| 1029 } |
| 1030 this.do_interface_attribute_asserts(self, member); |
| 1031 } else { |
| 1032 assert_true(member.name in self[this.name].prototype, |
| 1033 "The prototype object must have a property " + |
| 1034 format_value(member.name)); |
| 1035 |
| 1036 if (!member.has_extended_attribute("LenientThis")) { |
| 1037 assert_throws(new TypeError(), function() { |
| 1038 self[this.name].prototype[member.name]; |
| 1039 }.bind(this), "getting property on prototype object must throw T
ypeError"); |
| 1040 } else { |
| 1041 assert_equals(self[this.name].prototype[member.name], undefined, |
| 1042 "getting property on prototype object must return
undefined"); |
| 1043 } |
| 1044 this.do_interface_attribute_asserts(self[this.name].prototype, membe
r); |
| 1045 } |
| 1046 }.bind(this), this.name + " interface: attribute " + member.name); |
| 1047 }; |
| 1048 |
| 1049 //@} |
| 1050 IdlInterface.prototype.test_member_operation = function(member) |
| 1051 //@{ |
| 1052 { |
| 1053 test(function() |
| 1054 { |
| 1055 if (this.is_callback() && !this.has_constants()) { |
| 1056 return; |
| 1057 } |
| 1058 |
| 1059 assert_own_property(self, this.name, |
| 1060 "self does not have own property " + format_value(th
is.name)); |
| 1061 |
| 1062 if (this.is_callback()) { |
| 1063 assert_false("prototype" in self[this.name], |
| 1064 this.name + ' should not have a "prototype" property'); |
| 1065 return; |
| 1066 } |
| 1067 |
| 1068 assert_own_property(self[this.name], "prototype", |
| 1069 'interface "' + this.name + '" does not have own pro
perty "prototype"'); |
| 1070 |
| 1071 // "For each unique identifier of an operation defined on the |
| 1072 // interface, there must be a corresponding property on the |
| 1073 // interface prototype object (if it is a regular operation) or |
| 1074 // the interface object (if it is a static operation), unless |
| 1075 // the effective overload set for that identifier and operation |
| 1076 // and with an argument count of 0 (for the ECMAScript language |
| 1077 // binding) has no entries." |
| 1078 // |
| 1079 var memberHolderObject; |
| 1080 if (member["static"]) { |
| 1081 assert_own_property(self[this.name], member.name, |
| 1082 "interface object missing static operation"); |
| 1083 memberHolderObject = self[this.name]; |
| 1084 } else if (this.is_global()) { |
| 1085 assert_own_property(self, member.name, |
| 1086 "global object missing non-static operation"); |
| 1087 memberHolderObject = self; |
| 1088 } else { |
| 1089 assert_own_property(self[this.name].prototype, member.name, |
| 1090 "interface prototype object missing non-static operation"); |
| 1091 memberHolderObject = self[this.name].prototype; |
| 1092 } |
| 1093 |
| 1094 this.do_member_operation_asserts(memberHolderObject, member); |
| 1095 }.bind(this), this.name + " interface: operation " + member.name + |
| 1096 "(" + member.arguments.map(function(m) { return m.idlType.idlType; }) + |
| 1097 ")"); |
| 1098 }; |
| 1099 |
| 1100 //@} |
| 1101 IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject
, member) |
| 1102 //@{ |
| 1103 { |
| 1104 var operationUnforgeable = member.isUnforgeable; |
| 1105 var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name); |
| 1106 // "The property has attributes { [[Writable]]: B, |
| 1107 // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the |
| 1108 // operation is unforgeable on the interface, and true otherwise". |
| 1109 assert_false("get" in desc, "property has getter"); |
| 1110 assert_false("set" in desc, "property has setter"); |
| 1111 assert_equals(desc.writable, !operationUnforgeable, |
| 1112 "property should be writable if and only if not unforgeable"); |
| 1113 assert_true(desc.enumerable, "property is not enumerable"); |
| 1114 assert_equals(desc.configurable, !operationUnforgeable, |
| 1115 "property should be configurable if and only if not unforgeabl
e"); |
| 1116 // "The value of the property is a Function object whose |
| 1117 // behavior is as follows . . ." |
| 1118 assert_equals(typeof memberHolderObject[member.name], "function", |
| 1119 "property must be a function"); |
| 1120 // "The value of the Function object’s “length” property is |
| 1121 // a Number determined as follows: |
| 1122 // ". . . |
| 1123 // "Return the length of the shortest argument list of the |
| 1124 // entries in S." |
| 1125 // |
| 1126 // TODO: Doesn't handle overloading or variadic arguments. |
| 1127 assert_equals(memberHolderObject[member.name].length, |
| 1128 member.arguments.filter(function(arg) { |
| 1129 return !arg.optional; |
| 1130 }).length, |
| 1131 "property has wrong .length"); |
| 1132 |
| 1133 // Make some suitable arguments |
| 1134 var args = member.arguments.map(function(arg) { |
| 1135 return create_suitable_object(arg.idlType); |
| 1136 }); |
| 1137 |
| 1138 // "Let O be a value determined as follows: |
| 1139 // ". . . |
| 1140 // "Otherwise, throw a TypeError." |
| 1141 // This should be hit if the operation is not static, there is |
| 1142 // no [ImplicitThis] attribute, and the this value is null. |
| 1143 // |
| 1144 // TODO: We currently ignore the [ImplicitThis] case. Except we manually |
| 1145 // check for globals, since otherwise we'll invoke window.close(). And we |
| 1146 // have to skip this test for anything that on the proto chain of "self", |
| 1147 // since that does in fact have implicit-this behavior. |
| 1148 if (!member["static"]) { |
| 1149 if (!this.is_global() && |
| 1150 memberHolderObject[member.name] != self[member.name]) |
| 1151 { |
| 1152 assert_throws(new TypeError(), function() { |
| 1153 memberHolderObject[member.name].apply(null, args); |
| 1154 }, "calling operation with this = null didn't throw TypeError"); |
| 1155 } |
| 1156 |
| 1157 // ". . . If O is not null and is also not a platform object |
| 1158 // that implements interface I, throw a TypeError." |
| 1159 // |
| 1160 // TODO: Test a platform object that implements some other |
| 1161 // interface. (Have to be sure to get inheritance right.) |
| 1162 assert_throws(new TypeError(), function() { |
| 1163 memberHolderObject[member.name].apply({}, args); |
| 1164 }, "calling operation with this = {} didn't throw TypeError"); |
| 1165 } |
| 1166 } |
| 1167 |
| 1168 //@} |
| 1169 IdlInterface.prototype.test_member_stringifier = function(member) |
| 1170 //@{ |
| 1171 { |
| 1172 test(function() |
| 1173 { |
| 1174 if (this.is_callback() && !this.has_constants()) { |
| 1175 return; |
| 1176 } |
| 1177 |
| 1178 assert_own_property(self, this.name, |
| 1179 "self does not have own property " + format_value(th
is.name)); |
| 1180 |
| 1181 if (this.is_callback()) { |
| 1182 assert_false("prototype" in self[this.name], |
| 1183 this.name + ' should not have a "prototype" property'); |
| 1184 return; |
| 1185 } |
| 1186 |
| 1187 assert_own_property(self[this.name], "prototype", |
| 1188 'interface "' + this.name + '" does not have own pro
perty "prototype"'); |
| 1189 |
| 1190 // ". . . the property exists on the interface prototype object." |
| 1191 var interfacePrototypeObject = self[this.name].prototype; |
| 1192 assert_own_property(self[this.name].prototype, "toString", |
| 1193 "interface prototype object missing non-static operation"); |
| 1194 |
| 1195 var stringifierUnforgeable = member.isUnforgeable; |
| 1196 var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "to
String"); |
| 1197 // "The property has attributes { [[Writable]]: B, |
| 1198 // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the |
| 1199 // stringifier is unforgeable on the interface, and true otherwise." |
| 1200 assert_false("get" in desc, "property has getter"); |
| 1201 assert_false("set" in desc, "property has setter"); |
| 1202 assert_equals(desc.writable, !stringifierUnforgeable, |
| 1203 "property should be writable if and only if not unforgeabl
e"); |
| 1204 assert_true(desc.enumerable, "property is not enumerable"); |
| 1205 assert_equals(desc.configurable, !stringifierUnforgeable, |
| 1206 "property should be configurable if and only if not unforg
eable"); |
| 1207 // "The value of the property is a Function object, which behaves as |
| 1208 // follows . . ." |
| 1209 assert_equals(typeof interfacePrototypeObject.toString, "function", |
| 1210 "property must be a function"); |
| 1211 // "The value of the Function object’s “length” property is the Number |
| 1212 // value 0." |
| 1213 assert_equals(interfacePrototypeObject.toString.length, 0, |
| 1214 "property has wrong .length"); |
| 1215 |
| 1216 // "Let O be the result of calling ToObject on the this value." |
| 1217 assert_throws(new TypeError(), function() { |
| 1218 self[this.name].prototype.toString.apply(null, []); |
| 1219 }, "calling stringifier with this = null didn't throw TypeError"); |
| 1220 |
| 1221 // "If O is not an object that implements the interface on which the |
| 1222 // stringifier was declared, then throw a TypeError." |
| 1223 // |
| 1224 // TODO: Test a platform object that implements some other |
| 1225 // interface. (Have to be sure to get inheritance right.) |
| 1226 assert_throws(new TypeError(), function() { |
| 1227 self[this.name].prototype.toString.apply({}, []); |
| 1228 }, "calling stringifier with this = {} didn't throw TypeError"); |
| 1229 }.bind(this), this.name + " interface: stringifier"); |
| 1230 }; |
| 1231 |
| 1232 //@} |
| 1316 IdlInterface.prototype.test_members = function() | 1233 IdlInterface.prototype.test_members = function() |
| 1317 //@{ | 1234 //@{ |
| 1318 { | 1235 { |
| 1319 for (var i = 0; i < this.members.length; i++) | 1236 for (var i = 0; i < this.members.length; i++) |
| 1320 { | 1237 { |
| 1321 var member = this.members[i]; | 1238 var member = this.members[i]; |
| 1322 if (member.untested) | 1239 if (member.untested) { |
| 1323 { | |
| 1324 continue; | 1240 continue; |
| 1325 } | 1241 } |
| 1326 if (member.type == "const") | 1242 |
| 1327 { | 1243 switch (member.type) { |
| 1328 test(function() | 1244 case "const": |
| 1245 this.test_member_const(member); |
| 1246 break; |
| 1247 |
| 1248 case "attribute": |
| 1249 // For unforgeable attributes, we do the checks in |
| 1250 // test_interface_of instead. |
| 1251 if (!member.isUnforgeable) |
| 1329 { | 1252 { |
| 1330 assert_own_property(window, this.name, | 1253 this.test_member_attribute(member); |
| 1331 "window does not have own property " + forma
t_value(this.name)); | 1254 } |
| 1332 | 1255 break; |
| 1333 // "For each constant defined on an interface A, there must be | 1256 |
| 1334 // a corresponding property on the interface object, if it | 1257 case "operation": |
| 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 | 1258 // TODO: Need to correctly handle multiple operations with the same |
| 1414 // identifier. | 1259 // identifier. |
| 1415 if (!member.name) | 1260 // For unforgeable operations, we do the checks in |
| 1416 { | 1261 // test_interface_of instead. |
| 1417 // Unnamed getter or such | 1262 if (member.name) { |
| 1418 continue; | 1263 if (!member.isUnforgeable) |
| 1419 } | 1264 { |
| 1420 test(function() | 1265 this.test_member_operation(member); |
| 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 } | 1266 } |
| 1430 | 1267 } else if (member.stringifier) { |
| 1431 assert_own_property(window[this.name], "prototype", | 1268 this.test_member_stringifier(member); |
| 1432 'interface "' + this.name + '" does not have
own property "prototype"'); | 1269 } |
| 1433 | 1270 break; |
| 1434 // "For each unique identifier of an operation defined on the | 1271 |
| 1435 // interface, there must be a corresponding property on the | 1272 default: |
| 1436 // interface prototype object (if it is a regular operation) or | 1273 // TODO: check more member types. |
| 1437 // the interface object (if it is a static operation), unless | 1274 break; |
| 1438 // the effective overload set for that identifier and operation | 1275 } |
| 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 } | 1276 } |
| 1512 }; | 1277 }; |
| 1513 | 1278 |
| 1514 //@} | 1279 //@} |
| 1515 IdlInterface.prototype.test_object = function(desc) | 1280 IdlInterface.prototype.test_object = function(desc) |
| 1516 //@{ | 1281 //@{ |
| 1517 { | 1282 { |
| 1518 var obj, exception = null; | 1283 var obj, exception = null; |
| 1519 try | 1284 try |
| 1520 { | 1285 { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1560 // interface object, or the object is from a different global environment | 1325 // interface object, or the object is from a different global environment |
| 1561 // (not instanceof Object). TODO: test in this case that its prototype at | 1326 // (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. | 1327 // least looks correct, even if we can't test that it's actually correct. |
| 1563 if (!this.has_extended_attribute("NoInterfaceObject") | 1328 if (!this.has_extended_attribute("NoInterfaceObject") |
| 1564 && (typeof obj != expected_typeof || obj instanceof Object)) | 1329 && (typeof obj != expected_typeof || obj instanceof Object)) |
| 1565 { | 1330 { |
| 1566 test(function() | 1331 test(function() |
| 1567 { | 1332 { |
| 1568 assert_equals(exception, null, "Unexpected exception when evaluating
object"); | 1333 assert_equals(exception, null, "Unexpected exception when evaluating
object"); |
| 1569 assert_equals(typeof obj, expected_typeof, "wrong typeof object"); | 1334 assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
| 1570 assert_own_property(window, this.name, | 1335 assert_own_property(self, this.name, |
| 1571 "window does not have own property " + format_va
lue(this.name)); | 1336 "self does not have own property " + format_valu
e(this.name)); |
| 1572 assert_own_property(window[this.name], "prototype", | 1337 assert_own_property(self[this.name], "prototype", |
| 1573 'interface "' + this.name + '" does not have own
property "prototype"'); | 1338 'interface "' + this.name + '" does not have own
property "prototype"'); |
| 1574 | 1339 |
| 1575 // "The value of the internal [[Prototype]] property of the | 1340 // "The value of the internal [[Prototype]] property of the |
| 1576 // platform object is the interface prototype object of the primary | 1341 // platform object is the interface prototype object of the primary |
| 1577 // interface from the platform object’s associated global | 1342 // interface from the platform object’s associated global |
| 1578 // environment." | 1343 // environment." |
| 1579 assert_equals(Object.getPrototypeOf(obj), | 1344 assert_equals(Object.getPrototypeOf(obj), |
| 1580 window[this.name].prototype, | 1345 self[this.name].prototype, |
| 1581 desc + "'s prototype is not " + this.name + ".prototyp
e"); | 1346 desc + "'s prototype is not " + this.name + ".prototyp
e"); |
| 1582 }.bind(this), this.name + " must be primary interface of " + desc); | 1347 }.bind(this), this.name + " must be primary interface of " + desc); |
| 1583 } | 1348 } |
| 1584 | 1349 |
| 1585 // "The class string of a platform object that implements one or more | 1350 // "The class string of a platform object that implements one or more |
| 1586 // interfaces must be the identifier of the primary interface of the | 1351 // interfaces must be the identifier of the primary interface of the |
| 1587 // platform object." | 1352 // platform object." |
| 1588 test(function() | 1353 test(function() |
| 1589 { | 1354 { |
| 1590 assert_equals(exception, null, "Unexpected exception when evaluating obj
ect"); | 1355 assert_equals(exception, null, "Unexpected exception when evaluating obj
ect"); |
| 1591 assert_equals(typeof obj, expected_typeof, "wrong typeof object"); | 1356 assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
| 1592 assert_class_string(obj, this.name, "class string of " + desc); | 1357 assert_class_string(obj, this.name, "class string of " + desc); |
| 1593 if (!this.has_stringifier()) | 1358 if (!this.has_stringifier()) |
| 1594 { | 1359 { |
| 1595 assert_equals(String(obj), "[object " + this.name + "]", "String(" +
desc + ")"); | 1360 assert_equals(String(obj), "[object " + this.name + "]", "String(" +
desc + ")"); |
| 1596 } | 1361 } |
| 1597 }.bind(this), "Stringification of " + desc); | 1362 }.bind(this), "Stringification of " + desc); |
| 1598 }; | 1363 }; |
| 1599 | 1364 |
| 1600 //@} | 1365 //@} |
| 1601 IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect
ed_typeof) | 1366 IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect
ed_typeof) |
| 1602 //@{ | 1367 //@{ |
| 1603 { | 1368 { |
| 1604 // TODO: Indexed and named properties, more checks on interface members | 1369 // TODO: Indexed and named properties, more checks on interface members |
| 1605 this.already_tested = true; | 1370 this.already_tested = true; |
| 1606 | 1371 |
| 1607 for (var i = 0; i < this.members.length; i++) | 1372 for (var i = 0; i < this.members.length; i++) |
| 1608 { | 1373 { |
| 1609 var member = this.members[i]; | 1374 var member = this.members[i]; |
| 1610 if (member.has_extended_attribute("Unforgeable")) | 1375 if (member.type == "attribute" && member.isUnforgeable) |
| 1611 { | 1376 { |
| 1612 test(function() | 1377 test(function() |
| 1613 { | 1378 { |
| 1614 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); | 1379 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); |
| 1615 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); | 1380 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); |
| 1616 do_interface_attribute_asserts(obj, member); | 1381 this.do_interface_attribute_asserts(obj, member); |
| 1382 }.bind(this), this.name + " interface: " + desc + ' must have own pr
operty "' + member.name + '"'); |
| 1383 } |
| 1384 else if (member.type == "operation" && |
| 1385 member.name && |
| 1386 member.isUnforgeable) |
| 1387 { |
| 1388 test(function() |
| 1389 { |
| 1390 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); |
| 1391 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); |
| 1392 assert_own_property(obj, member.name, |
| 1393 "Doesn't have the unforgeable operation prop
erty"); |
| 1394 this.do_member_operation_asserts(obj, member); |
| 1617 }.bind(this), this.name + " interface: " + desc + ' must have own pr
operty "' + member.name + '"'); | 1395 }.bind(this), this.name + " interface: " + desc + ' must have own pr
operty "' + member.name + '"'); |
| 1618 } | 1396 } |
| 1619 else if ((member.type == "const" | 1397 else if ((member.type == "const" |
| 1620 || member.type == "attribute" | 1398 || member.type == "attribute" |
| 1621 || member.type == "operation") | 1399 || member.type == "operation") |
| 1622 && member.name) | 1400 && member.name) |
| 1623 { | 1401 { |
| 1624 test(function() | 1402 test(function() |
| 1625 { | 1403 { |
| 1626 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); | 1404 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); |
| 1627 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); | 1405 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); |
| 1628 if (!member["static"]) { | 1406 if (!member["static"]) { |
| 1629 assert_inherits(obj, member.name); | 1407 if (!this.is_global()) { |
| 1408 assert_inherits(obj, member.name); |
| 1409 } else { |
| 1410 assert_own_property(obj, member.name); |
| 1411 } |
| 1412 |
| 1630 if (member.type == "const") | 1413 if (member.type == "const") |
| 1631 { | 1414 { |
| 1632 assert_equals(obj[member.name], constValue(member.value)
); | 1415 assert_equals(obj[member.name], constValue(member.value)
); |
| 1633 } | 1416 } |
| 1634 if (member.type == "attribute") | 1417 if (member.type == "attribute") |
| 1635 { | 1418 { |
| 1636 // Attributes are accessor properties, so they might | 1419 // Attributes are accessor properties, so they might |
| 1637 // legitimately throw an exception rather than returning | 1420 // legitimately throw an exception rather than returning |
| 1638 // anything. | 1421 // anything. |
| 1639 var property, thrown = false; | 1422 var property, thrown = false; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1660 // TODO: This is wrong if there are multiple operations with the same | 1443 // TODO: This is wrong if there are multiple operations with the same |
| 1661 // identifier. | 1444 // identifier. |
| 1662 // TODO: Test passing arguments of the wrong type. | 1445 // TODO: Test passing arguments of the wrong type. |
| 1663 if (member.type == "operation" && member.name && member.arguments.length
) | 1446 if (member.type == "operation" && member.name && member.arguments.length
) |
| 1664 { | 1447 { |
| 1665 test(function() | 1448 test(function() |
| 1666 { | 1449 { |
| 1667 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); | 1450 assert_equals(exception, null, "Unexpected exception when evalua
ting object"); |
| 1668 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); | 1451 assert_equals(typeof obj, expected_typeof, "wrong typeof object"
); |
| 1669 if (!member["static"]) { | 1452 if (!member["static"]) { |
| 1670 assert_inherits(obj, member.name); | 1453 if (!this.is_global() && !member.isUnforgeable) { |
| 1454 assert_inherits(obj, member.name); |
| 1455 } else { |
| 1456 assert_own_property(obj, member.name); |
| 1457 } |
| 1671 } | 1458 } |
| 1672 else | 1459 else |
| 1673 { | 1460 { |
| 1674 assert_false(member.name in obj); | 1461 assert_false(member.name in obj); |
| 1675 } | 1462 } |
| 1676 var args = []; | 1463 var args = []; |
| 1677 for (var i = 0; i < member.arguments.length; i++) | 1464 for (var i = 0; i < member.arguments.length; i++) |
| 1678 { | 1465 { |
| 1679 if (member.arguments[i].optional) | 1466 if (member.arguments[i].optional) |
| 1680 { | 1467 { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1702 return true; | 1489 return true; |
| 1703 } | 1490 } |
| 1704 if (this.base && | 1491 if (this.base && |
| 1705 this.array.members[this.base].has_stringifier()) { | 1492 this.array.members[this.base].has_stringifier()) { |
| 1706 return true; | 1493 return true; |
| 1707 } | 1494 } |
| 1708 return false; | 1495 return false; |
| 1709 }; | 1496 }; |
| 1710 | 1497 |
| 1711 //@} | 1498 //@} |
| 1712 function do_interface_attribute_asserts(obj, member) | 1499 IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member) |
| 1713 //@{ | 1500 //@{ |
| 1714 { | 1501 { |
| 1715 // "For each attribute defined on the interface, there must exist a | 1502 // This function tests WebIDL as of 2015-01-27. |
| 1716 // corresponding property. If the attribute was declared with the | 1503 // TODO: Consider [Exposed]. |
| 1717 // [Unforgeable] extended attribute, then the property exists on every | 1504 |
| 1718 // object that implements the interface. Otherwise, it exists on the | 1505 // This is called by test_member_attribute() with the prototype as obj if |
| 1719 // interface’s interface prototype object." | 1506 // it is not a global, and the global otherwise, and by test_interface_of() |
| 1720 // | 1507 // with the object as obj. |
| 1721 // This is called by test_self() with the prototype as obj, and by | 1508 |
| 1722 // test_interface_of() with the object as obj. | 1509 // "For each exposed attribute of the interface, whether it was declared on |
| 1510 // the interface itself or one of its consequential interfaces, there MUST |
| 1511 // exist a corresponding property. The characteristics of this property are |
| 1512 // as follows:" |
| 1513 |
| 1514 // "The name of the property is the identifier of the attribute." |
| 1723 assert_own_property(obj, member.name); | 1515 assert_own_property(obj, member.name); |
| 1724 | 1516 |
| 1725 // "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]: | 1517 // "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]: |
| 1726 // true, [[Configurable]]: configurable }, where: | 1518 // true, [[Configurable]]: configurable }, where: |
| 1727 // "configurable is false if the attribute was declared with the | 1519 // "configurable is false if the attribute was declared with the |
| 1728 // [Unforgeable] extended attribute and true otherwise; | 1520 // [Unforgeable] extended attribute and true otherwise; |
| 1729 // "G is the attribute getter, defined below; and | 1521 // "G is the attribute getter, defined below; and |
| 1730 // "S is the attribute setter, also defined below." | 1522 // "S is the attribute setter, also defined below." |
| 1731 var desc = Object.getOwnPropertyDescriptor(obj, member.name); | 1523 var desc = Object.getOwnPropertyDescriptor(obj, member.name); |
| 1732 assert_false("value" in desc, 'property descriptor has value but is supposed
to be accessor'); | 1524 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'); | 1525 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"); | 1526 assert_true(desc.enumerable, "property is not enumerable"); |
| 1735 if (member.has_extended_attribute("Unforgeable")) | 1527 if (member.isUnforgeable) |
| 1736 { | 1528 { |
| 1737 assert_false(desc.configurable, "[Unforgeable] property must not be conf
igurable"); | 1529 assert_false(desc.configurable, "[Unforgeable] property must not be conf
igurable"); |
| 1738 } | 1530 } |
| 1739 else | 1531 else |
| 1740 { | 1532 { |
| 1741 assert_true(desc.configurable, "property must be configurable"); | 1533 assert_true(desc.configurable, "property must be configurable"); |
| 1742 } | 1534 } |
| 1743 | 1535 |
| 1536 |
| 1744 // "The attribute getter is a Function object whose behavior when invoked | 1537 // "The attribute getter is a Function object whose behavior when invoked |
| 1745 // is as follows: | 1538 // is as follows:" |
| 1746 // "... | 1539 assert_equals(typeof desc.get, "function", "getter must be Function"); |
| 1540 |
| 1541 // "If the attribute is a regular attribute, then:" |
| 1542 if (!member["static"]) { |
| 1543 // "If O is not a platform object that implements I, then: |
| 1544 // "If the attribute was specified with the [LenientThis] extended |
| 1545 // attribute, then return undefined. |
| 1546 // "Otherwise, throw a TypeError." |
| 1547 if (!member.has_extended_attribute("LenientThis")) { |
| 1548 assert_throws(new TypeError(), function() { |
| 1549 desc.get.call({}); |
| 1550 }.bind(this), "calling getter on wrong object type must throw TypeEr
ror"); |
| 1551 } else { |
| 1552 assert_equals(desc.get.call({}), undefined, |
| 1553 "calling getter on wrong object type must return undef
ined"); |
| 1554 } |
| 1555 } |
| 1556 |
| 1747 // "The value of the Function object’s “length” property is the Number | 1557 // "The value of the Function object’s “length” property is the Number |
| 1748 // value 0." | 1558 // 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"); | 1559 assert_equals(desc.get.length, 0, "getter length must be 0"); |
| 1751 // TODO: Account for LenientThis | 1560 |
| 1752 assert_throws(new TypeError(), function() | |
| 1753 { | |
| 1754 desc.get.call({}); | |
| 1755 }.bind(this), "calling getter on wrong object type must throw TypeError"); | |
| 1756 | 1561 |
| 1757 // TODO: Test calling setter on the interface prototype (should throw | 1562 // TODO: Test calling setter on the interface prototype (should throw |
| 1758 // TypeError in most cases). | 1563 // 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 | 1564 if (member.readonly |
| 1768 && !member.has_extended_attribute("PutForwards") | 1565 && !member.has_extended_attribute("PutForwards") |
| 1769 && !member.has_extended_attribute("Replaceable")) | 1566 && !member.has_extended_attribute("Replaceable")) |
| 1770 { | 1567 { |
| 1568 // "The attribute setter is undefined if the attribute is declared |
| 1569 // readonly and has neither a [PutForwards] nor a [Replaceable] |
| 1570 // extended attribute declared on it." |
| 1771 assert_equals(desc.set, undefined, "setter must be undefined for readonl
y attributes"); | 1571 assert_equals(desc.set, undefined, "setter must be undefined for readonl
y attributes"); |
| 1772 } | 1572 } |
| 1773 else | 1573 else |
| 1774 { | 1574 { |
| 1575 // "Otherwise, it is a Function object whose behavior when |
| 1576 // invoked is as follows:" |
| 1775 assert_equals(typeof desc.set, "function", "setter must be function for
PutForwards, Replaceable, or non-readonly attributes"); | 1577 assert_equals(typeof desc.set, "function", "setter must be function for
PutForwards, Replaceable, or non-readonly attributes"); |
| 1578 |
| 1579 // "If the attribute is a regular attribute, then:" |
| 1580 if (!member["static"]) { |
| 1581 // "If /validThis/ is false and the attribute was not specified |
| 1582 // with the [LenientThis] extended attribute, then throw a |
| 1583 // TypeError." |
| 1584 // "If the attribute is declared with a [Replaceable] extended |
| 1585 // attribute, then: ..." |
| 1586 // "If validThis is false, then return." |
| 1587 if (!member.has_extended_attribute("LenientThis")) { |
| 1588 assert_throws(new TypeError(), function() { |
| 1589 desc.set.call({}); |
| 1590 }.bind(this), "calling setter on wrong object type must throw Ty
peError"); |
| 1591 } else { |
| 1592 assert_equals(desc.set.call({}), undefined, |
| 1593 "calling setter on wrong object type must return u
ndefined"); |
| 1594 } |
| 1595 } |
| 1596 |
| 1597 // "The value of the Function object’s “length” property is the Number |
| 1598 // value 1." |
| 1776 assert_equals(desc.set.length, 1, "setter length must be 1"); | 1599 assert_equals(desc.set.length, 1, "setter length must be 1"); |
| 1777 } | 1600 } |
| 1778 } | 1601 } |
| 1779 //@} | 1602 //@} |
| 1780 | 1603 |
| 1781 /// IdlInterfaceMember /// | 1604 /// IdlInterfaceMember /// |
| 1782 function IdlInterfaceMember(obj) | 1605 function IdlInterfaceMember(obj) |
| 1783 //@{ | 1606 //@{ |
| 1784 { | 1607 { |
| 1785 /** | 1608 /** |
| 1786 * obj is an object produced by the WebIDLParser.js "ifMember" production. | 1609 * obj is an object produced by the WebIDLParser.js "ifMember" production. |
| 1787 * We just forward all properties to this object without modification, | 1610 * We just forward all properties to this object without modification, |
| 1788 * except for special extAttrs handling. | 1611 * except for special extAttrs handling. |
| 1789 */ | 1612 */ |
| 1790 for (var k in obj) | 1613 for (var k in obj) |
| 1791 { | 1614 { |
| 1792 this[k] = obj[k]; | 1615 this[k] = obj[k]; |
| 1793 } | 1616 } |
| 1794 if (!("extAttrs" in this)) | 1617 if (!("extAttrs" in this)) |
| 1795 { | 1618 { |
| 1796 this.extAttrs = []; | 1619 this.extAttrs = []; |
| 1797 } | 1620 } |
| 1621 |
| 1622 this.isUnforgeable = this.has_extended_attribute("Unforgeable"); |
| 1798 } | 1623 } |
| 1799 | 1624 |
| 1800 //@} | 1625 //@} |
| 1801 IdlInterfaceMember.prototype = Object.create(IdlObject.prototype); | 1626 IdlInterfaceMember.prototype = Object.create(IdlObject.prototype); |
| 1802 | 1627 |
| 1803 /// Internal helper functions /// | 1628 /// Internal helper functions /// |
| 1804 function create_suitable_object(type) | 1629 function create_suitable_object(type) |
| 1805 //@{ | 1630 //@{ |
| 1806 { | 1631 { |
| 1807 /** | 1632 /** |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1819 case "boolean": | 1644 case "boolean": |
| 1820 return true; | 1645 return true; |
| 1821 | 1646 |
| 1822 case "byte": case "octet": case "short": case "unsigned short": | 1647 case "byte": case "octet": case "short": case "unsigned short": |
| 1823 case "long": case "unsigned long": case "long long": | 1648 case "long": case "unsigned long": case "long long": |
| 1824 case "unsigned long long": case "float": case "double": | 1649 case "unsigned long long": case "float": case "double": |
| 1825 case "unrestricted float": case "unrestricted double": | 1650 case "unrestricted float": case "unrestricted double": |
| 1826 return 7; | 1651 return 7; |
| 1827 | 1652 |
| 1828 case "DOMString": | 1653 case "DOMString": |
| 1654 case "ByteString": |
| 1655 case "USVString": |
| 1829 return "foo"; | 1656 return "foo"; |
| 1830 | 1657 |
| 1831 case "object": | 1658 case "object": |
| 1832 return {a: "b"}; | 1659 return {a: "b"}; |
| 1833 | 1660 |
| 1834 case "Node": | 1661 case "Node": |
| 1835 return document.createTextNode("abc"); | 1662 return document.createTextNode("abc"); |
| 1836 } | 1663 } |
| 1837 return null; | 1664 return null; |
| 1838 } | 1665 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1875 /** An array of values produced by the "typedef" production. */ | 1702 /** An array of values produced by the "typedef" production. */ |
| 1876 this.values = obj.values; | 1703 this.values = obj.values; |
| 1877 | 1704 |
| 1878 } | 1705 } |
| 1879 //@} | 1706 //@} |
| 1880 | 1707 |
| 1881 IdlTypedef.prototype = Object.create(IdlObject.prototype); | 1708 IdlTypedef.prototype = Object.create(IdlObject.prototype); |
| 1882 | 1709 |
| 1883 }()); | 1710 }()); |
| 1884 // vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker: | 1711 // vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker: |
| OLD | NEW |