From 03af62ccba4cdb1f56f61c3380e11369604ee5ff Mon Sep 17 00:00:00 2001 From: Yunfei Hao Date: Sun, 31 Jul 2016 23:47:35 +0800 Subject: [PATCH] Init and add test cases for webapi-webvr-w3c-tests Impacted tests(approved): new 144, update 0, delete 0 Unit test platform: Crosswalk Project for Windows 20.49.525.0 Unit test result summary: pass 54, fail 90, block 0 BUG=CTS-1761 --- tools/resources/idlharness/LICENSE | 21 + tools/resources/idlharness/WebIDLParser.js | 1012 +++++++++ tools/resources/testharness/idlharness.js | 1805 +++++++++++++++++ webapi/webapi-webvr-w3c-tests/COPYING | 24 + webapi/webapi-webvr-w3c-tests/icon.png | Bin 0 -> 19366 bytes webapi/webapi-webvr-w3c-tests/inst.apk.py | 107 + webapi/webapi-webvr-w3c-tests/suite.json | 57 + webapi/webapi-webvr-w3c-tests/tests.full.xml | 20 + webapi/webapi-webvr-w3c-tests/tests.xml | 13 + .../webvr/idl_test.html | 277 +++ 10 files changed, 3336 insertions(+) create mode 100644 tools/resources/idlharness/LICENSE create mode 100644 tools/resources/idlharness/WebIDLParser.js create mode 100644 tools/resources/testharness/idlharness.js create mode 100644 webapi/webapi-webvr-w3c-tests/COPYING create mode 100644 webapi/webapi-webvr-w3c-tests/icon.png create mode 100755 webapi/webapi-webvr-w3c-tests/inst.apk.py create mode 100644 webapi/webapi-webvr-w3c-tests/suite.json create mode 100644 webapi/webapi-webvr-w3c-tests/tests.full.xml create mode 100644 webapi/webapi-webvr-w3c-tests/tests.xml create mode 100644 webapi/webapi-webvr-w3c-tests/webvr/idl_test.html diff --git a/tools/resources/idlharness/LICENSE b/tools/resources/idlharness/LICENSE new file mode 100644 index 000000000..fd21d439b --- /dev/null +++ b/tools/resources/idlharness/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Robin Berjon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/resources/idlharness/WebIDLParser.js b/tools/resources/idlharness/WebIDLParser.js new file mode 100644 index 000000000..9e504fc6e --- /dev/null +++ b/tools/resources/idlharness/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/tools/resources/testharness/idlharness.js b/tools/resources/testharness/idlharness.js new file mode 100644 index 000000000..b6a16af41 --- /dev/null +++ b/tools/resources/testharness/idlharness.js @@ -0,0 +1,1805 @@ +/* +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; +}; + +//@} +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"] = {}; + + // 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.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. + // TODO: Consider [Exposed]. + + // "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: diff --git a/webapi/webapi-webvr-w3c-tests/COPYING b/webapi/webapi-webvr-w3c-tests/COPYING new file mode 100644 index 000000000..926ebc540 --- /dev/null +++ b/webapi/webapi-webvr-w3c-tests/COPYING @@ -0,0 +1,24 @@ +Copyright (c) 2016 Intel Corporation. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of works must retain the original copyright notice, this list + of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the original copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this work without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/webapi/webapi-webvr-w3c-tests/icon.png b/webapi/webapi-webvr-w3c-tests/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d4fe8775cabf6c0e5e1a3e699dd59a2da301ab67 GIT binary patch literal 19366 zcmV+GKoq};P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRay97#k$RCwCdeRUwn=;yl32Nuj#wKYb_EH#Q%s0|LngSfOmiOD-1p33}E$Ye0a?@Fxzd1 zo+4P3WmvX)H3s(ViQe<(VNLh$Sh&$fsD1JY(iJP9x_8Imv174(!2)#b-J5FNy8}dk z2qe!z00|L+2*L~^QV@Xv1i=2?zJdUddo2+W2{R~7k!Kn5MuSKx)arF1B1oPCN&)r& z6c_vZh1`92bVU4tBKviOS(H)`rJ#(#@_F-+x3q}NpO4nLb0M8OqixkHw2T>peq+X9 z?fm(eH+?!}z4ee9gU{#BNB2epD?~8-@Wb&qfJykT{j16_!T-`fVFu?p>Mbo`BI-VJ zBt!&aj61i;3eFy65|Ki9L3648A2o=68GG)Kt&it zA|gUW0)PRCvQH8b5n&b(5i<)h3lpK+@Zo6WInmm+Xq`V_B+J?z?Ek5ML8v?Ku;c&O zhq5u~*sUA74H-f$Lxw<@A;y67oG3{M%w7`-ktULe0-&tOq5R+9|KNk#Lk~UNZ~iCq z`!8Rnjgu94H9YmU}fZB*?wbput*2&@y9qJ2PT3SBo*SFs%yX-t} z;n=Zb+ngX-0D%Y-kq8k(M94lKw3+P5A(H2k5`hK|#DKniX~lc*A%E{ZVSAGPOaJY- zqm|uLPd)X&psB_{j6wI777X5C0|EffGLY89%vMy!5GiG~j!3}@)C*GqP{025Zw9>e z)?1sbShaGCw$|2-+3*Me{Q-0#t*oR;ffP9#O#pN0t27!JAcB=ES76bi&oF!ToHfr) zdw!8pYHls9z24H&^76Ec6AXtGC0AdjWvrO`G=3 zl`B_$BhT~AS$He~U6s~QAf&YvL<&j~l+sSE6`U(B#|c*bAYv`8h=4^P%$-}w(xF>7 zbm-olf>-_@(AxhIp)xas8C?bqLZ=ZUNVEoL88o?n&V;&vNC8kpq~3hvjoP)7C-1m) z>9Pa!Jl~ao{z_{orI02mw9?R8K`Hx~(h7rPgI)&c;!TQ}<1ySJ>$GNelV|0`6J=jf28*x(!ApdJGTSnbR*Bt(jA1gpfJ+19j* zsI$*Hd!vs&o_9c&WqXUrSgkaYL_;SDG%0AUp%V?QG?Z4wwG+4^1yWYPq?~ZQP`xvZ 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 \"%s\"" % cmd + output = [] + cmd_return_code = 1 + cmd_proc = subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) + + while True: + output_line = cmd_proc.stdout.readline().strip("\r\n") + cmd_return_code = cmd_proc.poll() + if output_line == '' and cmd_return_code is not None: + break + sys.stdout.write("%s\n" % output_line) + sys.stdout.flush() + output.append(output_line) + + return (cmd_return_code, output) + + +def uninstPKGs(): + action_status = True + for root, dirs, files in os.walk(SCRIPT_DIR): + for file in files: + if file.endswith(".apk"): + cmd = "%s -s %s uninstall org.xwalk.%s" % ( + ADB_CMD, PARAMETERS.device, os.path.basename(os.path.splitext(file)[0])) + (return_code, output) = doCMD(cmd) + for line in output: + if "Failure" in line: + action_status = False + break + return action_status + + +def instPKGs(): + action_status = True + for root, dirs, files in os.walk(SCRIPT_DIR): + for file in files: + if file.endswith(".apk"): + cmd = "%s -s %s install %s" % (ADB_CMD, + PARAMETERS.device, os.path.join(root, file)) + (return_code, output) = doCMD(cmd) + for line in output: + if "Failure" in line: + action_status = False + break + return action_status + + +def main(): + try: + usage = "usage: inst.py -i" + opts_parser = OptionParser(usage=usage) + opts_parser.add_option( + "-s", dest="device", action="store", help="Specify device") + opts_parser.add_option( + "-i", dest="binstpkg", action="store_true", help="Install package") + opts_parser.add_option( + "-u", dest="buninstpkg", action="store_true", help="Uninstall package") + global PARAMETERS + (PARAMETERS, args) = opts_parser.parse_args() + except Exception as e: + print "Got wrong option: %s, exit ..." % e + sys.exit(1) + + if not PARAMETERS.device: + (return_code, output) = doCMD("adb devices") + for line in output: + if str.find(line, "\tdevice") != -1: + PARAMETERS.device = line.split("\t")[0] + break + + if not PARAMETERS.device: + print "No device found" + sys.exit(1) + + if PARAMETERS.binstpkg and PARAMETERS.buninstpkg: + print "-i and -u are conflict" + sys.exit(1) + + if PARAMETERS.buninstpkg: + if not uninstPKGs(): + sys.exit(1) + else: + if not instPKGs(): + sys.exit(1) + +if __name__ == "__main__": + main() + sys.exit(0) diff --git a/webapi/webapi-webvr-w3c-tests/suite.json b/webapi/webapi-webvr-w3c-tests/suite.json new file mode 100644 index 000000000..d4eeeb69f --- /dev/null +++ b/webapi/webapi-webvr-w3c-tests/suite.json @@ -0,0 +1,57 @@ +{ + "pkg-blacklist": [ + "pack.py", + "testcase.xsl", + "testresult.xsl", + "tests.css", + "icon.png", + "suite.json", + "inst.*" + ], + "pkg-list": { + "apk,cordova": { + "blacklist": [ + "*" + ], + "copylist": { + "inst.apk.py": "inst.py", + "tests.full.xml": "tests.full.xml", + "tests.xml": "tests.xml" + }, + "pkg-app": { + "copylist": { + "PACK-TOOL-ROOT/resources/testharness": "resources", + "PACK-TOOL-ROOT/resources/idlharness/WebIDLParser.js": "resources/WebIDLParser.js", + "PACK-TOOL-ROOT/resources/webrunner": "webrunner" + } + } + }, + "apk-aio, cordova-aio": { + "blacklist": [], + "copylist": { + "PACK-TOOL-ROOT/resources/testharness": "resources", + "PACK-TOOL-ROOT/resources/idlharness/WebIDLParser.js": "resources/WebIDLParser.js", + "PACK-TOOL-ROOT/resources/webrunner": "webrunner" + } + }, + "msi": { + "blacklist": [ + "*" + ], + "copylist": { + "PACK-TOOL-ROOT/resources/inst/inst.msi.py": "inst.py", + "tests.full.xml": "tests.full.xml", + "tests.xml": "tests.xml" + }, + "pkg-app": { + "copylist": { + "PACK-TOOL-ROOT/resources/testharness": "resources", + "PACK-TOOL-ROOT/resources/idlharness/WebIDLParser.js": "resources/WebIDLParser.js", + "PACK-TOOL-ROOT/resources/webrunner": "webrunner", + "icon.png": "icon.ico" + } + } + } + }, + "pkg-name": "webapi-webvr-w3c-tests" +} diff --git a/webapi/webapi-webvr-w3c-tests/tests.full.xml b/webapi/webapi-webvr-w3c-tests/tests.full.xml new file mode 100644 index 000000000..e6d36d435 --- /dev/null +++ b/webapi/webapi-webvr-w3c-tests/tests.full.xml @@ -0,0 +1,20 @@ + + + + + + + + /opt/webapi-webvr-w3c-tests/webvr/idl_test.html + + + + + https://w3c.github.io/webvr/ + + + + + + + diff --git a/webapi/webapi-webvr-w3c-tests/tests.xml b/webapi/webapi-webvr-w3c-tests/tests.xml new file mode 100644 index 000000000..badb709fa --- /dev/null +++ b/webapi/webapi-webvr-w3c-tests/tests.xml @@ -0,0 +1,13 @@ + + + + + + + + /opt/webapi-webvr-w3c-tests/webvr/idl_test.html + + + + + diff --git a/webapi/webapi-webvr-w3c-tests/webvr/idl_test.html b/webapi/webapi-webvr-w3c-tests/webvr/idl_test.html new file mode 100644 index 000000000..e03ebfd36 --- /dev/null +++ b/webapi/webapi-webvr-w3c-tests/webvr/idl_test.html @@ -0,0 +1,277 @@ + + + + +WebVR IDL Test: Basic tests for WebVR interface + + + + + + + + + + + +
+