WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-159979-20160720114409.patch (text/plain), 126.52 KB, created by
Jiewen Tan
on 2016-07-20 11:45:03 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Jiewen Tan
Created:
2016-07-20 11:45:03 PDT
Size:
126.52 KB
patch
obsolete
>Subversion Revision: 203379 >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 54bf4ebbe7f53df40d62c41caa04a13028f54a1f..baa1394d14e01102442e2df46397a12f030374e5 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,13 @@ >+2016-07-20 Jiewen Tan <jiewen_tan@apple.com> >+ >+ Fix timeout of imported/w3c/WebCryptoAPI/idlharness.html >+ https://bugs.webkit.org/show_bug.cgi?id=159979 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * TestExpectations: >+ Remove the skip tuple of the test. >+ > 2016-07-18 Andreas Kling <akling@apple.com> > > There should be a way to simulate memory pressure in layout tests >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index cf2eefc29de4e7c0a235068e3c57fdf975b07e3f..8dbd37c662c17659ddf029e2d797e4560607b2c8 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,96 @@ >+2016-07-20 Jiewen Tan <jiewen_tan@apple.com> >+ >+ Fix timeout of imported/w3c/WebCryptoAPI/idlharness.html >+ https://bugs.webkit.org/show_bug.cgi?id=159979 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add missing resources. >+ >+ * WebCryptoAPI/idlharness-expected.txt: >+ * WebCryptoAPI/idlharness.html: >+ * resources/WebIDLParser.js: Added. >+ (tokenise): >+ (WebIDLParseError): >+ (WebIDLParseError.prototype.toString): >+ (error): >+ (consume): >+ (ws): >+ (all_ws): >+ (integer_type): >+ (float_type): >+ (primitive_type): >+ (const_value): >+ (type_suffix): >+ (single_type): >+ (union_type): >+ (type): >+ (argument): >+ (argument_list): >+ (type_pair): >+ (simple_extended_attr): >+ (extended_attrs): >+ (default_): >+ (const_): >+ (inheritance): >+ (operation_rest): >+ (callback): >+ (attribute): >+ (return_type): >+ (operation): >+ (identifiers): >+ (serialiser): >+ (iterable_type): >+ (readonly_iterable_type): >+ (iterable): >+ (interface_): >+ (partial): >+ (dictionary): >+ (exception): >+ (enum_): >+ (parse): >+ * resources/idlharness.js: Added. >+ (constValue): >+ (minOverloadLength): >+ (throwOrReject): >+ (awaitNCallbacks): >+ (return.fround): >+ (fround): >+ (self.IdlArray): >+ (IdlArray.prototype.add_idls): >+ (IdlArray.prototype.add_untested_idls): >+ (IdlArray.prototype.internal_add_idls): >+ (IdlArray.prototype.add_objects): >+ (IdlArray.prototype.prevent_multiple_testing): >+ (IdlArray.prototype.recursively_get_implements): >+ (exposed_in): >+ (IdlArray.prototype.test): >+ (IdlArray.prototype.assert_type_is): >+ (IdlObject): >+ (IdlObject.prototype.test): >+ (IdlObject.prototype.has_extended_attribute): >+ (IdlInterface): >+ (IdlInterface.prototype.is_callback): >+ (IdlInterface.prototype.has_constants): >+ (IdlInterface.prototype.is_global): >+ (IdlInterface.prototype.test): >+ (IdlInterface.prototype.test_self): >+ (IdlInterface.prototype.test_member_const): >+ (IdlInterface.prototype.test_member_attribute): >+ (IdlInterface.prototype.test_member_operation): >+ (IdlInterface.prototype.do_member_operation_asserts): >+ (IdlInterface.prototype.test_member_stringifier): >+ (IdlInterface.prototype.test_members): >+ (IdlInterface.prototype.test_object): >+ (IdlInterface.prototype.test_primary_interface_of): >+ (IdlInterface.prototype.test_interface_of): >+ (IdlInterface.prototype.has_stringifier): >+ (IdlInterface.prototype.do_interface_attribute_asserts): >+ (IdlInterfaceMember): >+ (create_suitable_object): >+ (IdlEnum): >+ (IdlTypedef): >+ > 2016-07-18 Chris Dumez <cdumez@apple.com> > > The 2 first parameters to addEventListener() / removeEventListener() should be mandatory >diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations >index ef9b3a1d8a6f10f2340a639d0be15a0b564d687d..65047826fbeee2ad4b59e9044724a135aa786850 100644 >--- a/LayoutTests/TestExpectations >+++ b/LayoutTests/TestExpectations >@@ -1037,7 +1037,6 @@ imported/w3c/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html [ Skip ] > imported/w3c/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html [ Skip ] > imported/w3c/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html [ Skip ] > imported/w3c/WebCryptoAPI/generateKey/test_successes.html [ Skip ] >-imported/w3c/WebCryptoAPI/idlharness.html [ Skip ] > > editing/deleting/delete-emoji.html [ Slow ] > >diff --git a/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt b/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt >index 6ee3f713ff296369d0b405f81dd648f05ac0404c..aac86ae8ce963889de7a9a7490e0ba8ac8ac4fb2 100644 >--- a/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt >+++ b/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt >@@ -1,2 +1,70 @@ >-FAIL: Timed out waiting for notifyDone to be called >+Description >+ >+This test verifies that the implementations of the WebCrypto API match with its WebIDL definition. >+ >+ >+PASS Crypto interface: existence and properties of interface object >+PASS Crypto interface object length >+PASS Crypto interface object name >+PASS Crypto interface: existence and properties of interface prototype object >+PASS Crypto interface: existence and properties of interface prototype object's "constructor" property >+FAIL Crypto interface: attribute subtle assert_true: The prototype object must have a property "subtle" expected true got false >+PASS Crypto interface: operation getRandomValues(ArrayBufferView) >+PASS Crypto must be primary interface of crypto >+PASS Stringification of crypto >+FAIL Crypto interface: crypto must inherit property "subtle" with the proper type (0) assert_inherits: property "subtle" not found in prototype chain >+PASS Crypto interface: crypto must inherit property "getRandomValues" with the proper type (1) >+PASS Crypto interface: calling getRandomValues(ArrayBufferView) on crypto with too few arguments must throw TypeError >+FAIL CryptoKey interface: existence and properties of interface object assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface object length assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface object name assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface: attribute type assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface: attribute extractable assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface: attribute algorithm assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL CryptoKey interface: attribute usages assert_own_property: self does not have own property "CryptoKey" expected property "CryptoKey" missing >+FAIL SubtleCrypto interface: existence and properties of interface object assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface object length assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface object name assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation encrypt(AlgorithmIdentifier,CryptoKey,BufferSource) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation decrypt(AlgorithmIdentifier,CryptoKey,BufferSource) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation sign(AlgorithmIdentifier,CryptoKey,BufferSource) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation verify(AlgorithmIdentifier,CryptoKey,BufferSource,BufferSource) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation digest(AlgorithmIdentifier,BufferSource) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation generateKey(AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier,CryptoKey,AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier,CryptoKey,unsigned long) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation importKey(KeyFormat,[object Object],[object Object],AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation exportKey(KeyFormat,CryptoKey) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation wrapKey(KeyFormat,CryptoKey,CryptoKey,AlgorithmIdentifier) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto interface: operation unwrapKey(KeyFormat,BufferSource,CryptoKey,AlgorithmIdentifier,AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property "SubtleCrypto" expected property "SubtleCrypto" missing >+FAIL SubtleCrypto must be primary interface of crypto.subtle assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL Stringification of crypto.subtle assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "encrypt" with the proper type (0) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling encrypt(AlgorithmIdentifier,CryptoKey,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "decrypt" with the proper type (1) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling decrypt(AlgorithmIdentifier,CryptoKey,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "sign" with the proper type (2) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling sign(AlgorithmIdentifier,CryptoKey,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "verify" with the proper type (3) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling verify(AlgorithmIdentifier,CryptoKey,BufferSource,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "digest" with the proper type (4) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling digest(AlgorithmIdentifier,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "generateKey" with the proper type (5) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling generateKey(AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "deriveKey" with the proper type (6) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier,CryptoKey,AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "deriveBits" with the proper type (7) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling deriveBits(AlgorithmIdentifier,CryptoKey,unsigned long) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "importKey" with the proper type (8) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling importKey(KeyFormat,[object Object],[object Object],AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "exportKey" with the proper type (9) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling exportKey(KeyFormat,CryptoKey) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "wrapKey" with the proper type (10) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling wrapKey(KeyFormat,CryptoKey,CryptoKey,AlgorithmIdentifier) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: crypto.subtle must inherit property "unwrapKey" with the proper type (11) assert_equals: wrong typeof object expected "object" but got "undefined" >+FAIL SubtleCrypto interface: calling unwrapKey(KeyFormat,BufferSource,CryptoKey,AlgorithmIdentifier,AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined" > >diff --git a/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html b/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html >index e4067de2fd3ac9b3f5b404052b67239790c3fd66..8651bf5268bc84e9e962f548f5243c6be248694e 100644 >--- a/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html >+++ b/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html >@@ -1,3 +1,4 @@ >+ > <!doctype html> > <html> > <head> >@@ -7,8 +8,8 @@ > > <script src=../../../resources/testharness.js></script> > <script src=../../../resources/testharnessreport.js></script> >-<script src=/resources/WebIDLParser.js></script> >-<script src=/resources/idlharness.js></script> >+<script src=../resources/WebIDLParser.js></script> >+<script src=../resources/idlharness.js></script> > </head> > <body> > >diff --git a/LayoutTests/imported/w3c/resources/WebIDLParser.js b/LayoutTests/imported/w3c/resources/WebIDLParser.js >new file mode 100644 >index 0000000000000000000000000000000000000000..9e504fc6e1fdefd19cc7f71822e3dbfd4be5e678 >--- /dev/null >+++ b/LayoutTests/imported/w3c/resources/WebIDLParser.js >@@ -0,0 +1,1012 @@ >+ >+ >+(function () { >+ var tokenise = function (str) { >+ var tokens = [] >+ , re = { >+ "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/ >+ , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/ >+ , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/ >+ , "string": /^"[^"]*"/ >+ , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/ >+ , "other": /^[^\t\n\r 0-9A-Z_a-z]/ >+ } >+ , types = [] >+ ; >+ for (var k in re) types.push(k); >+ while (str.length > 0) { >+ var matched = false; >+ for (var i = 0, n = types.length; i < n; i++) { >+ var type = types[i]; >+ str = str.replace(re[type], function (tok) { >+ tokens.push({ type: type, value: tok }); >+ matched = true; >+ return ""; >+ }); >+ if (matched) break; >+ } >+ if (matched) continue; >+ throw new Error("Token stream not progressing"); >+ } >+ return tokens; >+ }; >+ >+ var parse = function (tokens, opt) { >+ var line = 1; >+ tokens = tokens.slice(); >+ >+ var FLOAT = "float" >+ , INT = "integer" >+ , ID = "identifier" >+ , STR = "string" >+ , OTHER = "other" >+ ; >+ >+ var WebIDLParseError = function (str, line, input, tokens) { >+ this.message = str; >+ this.line = line; >+ this.input = input; >+ this.tokens = tokens; >+ }; >+ WebIDLParseError.prototype.toString = function () { >+ return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" + >+ JSON.stringify(this.tokens, null, 4); >+ }; >+ >+ var error = function (str) { >+ var tok = "", numTokens = 0, maxTokens = 5; >+ while (numTokens < maxTokens && tokens.length > numTokens) { >+ tok += tokens[numTokens].value; >+ numTokens++; >+ } >+ throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5)); >+ }; >+ >+ var last_token = null; >+ >+ var consume = function (type, value) { >+ if (!tokens.length || tokens[0].type !== type) return; >+ if (typeof value === "undefined" || tokens[0].value === value) { >+ last_token = tokens.shift(); >+ if (type === ID) last_token.value = last_token.value.replace(/^_/, ""); >+ return last_token; >+ } >+ }; >+ >+ var ws = function () { >+ if (!tokens.length) return; >+ if (tokens[0].type === "whitespace") { >+ var t = tokens.shift(); >+ t.value.replace(/\n/g, function (m) { line++; return m; }); >+ return t; >+ } >+ }; >+ >+ var all_ws = function (store, pea) { // pea == post extended attribute, tpea = same for types >+ var t = { type: "whitespace", value: "" }; >+ while (true) { >+ var w = ws(); >+ if (!w) break; >+ t.value += w.value; >+ } >+ if (t.value.length > 0) { >+ if (store) { >+ var w = t.value >+ , re = { >+ "ws": /^([\t\n\r ]+)/ >+ , "line-comment": /^\/\/(.*)\n?/m >+ , "multiline-comment": /^\/\*((?:.|\n|\r)*?)\*\// >+ } >+ , wsTypes = [] >+ ; >+ for (var k in re) wsTypes.push(k); >+ while (w.length) { >+ var matched = false; >+ for (var i = 0, n = wsTypes.length; i < n; i++) { >+ var type = wsTypes[i]; >+ w = w.replace(re[type], function (tok, m1) { >+ store.push({ type: type + (pea ? ("-" + pea) : ""), value: m1 }); >+ matched = true; >+ return ""; >+ }); >+ if (matched) break; >+ } >+ if (matched) continue; >+ throw new Error("Surprising white space construct."); // this shouldn't happen >+ } >+ } >+ return t; >+ } >+ }; >+ >+ var integer_type = function () { >+ var ret = ""; >+ all_ws(); >+ if (consume(ID, "unsigned")) ret = "unsigned "; >+ all_ws(); >+ if (consume(ID, "short")) return ret + "short"; >+ if (consume(ID, "long")) { >+ ret += "long"; >+ all_ws(); >+ if (consume(ID, "long")) return ret + " long"; >+ return ret; >+ } >+ if (ret) error("Failed to parse integer type"); >+ }; >+ >+ var float_type = function () { >+ var ret = ""; >+ all_ws(); >+ if (consume(ID, "unrestricted")) ret = "unrestricted "; >+ all_ws(); >+ if (consume(ID, "float")) return ret + "float"; >+ if (consume(ID, "double")) return ret + "double"; >+ if (ret) error("Failed to parse float type"); >+ }; >+ >+ var primitive_type = function () { >+ var num_type = integer_type() || float_type(); >+ if (num_type) return num_type; >+ all_ws(); >+ if (consume(ID, "boolean")) return "boolean"; >+ if (consume(ID, "byte")) return "byte"; >+ if (consume(ID, "octet")) return "octet"; >+ }; >+ >+ var const_value = function () { >+ if (consume(ID, "true")) return { type: "boolean", value: true }; >+ if (consume(ID, "false")) return { type: "boolean", value: false }; >+ if (consume(ID, "null")) return { type: "null" }; >+ if (consume(ID, "Infinity")) return { type: "Infinity", negative: false }; >+ if (consume(ID, "NaN")) return { type: "NaN" }; >+ var ret = consume(FLOAT) || consume(INT); >+ if (ret) return { type: "number", value: 1 * ret.value }; >+ var tok = consume(OTHER, "-"); >+ if (tok) { >+ if (consume(ID, "Infinity")) return { type: "Infinity", negative: true }; >+ else tokens.unshift(tok); >+ } >+ }; >+ >+ var type_suffix = function (obj) { >+ while (true) { >+ all_ws(); >+ if (consume(OTHER, "?")) { >+ if (obj.nullable) error("Can't nullable more than once"); >+ obj.nullable = true; >+ } >+ else if (consume(OTHER, "[")) { >+ all_ws(); >+ consume(OTHER, "]") || error("Unterminated array type"); >+ if (!obj.array) { >+ obj.array = 1; >+ obj.nullableArray = [obj.nullable]; >+ } >+ else { >+ obj.array++; >+ obj.nullableArray.push(obj.nullable); >+ } >+ obj.nullable = false; >+ } >+ else return; >+ } >+ }; >+ >+ var single_type = function () { >+ var prim = primitive_type() >+ , ret = { sequence: false, generic: null, nullable: false, array: false, union: false } >+ , name >+ , value >+ ; >+ if (prim) { >+ ret.idlType = prim; >+ } >+ else if (name = consume(ID)) { >+ value = name.value; >+ all_ws(); >+ // Generic types >+ if (consume(OTHER, "<")) { >+ // backwards compat >+ if (value === "sequence") { >+ ret.sequence = true; >+ } >+ ret.generic = value; >+ ret.idlType = type() || error("Error parsing generic type " + value); >+ all_ws(); >+ if (!consume(OTHER, ">")) error("Unterminated generic type " + value); >+ type_suffix(ret); >+ return ret; >+ } >+ else { >+ ret.idlType = value; >+ } >+ } >+ else { >+ return; >+ } >+ type_suffix(ret); >+ if (ret.nullable && !ret.array && ret.idlType === "any") error("Type any cannot be made nullable"); >+ return ret; >+ }; >+ >+ var union_type = function () { >+ all_ws(); >+ if (!consume(OTHER, "(")) return; >+ var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] }; >+ var fst = type() || error("Union type with no content"); >+ ret.idlType.push(fst); >+ while (true) { >+ all_ws(); >+ if (!consume(ID, "or")) break; >+ var typ = type() || error("No type after 'or' in union type"); >+ ret.idlType.push(typ); >+ } >+ if (!consume(OTHER, ")")) error("Unterminated union type"); >+ type_suffix(ret); >+ return ret; >+ }; >+ >+ var type = function () { >+ return single_type() || union_type(); >+ }; >+ >+ var argument = function (store) { >+ var ret = { optional: false, variadic: false }; >+ ret.extAttrs = extended_attrs(store); >+ all_ws(store, "pea"); >+ var opt_token = consume(ID, "optional"); >+ if (opt_token) { >+ ret.optional = true; >+ all_ws(); >+ } >+ ret.idlType = type(); >+ if (!ret.idlType) { >+ if (opt_token) tokens.unshift(opt_token); >+ return; >+ } >+ var type_token = last_token; >+ if (!ret.optional) { >+ all_ws(); >+ if (tokens.length >= 3 && >+ tokens[0].type === "other" && tokens[0].value === "." && >+ tokens[1].type === "other" && tokens[1].value === "." && >+ tokens[2].type === "other" && tokens[2].value === "." >+ ) { >+ tokens.shift(); >+ tokens.shift(); >+ tokens.shift(); >+ ret.variadic = true; >+ } >+ } >+ all_ws(); >+ var name = consume(ID); >+ if (!name) { >+ if (opt_token) tokens.unshift(opt_token); >+ tokens.unshift(type_token); >+ return; >+ } >+ ret.name = name.value; >+ if (ret.optional) { >+ all_ws(); >+ ret["default"] = default_(); >+ } >+ return ret; >+ }; >+ >+ var argument_list = function (store) { >+ var ret = [] >+ , arg = argument(store ? ret : null) >+ ; >+ if (!arg) return; >+ ret.push(arg); >+ while (true) { >+ all_ws(store ? ret : null); >+ if (!consume(OTHER, ",")) return ret; >+ var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list"); >+ ret.push(nxt); >+ } >+ }; >+ >+ var type_pair = function () { >+ all_ws(); >+ var k = type(); >+ if (!k) return; >+ all_ws() >+ if (!consume(OTHER, ",")) return; >+ all_ws(); >+ var v = type(); >+ if (!v) return; >+ return [k, v]; >+ }; >+ >+ var simple_extended_attr = function (store) { >+ all_ws(); >+ var name = consume(ID); >+ if (!name) return; >+ var ret = { >+ name: name.value >+ , "arguments": null >+ }; >+ all_ws(); >+ var eq = consume(OTHER, "="); >+ if (eq) { >+ var rhs; >+ all_ws(); >+ if (rhs = consume(ID)) { >+ ret.rhs = rhs >+ } >+ else if (consume(OTHER, "(")) { >+ // [Exposed=(Window,Worker)] >+ rhs = []; >+ var id = consume(ID); >+ if (id) { >+ rhs = [id.value]; >+ } >+ identifiers(rhs); >+ consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair"); >+ ret.rhs = { >+ type: "identifier-list", >+ value: rhs >+ }; >+ } >+ if (!ret.rhs) return error("No right hand side to extended attribute assignment"); >+ } >+ all_ws(); >+ if (consume(OTHER, "(")) { >+ var args, pair; >+ // [Constructor(DOMString str)] >+ if (args = argument_list(store)) { >+ ret["arguments"] = args; >+ } >+ // [MapClass(DOMString, DOMString)] >+ else if (pair = type_pair()) { >+ ret.typePair = pair; >+ } >+ // [Constructor()] >+ else { >+ ret["arguments"] = []; >+ } >+ all_ws(); >+ consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair"); >+ } >+ return ret; >+ }; >+ >+ // Note: we parse something simpler than the official syntax. It's all that ever >+ // seems to be used >+ var extended_attrs = function (store) { >+ var eas = []; >+ all_ws(store); >+ if (!consume(OTHER, "[")) return eas; >+ eas[0] = simple_extended_attr(store) || error("Extended attribute with not content"); >+ all_ws(); >+ while (consume(OTHER, ",")) { >+ eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute")); >+ all_ws(); >+ } >+ consume(OTHER, "]") || error("No end of extended attribute"); >+ return eas; >+ }; >+ >+ var default_ = function () { >+ all_ws(); >+ if (consume(OTHER, "=")) { >+ all_ws(); >+ var def = const_value(); >+ if (def) { >+ return def; >+ } >+ else if (consume(OTHER, "[")) { >+ if (!consume(OTHER, "]")) error("Default sequence value must be empty"); >+ return { type: "sequence", value: [] }; >+ } >+ else { >+ var str = consume(STR) || error("No value for default"); >+ str.value = str.value.replace(/^"/, "").replace(/"$/, ""); >+ return str; >+ } >+ } >+ }; >+ >+ var const_ = function (store) { >+ all_ws(store, "pea"); >+ if (!consume(ID, "const")) return; >+ var ret = { type: "const", nullable: false }; >+ all_ws(); >+ var typ = primitive_type(); >+ if (!typ) { >+ typ = consume(ID) || error("No type for const"); >+ typ = typ.value; >+ } >+ ret.idlType = typ; >+ all_ws(); >+ if (consume(OTHER, "?")) { >+ ret.nullable = true; >+ all_ws(); >+ } >+ var name = consume(ID) || error("No name for const"); >+ ret.name = name.value; >+ all_ws(); >+ consume(OTHER, "=") || error("No value assignment for const"); >+ all_ws(); >+ var cnt = const_value(); >+ if (cnt) ret.value = cnt; >+ else error("No value for const"); >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated const"); >+ return ret; >+ }; >+ >+ var inheritance = function () { >+ all_ws(); >+ if (consume(OTHER, ":")) { >+ all_ws(); >+ var inh = consume(ID) || error ("No type in inheritance"); >+ return inh.value; >+ } >+ }; >+ >+ var operation_rest = function (ret, store) { >+ all_ws(); >+ if (!ret) ret = {}; >+ var name = consume(ID); >+ ret.name = name ? name.value : null; >+ all_ws(); >+ consume(OTHER, "(") || error("Invalid operation"); >+ ret["arguments"] = argument_list(store) || []; >+ all_ws(); >+ consume(OTHER, ")") || error("Unterminated operation"); >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated operation"); >+ return ret; >+ }; >+ >+ var callback = function (store) { >+ all_ws(store, "pea"); >+ var ret; >+ if (!consume(ID, "callback")) return; >+ all_ws(); >+ var tok = consume(ID, "interface"); >+ if (tok) { >+ tokens.unshift(tok); >+ ret = interface_(); >+ ret.type = "callback interface"; >+ return ret; >+ } >+ var name = consume(ID) || error("No name for callback"); >+ ret = { type: "callback", name: name.value }; >+ all_ws(); >+ consume(OTHER, "=") || error("No assignment in callback"); >+ all_ws(); >+ ret.idlType = return_type(); >+ all_ws(); >+ consume(OTHER, "(") || error("No arguments in callback"); >+ ret["arguments"] = argument_list(store) || []; >+ all_ws(); >+ consume(OTHER, ")") || error("Unterminated callback"); >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated callback"); >+ return ret; >+ }; >+ >+ var attribute = function (store) { >+ all_ws(store, "pea"); >+ var grabbed = [] >+ , ret = { >+ type: "attribute" >+ , "static": false >+ , stringifier: false >+ , inherit: false >+ , readonly: false >+ }; >+ if (consume(ID, "static")) { >+ ret["static"] = true; >+ grabbed.push(last_token); >+ } >+ else if (consume(ID, "stringifier")) { >+ ret.stringifier = true; >+ grabbed.push(last_token); >+ } >+ var w = all_ws(); >+ if (w) grabbed.push(w); >+ if (consume(ID, "inherit")) { >+ if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit"); >+ ret.inherit = true; >+ grabbed.push(last_token); >+ var w = all_ws(); >+ if (w) grabbed.push(w); >+ } >+ if (consume(ID, "readonly")) { >+ ret.readonly = true; >+ grabbed.push(last_token); >+ var w = all_ws(); >+ if (w) grabbed.push(w); >+ } >+ if (!consume(ID, "attribute")) { >+ tokens = grabbed.concat(tokens); >+ return; >+ } >+ all_ws(); >+ ret.idlType = type() || error("No type in attribute"); >+ if (ret.idlType.sequence) error("Attributes cannot accept sequence types"); >+ all_ws(); >+ var name = consume(ID) || error("No name in attribute"); >+ ret.name = name.value; >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated attribute"); >+ return ret; >+ }; >+ >+ var return_type = function () { >+ var typ = type(); >+ if (!typ) { >+ if (consume(ID, "void")) { >+ return "void"; >+ } >+ else error("No return type"); >+ } >+ return typ; >+ }; >+ >+ var operation = function (store) { >+ all_ws(store, "pea"); >+ var ret = { >+ type: "operation" >+ , getter: false >+ , setter: false >+ , creator: false >+ , deleter: false >+ , legacycaller: false >+ , "static": false >+ , stringifier: false >+ }; >+ while (true) { >+ all_ws(); >+ if (consume(ID, "getter")) ret.getter = true; >+ else if (consume(ID, "setter")) ret.setter = true; >+ else if (consume(ID, "creator")) ret.creator = true; >+ else if (consume(ID, "deleter")) ret.deleter = true; >+ else if (consume(ID, "legacycaller")) ret.legacycaller = true; >+ else break; >+ } >+ if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) { >+ all_ws(); >+ ret.idlType = return_type(); >+ operation_rest(ret, store); >+ return ret; >+ } >+ if (consume(ID, "static")) { >+ ret["static"] = true; >+ ret.idlType = return_type(); >+ operation_rest(ret, store); >+ return ret; >+ } >+ else if (consume(ID, "stringifier")) { >+ ret.stringifier = true;- >+ all_ws(); >+ if (consume(OTHER, ";")) return ret; >+ ret.idlType = return_type(); >+ operation_rest(ret, store); >+ return ret; >+ } >+ ret.idlType = return_type(); >+ all_ws(); >+ if (consume(ID, "iterator")) { >+ all_ws(); >+ ret.type = "iterator"; >+ if (consume(ID, "object")) { >+ ret.iteratorObject = "object"; >+ } >+ else if (consume(OTHER, "=")) { >+ all_ws(); >+ var name = consume(ID) || error("No right hand side in iterator"); >+ ret.iteratorObject = name.value; >+ } >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated iterator"); >+ return ret; >+ } >+ else { >+ operation_rest(ret, store); >+ return ret; >+ } >+ }; >+ >+ var identifiers = function (arr) { >+ while (true) { >+ all_ws(); >+ if (consume(OTHER, ",")) { >+ all_ws(); >+ var name = consume(ID) || error("Trailing comma in identifiers list"); >+ arr.push(name.value); >+ } >+ else break; >+ } >+ }; >+ >+ var serialiser = function (store) { >+ all_ws(store, "pea"); >+ if (!consume(ID, "serializer")) return; >+ var ret = { type: "serializer" }; >+ all_ws(); >+ if (consume(OTHER, "=")) { >+ all_ws(); >+ if (consume(OTHER, "{")) { >+ ret.patternMap = true; >+ all_ws(); >+ var id = consume(ID); >+ if (id && id.value === "getter") { >+ ret.names = ["getter"]; >+ } >+ else if (id && id.value === "inherit") { >+ ret.names = ["inherit"]; >+ identifiers(ret.names); >+ } >+ else if (id) { >+ ret.names = [id.value]; >+ identifiers(ret.names); >+ } >+ else { >+ ret.names = []; >+ } >+ all_ws(); >+ consume(OTHER, "}") || error("Unterminated serializer pattern map"); >+ } >+ else if (consume(OTHER, "[")) { >+ ret.patternList = true; >+ all_ws(); >+ var id = consume(ID); >+ if (id && id.value === "getter") { >+ ret.names = ["getter"]; >+ } >+ else if (id) { >+ ret.names = [id.value]; >+ identifiers(ret.names); >+ } >+ else { >+ ret.names = []; >+ } >+ all_ws(); >+ consume(OTHER, "]") || error("Unterminated serializer pattern list"); >+ } >+ else { >+ var name = consume(ID) || error("Invalid serializer"); >+ ret.name = name.value; >+ } >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated serializer"); >+ return ret; >+ } >+ else if (consume(OTHER, ";")) { >+ // noop, just parsing >+ } >+ else { >+ ret.idlType = return_type(); >+ all_ws(); >+ ret.operation = operation_rest(null, store); >+ } >+ return ret; >+ }; >+ >+ var iterable_type = function() { >+ if (consume(ID, "iterable")) return "iterable"; >+ else if (consume(ID, "legacyiterable")) return "legacyiterable"; >+ else if (consume(ID, "maplike")) return "maplike"; >+ else if (consume(ID, "setlike")) return "setlike"; >+ else return; >+ } >+ >+ var readonly_iterable_type = function() { >+ if (consume(ID, "maplike")) return "maplike"; >+ else if (consume(ID, "setlike")) return "setlike"; >+ else return; >+ } >+ >+ var iterable = function (store) { >+ all_ws(store, "pea"); >+ var grabbed = [], >+ ret = {type: null, idlType: null, readonly: false}; >+ if (consume(ID, "readonly")) { >+ ret.readonly = true; >+ grabbed.push(last_token); >+ var w = all_ws(); >+ if (w) grabbed.push(w); >+ } >+ var consumeItType = ret.readonly ? readonly_iterable_type : iterable_type; >+ >+ var ittype = consumeItType(); >+ if (!ittype) { >+ tokens = grabbed.concat(tokens); >+ return; >+ } >+ >+ var secondTypeRequired = ittype === "maplike"; >+ var secondTypeAllowed = secondTypeRequired || ittype === "iterable"; >+ ret.type = ittype; >+ if (ret.type !== 'maplike' && ret.type !== 'setlike') >+ delete ret.readonly; >+ all_ws(); >+ if (consume(OTHER, "<")) { >+ ret.idlType = type() || error("Error parsing " + ittype + " declaration"); >+ all_ws(); >+ if (secondTypeAllowed) { >+ var type2 = null; >+ if (consume(OTHER, ",")) { >+ all_ws(); >+ type2 = type(); >+ all_ws(); >+ } >+ if (type2) >+ ret.idlType = [ret.idlType, type2]; >+ else if (secondTypeRequired) >+ error("Missing second type argument in " + ittype + " declaration"); >+ } >+ if (!consume(OTHER, ">")) error("Unterminated " + ittype + " declaration"); >+ all_ws(); >+ if (!consume(OTHER, ";")) error("Missing semicolon after " + ittype + " declaration"); >+ } >+ else >+ error("Error parsing " + ittype + " declaration"); >+ >+ return ret; >+ } >+ >+ var interface_ = function (isPartial, store) { >+ all_ws(isPartial ? null : store, "pea"); >+ if (!consume(ID, "interface")) return; >+ all_ws(); >+ var name = consume(ID) || error("No name for interface"); >+ var mems = [] >+ , ret = { >+ type: "interface" >+ , name: name.value >+ , partial: false >+ , members: mems >+ }; >+ if (!isPartial) ret.inheritance = inheritance() || null; >+ all_ws(); >+ consume(OTHER, "{") || error("Bodyless interface"); >+ while (true) { >+ all_ws(store ? mems : null); >+ if (consume(OTHER, "}")) { >+ all_ws(); >+ consume(OTHER, ";") || error("Missing semicolon after interface"); >+ return ret; >+ } >+ var ea = extended_attrs(store ? mems : null); >+ all_ws(); >+ var cnt = const_(store ? mems : null); >+ if (cnt) { >+ cnt.extAttrs = ea; >+ ret.members.push(cnt); >+ continue; >+ } >+ var mem = (opt.allowNestedTypedefs && typedef(store ? mems : null)) || >+ iterable(store ? mems : null) || >+ serialiser(store ? mems : null) || >+ attribute(store ? mems : null) || >+ operation(store ? mems : null) || >+ error("Unknown member"); >+ mem.extAttrs = ea; >+ ret.members.push(mem); >+ } >+ }; >+ >+ var partial = function (store) { >+ all_ws(store, "pea"); >+ if (!consume(ID, "partial")) return; >+ var thing = dictionary(true, store) || >+ interface_(true, store) || >+ error("Partial doesn't apply to anything"); >+ thing.partial = true; >+ return thing; >+ }; >+ >+ var dictionary = function (isPartial, store) { >+ all_ws(isPartial ? null : store, "pea"); >+ if (!consume(ID, "dictionary")) return; >+ all_ws(); >+ var name = consume(ID) || error("No name for dictionary"); >+ var mems = [] >+ , ret = { >+ type: "dictionary" >+ , name: name.value >+ , partial: false >+ , members: mems >+ }; >+ if (!isPartial) ret.inheritance = inheritance() || null; >+ all_ws(); >+ consume(OTHER, "{") || error("Bodyless dictionary"); >+ while (true) { >+ all_ws(store ? mems : null); >+ if (consume(OTHER, "}")) { >+ all_ws(); >+ consume(OTHER, ";") || error("Missing semicolon after dictionary"); >+ return ret; >+ } >+ var ea = extended_attrs(store ? mems : null); >+ all_ws(store ? mems : null, "pea"); >+ var required = consume(ID, "required"); >+ var typ = type() || error("No type for dictionary member"); >+ all_ws(); >+ var name = consume(ID) || error("No name for dictionary member"); >+ var dflt = default_(); >+ if (required && dflt) error("Required member must not have a default"); >+ ret.members.push({ >+ type: "field" >+ , name: name.value >+ , required: !!required >+ , idlType: typ >+ , extAttrs: ea >+ , "default": dflt >+ }); >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated dictionary member"); >+ } >+ }; >+ >+ var exception = function (store) { >+ all_ws(store, "pea"); >+ if (!consume(ID, "exception")) return; >+ all_ws(); >+ var name = consume(ID) || error("No name for exception"); >+ var mems = [] >+ , ret = { >+ type: "exception" >+ , name: name.value >+ , members: mems >+ }; >+ ret.inheritance = inheritance() || null; >+ all_ws(); >+ consume(OTHER, "{") || error("Bodyless exception"); >+ while (true) { >+ all_ws(store ? mems : null); >+ if (consume(OTHER, "}")) { >+ all_ws(); >+ consume(OTHER, ";") || error("Missing semicolon after exception"); >+ return ret; >+ } >+ var ea = extended_attrs(store ? mems : null); >+ all_ws(store ? mems : null, "pea"); >+ var cnt = const_(); >+ if (cnt) { >+ cnt.extAttrs = ea; >+ ret.members.push(cnt); >+ } >+ else { >+ var typ = type(); >+ all_ws(); >+ var name = consume(ID); >+ all_ws(); >+ if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body"); >+ ret.members.push({ >+ type: "field" >+ , name: name.value >+ , idlType: typ >+ , extAttrs: ea >+ }); >+ } >+ } >+ }; >+ >+ var enum_ = function (store) { >+ all_ws(store, "pea"); >+ if (!consume(ID, "enum")) return; >+ all_ws(); >+ var name = consume(ID) || error("No name for enum"); >+ var vals = [] >+ , ret = { >+ type: "enum" >+ , name: name.value >+ , values: vals >+ }; >+ all_ws(); >+ consume(OTHER, "{") || error("No curly for enum"); >+ var saw_comma = false; >+ while (true) { >+ all_ws(store ? vals : null); >+ if (consume(OTHER, "}")) { >+ all_ws(); >+ consume(OTHER, ";") || error("No semicolon after enum"); >+ return ret; >+ } >+ var val = consume(STR) || error("Unexpected value in enum"); >+ ret.values.push(val.value.replace(/"/g, "")); >+ all_ws(store ? vals : null); >+ if (consume(OTHER, ",")) { >+ if (store) vals.push({ type: "," }); >+ all_ws(store ? vals : null); >+ saw_comma = true; >+ } >+ else { >+ saw_comma = false; >+ } >+ } >+ }; >+ >+ var typedef = function (store) { >+ all_ws(store, "pea"); >+ if (!consume(ID, "typedef")) return; >+ var ret = { >+ type: "typedef" >+ }; >+ all_ws(); >+ ret.typeExtAttrs = extended_attrs(); >+ all_ws(store, "tpea"); >+ ret.idlType = type() || error("No type in typedef"); >+ all_ws(); >+ var name = consume(ID) || error("No name in typedef"); >+ ret.name = name.value; >+ all_ws(); >+ consume(OTHER, ";") || error("Unterminated typedef"); >+ return ret; >+ }; >+ >+ var implements_ = function (store) { >+ all_ws(store, "pea"); >+ var target = consume(ID); >+ if (!target) return; >+ var w = all_ws(); >+ if (consume(ID, "implements")) { >+ var ret = { >+ type: "implements" >+ , target: target.value >+ }; >+ all_ws(); >+ var imp = consume(ID) || error("Incomplete implements statement"); >+ ret["implements"] = imp.value; >+ all_ws(); >+ consume(OTHER, ";") || error("No terminating ; for implements statement"); >+ return ret; >+ } >+ else { >+ // rollback >+ tokens.unshift(w); >+ tokens.unshift(target); >+ } >+ }; >+ >+ var definition = function (store) { >+ return callback(store) || >+ interface_(false, store) || >+ partial(store) || >+ dictionary(false, store) || >+ exception(store) || >+ enum_(store) || >+ typedef(store) || >+ implements_(store) >+ ; >+ }; >+ >+ var definitions = function (store) { >+ if (!tokens.length) return []; >+ var defs = []; >+ while (true) { >+ var ea = extended_attrs(store ? defs : null) >+ , def = definition(store ? defs : null); >+ if (!def) { >+ if (ea.length) error("Stray extended attributes"); >+ break; >+ } >+ def.extAttrs = ea; >+ defs.push(def); >+ } >+ return defs; >+ }; >+ var res = definitions(opt.ws); >+ if (tokens.length) error("Unrecognised tokens"); >+ return res; >+ }; >+ >+ var inNode = typeof module !== "undefined" && module.exports >+ , obj = { >+ parse: function (str, opt) { >+ if (!opt) opt = {}; >+ var tokens = tokenise(str); >+ return parse(tokens, opt); >+ } >+ }; >+ >+ if (inNode) module.exports = obj; >+ else self.WebIDL2 = obj; >+}()); >diff --git a/LayoutTests/imported/w3c/resources/idlharness.js b/LayoutTests/imported/w3c/resources/idlharness.js >new file mode 100644 >index 0000000000000000000000000000000000000000..5002ec50b365c0f303a2b9992749b5a07e022eac >--- /dev/null >+++ b/LayoutTests/imported/w3c/resources/idlharness.js >@@ -0,0 +1,1850 @@ >+/* >+Distributed under both the W3C Test Suite License [1] and the W3C >+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the >+policies and contribution forms [3]. >+ >+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license >+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license >+[3] http://www.w3.org/2004/10/27-testcases >+*/ >+ >+/* For user documentation see docs/idlharness.md */ >+ >+/** >+ * Notes for people who want to edit this file (not just use it as a library): >+ * >+ * Most of the interesting stuff happens in the derived classes of IdlObject, >+ * especially IdlInterface. The entry point for all IdlObjects is .test(), >+ * which is called by IdlArray.test(). An IdlObject is conceptually just >+ * "thing we want to run tests on", and an IdlArray is an array of IdlObjects >+ * with some additional data thrown in. >+ * >+ * The object model is based on what WebIDLParser.js produces, which is in turn >+ * based on its pegjs grammar. If you want to figure out what properties an >+ * object will have from WebIDLParser.js, the best way is to look at the >+ * grammar: >+ * >+ * https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg >+ * >+ * So for instance: >+ * >+ * // interface definition >+ * interface >+ * = extAttrs:extendedAttributeList? S? "interface" S name:identifier w herit:ifInheritance? w "{" w mem:ifMember* w "}" w ";" w >+ * { return { type: "interface", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; } >+ * >+ * This means that an "interface" object will have a .type property equal to >+ * the string "interface", a .name property equal to the identifier that the >+ * parser found, an .inheritance property equal to either null or the result of >+ * the "ifInheritance" production found elsewhere in the grammar, and so on. >+ * After each grammatical production is a JavaScript function in curly braces >+ * that gets called with suitable arguments and returns some JavaScript value. >+ * >+ * (Note that the version of WebIDLParser.js we use might sometimes be >+ * out-of-date or forked.) >+ * >+ * The members and methods of the classes defined by this file are all at least >+ * briefly documented, hopefully. >+ */ >+(function(){ >+"use strict"; >+/// Helpers /// >+function constValue (cnt) { >+ if (cnt.type === "null") return null; >+ if (cnt.type === "NaN") return NaN; >+ if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity; >+ return cnt.value; >+} >+ >+function minOverloadLength(overloads) { >+ if (!overloads.length) { >+ return 0; >+ } >+ >+ return overloads.map(function(attr) { >+ return attr.arguments ? attr.arguments.filter(function(arg) { >+ return !arg.optional && !arg.variadic; >+ }).length : 0; >+ }) >+ .reduce(function(m, n) { return Math.min(m, n); }); >+} >+ >+function throwOrReject(a_test, operation, fn, obj, args, message, cb) { >+ if (operation.idlType.generic !== "Promise") { >+ assert_throws(new TypeError(), function() { >+ fn.apply(obj, args); >+ }, message); >+ cb(); >+ } else { >+ try { >+ promise_rejects(a_test, new TypeError(), fn.apply(obj, args)).then(cb, cb); >+ } catch (e){ >+ a_test.step(function() { >+ assert_unreached("Throws \"" + e + "\" instead of rejecting promise"); >+ cb(); >+ }); >+ } >+ } >+} >+ >+function awaitNCallbacks(n, cb, ctx) { >+ var counter = 0; >+ return function() { >+ counter++; >+ if (counter >= n) { >+ cb(); >+ } >+ }; >+} >+ >+var fround = (function(){ >+ if (Math.fround) return Math.fround; >+ >+ var arr = new Float32Array(1); >+ return function fround(n) { >+ arr[0] = n; >+ return arr[0]; >+ }; >+})(); >+ >+/// IdlArray /// >+// Entry point >+self.IdlArray = function() >+//@{ >+{ >+ /** >+ * A map from strings to the corresponding named IdlObject, such as >+ * IdlInterface or IdlException. These are the things that test() will run >+ * tests on. >+ */ >+ this.members = {}; >+ >+ /** >+ * A map from strings to arrays of strings. The keys are interface or >+ * exception names, and are expected to also exist as keys in this.members >+ * (otherwise they'll be ignored). This is populated by add_objects() -- >+ * see documentation at the start of the file. The actual tests will be >+ * run by calling this.members[name].test_object(obj) for each obj in >+ * this.objects[name]. obj is a string that will be eval'd to produce a >+ * JavaScript value, which is supposed to be an object implementing the >+ * given IdlObject (interface, exception, etc.). >+ */ >+ this.objects = {}; >+ >+ /** >+ * When adding multiple collections of IDLs one at a time, an earlier one >+ * might contain a partial interface or implements statement that depends >+ * on a later one. Save these up and handle them right before we run >+ * tests. >+ * >+ * .partials is simply an array of objects from WebIDLParser.js' >+ * "partialinterface" production. .implements maps strings to arrays of >+ * strings, such that >+ * >+ * A implements B; >+ * A implements C; >+ * D implements E; >+ * >+ * results in { A: ["B", "C"], D: ["E"] }. >+ */ >+ this.partials = []; >+ this["implements"] = {}; >+}; >+ >+//@} >+IdlArray.prototype.add_idls = function(raw_idls) >+//@{ >+{ >+ /** Entry point. See documentation at beginning of file. */ >+ this.internal_add_idls(WebIDL2.parse(raw_idls)); >+}; >+ >+//@} >+IdlArray.prototype.add_untested_idls = function(raw_idls) >+//@{ >+{ >+ /** Entry point. See documentation at beginning of file. */ >+ var parsed_idls = WebIDL2.parse(raw_idls); >+ for (var i = 0; i < parsed_idls.length; i++) >+ { >+ parsed_idls[i].untested = true; >+ if ("members" in parsed_idls[i]) >+ { >+ for (var j = 0; j < parsed_idls[i].members.length; j++) >+ { >+ parsed_idls[i].members[j].untested = true; >+ } >+ } >+ } >+ this.internal_add_idls(parsed_idls); >+}; >+ >+//@} >+IdlArray.prototype.internal_add_idls = function(parsed_idls) >+//@{ >+{ >+ /** >+ * Internal helper called by add_idls() and add_untested_idls(). >+ * parsed_idls is an array of objects that come from WebIDLParser.js's >+ * "definitions" production. The add_untested_idls() entry point >+ * additionally sets an .untested property on each object (and its >+ * .members) so that they'll be skipped by test() -- they'll only be >+ * used for base interfaces of tested interfaces, return types, etc. >+ */ >+ parsed_idls.forEach(function(parsed_idl) >+ { >+ if (parsed_idl.type == "interface" && parsed_idl.partial) >+ { >+ this.partials.push(parsed_idl); >+ return; >+ } >+ >+ if (parsed_idl.type == "implements") >+ { >+ if (!(parsed_idl.target in this["implements"])) >+ { >+ this["implements"][parsed_idl.target] = []; >+ } >+ this["implements"][parsed_idl.target].push(parsed_idl["implements"]); >+ return; >+ } >+ >+ parsed_idl.array = this; >+ if (parsed_idl.name in this.members) >+ { >+ throw "Duplicate identifier " + parsed_idl.name; >+ } >+ switch(parsed_idl.type) >+ { >+ case "interface": >+ this.members[parsed_idl.name] = >+ new IdlInterface(parsed_idl, /* is_callback = */ false); >+ break; >+ >+ case "dictionary": >+ // Nothing to test, but we need the dictionary info around for type >+ // checks >+ this.members[parsed_idl.name] = new IdlDictionary(parsed_idl); >+ break; >+ >+ case "typedef": >+ this.members[parsed_idl.name] = new IdlTypedef(parsed_idl); >+ break; >+ >+ case "callback": >+ // TODO >+ console.log("callback not yet supported"); >+ break; >+ >+ case "enum": >+ this.members[parsed_idl.name] = new IdlEnum(parsed_idl); >+ break; >+ >+ case "callback interface": >+ this.members[parsed_idl.name] = >+ new IdlInterface(parsed_idl, /* is_callback = */ true); >+ break; >+ >+ default: >+ throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported"; >+ } >+ }.bind(this)); >+}; >+ >+//@} >+IdlArray.prototype.add_objects = function(dict) >+//@{ >+{ >+ /** Entry point. See documentation at beginning of file. */ >+ for (var k in dict) >+ { >+ if (k in this.objects) >+ { >+ this.objects[k] = this.objects[k].concat(dict[k]); >+ } >+ else >+ { >+ this.objects[k] = dict[k]; >+ } >+ } >+}; >+ >+//@} >+IdlArray.prototype.prevent_multiple_testing = function(name) >+//@{ >+{ >+ /** Entry point. See documentation at beginning of file. */ >+ this.members[name].prevent_multiple_testing = true; >+}; >+ >+//@} >+IdlArray.prototype.recursively_get_implements = function(interface_name) >+//@{ >+{ >+ /** >+ * Helper function for test(). Returns an array of things that implement >+ * interface_name, so if the IDL contains >+ * >+ * A implements B; >+ * B implements C; >+ * B implements D; >+ * >+ * then recursively_get_implements("A") should return ["B", "C", "D"]. >+ */ >+ var ret = this["implements"][interface_name]; >+ if (ret === undefined) >+ { >+ return []; >+ } >+ for (var i = 0; i < this["implements"][interface_name].length; i++) >+ { >+ ret = ret.concat(this.recursively_get_implements(ret[i])); >+ if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i])) >+ { >+ throw "Circular implements statements involving " + ret[i]; >+ } >+ } >+ return ret; >+}; >+ >+function exposed_in(globals) { >+ if ('document' in self) { >+ return globals.indexOf("Window") >= 0; >+ } >+ if ('DedicatedWorkerGlobalScope' in self && >+ self instanceof DedicatedWorkerGlobalScope) { >+ return globals.indexOf("Worker") >= 0 || >+ globals.indexOf("DedicatedWorker") >= 0; >+ } >+ if ('SharedWorkerGlobalScope' in self && >+ self instanceof SharedWorkerGlobalScope) { >+ return globals.indexOf("Worker") >= 0 || >+ globals.indexOf("SharedWorker") >= 0; >+ } >+ if ('ServiceWorkerGlobalScope' in self && >+ self instanceof ServiceWorkerGlobalScope) { >+ return globals.indexOf("Worker") >= 0 || >+ globals.indexOf("ServiceWorker") >= 0; >+ } >+ throw "Unexpected global object"; >+} >+ >+//@} >+IdlArray.prototype.test = function() >+//@{ >+{ >+ /** Entry point. See documentation at beginning of file. */ >+ >+ // First merge in all the partial interfaces and implements statements we >+ // encountered. >+ this.partials.forEach(function(parsed_idl) >+ { >+ if (!(parsed_idl.name in this.members) >+ || !(this.members[parsed_idl.name] instanceof IdlInterface)) >+ { >+ throw "Partial interface " + parsed_idl.name + " with no original interface"; >+ } >+ if (parsed_idl.extAttrs) >+ { >+ parsed_idl.extAttrs.forEach(function(extAttr) >+ { >+ this.members[parsed_idl.name].extAttrs.push(extAttr); >+ }.bind(this)); >+ } >+ parsed_idl.members.forEach(function(member) >+ { >+ this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member)); >+ }.bind(this)); >+ }.bind(this)); >+ this.partials = []; >+ >+ for (var lhs in this["implements"]) >+ { >+ this.recursively_get_implements(lhs).forEach(function(rhs) >+ { >+ var errStr = lhs + " implements " + rhs + ", but "; >+ if (!(lhs in this.members)) throw errStr + lhs + " is undefined."; >+ if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface."; >+ if (!(rhs in this.members)) throw errStr + rhs + " is undefined."; >+ if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface."; >+ this.members[rhs].members.forEach(function(member) >+ { >+ this.members[lhs].members.push(new IdlInterfaceMember(member)); >+ }.bind(this)); >+ }.bind(this)); >+ } >+ this["implements"] = {}; >+ >+ Object.getOwnPropertyNames(this.members).forEach(function(memberName) { >+ var member = this.members[memberName]; >+ if (!(member instanceof IdlInterface)) { >+ return; >+ } >+ >+ var exposed = member.extAttrs.filter(function(a) { return a.name == "Exposed" }); >+ if (exposed.length > 1) { >+ throw "Unexpected Exposed extended attributes on " + memberName + ": " + exposed; >+ } >+ >+ var globals = exposed.length === 1 >+ ? exposed[0].rhs.value >+ : ["Window"]; >+ member.exposed = exposed_in(globals); >+ }.bind(this)); >+ >+ // Now run test() on every member, and test_object() for every object. >+ for (var name in this.members) >+ { >+ this.members[name].test(); >+ if (name in this.objects) >+ { >+ this.objects[name].forEach(function(str) >+ { >+ this.members[name].test_object(str); >+ }.bind(this)); >+ } >+ } >+}; >+ >+//@} >+IdlArray.prototype.assert_type_is = function(value, type) >+//@{ >+{ >+ /** >+ * Helper function that tests that value is an instance of type according >+ * to the rules of WebIDL. value is any JavaScript value, and type is an >+ * object produced by WebIDLParser.js' "type" production. That production >+ * is fairly elaborate due to the complexity of WebIDL's types, so it's >+ * best to look at the grammar to figure out what properties it might have. >+ */ >+ if (type.idlType == "any") >+ { >+ // No assertions to make >+ return; >+ } >+ >+ if (type.nullable && value === null) >+ { >+ // This is fine >+ return; >+ } >+ >+ if (type.array) >+ { >+ // TODO: not supported yet >+ return; >+ } >+ >+ if (type.sequence) >+ { >+ assert_true(Array.isArray(value), "is not array"); >+ if (!value.length) >+ { >+ // Nothing we can do. >+ return; >+ } >+ this.assert_type_is(value[0], type.idlType.idlType); >+ return; >+ } >+ >+ type = type.idlType; >+ >+ switch(type) >+ { >+ case "void": >+ assert_equals(value, undefined); >+ return; >+ >+ case "boolean": >+ assert_equals(typeof value, "boolean"); >+ return; >+ >+ case "byte": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, Math.floor(value), "not an integer"); >+ assert_true(-128 <= value && value <= 127, "byte " + value + " not in range [-128, 127]"); >+ return; >+ >+ case "octet": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, Math.floor(value), "not an integer"); >+ assert_true(0 <= value && value <= 255, "octet " + value + " not in range [0, 255]"); >+ return; >+ >+ case "short": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, Math.floor(value), "not an integer"); >+ assert_true(-32768 <= value && value <= 32767, "short " + value + " not in range [-32768, 32767]"); >+ return; >+ >+ case "unsigned short": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, Math.floor(value), "not an integer"); >+ assert_true(0 <= value && value <= 65535, "unsigned short " + value + " not in range [0, 65535]"); >+ return; >+ >+ case "long": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, Math.floor(value), "not an integer"); >+ assert_true(-2147483648 <= value && value <= 2147483647, "long " + value + " not in range [-2147483648, 2147483647]"); >+ return; >+ >+ case "unsigned long": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, Math.floor(value), "not an integer"); >+ assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " not in range [0, 4294967295]"); >+ return; >+ >+ case "long long": >+ assert_equals(typeof value, "number"); >+ return; >+ >+ case "unsigned long long": >+ case "DOMTimeStamp": >+ assert_equals(typeof value, "number"); >+ assert_true(0 <= value, "unsigned long long is negative"); >+ return; >+ >+ case "float": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, fround(value), "float rounded to 32-bit float should be itself"); >+ assert_not_equals(value, Infinity); >+ assert_not_equals(value, -Infinity); >+ assert_not_equals(value, NaN); >+ return; >+ >+ case "DOMHighResTimeStamp": >+ case "double": >+ assert_equals(typeof value, "number"); >+ assert_not_equals(value, Infinity); >+ assert_not_equals(value, -Infinity); >+ assert_not_equals(value, NaN); >+ return; >+ >+ case "unrestricted float": >+ assert_equals(typeof value, "number"); >+ assert_equals(value, fround(value), "unrestricted float rounded to 32-bit float should be itself"); >+ return; >+ >+ case "unrestricted double": >+ assert_equals(typeof value, "number"); >+ return; >+ >+ case "DOMString": >+ assert_equals(typeof value, "string"); >+ return; >+ >+ case "ByteString": >+ assert_equals(typeof value, "string"); >+ assert_regexp_match(value, /^[\x00-\x7F]*$/); >+ return; >+ >+ case "USVString": >+ assert_equals(typeof value, "string"); >+ assert_regexp_match(value, /^([\x00-\ud7ff\ue000-\uffff]|[\ud800-\udbff][\udc00-\udfff])*$/); >+ return; >+ >+ case "object": >+ assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function"); >+ return; >+ } >+ >+ if (!(type in this.members)) >+ { >+ throw "Unrecognized type " + type; >+ } >+ >+ if (this.members[type] instanceof IdlInterface) >+ { >+ // We don't want to run the full >+ // 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 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 self) >+ { >+ assert_true(value instanceof self[type], "not instanceof " + type); >+ } >+ } >+ else if (this.members[type] instanceof IdlEnum) >+ { >+ assert_equals(typeof value, "string"); >+ } >+ else if (this.members[type] instanceof IdlDictionary) >+ { >+ // TODO: Test when we actually have something to test this on >+ } >+ else if (this.members[type] instanceof IdlTypedef) >+ { >+ // TODO: Test when we actually have something to test this on >+ } >+ else >+ { >+ throw "Type " + type + " isn't an interface or dictionary"; >+ } >+}; >+//@} >+ >+/// IdlObject /// >+function IdlObject() {} >+IdlObject.prototype.test = function() >+//@{ >+{ >+ /** >+ * By default, this does nothing, so no actual tests are run for IdlObjects >+ * that don't define any (e.g., IdlDictionary at the time of this writing). >+ */ >+}; >+ >+//@} >+IdlObject.prototype.has_extended_attribute = function(name) >+//@{ >+{ >+ /** >+ * This is only meaningful for things that support extended attributes, >+ * such as interfaces, exceptions, and members. >+ */ >+ return this.extAttrs.some(function(o) >+ { >+ return o.name == name; >+ }); >+}; >+ >+//@} >+ >+/// IdlDictionary /// >+// Used for IdlArray.prototype.assert_type_is >+function IdlDictionary(obj) >+//@{ >+{ >+ /** >+ * obj is an object produced by the WebIDLParser.js "dictionary" >+ * production. >+ */ >+ >+ /** Self-explanatory. */ >+ this.name = obj.name; >+ >+ /** An array of objects produced by the "dictionaryMember" production. */ >+ this.members = obj.members; >+ >+ /** >+ * The name (as a string) of the dictionary type we inherit from, or null >+ * if there is none. >+ */ >+ this.base = obj.inheritance; >+} >+ >+//@} >+IdlDictionary.prototype = Object.create(IdlObject.prototype); >+ >+/// IdlInterface /// >+function IdlInterface(obj, is_callback) { >+ /** >+ * obj is an object produced by the WebIDLParser.js "interface" production. >+ */ >+ >+ /** Self-explanatory. */ >+ this.name = obj.name; >+ >+ /** A back-reference to our IdlArray. */ >+ this.array = obj.array; >+ >+ /** >+ * An indicator of whether we should run tests on the interface object and >+ * interface prototype object. Tests on members are controlled by .untested >+ * on each member, not this. >+ */ >+ this.untested = obj.untested; >+ >+ /** An array of objects produced by the "ExtAttr" production. */ >+ this.extAttrs = obj.extAttrs; >+ >+ /** 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"; >+ }); >+}; >+//@} >+ >+IdlInterface.prototype.test = function() >+//@{ >+{ >+ if (this.has_extended_attribute("NoInterfaceObject")) >+ { >+ // No tests to do without an instance. TODO: We should still be able >+ // to run tests on the prototype object, if we obtain one through some >+ // other means. >+ return; >+ } >+ >+ if (!this.exposed) { >+ test(function() { >+ assert_false(this.name in self); >+ }.bind(this), this.name + " interface: existence and properties of interface object"); >+ return; >+ } >+ >+ if (!this.untested) >+ { >+ // First test things to do with the exception/interface object and >+ // exception/interface prototype object. >+ this.test_self(); >+ } >+ // Then test things to do with its members (constants, fields, attributes, >+ // operations, . . .). These are run even if .untested is true, because >+ // members might themselves be marked as .untested. This might happen to >+ // interfaces if the interface itself is untested but a partial interface >+ // that extends it is tested -- then the interface itself and its initial >+ // members will be marked as untested, but the members added by the partial >+ // interface are still tested. >+ this.test_members(); >+}; >+//@} >+ >+IdlInterface.prototype.test_self = function() >+//@{ >+{ >+ test(function() >+ { >+ // This function tests WebIDL as of 2015-01-13. >+ >+ // "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, >+ // a corresponding property MUST exist on the ECMAScript global object. >+ // The name of the property is the identifier of the interface, and its >+ // value is an object called the interface object. >+ // The property has the attributes { [[Writable]]: true, >+ // [[Enumerable]]: false, [[Configurable]]: true }." >+ if (this.is_callback() && !this.has_constants()) { >+ return; >+ } >+ >+ // TODO: Should we test here that the property is actually writable >+ // etc., or trust getOwnPropertyDescriptor? >+ 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(self[this.name]), Object.prototype, >+ "prototype of self's property " + format_value(this.name) + " is not Object.prototype"); >+ >+ return; >+ } >+ >+ // "The interface object for a given non-callback interface is a >+ // function object." >+ // "If an object is defined to be a function object, then it has >+ // characteristics as follows:" >+ >+ // Its [[Prototype]] internal property is otherwise specified (see >+ // below). >+ >+ // "* Its [[Get]] internal property is set as described in ECMA-262 >+ // section 9.1.8." >+ // Not much to test for this. >+ >+ // "* Its [[Construct]] internal property is set as described in >+ // ECMA-262 section 19.2.2.3." >+ // Tested below if no constructor is defined. TODO: test constructors >+ // if defined. >+ >+ // "* Its @@hasInstance property is set as described in ECMA-262 >+ // section 19.2.3.8, unless otherwise specified." >+ // TODO >+ >+ // 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 >+ // follows . . . >+ // >+ // "If I was not declared with a [Constructor] extended attribute, >+ // then throw a TypeError." >+ assert_throws(new TypeError(), function() { >+ self[this.name](); >+ }.bind(this), "interface object didn't throw TypeError when called as a function"); >+ assert_throws(new TypeError(), function() { >+ 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 2014-10-25. >+ // https://heycam.github.io/webidl/#es-interface-call >+ >+ 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]]: true } whose value is >+ // a Number." >+ 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_true(desc.configurable, this.name + ".length is not configurable"); >+ >+ var constructors = this.extAttrs >+ .filter(function(attr) { return attr.name == "Constructor"; }); >+ var expected_length = minOverloadLength(constructors); >+ assert_equals(self[this.name].length, expected_length, "wrong value for " + this.name + ".length"); >+ }.bind(this), this.name + " interface object length"); >+ } >+ >+ if (!this.is_callback() || this.has_constants()) { >+ test(function() { >+ // This function tests WebIDL as of 2015-11-17. >+ // https://heycam.github.io/webidl/#interface-object >+ >+ assert_own_property(self, this.name, >+ "self does not have own property " + format_value(this.name)); >+ >+ // "All interface objects must have a property named ânameâ with >+ // attributes { [[Writable]]: false, [[Enumerable]]: false, >+ // [[Configurable]]: true } whose value is the identifier of the >+ // corresponding interface." >+ >+ assert_own_property(self[this.name], "name"); >+ var desc = Object.getOwnPropertyDescriptor(self[this.name], "name"); >+ assert_false("get" in desc, this.name + ".name has getter"); >+ assert_false("set" in desc, this.name + ".name has setter"); >+ assert_false(desc.writable, this.name + ".name is writable"); >+ assert_false(desc.enumerable, this.name + ".name is enumerable"); >+ assert_true(desc.configurable, this.name + ".name is not configurable"); >+ assert_equals(self[this.name].name, this.name, "wrong value for " + this.name + ".name"); >+ }.bind(this), this.name + " interface object name"); >+ } >+ >+ // TODO: Test named constructors if I find any interfaces that have them. >+ >+ test(function() >+ { >+ // This function tests WebIDL as of 2015-01-21. >+ // https://heycam.github.io/webidl/#interface-object >+ >+ 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; >+ } >+ >+ // "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(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"); >+ assert_false(desc.enumerable, this.name + ".prototype is enumerable"); >+ assert_false(desc.configurable, this.name + ".prototype is configurable"); >+ >+ // Next, test that the [[Prototype]] of the interface prototype object >+ // is correct. (This is made somewhat difficult by the existence of >+ // [NoInterfaceObject].) >+ // TODO: Aryeh thinks there's at least other place in this file where >+ // we try to figure out if an interface prototype object is >+ // correct. Consolidate that code. >+ >+ // "The interface prototype object for a given interface A must have an >+ // 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). >+ 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 { >+ 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(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(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() >+ { >+ 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"'); >+ >+ // "If the [NoInterfaceObject] extended attribute was not specified on >+ // the interface, then the interface prototype object must also have a >+ // 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(self[this.name].prototype, "constructor", >+ this.name + '.prototype does not have own property "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(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) >+//@{ >+{ >+ if (!this.has_constants()) { >+ throw "Internal error: test_member_const called without any constants"; >+ } >+ >+ test(function() >+ { >+ 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() >+ { >+ 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)); >+ >+ var getter = Object.getOwnPropertyDescriptor(self, member.name).get; >+ assert_equals(typeof(getter), "function", >+ format_value(member.name) + " must have a getter"); >+ >+ // 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) { >+ 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) >+//@{ >+{ >+ var a_test = async_test(this.name + " interface: operation " + member.name + >+ "(" + member.arguments.map( >+ function(m) {return m.idlType.idlType; } ) >+ +")"); >+ a_test.step(function() >+ { >+ // This function tests WebIDL as of 2015-12-29. >+ // https://heycam.github.io/webidl/#es-operations >+ >+ if (this.is_callback() && !this.has_constants()) { >+ a_test.done(); >+ 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'); >+ a_test.done(); >+ return; >+ } >+ >+ assert_own_property(self[this.name], "prototype", >+ 'interface "' + this.name + '" does not have own property "prototype"'); >+ >+ // "For each unique identifier of an exposed operation defined on the >+ // interface, there must exist a corresponding property, unless the >+ // effective overload set for that identifier and operation and with an >+ // argument count of 0 has no entries." >+ >+ // TODO: Consider [Exposed]. >+ >+ // "The location of the property is determined as follows:" >+ var memberHolderObject; >+ // "* If the operation is static, then the property exists on the >+ // interface object." >+ if (member["static"]) { >+ assert_own_property(self[this.name], member.name, >+ "interface object missing static operation"); >+ memberHolderObject = self[this.name]; >+ // "* Otherwise, [...] if the interface was declared with the [Global] >+ // or [PrimaryGlobal] extended attribute, then the property exists >+ // on every object that implements the interface." >+ } else if (this.is_global()) { >+ assert_own_property(self, member.name, >+ "global object missing non-static operation"); >+ memberHolderObject = self; >+ // "* Otherwise, the property exists solely on the interfaceâs >+ // interface prototype object." >+ } 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, a_test); >+ }.bind(this)); >+}; >+ >+//@} >+IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject, member, a_test) >+//@{ >+{ >+ var done = a_test.done.bind(a_test); >+ 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." >+ assert_equals(memberHolderObject[member.name].length, >+ minOverloadLength(this.members.filter(function(m) { >+ return m.type == "operation" && m.name == member.name; >+ })), >+ "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"]) { >+ var cb; >+ if (!this.is_global() && >+ memberHolderObject[member.name] != self[member.name]) >+ { >+ cb = awaitNCallbacks(2, done); >+ throwOrReject(a_test, member, memberHolderObject[member.name], null, args, >+ "calling operation with this = null didn't throw TypeError", cb); >+ } else { >+ cb = awaitNCallbacks(1, done); >+ } >+ >+ // ". . . 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.) >+ throwOrReject(a_test, member, memberHolderObject[member.name], {}, args, >+ "calling operation with this = {} didn't throw TypeError", cb); >+ } else { >+ done(); >+ } >+} >+ >+//@} >+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) { >+ continue; >+ } >+ >+ switch (member.type) { >+ case "const": >+ this.test_member_const(member); >+ break; >+ >+ case "attribute": >+ // For unforgeable attributes, we do the checks in >+ // test_interface_of instead. >+ if (!member.isUnforgeable) >+ { >+ this.test_member_attribute(member); >+ } >+ break; >+ >+ case "operation": >+ // TODO: Need to correctly handle multiple operations with the same >+ // identifier. >+ // For unforgeable operations, we do the checks in >+ // test_interface_of instead. >+ if (member.name) { >+ if (!member.isUnforgeable) >+ { >+ this.test_member_operation(member); >+ } >+ } else if (member.stringifier) { >+ this.test_member_stringifier(member); >+ } >+ break; >+ >+ default: >+ // TODO: check more member types. >+ break; >+ } >+ } >+}; >+ >+//@} >+IdlInterface.prototype.test_object = function(desc) >+//@{ >+{ >+ var obj, exception = null; >+ try >+ { >+ obj = eval(desc); >+ } >+ catch(e) >+ { >+ exception = e; >+ } >+ >+ var expected_typeof = >+ this.members.some(function(member) { return member.legacycaller; }) >+ ? "function" >+ : "object"; >+ >+ this.test_primary_interface_of(desc, obj, exception, expected_typeof); >+ var current_interface = this; >+ while (current_interface) >+ { >+ if (!(current_interface.name in this.array.members)) >+ { >+ throw "Interface " + current_interface.name + " not found (inherited by " + this.name + ")"; >+ } >+ if (current_interface.prevent_multiple_testing && current_interface.already_tested) >+ { >+ return; >+ } >+ current_interface.test_interface_of(desc, obj, exception, expected_typeof); >+ current_interface = this.array.members[current_interface.base]; >+ } >+}; >+ >+//@} >+IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception, expected_typeof) >+//@{ >+{ >+ // 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 != expected_typeof || obj instanceof Object)) >+ { >+ test(function() >+ { >+ assert_equals(exception, null, "Unexpected exception when evaluating object"); >+ assert_equals(typeof obj, expected_typeof, "wrong typeof object"); >+ 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 >+ // platform object is the interface prototype object of the primary >+ // interface from the platform objectâs associated global >+ // environment." >+ assert_equals(Object.getPrototypeOf(obj), >+ self[this.name].prototype, >+ desc + "'s prototype is not " + this.name + ".prototype"); >+ }.bind(this), this.name + " must be primary interface of " + desc); >+ } >+ >+ // "The class string of a platform object that implements one or more >+ // interfaces must be the identifier of the primary interface of the >+ // platform object." >+ test(function() >+ { >+ assert_equals(exception, null, "Unexpected exception when evaluating object"); >+ assert_equals(typeof obj, expected_typeof, "wrong typeof object"); >+ assert_class_string(obj, this.name, "class string of " + desc); >+ if (!this.has_stringifier()) >+ { >+ assert_equals(String(obj), "[object " + this.name + "]", "String(" + desc + ")"); >+ } >+ }.bind(this), "Stringification of " + desc); >+}; >+ >+//@} >+IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof) >+//@{ >+{ >+ // TODO: Indexed and named properties, more checks on interface members >+ this.already_tested = true; >+ >+ for (var i = 0; i < this.members.length; i++) >+ { >+ var member = this.members[i]; >+ 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) >+ { >+ var a_test = async_test(this.name + " interface: " + desc + ' must have own property "' + member.name + '"'); >+ a_test.step(function() >+ { >+ assert_equals(exception, null, "Unexpected exception when evaluating object"); >+ assert_equals(typeof obj, expected_typeof, "wrong typeof object"); >+ assert_own_property(obj, member.name, >+ "Doesn't have the unforgeable operation property"); >+ this.do_member_operation_asserts(obj, member, a_test); >+ }.bind(this)); >+ } >+ else if ((member.type == "const" >+ || member.type == "attribute" >+ || member.type == "operation") >+ && member.name) >+ { >+ test(function() >+ { >+ assert_equals(exception, null, "Unexpected exception when evaluating object"); >+ assert_equals(typeof obj, expected_typeof, "wrong typeof object"); >+ if (!member["static"]) { >+ 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)); >+ } >+ if (member.type == "attribute") >+ { >+ // Attributes are accessor properties, so they might >+ // legitimately throw an exception rather than returning >+ // anything. >+ var property, thrown = false; >+ try >+ { >+ property = obj[member.name]; >+ } >+ catch (e) >+ { >+ thrown = true; >+ } >+ if (!thrown) >+ { >+ this.array.assert_type_is(property, member.idlType); >+ } >+ } >+ if (member.type == "operation") >+ { >+ assert_equals(typeof obj[member.name], "function"); >+ } >+ } >+ }.bind(this), this.name + " interface: " + desc + ' must inherit property "' + member.name + '" with the proper type (' + i + ')'); >+ } >+ // TODO: This is wrong if there are multiple operations with the same >+ // identifier. >+ // TODO: Test passing arguments of the wrong type. >+ if (member.type == "operation" && member.name && member.arguments.length) >+ { >+ var a_test = async_test( this.name + " interface: calling " + member.name + >+ "(" + member.arguments.map(function(m) { return m.idlType.idlType; }) + >+ ") on " + desc + " with too few arguments must throw TypeError"); >+ a_test.step(function() >+ { >+ assert_equals(exception, null, "Unexpected exception when evaluating object"); >+ assert_equals(typeof obj, expected_typeof, "wrong typeof object"); >+ if (!member["static"]) { >+ if (!this.is_global() && !member.isUnforgeable) { >+ assert_inherits(obj, member.name); >+ } else { >+ assert_own_property(obj, member.name); >+ } >+ } >+ else >+ { >+ assert_false(member.name in obj); >+ } >+ >+ var minLength = minOverloadLength(this.members.filter(function(m) { >+ return m.type == "operation" && m.name == member.name; >+ })); >+ var args = []; >+ var cb = awaitNCallbacks(minLength, a_test.done.bind(a_test)); >+ for (var i = 0; i < minLength; i++) { >+ throwOrReject(a_test, member, obj[member.name], obj, args, "Called with " + i + " arguments", cb); >+ >+ args.push(create_suitable_object(member.arguments[i].idlType)); >+ } >+ if (minLength === 0) { >+ cb(); >+ } >+ }.bind(this)); >+ } >+ } >+}; >+ >+//@} >+IdlInterface.prototype.has_stringifier = function() >+//@{ >+{ >+ if (this.members.some(function(member) { return member.stringifier; })) { >+ return true; >+ } >+ if (this.base && >+ this.array.members[this.base].has_stringifier()) { >+ return true; >+ } >+ return false; >+}; >+ >+//@} >+IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member) >+//@{ >+{ >+ // 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]]: >+ // true, [[Configurable]]: configurable }, where: >+ // "configurable is false if the attribute was declared with the >+ // [Unforgeable] extended attribute and true otherwise; >+ // "G is the attribute getter, defined below; and >+ // "S is the attribute setter, also defined below." >+ var desc = Object.getOwnPropertyDescriptor(obj, 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'); >+ assert_true(desc.enumerable, "property is not enumerable"); >+ if (member.isUnforgeable) >+ { >+ assert_false(desc.configurable, "[Unforgeable] property must not be configurable"); >+ } >+ else >+ { >+ assert_true(desc.configurable, "property must be configurable"); >+ } >+ >+ >+ // "The attribute getter is a Function object whose behavior when invoked >+ // 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(desc.get.length, 0, "getter length must be 0"); >+ >+ >+ // TODO: Test calling setter on the interface prototype (should throw >+ // TypeError in most cases). >+ 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"); >+ } >+} >+//@} >+ >+/// IdlInterfaceMember /// >+function IdlInterfaceMember(obj) >+//@{ >+{ >+ /** >+ * obj is an object produced by the WebIDLParser.js "ifMember" production. >+ * We just forward all properties to this object without modification, >+ * except for special extAttrs handling. >+ */ >+ for (var k in obj) >+ { >+ this[k] = obj[k]; >+ } >+ if (!("extAttrs" in this)) >+ { >+ this.extAttrs = []; >+ } >+ >+ this.isUnforgeable = this.has_extended_attribute("Unforgeable"); >+} >+ >+//@} >+IdlInterfaceMember.prototype = Object.create(IdlObject.prototype); >+ >+/// Internal helper functions /// >+function create_suitable_object(type) >+//@{ >+{ >+ /** >+ * type is an object produced by the WebIDLParser.js "type" production. We >+ * return a JavaScript value that matches the type, if we can figure out >+ * how. >+ */ >+ if (type.nullable) >+ { >+ return null; >+ } >+ switch (type.idlType) >+ { >+ case "any": >+ case "boolean": >+ return true; >+ >+ case "byte": case "octet": case "short": case "unsigned short": >+ case "long": case "unsigned long": case "long long": >+ case "unsigned long long": case "float": case "double": >+ case "unrestricted float": case "unrestricted double": >+ return 7; >+ >+ case "DOMString": >+ case "ByteString": >+ case "USVString": >+ return "foo"; >+ >+ case "object": >+ return {a: "b"}; >+ >+ case "Node": >+ return document.createTextNode("abc"); >+ } >+ return null; >+} >+//@} >+ >+/// IdlEnum /// >+// Used for IdlArray.prototype.assert_type_is >+function IdlEnum(obj) >+//@{ >+{ >+ /** >+ * obj is an object produced by the WebIDLParser.js "dictionary" >+ * production. >+ */ >+ >+ /** Self-explanatory. */ >+ this.name = obj.name; >+ >+ /** An array of values produced by the "enum" production. */ >+ this.values = obj.values; >+ >+} >+//@} >+ >+IdlEnum.prototype = Object.create(IdlObject.prototype); >+ >+/// IdlTypedef /// >+// Used for IdlArray.prototype.assert_type_is >+function IdlTypedef(obj) >+//@{ >+{ >+ /** >+ * obj is an object produced by the WebIDLParser.js "typedef" >+ * production. >+ */ >+ >+ /** Self-explanatory. */ >+ this.name = obj.name; >+ >+ /** An array of values produced by the "typedef" production. */ >+ this.values = obj.values; >+ >+} >+//@} >+ >+IdlTypedef.prototype = Object.create(IdlObject.prototype); >+ >+}()); >+// vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker:
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 159979
: 284132