Index: LayoutTests/http/tests/w3c/resources/idlharness.js |
diff --git a/LayoutTests/http/tests/w3c/resources/idlharness.js b/LayoutTests/http/tests/w3c/resources/idlharness.js |
index 15c1d04f206be9f039e32fd6e6e89bcc5a4926f7..b8a87c6699008ae62b07f402ad7b4e8b29bb725c 100644 |
--- a/LayoutTests/http/tests/w3c/resources/idlharness.js |
+++ b/LayoutTests/http/tests/w3c/resources/idlharness.js |
@@ -8,131 +8,7 @@ policies and contribution forms [3]. |
[3] http://www.w3.org/2004/10/27-testcases |
*/ |
-/* |
- * This file automatically generates browser tests for WebIDL interfaces, using |
- * the testharness.js framework. To use, first include the following: |
- * |
- * <script src=/resources/testharness.js></script> |
- * <script src=/resources/testharnessreport.js></script> |
- * <script src=/resources/WebIDLParser.js></script> |
- * <script src=/resources/idlharness.js></script> |
- * |
- * Then you'll need some type of IDLs. Here's some script that can be run on a |
- * spec written in HTML, which will grab all the elements with class="idl", |
- * concatenate them, and replace the body so you can copy-paste: |
- * |
- var s = ""; |
- [].forEach.call(document.getElementsByClassName("idl"), function(idl) { |
- //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914 |
- if (!idl.classList.contains("extract")) |
- { |
- s += idl.textContent + "\n\n"; |
- } |
- }); |
- document.body.innerHTML = '<pre></pre>'; |
- document.body.firstChild.textContent = s; |
- * |
- * (TODO: write this in Python or something so that it can be done from the |
- * command line instead.) |
- * |
- * Once you have that, put it in your script somehow. The easiest way is to |
- * embed it literally in an HTML file with <script type=text/plain> or similar, |
- * so that you don't have to do any escaping. Another possibility is to put it |
- * in a separate .idl file that's fetched via XHR or similar. Sample usage: |
- * |
- * var idl_array = new IdlArray(); |
- * idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };"); |
- * idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };"); |
- * idl_array.add_objects({Document: ["document"]}); |
- * idl_array.test(); |
- * |
- * This tests that window.Document exists and meets all the requirements of |
- * WebIDL. It also tests that window.document (the result of evaluating the |
- * string "document") has URL and nodeName properties that behave as they |
- * should, and otherwise meets WebIDL's requirements for an object whose |
- * primary interface is Document. It does not test that window.Node exists, |
- * which is what you want if the Node interface is already tested in some other |
- * specification's suite and your specification only extends or refers to it. |
- * Of course, each IDL string can define many different things, and calls to |
- * add_objects() can register many different objects for different interfaces: |
- * this is a very simple example. |
- * |
- * TODO: Write assert_writable, assert_enumerable, assert_configurable and |
- * their inverses, and use those instead of just checking |
- * getOwnPropertyDescriptor. |
- * |
- * == Public methods of IdlArray == |
- * |
- * IdlArray objects can be obtained with new IdlArray(). Anything not |
- * documented in this section should be considered an implementation detail, |
- * and outside callers should not use it. |
- * |
- * add_idls(idl_string): |
- * Parses idl_string (throwing on parse error) and adds the results to the |
- * IdlArray. All the definitions will be tested when you run test(). If |
- * some of the definitions refer to other definitions, those must be present |
- * too. For instance, if idl_string says that Document inherits from Node, |
- * the Node interface must also have been provided in some call to add_idls() |
- * or add_untested_idls(). |
- * |
- * add_untested_idls(idl_string): |
- * Like add_idls(), but the definitions will not be tested. If an untested |
- * interface is added and then extended with a tested partial interface, the |
- * members of the partial interface will still be tested. Also, all the |
- * members will still be tested for objects added with add_objects(), because |
- * you probably want to test that (for instance) window.document has all the |
- * properties from Node, not just Document, even if the Node interface itself |
- * is tested in a different test suite. |
- * |
- * add_objects(dict): |
- * dict should be an object whose keys are the names of interfaces or |
- * exceptions, and whose values are arrays of strings. When an interface or |
- * exception is tested, every string registered for it with add_objects() |
- * will be evaluated, and tests will be run on the result to verify that it |
- * correctly implements that interface or exception. This is the only way to |
- * test anything about [NoInterfaceObject] interfaces, and there are many |
- * tests that can't be run on any interface without an object to fiddle with. |
- * |
- * The interface has to be the *primary* interface of all the objects |
- * provided. For example, don't pass {Node: ["document"]}, but rather |
- * {Document: ["document"]}. Assuming the Document interface was declared to |
- * inherit from Node, this will automatically test that document implements |
- * the Node interface too. |
- * |
- * Warning: methods will be called on any provided objects, in a manner that |
- * WebIDL requires be safe. For instance, if a method has mandatory |
- * arguments, the test suite will try calling it with too few arguments to |
- * see if it throws an exception. If an implementation incorrectly runs the |
- * function instead of throwing, this might have side effects, possibly even |
- * preventing the test suite from running correctly. |
- * |
- * prevent_multiple_testing(name): |
- * This is a niche method for use in case you're testing many objects that |
- * implement the same interfaces, and don't want to retest the same |
- * interfaces every single time. For instance, HTML defines many interfaces |
- * that all inherit from HTMLElement, so the HTML test suite has something |
- * like |
- * .add_objects({ |
- * HTMLHtmlElement: ['document.documentElement'], |
- * HTMLHeadElement: ['document.head'], |
- * HTMLBodyElement: ['document.body'], |
- * ... |
- * }) |
- * and so on for dozens of element types. This would mean that it would |
- * retest that each and every one of those elements implements HTMLElement, |
- * Element, and Node, which would be thousands of basically redundant tests. |
- * The test suite therefore calls prevent_multiple_testing("HTMLElement"). |
- * This means that once one object has been tested to implement HTMLElement |
- * and its ancestors, no other object will be. Thus in the example code |
- * above, the harness would test that document.documentElement correctly |
- * implements HTMLHtmlElement, HTMLElement, Element, and Node; but |
- * document.head would only be tested for HTMLHeadElement, and so on for |
- * further objects. |
- * |
- * test(): |
- * Run all tests. This should be called after you've called all other |
- * methods to add IDLs and objects. |
- */ |
+/* For user documentation see docs/idlharness.md */ |
/** |
* Notes for people who want to edit this file (not just use it as a library): |
@@ -182,7 +58,7 @@ function constValue (cnt) { |
/// IdlArray /// |
// Entry point |
-window.IdlArray = function() |
+self.IdlArray = function() |
//@{ |
{ |
/** |
@@ -290,11 +166,8 @@ IdlArray.prototype.internal_add_idls = function(parsed_idls) |
switch(parsed_idl.type) |
{ |
case "interface": |
- this.members[parsed_idl.name] = new IdlInterface(parsed_idl); |
- break; |
- |
- case "exception": |
- this.members[parsed_idl.name] = new IdlException(parsed_idl); |
+ this.members[parsed_idl.name] = |
+ new IdlInterface(parsed_idl, /* is_callback = */ false); |
break; |
case "dictionary": |
@@ -317,8 +190,8 @@ IdlArray.prototype.internal_add_idls = function(parsed_idls) |
break; |
case "callback interface": |
- // TODO |
- console.log("callback interface not yet supported"); |
+ this.members[parsed_idl.name] = |
+ new IdlInterface(parsed_idl, /* is_callback = */ true); |
break; |
default: |
@@ -537,12 +410,14 @@ IdlArray.prototype.assert_type_is = function(value, type) |
return; |
case "unsigned long long": |
+ case "DOMTimeStamp": |
assert_equals(typeof value, "number"); |
assert_true(0 <= value, "unsigned long long is negative"); |
return; |
case "float": |
case "double": |
+ case "DOMHighResTimeStamp": |
case "unrestricted float": |
case "unrestricted double": |
// TODO: distinguish these cases |
@@ -550,6 +425,9 @@ IdlArray.prototype.assert_type_is = function(value, type) |
return; |
case "DOMString": |
+ case "ByteString": |
+ case "USVString": |
+ // TODO: https://github.com/w3c/testharness.js/issues/92 |
assert_equals(typeof value, "string"); |
return; |
@@ -569,13 +447,13 @@ IdlArray.prototype.assert_type_is = function(value, type) |
// IdlInterface.prototype.test_instance_of, because that could result |
// in an infinite loop. TODO: This means we don't have tests for |
// NoInterfaceObject interfaces, and we also can't test objects that |
- // come from another window. |
+ // come from another self. |
assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function"); |
if (value instanceof Object |
&& !this.members[type].has_extended_attribute("NoInterfaceObject") |
- && type in window) |
+ && type in self) |
{ |
- assert_true(value instanceof window[type], "not instanceof " + type); |
+ assert_true(value instanceof self[type], "not instanceof " + type); |
} |
} |
else if (this.members[type] instanceof IdlEnum) |
@@ -650,11 +528,8 @@ function IdlDictionary(obj) |
//@} |
IdlDictionary.prototype = Object.create(IdlObject.prototype); |
-/// IdlExceptionOrInterface /// |
-// Code sharing! |
-function IdlExceptionOrInterface(obj) |
-//@{ |
-{ |
+/// IdlInterface /// |
+function IdlInterface(obj, is_callback) { |
/** |
* obj is an object produced by the WebIDLParser.js "exception" or |
* "interface" production, as appropriate. |
@@ -678,17 +553,48 @@ function IdlExceptionOrInterface(obj) |
/** An array of IdlInterfaceMembers. */ |
this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); }); |
+ if (this.has_extended_attribute("Unforgeable")) { |
+ this.members |
+ .filter(function(m) { return !m["static"] && (m.type == "attribute" || m.type == "operation"); }) |
+ .forEach(function(m) { return m.isUnforgeable = true; }); |
+ } |
/** |
* The name (as a string) of the type we inherit from, or null if there is |
* none. |
*/ |
this.base = obj.inheritance; |
+ |
+ this._is_callback = is_callback; |
} |
+IdlInterface.prototype = Object.create(IdlObject.prototype); |
+IdlInterface.prototype.is_callback = function() |
+//@{ |
+{ |
+ return this._is_callback; |
+}; |
+//@} |
+ |
+IdlInterface.prototype.has_constants = function() |
+//@{ |
+{ |
+ return this.members.some(function(member) { |
+ return member.type === "const"; |
+ }); |
+}; |
+//@} |
+IdlInterface.prototype.is_global = function() |
+//@{ |
+{ |
+ return this.extAttrs.some(function(attribute) { |
+ return attribute.name === "Global" || |
+ attribute.name === "PrimaryGlobal"; |
+ }); |
+}; |
//@} |
-IdlExceptionOrInterface.prototype = Object.create(IdlObject.prototype); |
-IdlExceptionOrInterface.prototype.test = function() |
+ |
+IdlInterface.prototype.test = function() |
//@{ |
{ |
if (this.has_extended_attribute("NoInterfaceObject")) |
@@ -714,355 +620,6 @@ IdlExceptionOrInterface.prototype.test = function() |
// interface are still tested. |
this.test_members(); |
}; |
- |
-//@} |
- |
-/// IdlException /// |
-function IdlException(obj) { IdlExceptionOrInterface.call(this, obj); } |
-IdlException.prototype = Object.create(IdlExceptionOrInterface.prototype); |
-IdlException.prototype.test_self = function() |
-//@{ |
-{ |
- test(function() |
- { |
- // "For every exception that is not declared with the |
- // [NoInterfaceObject] extended attribute, a corresponding property |
- // must exist on the exception’s relevant namespace object. The name of |
- // the property is the identifier of the exception, and its value is an |
- // object called the exception interface object, which provides access |
- // to any constants that have been associated with the exception. The |
- // property has the attributes { [[Writable]]: true, [[Enumerable]]: |
- // false, [[Configurable]]: true }." |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- var desc = Object.getOwnPropertyDescriptor(window, this.name); |
- assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter"); |
- assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter"); |
- assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable"); |
- assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable"); |
- assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable"); |
- |
- // "The exception interface object for a given exception must be a |
- // function object." |
- // "If an object is defined to be a function object, then it has |
- // characteristics as follows:" |
- // "Its [[Prototype]] internal property is the Function prototype |
- // object." |
- // Note: This doesn't match browsers as of December 2011, see |
- // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14813 |
- assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototype, |
- "prototype of window's property " + format_value(this.name) + " is not Function.prototype"); |
- // "Its [[Get]] internal property is set as described in ECMA-262 |
- // section 15.3.5.4." |
- // Not much to test for this. |
- // "Its [[Construct]] internal property is set as described in ECMA-262 |
- // section 13.2.2." |
- // Tested below. |
- // "Its [[HasInstance]] internal property is set as described in |
- // ECMA-262 section 15.3.5.3, unless otherwise specified." |
- // TODO |
- // "Its [[Class]] internal property is “Function”." |
- // String() returns something implementation-dependent, because it |
- // calls Function#toString. |
- assert_class_string(window[this.name], "Function", |
- "class string of " + this.name); |
- |
- // TODO: Test 4.9.1.1. Exception interface object [[Call]] method |
- // (which does not match browsers: |
- // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14885) |
- }.bind(this), this.name + " exception: existence and properties of exception interface object"); |
- |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- |
- // "The exception interface object must also have a property named |
- // “prototype” with attributes { [[Writable]]: false, [[Enumerable]]: |
- // false, [[Configurable]]: false } whose value is an object called the |
- // exception interface prototype object. This object also provides |
- // access to the constants that are declared on the exception." |
- assert_own_property(window[this.name], "prototype", |
- 'exception "' + this.name + '" does not have own property "prototype"'); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype"); |
- assert_false("get" in desc, this.name + ".prototype has getter"); |
- assert_false("set" in desc, this.name + ".prototype has setter"); |
- assert_false(desc.writable, this.name + ".prototype is writable"); |
- assert_false(desc.enumerable, this.name + ".prototype is enumerable"); |
- assert_false(desc.configurable, this.name + ".prototype is configurable"); |
- |
- // "The exception interface prototype object for a given exception must |
- // have an internal [[Prototype]] property whose value is as follows: |
- // |
- // "If the exception is declared to inherit from another exception, |
- // then the value of the internal [[Prototype]] property is the |
- // exception interface prototype object for the inherited exception. |
- // "Otherwise, the exception is not declared to inherit from another |
- // exception. The value of the internal [[Prototype]] property is the |
- // Error prototype object ([ECMA-262], section 15.11.3.1)." |
- // |
- // Note: This doesn't match browsers as of December 2011, see |
- // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14887. |
- var inherit_exception = this.base ? this.base : "Error"; |
- assert_own_property(window, inherit_exception, |
- 'should inherit from ' + inherit_exception + ', but window has no such property'); |
- assert_own_property(window[inherit_exception], "prototype", |
- 'should inherit from ' + inherit_exception + ', but that object has no "prototype" property'); |
- assert_equals(Object.getPrototypeOf(window[this.name].prototype), |
- window[inherit_exception].prototype, |
- 'prototype of ' + this.name + '.prototype is not ' + inherit_exception + '.prototype'); |
- |
- // "The class string of an exception interface prototype object is the |
- // concatenation of the exception’s identifier and the string |
- // “Prototype”." |
- assert_class_string(window[this.name].prototype, this.name + "Prototype", |
- "class string of " + this.name + ".prototype"); |
- // TODO: Test String(), based on ES definition of |
- // Error.prototype.toString? |
- }.bind(this), this.name + " exception: existence and properties of exception interface prototype object"); |
- |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
- 'interface "' + this.name + '" does not have own property "prototype"'); |
- |
- // "There must be a property named “name” on the exception interface |
- // prototype object with attributes { [[Writable]]: true, |
- // [[Enumerable]]: false, [[Configurable]]: true } and whose value is |
- // the identifier of the exception." |
- assert_own_property(window[this.name].prototype, "name", |
- 'prototype object does not have own property "name"'); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "name"); |
- assert_false("get" in desc, this.name + ".prototype.name has getter"); |
- assert_false("set" in desc, this.name + ".prototype.name has setter"); |
- assert_true(desc.writable, this.name + ".prototype.name is not writable"); |
- assert_false(desc.enumerable, this.name + ".prototype.name is enumerable"); |
- assert_true(desc.configurable, this.name + ".prototype.name is not configurable"); |
- assert_equals(desc.value, this.name, this.name + ".prototype.name has incorrect value"); |
- }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"name\" property"); |
- |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
- 'interface "' + this.name + '" does not have own property "prototype"'); |
- |
- // "If the [NoInterfaceObject] extended attribute was not specified on |
- // the exception, then there must also be a property named |
- // “constructor” on the exception interface prototype object with |
- // attributes { [[Writable]]: true, [[Enumerable]]: false, |
- // [[Configurable]]: true } and whose value is a reference to the |
- // exception interface object for the exception." |
- assert_own_property(window[this.name].prototype, "constructor", |
- this.name + '.prototype does not have own property "constructor"'); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor"); |
- assert_false("get" in desc, this.name + ".prototype.constructor has getter"); |
- assert_false("set" in desc, this.name + ".prototype.constructor has setter"); |
- assert_true(desc.writable, this.name + ".prototype.constructor is not writable"); |
- assert_false(desc.enumerable, this.name + ".prototype.constructor is enumerable"); |
- assert_true(desc.configurable, this.name + ".prototype.constructor in not configurable"); |
- assert_equals(window[this.name].prototype.constructor, window[this.name], |
- this.name + '.prototype.constructor is not the same object as ' + this.name); |
- }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"constructor\" property"); |
-}; |
- |
-//@} |
-IdlException.prototype.test_members = function() |
-//@{ |
-{ |
- for (var i = 0; i < this.members.length; i++) |
- { |
- var member = this.members[i]; |
- if (member.untested) |
- { |
- continue; |
- } |
- if (member.type == "const" && member.name != "prototype") |
- { |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- |
- // "For each constant defined on the exception, there must be a |
- // corresponding property on the exception interface object, if |
- // it exists, if the identifier of the constant is not |
- // “prototype”." |
- assert_own_property(window[this.name], member.name); |
- // "The value of the property is the ECMAScript value that is |
- // equivalent to the constant’s IDL value, according to the |
- // rules in section 4.2 above." |
- assert_equals(window[this.name][member.name], constValue(member.value), |
- "property has wrong value"); |
- // "The property has attributes { [[Writable]]: false, |
- // [[Enumerable]]: true, [[Configurable]]: false }." |
- var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name); |
- assert_false("get" in desc, "property has getter"); |
- assert_false("set" in desc, "property has setter"); |
- assert_false(desc.writable, "property is writable"); |
- assert_true(desc.enumerable, "property is not enumerable"); |
- assert_false(desc.configurable, "property is configurable"); |
- }.bind(this), this.name + " exception: constant " + member.name + " on exception interface object"); |
- // "In addition, a property with the same characteristics must |
- // exist on the exception interface prototype object." |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
- 'exception "' + this.name + '" does not have own property "prototype"'); |
- |
- assert_own_property(window[this.name].prototype, member.name); |
- assert_equals(window[this.name].prototype[member.name], constValue(member.value), |
- "property has wrong value"); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name); |
- assert_false("get" in desc, "property has getter"); |
- assert_false("set" in desc, "property has setter"); |
- assert_false(desc.writable, "property is writable"); |
- assert_true(desc.enumerable, "property is not enumerable"); |
- assert_false(desc.configurable, "property is configurable"); |
- }.bind(this), this.name + " exception: constant " + member.name + " on exception interface prototype object"); |
- } |
- else if (member.type == "field") |
- { |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
- 'exception "' + this.name + '" does not have own property "prototype"'); |
- |
- // "For each exception field, there must be a corresponding |
- // property on the exception interface prototype object, whose |
- // characteristics are as follows: |
- // "The name of the property is the identifier of the exception |
- // field." |
- assert_own_property(window[this.name].prototype, member.name); |
- // "The property has attributes { [[Get]]: G, [[Enumerable]]: |
- // true, [[Configurable]]: true }, where G is the exception |
- // field getter, defined below." |
- var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name); |
- assert_false("value" in desc, "property descriptor has value but is supposed to be accessor"); |
- assert_false("writable" in desc, 'property descriptor has "writable" field but is supposed to be accessor'); |
- // TODO: ES5 doesn't seem to say whether desc should have a |
- // .set property. |
- assert_true(desc.enumerable, "property is not enumerable"); |
- assert_true(desc.configurable, "property is not configurable"); |
- // "The exception field getter is a Function object whose |
- // behavior when invoked is as follows:" |
- assert_equals(typeof desc.get, "function", "typeof getter"); |
- // "The value of the Function object’s “length” property is the |
- // Number value 0." |
- // This test is before the TypeError tests so that it's easiest |
- // to see that Firefox 11a1 only fails one assert in this test. |
- assert_equals(desc.get.length, 0, "getter length"); |
- // "Let O be the result of calling ToObject on the this value. |
- // "If O is not a platform object representing an exception for |
- // the exception on which the exception field was declared, |
- // then throw a TypeError." |
- // TODO: Test on a platform object representing an exception. |
- assert_throws(new TypeError(), function() |
- { |
- window[this.name].prototype[member.name]; |
- }.bind(this), "getting property on prototype object must throw TypeError"); |
- assert_throws(new TypeError(), function() |
- { |
- desc.get.call({}); |
- }.bind(this), "calling getter on wrong object type must throw TypeError"); |
- }.bind(this), this.name + " exception: field " + member.name + " on exception interface prototype object"); |
- } |
- } |
-}; |
- |
-//@} |
-IdlException.prototype.test_object = function(desc) |
-//@{ |
-{ |
- var obj, exception = null; |
- try |
- { |
- obj = eval(desc); |
- } |
- catch(e) |
- { |
- exception = e; |
- } |
- |
- test(function() |
- { |
- assert_equals(exception, null, "Unexpected exception when evaluating object"); |
- assert_equals(typeof obj, "object", "wrong typeof object"); |
- |
- // We can't easily test that its prototype is correct if there's no |
- // interface object, or the object is from a different global |
- // environment (not instanceof Object). TODO: test in this case that |
- // its prototype at least looks correct, even if we can't test that |
- // it's actually correct. |
- if (!this.has_extended_attribute("NoInterfaceObject") |
- && (typeof obj != "object" || obj instanceof Object)) |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
- 'exception "' + this.name + '" does not have own property "prototype"'); |
- |
- // "The value of the internal [[Prototype]] property of the |
- // exception object must be the exception interface prototype |
- // object from the global environment the exception object is |
- // associated with." |
- assert_equals(Object.getPrototypeOf(obj), |
- window[this.name].prototype, |
- desc + "'s prototype is not " + this.name + ".prototype"); |
- } |
- |
- // "The class string of the exception object must be the identifier of |
- // the exception." |
- assert_class_string(obj, this.name, "class string of " + desc); |
- // Stringifier is not defined for DOMExceptions, because message isn't |
- // defined. |
- }.bind(this), this.name + " must be represented by " + desc); |
- |
- for (var i = 0; i < this.members.length; i++) |
- { |
- var member = this.members[i]; |
- test(function() |
- { |
- assert_equals(exception, null, "Unexpected exception when evaluating object"); |
- assert_equals(typeof obj, "object", "wrong typeof object"); |
- assert_inherits(obj, member.name); |
- if (member.type == "const") |
- { |
- assert_equals(obj[member.name], constValue(member.value)); |
- } |
- if (member.type == "field") |
- { |
- this.array.assert_type_is(obj[member.name], member.idlType); |
- } |
- }.bind(this), this.name + " exception: " + desc + ' must inherit property "' + member.name + '" with the proper type'); |
- } |
-}; |
-//@} |
- |
-/// IdlInterface /// |
-function IdlInterface(obj) { IdlExceptionOrInterface.call(this, obj); } |
-IdlInterface.prototype = Object.create(IdlExceptionOrInterface.prototype); |
-IdlInterface.prototype.is_callback = function() |
-//@{ |
-{ |
- return this.has_extended_attribute("Callback"); |
-}; |
-//@} |
- |
-IdlInterface.prototype.has_constants = function() |
-//@{ |
-{ |
- return this.members.some(function(member) { |
- return member.type === "const"; |
- }); |
-}; |
//@} |
IdlInterface.prototype.test_self = function() |
@@ -1070,9 +627,11 @@ IdlInterface.prototype.test_self = function() |
{ |
test(function() |
{ |
- // This function tests WebIDL as of 2012-11-28. |
+ // This function tests WebIDL as of 2015-01-13. |
+ // TODO: Consider [Exposed]. |
- // "For every interface that: |
+ // "For every interface that is exposed in a given ECMAScript global |
+ // environment and: |
// * is a callback interface that has constants declared on it, or |
// * is a non-callback interface that is not declared with the |
// [NoInterfaceObject] extended attribute, |
@@ -1087,20 +646,20 @@ IdlInterface.prototype.test_self = function() |
// TODO: Should we test here that the property is actually writable |
// etc., or trust getOwnPropertyDescriptor? |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- var desc = Object.getOwnPropertyDescriptor(window, this.name); |
- assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter"); |
- assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter"); |
- assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable"); |
- assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable"); |
- assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable"); |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ var desc = Object.getOwnPropertyDescriptor(self, this.name); |
+ assert_false("get" in desc, "self's property " + format_value(this.name) + " has getter"); |
+ assert_false("set" in desc, "self's property " + format_value(this.name) + " has setter"); |
+ assert_true(desc.writable, "self's property " + format_value(this.name) + " is not writable"); |
+ assert_false(desc.enumerable, "self's property " + format_value(this.name) + " is enumerable"); |
+ assert_true(desc.configurable, "self's property " + format_value(this.name) + " is not configurable"); |
if (this.is_callback()) { |
// "The internal [[Prototype]] property of an interface object for |
// a callback interface MUST be the Object.prototype object." |
- assert_equals(Object.getPrototypeOf(window[this.name]), Object.prototype, |
- "prototype of window's property " + format_value(this.name) + " is not Object.prototype"); |
+ assert_equals(Object.getPrototypeOf(self[this.name]), Object.prototype, |
+ "prototype of self's property " + format_value(this.name) + " is not Object.prototype"); |
return; |
} |
@@ -1110,28 +669,53 @@ IdlInterface.prototype.test_self = function() |
// "If an object is defined to be a function object, then it has |
// characteristics as follows:" |
- // "* Its [[Prototype]] internal property is the Function prototype |
- // object." |
- assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototype, |
- "prototype of window's property " + format_value(this.name) + " is not Function.prototype"); |
+ // Its [[Prototype]] internal property is otherwise specified (see |
+ // below). |
// "* Its [[Get]] internal property is set as described in ECMA-262 |
- // section 15.3.5.4." |
+ // section 9.1.8." |
// Not much to test for this. |
// "* Its [[Construct]] internal property is set as described in |
- // ECMA-262 section 13.2.2." |
+ // ECMA-262 section 19.2.2.3." |
// Tested below if no constructor is defined. TODO: test constructors |
// if defined. |
- // "* Its [[HasInstance]] internal property is set as described in |
- // ECMA-262 section 15.3.5.3, unless otherwise specified." |
+ // "* Its @@hasInstance property is set as described in ECMA-262 |
+ // section 19.2.3.8, unless otherwise specified." |
// TODO |
- // "* Its [[NativeBrand]] internal property is “Function”." |
- // String() returns something implementation-dependent, because it calls |
- // Function#toString. |
- assert_class_string(window[this.name], "Function", "class string of " + this.name); |
+ // ES6 (rev 30) 19.1.3.6: |
+ // "Else, if O has a [[Call]] internal method, then let builtinTag be |
+ // "Function"." |
+ assert_class_string(self[this.name], "Function", "class string of " + this.name); |
+ |
+ // "The [[Prototype]] internal property of an interface object for a |
+ // non-callback interface is determined as follows:" |
+ var prototype = Object.getPrototypeOf(self[this.name]); |
+ if (this.base) { |
+ // "* If the interface inherits from some other interface, the |
+ // value of [[Prototype]] is the interface object for that other |
+ // interface." |
+ var has_interface_object = |
+ !this.array |
+ .members[this.base] |
+ .has_extended_attribute("NoInterfaceObject"); |
+ if (has_interface_object) { |
+ assert_own_property(self, this.base, |
+ 'should inherit from ' + this.base + |
+ ', but self has no such property'); |
+ assert_equals(prototype, self[this.base], |
+ 'prototype of ' + this.name + ' is not ' + |
+ this.base); |
+ } |
+ } else { |
+ // "If the interface doesn't inherit from any other interface, the |
+ // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262], |
+ // section 6.1.7.4)." |
+ assert_equals(prototype, Function.prototype, |
+ "prototype of self's property " + format_value(this.name) + " is not Function.prototype"); |
+ } |
if (!this.has_extended_attribute("Constructor")) { |
// "The internal [[Call]] method of the interface object behaves as |
@@ -1140,33 +724,33 @@ IdlInterface.prototype.test_self = function() |
// "If I was not declared with a [Constructor] extended attribute, |
// then throw a TypeError." |
assert_throws(new TypeError(), function() { |
- window[this.name](); |
+ self[this.name](); |
}.bind(this), "interface object didn't throw TypeError when called as a function"); |
assert_throws(new TypeError(), function() { |
- new window[this.name](); |
+ new self[this.name](); |
}.bind(this), "interface object didn't throw TypeError when called as a constructor"); |
} |
}.bind(this), this.name + " interface: existence and properties of interface object"); |
if (!this.is_callback()) { |
test(function() { |
- // This function tests WebIDL as of 2013-08-25. |
- // http://dev.w3.org/2006/webapi/WebIDL/#es-interface-call |
+ // This function tests WebIDL as of 2014-10-25. |
+ // https://heycam.github.io/webidl/#es-interface-call |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
// "Interface objects for non-callback interfaces MUST have a |
// property named “length” with attributes { [[Writable]]: false, |
- // [[Enumerable]]: false, [[Configurable]]: false } whose value is |
+ // [[Enumerable]]: false, [[Configurable]]: true } whose value is |
// a Number." |
- assert_own_property(window[this.name], "length"); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name], "length"); |
+ assert_own_property(self[this.name], "length"); |
+ var desc = Object.getOwnPropertyDescriptor(self[this.name], "length"); |
assert_false("get" in desc, this.name + ".length has getter"); |
assert_false("set" in desc, this.name + ".length has setter"); |
assert_false(desc.writable, this.name + ".length is writable"); |
assert_false(desc.enumerable, this.name + ".length is enumerable"); |
- assert_false(desc.configurable, this.name + ".length is configurable"); |
+ assert_true(desc.configurable, this.name + ".length is not configurable"); |
var constructors = this.extAttrs |
.filter(function(attr) { return attr.name == "Constructor"; }); |
@@ -1186,7 +770,7 @@ IdlInterface.prototype.test_self = function() |
}) |
.reduce(function(m, n) { return Math.min(m, n); }); |
} |
- assert_equals(window[this.name].length, expected_length, "wrong value for " + this.name + ".length"); |
+ assert_equals(self[this.name].length, expected_length, "wrong value for " + this.name + ".length"); |
}.bind(this), this.name + " interface object length"); |
} |
@@ -1194,24 +778,32 @@ IdlInterface.prototype.test_self = function() |
test(function() |
{ |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
+ // This function tests WebIDL as of 2015-01-21. |
+ // https://heycam.github.io/webidl/#interface-object |
- if (this.has_extended_attribute("Callback")) { |
- assert_false("prototype" in window[this.name], |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ |
+ if (this.is_callback()) { |
+ assert_false("prototype" in self[this.name], |
this.name + ' should not have a "prototype" property'); |
return; |
} |
- // "The interface object must also have a property named “prototype” |
- // with attributes { [[Writable]]: false, [[Enumerable]]: false, |
- // [[Configurable]]: false } whose value is an object called the |
- // interface prototype object. This object has properties that |
- // correspond to the attributes and operations defined on the |
- // interface, and is described in more detail in section 4.5.3 below." |
- assert_own_property(window[this.name], "prototype", |
+ // "An interface object for a non-callback interface must have a |
+ // property named “prototype” with attributes { [[Writable]]: false, |
+ // [[Enumerable]]: false, [[Configurable]]: false } whose value is an |
+ // object called the interface prototype object. This object has |
+ // properties that correspond to the regular attributes and regular |
+ // operations defined on the interface, and is described in more detail |
+ // in section 4.5.4 below." |
+ assert_own_property(self[this.name], "prototype", |
'interface "' + this.name + '" does not have own property "prototype"'); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype"); |
+ var desc = Object.getOwnPropertyDescriptor(self[this.name], "prototype"); |
assert_false("get" in desc, this.name + ".prototype has getter"); |
assert_false("set" in desc, this.name + ".prototype has setter"); |
assert_false(desc.writable, this.name + ".prototype is writable"); |
@@ -1226,72 +818,86 @@ IdlInterface.prototype.test_self = function() |
// correct. Consolidate that code. |
// "The interface prototype object for a given interface A must have an |
- // internal [[Prototype]] property whose value is as follows: |
- // "If A is not declared to inherit from another interface, then the |
- // value of the internal [[Prototype]] property of A is the Array |
- // prototype object ([ECMA-262], section 15.4.4) if the interface was |
- // declared with ArrayClass, or the Object prototype object otherwise |
+ // internal [[Prototype]] property whose value is returned from the |
+ // following steps: |
+ // "If A is declared with the [Global] or [PrimaryGlobal] extended |
+ // attribute, and A supports named properties, then return the named |
+ // properties object for A, as defined in section 4.5.5 below. |
+ // "Otherwise, if A is declared to inherit from another interface, then |
+ // return the interface prototype object for the inherited interface. |
+ // "Otherwise, if A is declared with the [ArrayClass] extended |
+ // attribute, then return %ArrayPrototype% ([ECMA-262], section |
+ // 6.1.7.4). |
+ // "Otherwise, return %ObjectPrototype% ([ECMA-262], section 6.1.7.4). |
// ([ECMA-262], section 15.2.4). |
- // "Otherwise, A does inherit from another interface. The value of the |
- // internal [[Prototype]] property of A is the interface prototype |
- // object for the inherited interface." |
- var inherit_interface, inherit_interface_has_interface_object; |
- if (this.base) { |
- inherit_interface = this.base; |
- inherit_interface_has_interface_object = |
- !this.array |
- .members[inherit_interface] |
- .has_extended_attribute("NoInterfaceObject"); |
- } else if (this.has_extended_attribute('ArrayClass')) { |
- inherit_interface = 'Array'; |
- inherit_interface_has_interface_object = true; |
- } else { |
- inherit_interface = 'Object'; |
- inherit_interface_has_interface_object = true; |
- } |
- if (inherit_interface_has_interface_object) { |
- assert_own_property(window, inherit_interface, |
- 'should inherit from ' + inherit_interface + ', but window has no such property'); |
- assert_own_property(window[inherit_interface], 'prototype', |
- 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property'); |
- assert_equals(Object.getPrototypeOf(window[this.name].prototype), |
- window[inherit_interface].prototype, |
- 'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype'); |
+ if (this.name === "Window") { |
+ assert_class_string(Object.getPrototypeOf(self[this.name].prototype), |
+ 'WindowProperties', |
+ 'Class name for prototype of Window' + |
+ '.prototype is not "WindowProperties"'); |
} else { |
- // We can't test that we get the correct object, because this is the |
- // only way to get our hands on it. We only test that its class |
- // string, at least, is correct. |
- assert_class_string(Object.getPrototypeOf(window[this.name].prototype), |
- inherit_interface + 'Prototype', |
- 'Class name for prototype of ' + this.name + |
- '.prototype is not "' + inherit_interface + 'Prototype"'); |
+ var inherit_interface, inherit_interface_has_interface_object; |
+ if (this.base) { |
+ inherit_interface = this.base; |
+ inherit_interface_has_interface_object = |
+ !this.array |
+ .members[inherit_interface] |
+ .has_extended_attribute("NoInterfaceObject"); |
+ } else if (this.has_extended_attribute('ArrayClass')) { |
+ inherit_interface = 'Array'; |
+ inherit_interface_has_interface_object = true; |
+ } else { |
+ inherit_interface = 'Object'; |
+ inherit_interface_has_interface_object = true; |
+ } |
+ if (inherit_interface_has_interface_object) { |
+ assert_own_property(self, inherit_interface, |
+ 'should inherit from ' + inherit_interface + ', but self has no such property'); |
+ assert_own_property(self[inherit_interface], 'prototype', |
+ 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property'); |
+ assert_equals(Object.getPrototypeOf(self[this.name].prototype), |
+ self[inherit_interface].prototype, |
+ 'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype'); |
+ } else { |
+ // We can't test that we get the correct object, because this is the |
+ // only way to get our hands on it. We only test that its class |
+ // string, at least, is correct. |
+ assert_class_string(Object.getPrototypeOf(self[this.name].prototype), |
+ inherit_interface + 'Prototype', |
+ 'Class name for prototype of ' + this.name + |
+ '.prototype is not "' + inherit_interface + 'Prototype"'); |
+ } |
} |
// "The class string of an interface prototype object is the |
// concatenation of the interface’s identifier and the string |
// “Prototype”." |
- assert_class_string(window[this.name].prototype, this.name + "Prototype", |
+ assert_class_string(self[this.name].prototype, this.name + "Prototype", |
"class string of " + this.name + ".prototype"); |
// String() should end up calling {}.toString if nothing defines a |
// stringifier. |
if (!this.has_stringifier()) { |
- assert_equals(String(window[this.name].prototype), "[object " + this.name + "Prototype]", |
+ assert_equals(String(self[this.name].prototype), "[object " + this.name + "Prototype]", |
"String(" + this.name + ".prototype)"); |
} |
}.bind(this), this.name + " interface: existence and properties of interface prototype object"); |
test(function() |
{ |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
- if (this.has_extended_attribute("Callback")) { |
- assert_false("prototype" in window[this.name], |
+ if (this.is_callback()) { |
+ assert_false("prototype" in self[this.name], |
this.name + ' should not have a "prototype" property'); |
return; |
} |
- assert_own_property(window[this.name], "prototype", |
+ assert_own_property(self[this.name], "prototype", |
'interface "' + this.name + '" does not have own property "prototype"'); |
// "If the [NoInterfaceObject] extended attribute was not specified on |
@@ -1299,215 +905,374 @@ IdlInterface.prototype.test_self = function() |
// property named “constructor” with attributes { [[Writable]]: true, |
// [[Enumerable]]: false, [[Configurable]]: true } whose value is a |
// reference to the interface object for the interface." |
- assert_own_property(window[this.name].prototype, "constructor", |
+ assert_own_property(self[this.name].prototype, "constructor", |
this.name + '.prototype does not have own property "constructor"'); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor"); |
+ var desc = Object.getOwnPropertyDescriptor(self[this.name].prototype, "constructor"); |
assert_false("get" in desc, this.name + ".prototype.constructor has getter"); |
assert_false("set" in desc, this.name + ".prototype.constructor has setter"); |
assert_true(desc.writable, this.name + ".prototype.constructor is not writable"); |
assert_false(desc.enumerable, this.name + ".prototype.constructor is enumerable"); |
assert_true(desc.configurable, this.name + ".prototype.constructor in not configurable"); |
- assert_equals(window[this.name].prototype.constructor, window[this.name], |
+ assert_equals(self[this.name].prototype.constructor, self[this.name], |
this.name + '.prototype.constructor is not the same object as ' + this.name); |
}.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property'); |
}; |
//@} |
+IdlInterface.prototype.test_member_const = function(member) |
+//@{ |
+{ |
+ test(function() |
+ { |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ |
+ // "For each constant defined on an interface A, there must be |
+ // a corresponding property on the interface object, if it |
+ // exists." |
+ assert_own_property(self[this.name], member.name); |
+ // "The value of the property is that which is obtained by |
+ // converting the constant’s IDL value to an ECMAScript |
+ // value." |
+ assert_equals(self[this.name][member.name], constValue(member.value), |
+ "property has wrong value"); |
+ // "The property has attributes { [[Writable]]: false, |
+ // [[Enumerable]]: true, [[Configurable]]: false }." |
+ var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name); |
+ assert_false("get" in desc, "property has getter"); |
+ assert_false("set" in desc, "property has setter"); |
+ assert_false(desc.writable, "property is writable"); |
+ assert_true(desc.enumerable, "property is not enumerable"); |
+ assert_false(desc.configurable, "property is configurable"); |
+ }.bind(this), this.name + " interface: constant " + member.name + " on interface object"); |
+ // "In addition, a property with the same characteristics must |
+ // exist on the interface prototype object." |
+ test(function() |
+ { |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ |
+ if (this.is_callback()) { |
+ assert_false("prototype" in self[this.name], |
+ this.name + ' should not have a "prototype" property'); |
+ return; |
+ } |
+ |
+ assert_own_property(self[this.name], "prototype", |
+ 'interface "' + this.name + '" does not have own property "prototype"'); |
+ |
+ assert_own_property(self[this.name].prototype, member.name); |
+ assert_equals(self[this.name].prototype[member.name], constValue(member.value), |
+ "property has wrong value"); |
+ var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name); |
+ assert_false("get" in desc, "property has getter"); |
+ assert_false("set" in desc, "property has setter"); |
+ assert_false(desc.writable, "property is writable"); |
+ assert_true(desc.enumerable, "property is not enumerable"); |
+ assert_false(desc.configurable, "property is configurable"); |
+ }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object"); |
+}; |
+ |
+ |
+//@} |
+IdlInterface.prototype.test_member_attribute = function(member) |
+//@{ |
+{ |
+ test(function() |
+ { |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ assert_own_property(self[this.name], "prototype", |
+ 'interface "' + this.name + '" does not have own property "prototype"'); |
+ |
+ if (member["static"]) { |
+ assert_own_property(self[this.name], member.name, |
+ "The interface object must have a property " + |
+ format_value(member.name)); |
+ } else if (this.is_global()) { |
+ assert_own_property(self, member.name, |
+ "The global object must have a property " + |
+ format_value(member.name)); |
+ assert_false(member.name in self[this.name].prototype, |
+ "The prototype object must not have a property " + |
+ format_value(member.name)); |
+ |
+ // Try/catch around the get here, since it can legitimately throw. |
+ // If it does, we obviously can't check for equality with direct |
+ // invocation of the getter. |
+ var gotValue; |
+ var propVal; |
+ try { |
+ propVal = self[member.name]; |
+ gotValue = true; |
+ } catch (e) { |
+ gotValue = false; |
+ } |
+ if (gotValue) { |
+ var getter = Object.getOwnPropertyDescriptor(self, member.name).get; |
+ assert_equals(typeof(getter), "function", |
+ format_value(member.name) + " must have a getter"); |
+ assert_equals(propVal, getter.call(undefined), |
+ "Gets on a global should not require an explicit this"); |
+ } |
+ this.do_interface_attribute_asserts(self, member); |
+ } else { |
+ assert_true(member.name in self[this.name].prototype, |
+ "The prototype object must have a property " + |
+ format_value(member.name)); |
+ |
+ if (!member.has_extended_attribute("LenientThis")) { |
+ assert_throws(new TypeError(), function() { |
+ self[this.name].prototype[member.name]; |
+ }.bind(this), "getting property on prototype object must throw TypeError"); |
+ } else { |
+ assert_equals(self[this.name].prototype[member.name], undefined, |
+ "getting property on prototype object must return undefined"); |
+ } |
+ this.do_interface_attribute_asserts(self[this.name].prototype, member); |
+ } |
+ }.bind(this), this.name + " interface: attribute " + member.name); |
+}; |
+ |
+//@} |
+IdlInterface.prototype.test_member_operation = function(member) |
+//@{ |
+{ |
+ test(function() |
+ { |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ |
+ if (this.is_callback()) { |
+ assert_false("prototype" in self[this.name], |
+ this.name + ' should not have a "prototype" property'); |
+ return; |
+ } |
+ |
+ assert_own_property(self[this.name], "prototype", |
+ 'interface "' + this.name + '" does not have own property "prototype"'); |
+ |
+ // "For each unique identifier of an operation defined on the |
+ // interface, there must be a corresponding property on the |
+ // interface prototype object (if it is a regular operation) or |
+ // the interface object (if it is a static operation), unless |
+ // the effective overload set for that identifier and operation |
+ // and with an argument count of 0 (for the ECMAScript language |
+ // binding) has no entries." |
+ // |
+ var memberHolderObject; |
+ if (member["static"]) { |
+ assert_own_property(self[this.name], member.name, |
+ "interface object missing static operation"); |
+ memberHolderObject = self[this.name]; |
+ } else if (this.is_global()) { |
+ assert_own_property(self, member.name, |
+ "global object missing non-static operation"); |
+ memberHolderObject = self; |
+ } else { |
+ assert_own_property(self[this.name].prototype, member.name, |
+ "interface prototype object missing non-static operation"); |
+ memberHolderObject = self[this.name].prototype; |
+ } |
+ |
+ this.do_member_operation_asserts(memberHolderObject, member); |
+ }.bind(this), this.name + " interface: operation " + member.name + |
+ "(" + member.arguments.map(function(m) { return m.idlType.idlType; }) + |
+ ")"); |
+}; |
+ |
+//@} |
+IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject, member) |
+//@{ |
+{ |
+ var operationUnforgeable = member.isUnforgeable; |
+ var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name); |
+ // "The property has attributes { [[Writable]]: B, |
+ // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the |
+ // operation is unforgeable on the interface, and true otherwise". |
+ assert_false("get" in desc, "property has getter"); |
+ assert_false("set" in desc, "property has setter"); |
+ assert_equals(desc.writable, !operationUnforgeable, |
+ "property should be writable if and only if not unforgeable"); |
+ assert_true(desc.enumerable, "property is not enumerable"); |
+ assert_equals(desc.configurable, !operationUnforgeable, |
+ "property should be configurable if and only if not unforgeable"); |
+ // "The value of the property is a Function object whose |
+ // behavior is as follows . . ." |
+ assert_equals(typeof memberHolderObject[member.name], "function", |
+ "property must be a function"); |
+ // "The value of the Function object’s “length” property is |
+ // a Number determined as follows: |
+ // ". . . |
+ // "Return the length of the shortest argument list of the |
+ // entries in S." |
+ // |
+ // TODO: Doesn't handle overloading or variadic arguments. |
+ assert_equals(memberHolderObject[member.name].length, |
+ member.arguments.filter(function(arg) { |
+ return !arg.optional; |
+ }).length, |
+ "property has wrong .length"); |
+ |
+ // Make some suitable arguments |
+ var args = member.arguments.map(function(arg) { |
+ return create_suitable_object(arg.idlType); |
+ }); |
+ |
+ // "Let O be a value determined as follows: |
+ // ". . . |
+ // "Otherwise, throw a TypeError." |
+ // This should be hit if the operation is not static, there is |
+ // no [ImplicitThis] attribute, and the this value is null. |
+ // |
+ // TODO: We currently ignore the [ImplicitThis] case. Except we manually |
+ // check for globals, since otherwise we'll invoke window.close(). And we |
+ // have to skip this test for anything that on the proto chain of "self", |
+ // since that does in fact have implicit-this behavior. |
+ if (!member["static"]) { |
+ if (!this.is_global() && |
+ memberHolderObject[member.name] != self[member.name]) |
+ { |
+ assert_throws(new TypeError(), function() { |
+ memberHolderObject[member.name].apply(null, args); |
+ }, "calling operation with this = null didn't throw TypeError"); |
+ } |
+ |
+ // ". . . If O is not null and is also not a platform object |
+ // that implements interface I, throw a TypeError." |
+ // |
+ // TODO: Test a platform object that implements some other |
+ // interface. (Have to be sure to get inheritance right.) |
+ assert_throws(new TypeError(), function() { |
+ memberHolderObject[member.name].apply({}, args); |
+ }, "calling operation with this = {} didn't throw TypeError"); |
+ } |
+} |
+ |
+//@} |
+IdlInterface.prototype.test_member_stringifier = function(member) |
+//@{ |
+{ |
+ test(function() |
+ { |
+ if (this.is_callback() && !this.has_constants()) { |
+ return; |
+ } |
+ |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ |
+ if (this.is_callback()) { |
+ assert_false("prototype" in self[this.name], |
+ this.name + ' should not have a "prototype" property'); |
+ return; |
+ } |
+ |
+ assert_own_property(self[this.name], "prototype", |
+ 'interface "' + this.name + '" does not have own property "prototype"'); |
+ |
+ // ". . . the property exists on the interface prototype object." |
+ var interfacePrototypeObject = self[this.name].prototype; |
+ assert_own_property(self[this.name].prototype, "toString", |
+ "interface prototype object missing non-static operation"); |
+ |
+ var stringifierUnforgeable = member.isUnforgeable; |
+ var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "toString"); |
+ // "The property has attributes { [[Writable]]: B, |
+ // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the |
+ // stringifier is unforgeable on the interface, and true otherwise." |
+ assert_false("get" in desc, "property has getter"); |
+ assert_false("set" in desc, "property has setter"); |
+ assert_equals(desc.writable, !stringifierUnforgeable, |
+ "property should be writable if and only if not unforgeable"); |
+ assert_true(desc.enumerable, "property is not enumerable"); |
+ assert_equals(desc.configurable, !stringifierUnforgeable, |
+ "property should be configurable if and only if not unforgeable"); |
+ // "The value of the property is a Function object, which behaves as |
+ // follows . . ." |
+ assert_equals(typeof interfacePrototypeObject.toString, "function", |
+ "property must be a function"); |
+ // "The value of the Function object’s “length” property is the Number |
+ // value 0." |
+ assert_equals(interfacePrototypeObject.toString.length, 0, |
+ "property has wrong .length"); |
+ |
+ // "Let O be the result of calling ToObject on the this value." |
+ assert_throws(new TypeError(), function() { |
+ self[this.name].prototype.toString.apply(null, []); |
+ }, "calling stringifier with this = null didn't throw TypeError"); |
+ |
+ // "If O is not an object that implements the interface on which the |
+ // stringifier was declared, then throw a TypeError." |
+ // |
+ // TODO: Test a platform object that implements some other |
+ // interface. (Have to be sure to get inheritance right.) |
+ assert_throws(new TypeError(), function() { |
+ self[this.name].prototype.toString.apply({}, []); |
+ }, "calling stringifier with this = {} didn't throw TypeError"); |
+ }.bind(this), this.name + " interface: stringifier"); |
+}; |
+ |
+//@} |
IdlInterface.prototype.test_members = function() |
//@{ |
{ |
for (var i = 0; i < this.members.length; i++) |
{ |
var member = this.members[i]; |
- if (member.untested) |
- { |
+ if (member.untested) { |
continue; |
} |
- if (member.type == "const") |
- { |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- |
- // "For each constant defined on an interface A, there must be |
- // a corresponding property on the interface object, if it |
- // exists." |
- assert_own_property(window[this.name], member.name); |
- // "The value of the property is that which is obtained by |
- // converting the constant’s IDL value to an ECMAScript |
- // value." |
- assert_equals(window[this.name][member.name], constValue(member.value), |
- "property has wrong value"); |
- // "The property has attributes { [[Writable]]: false, |
- // [[Enumerable]]: true, [[Configurable]]: false }." |
- var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name); |
- assert_false("get" in desc, "property has getter"); |
- assert_false("set" in desc, "property has setter"); |
- assert_false(desc.writable, "property is writable"); |
- assert_true(desc.enumerable, "property is not enumerable"); |
- assert_false(desc.configurable, "property is configurable"); |
- }.bind(this), this.name + " interface: constant " + member.name + " on interface object"); |
- // "In addition, a property with the same characteristics must |
- // exist on the interface prototype object." |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- if (this.has_extended_attribute("Callback")) { |
- assert_false("prototype" in window[this.name], |
- this.name + ' should not have a "prototype" property'); |
- return; |
- } |
+ switch (member.type) { |
+ case "const": |
+ this.test_member_const(member); |
+ break; |
- assert_own_property(window[this.name], "prototype", |
- 'interface "' + this.name + '" does not have own property "prototype"'); |
- |
- assert_own_property(window[this.name].prototype, member.name); |
- assert_equals(window[this.name].prototype[member.name], constValue(member.value), |
- "property has wrong value"); |
- var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name); |
- assert_false("get" in desc, "property has getter"); |
- assert_false("set" in desc, "property has setter"); |
- assert_false(desc.writable, "property is writable"); |
- assert_true(desc.enumerable, "property is not enumerable"); |
- assert_false(desc.configurable, "property is configurable"); |
- }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object"); |
- } |
- else if (member.type == "attribute") |
- { |
- if (member.has_extended_attribute("Unforgeable")) |
+ case "attribute": |
+ // For unforgeable attributes, we do the checks in |
+ // test_interface_of instead. |
+ if (!member.isUnforgeable) |
{ |
- // We do the checks in test_interface_of instead |
- continue; |
+ this.test_member_attribute(member); |
} |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
- 'interface "' + this.name + '" does not have own property "prototype"'); |
- |
- if (member["static"]) { |
- assert_own_property(window[this.name], member.name, |
- "The interface object must have a property " + |
- format_value(member.name)); |
- } |
- else |
- { |
- assert_true(member.name in window[this.name].prototype, |
- "The prototype object must have a property " + |
- format_value(member.name)); |
- |
- // TODO: Needs to test for LenientThis. |
- assert_throws(new TypeError(), function() { |
- window[this.name].prototype[member.name]; |
- }.bind(this), "getting property on prototype object must throw TypeError"); |
- do_interface_attribute_asserts(window[this.name].prototype, member); |
- } |
- }.bind(this), this.name + " interface: attribute " + member.name); |
- } |
- else if (member.type == "operation") |
- { |
+ break; |
+ |
+ case "operation": |
// TODO: Need to correctly handle multiple operations with the same |
// identifier. |
- if (!member.name) |
- { |
- // Unnamed getter or such |
- continue; |
- } |
- test(function() |
- { |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- |
- if (this.has_extended_attribute("Callback")) { |
- assert_false("prototype" in window[this.name], |
- this.name + ' should not have a "prototype" property'); |
- return; |
- } |
- |
- assert_own_property(window[this.name], "prototype", |
- 'interface "' + this.name + '" does not have own property "prototype"'); |
- |
- // "For each unique identifier of an operation defined on the |
- // interface, there must be a corresponding property on the |
- // interface prototype object (if it is a regular operation) or |
- // the interface object (if it is a static operation), unless |
- // the effective overload set for that identifier and operation |
- // and with an argument count of 0 (for the ECMAScript language |
- // binding) has no entries." |
- // |
- var prototypeOrInterfaceObject; |
- if (member["static"]) { |
- assert_own_property(window[this.name], member.name, |
- "interface prototype object missing static operation"); |
- prototypeOrInterfaceObject = window[this.name]; |
- } |
- else |
+ // For unforgeable operations, we do the checks in |
+ // test_interface_of instead. |
+ if (member.name) { |
+ if (!member.isUnforgeable) |
{ |
- assert_own_property(window[this.name].prototype, member.name, |
- "interface prototype object missing non-static operation"); |
- prototypeOrInterfaceObject = window[this.name].prototype; |
- } |
- |
- var desc = Object.getOwnPropertyDescriptor(prototypeOrInterfaceObject, member.name); |
- // "The property has attributes { [[Writable]]: true, |
- // [[Enumerable]]: true, [[Configurable]]: true }." |
- assert_false("get" in desc, "property has getter"); |
- assert_false("set" in desc, "property has setter"); |
- assert_true(desc.writable, "property is not writable"); |
- assert_true(desc.enumerable, "property is not enumerable"); |
- assert_true(desc.configurable, "property is not configurable"); |
- // "The value of the property is a Function object whose |
- // behavior is as follows . . ." |
- assert_equals(typeof prototypeOrInterfaceObject[member.name], "function", |
- "property must be a function"); |
- // "The value of the Function object’s “length” property is |
- // a Number determined as follows: |
- // ". . . |
- // "Return the length of the shortest argument list of the |
- // entries in S." |
- // |
- // TODO: Doesn't handle overloading or variadic arguments. |
- assert_equals(prototypeOrInterfaceObject[member.name].length, |
- member.arguments.filter(function(arg) { |
- return !arg.optional; |
- }).length, |
- "property has wrong .length"); |
- |
- // Make some suitable arguments |
- var args = member.arguments.map(function(arg) { |
- return create_suitable_object(arg.idlType); |
- }); |
- |
- // "Let O be a value determined as follows: |
- // ". . . |
- // "Otherwise, throw a TypeError." |
- // This should be hit if the operation is not static, there is |
- // no [ImplicitThis] attribute, and the this value is null. |
- // |
- // TODO: We currently ignore the [ImplicitThis] case. |
- if (!member["static"]) { |
- assert_throws(new TypeError(), function() { |
- window[this.name].prototype[member.name].apply(null, args); |
- }, "calling operation with this = null didn't throw TypeError"); |
+ this.test_member_operation(member); |
} |
+ } else if (member.stringifier) { |
+ this.test_member_stringifier(member); |
+ } |
+ break; |
- // ". . . If O is not null and is also not a platform object |
- // that implements interface I, throw a TypeError." |
- // |
- // TODO: Test a platform object that implements some other |
- // interface. (Have to be sure to get inheritance right.) |
- assert_throws(new TypeError(), function() { |
- window[this.name].prototype[member.name].apply({}, args); |
- }, "calling operation with this = {} didn't throw TypeError"); |
- }.bind(this), this.name + " interface: operation " + member.name + |
- "(" + member.arguments.map(function(m) { return m.idlType.idlType; }) + |
- ")"); |
+ default: |
+ // TODO: check more member types. |
+ break; |
} |
- // TODO: check more member types, like stringifier |
} |
}; |
@@ -1567,9 +1332,9 @@ IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception |
{ |
assert_equals(exception, null, "Unexpected exception when evaluating object"); |
assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
- assert_own_property(window, this.name, |
- "window does not have own property " + format_value(this.name)); |
- assert_own_property(window[this.name], "prototype", |
+ assert_own_property(self, this.name, |
+ "self does not have own property " + format_value(this.name)); |
+ assert_own_property(self[this.name], "prototype", |
'interface "' + this.name + '" does not have own property "prototype"'); |
// "The value of the internal [[Prototype]] property of the |
@@ -1577,7 +1342,7 @@ IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception |
// interface from the platform object’s associated global |
// environment." |
assert_equals(Object.getPrototypeOf(obj), |
- window[this.name].prototype, |
+ self[this.name].prototype, |
desc + "'s prototype is not " + this.name + ".prototype"); |
}.bind(this), this.name + " must be primary interface of " + desc); |
} |
@@ -1607,13 +1372,26 @@ IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect |
for (var i = 0; i < this.members.length; i++) |
{ |
var member = this.members[i]; |
- if (member.has_extended_attribute("Unforgeable")) |
+ if (member.type == "attribute" && member.isUnforgeable) |
+ { |
+ test(function() |
+ { |
+ assert_equals(exception, null, "Unexpected exception when evaluating object"); |
+ assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
+ this.do_interface_attribute_asserts(obj, member); |
+ }.bind(this), this.name + " interface: " + desc + ' must have own property "' + member.name + '"'); |
+ } |
+ else if (member.type == "operation" && |
+ member.name && |
+ member.isUnforgeable) |
{ |
test(function() |
{ |
assert_equals(exception, null, "Unexpected exception when evaluating object"); |
assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
- do_interface_attribute_asserts(obj, member); |
+ assert_own_property(obj, member.name, |
+ "Doesn't have the unforgeable operation property"); |
+ this.do_member_operation_asserts(obj, member); |
}.bind(this), this.name + " interface: " + desc + ' must have own property "' + member.name + '"'); |
} |
else if ((member.type == "const" |
@@ -1626,7 +1404,12 @@ IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect |
assert_equals(exception, null, "Unexpected exception when evaluating object"); |
assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
if (!member["static"]) { |
- assert_inherits(obj, member.name); |
+ if (!this.is_global()) { |
+ assert_inherits(obj, member.name); |
+ } else { |
+ assert_own_property(obj, member.name); |
+ } |
+ |
if (member.type == "const") |
{ |
assert_equals(obj[member.name], constValue(member.value)); |
@@ -1667,7 +1450,11 @@ IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect |
assert_equals(exception, null, "Unexpected exception when evaluating object"); |
assert_equals(typeof obj, expected_typeof, "wrong typeof object"); |
if (!member["static"]) { |
- assert_inherits(obj, member.name); |
+ if (!this.is_global() && !member.isUnforgeable) { |
+ assert_inherits(obj, member.name); |
+ } else { |
+ assert_own_property(obj, member.name); |
+ } |
} |
else |
{ |
@@ -1709,17 +1496,22 @@ IdlInterface.prototype.has_stringifier = function() |
}; |
//@} |
-function do_interface_attribute_asserts(obj, member) |
+IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member) |
//@{ |
{ |
- // "For each attribute defined on the interface, there must exist a |
- // corresponding property. If the attribute was declared with the |
- // [Unforgeable] extended attribute, then the property exists on every |
- // object that implements the interface. Otherwise, it exists on the |
- // interface’s interface prototype object." |
- // |
- // This is called by test_self() with the prototype as obj, and by |
- // test_interface_of() with the object as obj. |
+ // This function tests WebIDL as of 2015-01-27. |
+ // TODO: Consider [Exposed]. |
+ |
+ // This is called by test_member_attribute() with the prototype as obj if |
+ // it is not a global, and the global otherwise, and by test_interface_of() |
+ // with the object as obj. |
+ |
+ // "For each exposed attribute of the interface, whether it was declared on |
+ // the interface itself or one of its consequential interfaces, there MUST |
+ // exist a corresponding property. The characteristics of this property are |
+ // as follows:" |
+ |
+ // "The name of the property is the identifier of the attribute." |
assert_own_property(obj, member.name); |
// "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]: |
@@ -1732,7 +1524,7 @@ function do_interface_attribute_asserts(obj, member) |
assert_false("value" in desc, 'property descriptor has value but is supposed to be accessor'); |
assert_false("writable" in desc, 'property descriptor has "writable" field but is supposed to be accessor'); |
assert_true(desc.enumerable, "property is not enumerable"); |
- if (member.has_extended_attribute("Unforgeable")) |
+ if (member.isUnforgeable) |
{ |
assert_false(desc.configurable, "[Unforgeable] property must not be configurable"); |
} |
@@ -1741,38 +1533,69 @@ function do_interface_attribute_asserts(obj, member) |
assert_true(desc.configurable, "property must be configurable"); |
} |
+ |
// "The attribute getter is a Function object whose behavior when invoked |
- // is as follows: |
- // "... |
+ // is as follows:" |
+ assert_equals(typeof desc.get, "function", "getter must be Function"); |
+ |
+ // "If the attribute is a regular attribute, then:" |
+ if (!member["static"]) { |
+ // "If O is not a platform object that implements I, then: |
+ // "If the attribute was specified with the [LenientThis] extended |
+ // attribute, then return undefined. |
+ // "Otherwise, throw a TypeError." |
+ if (!member.has_extended_attribute("LenientThis")) { |
+ assert_throws(new TypeError(), function() { |
+ desc.get.call({}); |
+ }.bind(this), "calling getter on wrong object type must throw TypeError"); |
+ } else { |
+ assert_equals(desc.get.call({}), undefined, |
+ "calling getter on wrong object type must return undefined"); |
+ } |
+ } |
+ |
// "The value of the Function object’s “length” property is the Number |
// value 0." |
- assert_equals(typeof desc.get, "function", "getter must be Function"); |
assert_equals(desc.get.length, 0, "getter length must be 0"); |
- // TODO: Account for LenientThis |
- assert_throws(new TypeError(), function() |
- { |
- desc.get.call({}); |
- }.bind(this), "calling getter on wrong object type must throw TypeError"); |
+ |
// TODO: Test calling setter on the interface prototype (should throw |
// TypeError in most cases). |
- // |
- // "The attribute setter is undefined if the attribute is declared readonly |
- // and has neither a [PutForwards] nor a [Replaceable] extended attribute |
- // declared on it. Otherwise, it is a Function object whose behavior when |
- // invoked is as follows: |
- // "... |
- // "The value of the Function object’s “length” property is the Number |
- // value 1." |
if (member.readonly |
&& !member.has_extended_attribute("PutForwards") |
&& !member.has_extended_attribute("Replaceable")) |
{ |
+ // "The attribute setter is undefined if the attribute is declared |
+ // readonly and has neither a [PutForwards] nor a [Replaceable] |
+ // extended attribute declared on it." |
assert_equals(desc.set, undefined, "setter must be undefined for readonly attributes"); |
} |
else |
{ |
+ // "Otherwise, it is a Function object whose behavior when |
+ // invoked is as follows:" |
assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes"); |
+ |
+ // "If the attribute is a regular attribute, then:" |
+ if (!member["static"]) { |
+ // "If /validThis/ is false and the attribute was not specified |
+ // with the [LenientThis] extended attribute, then throw a |
+ // TypeError." |
+ // "If the attribute is declared with a [Replaceable] extended |
+ // attribute, then: ..." |
+ // "If validThis is false, then return." |
+ if (!member.has_extended_attribute("LenientThis")) { |
+ assert_throws(new TypeError(), function() { |
+ desc.set.call({}); |
+ }.bind(this), "calling setter on wrong object type must throw TypeError"); |
+ } else { |
+ assert_equals(desc.set.call({}), undefined, |
+ "calling setter on wrong object type must return undefined"); |
+ } |
+ } |
+ |
+ // "The value of the Function object’s “length” property is the Number |
+ // value 1." |
assert_equals(desc.set.length, 1, "setter length must be 1"); |
} |
} |
@@ -1795,6 +1618,8 @@ function IdlInterfaceMember(obj) |
{ |
this.extAttrs = []; |
} |
+ |
+ this.isUnforgeable = this.has_extended_attribute("Unforgeable"); |
} |
//@} |
@@ -1826,6 +1651,8 @@ function create_suitable_object(type) |
return 7; |
case "DOMString": |
+ case "ByteString": |
+ case "USVString": |
return "foo"; |
case "object": |