mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1104433 part 2 - Update dom/imptests/testharness.js and friends; rs=Ms2ger
This commit is contained in:
parent
9a78398b6b
commit
42cc797d1e
@ -31,7 +31,7 @@
|
||||
return tokens;
|
||||
};
|
||||
|
||||
var parse = function (tokens) {
|
||||
var parse = function (tokens, opt) {
|
||||
var line = 1;
|
||||
tokens = tokens.slice();
|
||||
|
||||
@ -82,14 +82,41 @@
|
||||
}
|
||||
};
|
||||
|
||||
var all_ws = function () {
|
||||
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) return t;
|
||||
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 () {
|
||||
@ -151,8 +178,15 @@
|
||||
else if (consume(OTHER, "[")) {
|
||||
all_ws();
|
||||
consume(OTHER, "]") || error("Unterminated array type");
|
||||
if (!obj.array) obj.array = 1;
|
||||
else obj.array++;
|
||||
if (!obj.array) {
|
||||
obj.array = 1;
|
||||
obj.nullableArray = [obj.nullable];
|
||||
}
|
||||
else {
|
||||
obj.array++;
|
||||
obj.nullableArray.push(obj.nullable);
|
||||
}
|
||||
obj.nullable = false;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
@ -160,40 +194,46 @@
|
||||
|
||||
var single_type = function () {
|
||||
var prim = primitive_type()
|
||||
, ret = { sequence: false, nullable: false, array: false, union: false }
|
||||
, ret = { sequence: false, generic: null, nullable: false, array: false, union: false }
|
||||
, name
|
||||
, value
|
||||
;
|
||||
if (prim) {
|
||||
ret.idlType = prim;
|
||||
}
|
||||
else if (consume(ID, "sequence")) {
|
||||
else if (name = consume(ID)) {
|
||||
value = name.value;
|
||||
all_ws();
|
||||
if (!consume(OTHER, "<")) {
|
||||
ret.idlType = "sequence";
|
||||
}
|
||||
else {
|
||||
ret.sequence = true;
|
||||
ret.idlType = type() || error("Error parsing sequence type");
|
||||
// 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 sequence");
|
||||
if (!consume(OTHER, ">")) error("Unterminated generic type " + value);
|
||||
all_ws();
|
||||
if (consume(OTHER, "?")) ret.nullable = true;
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
ret.idlType = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var name = consume(ID);
|
||||
if (!name) return;
|
||||
ret.idlType = name.value;
|
||||
return;
|
||||
}
|
||||
type_suffix(ret);
|
||||
if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable");
|
||||
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, nullable: false, array: false, union: true, idlType: [] };
|
||||
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) {
|
||||
@ -211,16 +251,21 @@
|
||||
return single_type() || union_type();
|
||||
};
|
||||
|
||||
var argument = function () {
|
||||
var argument = function (store) {
|
||||
var ret = { optional: false, variadic: false };
|
||||
ret.extAttrs = extended_attrs();
|
||||
all_ws();
|
||||
if (consume(ID, "optional")) {
|
||||
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) return;
|
||||
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 &&
|
||||
@ -235,7 +280,12 @@
|
||||
}
|
||||
}
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name in argument");
|
||||
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();
|
||||
@ -244,20 +294,33 @@
|
||||
return ret;
|
||||
};
|
||||
|
||||
var argument_list = function () {
|
||||
var arg = argument(), ret = [];
|
||||
if (!arg) return ret;
|
||||
var argument_list = function (store) {
|
||||
var ret = []
|
||||
, arg = argument(store ? ret : null)
|
||||
;
|
||||
if (!arg) return;
|
||||
ret.push(arg);
|
||||
while (true) {
|
||||
all_ws();
|
||||
all_ws(store ? ret : null);
|
||||
if (!consume(OTHER, ",")) return ret;
|
||||
all_ws();
|
||||
var nxt = argument() || error("Trailing comma in arguments list");
|
||||
var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list");
|
||||
ret.push(nxt);
|
||||
}
|
||||
};
|
||||
|
||||
var simple_extended_attr = function () {
|
||||
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;
|
||||
@ -274,24 +337,35 @@
|
||||
}
|
||||
all_ws();
|
||||
if (consume(OTHER, "(")) {
|
||||
ret["arguments"] = argument_list();
|
||||
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("Unclosed argument in extended attribute");
|
||||
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 () {
|
||||
var extended_attrs = function (store) {
|
||||
var eas = [];
|
||||
all_ws();
|
||||
all_ws(store);
|
||||
if (!consume(OTHER, "[")) return eas;
|
||||
eas[0] = simple_extended_attr() || error("Extended attribute with not content");
|
||||
eas[0] = simple_extended_attr(store) || error("Extended attribute with not content");
|
||||
all_ws();
|
||||
while (consume(OTHER, ",")) {
|
||||
all_ws();
|
||||
eas.push(simple_extended_attr() || error("Trailing comma in extended attribute"));
|
||||
eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute"));
|
||||
all_ws();
|
||||
}
|
||||
consume(OTHER, "]") || error("No end of extended attribute");
|
||||
@ -314,8 +388,8 @@
|
||||
}
|
||||
};
|
||||
|
||||
var const_ = function () {
|
||||
all_ws();
|
||||
var const_ = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "const")) return;
|
||||
var ret = { type: "const", nullable: false };
|
||||
all_ws();
|
||||
@ -352,14 +426,14 @@
|
||||
}
|
||||
};
|
||||
|
||||
var operation_rest = function (ret) {
|
||||
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();
|
||||
ret["arguments"] = argument_list(store) || [];
|
||||
all_ws();
|
||||
consume(OTHER, ")") || error("Unterminated operation");
|
||||
all_ws();
|
||||
@ -367,8 +441,8 @@
|
||||
return ret;
|
||||
};
|
||||
|
||||
var callback = function () {
|
||||
all_ws();
|
||||
var callback = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var ret;
|
||||
if (!consume(ID, "callback")) return;
|
||||
all_ws();
|
||||
@ -387,7 +461,7 @@
|
||||
ret.idlType = return_type();
|
||||
all_ws();
|
||||
consume(OTHER, "(") || error("No arguments in callback");
|
||||
ret["arguments"] = argument_list();
|
||||
ret["arguments"] = argument_list(store) || [];
|
||||
all_ws();
|
||||
consume(OTHER, ")") || error("Unterminated callback");
|
||||
all_ws();
|
||||
@ -395,8 +469,8 @@
|
||||
return ret;
|
||||
};
|
||||
|
||||
var attribute = function () {
|
||||
all_ws();
|
||||
var attribute = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var grabbed = []
|
||||
, ret = {
|
||||
type: "attribute"
|
||||
@ -454,8 +528,8 @@
|
||||
return typ;
|
||||
};
|
||||
|
||||
var operation = function () {
|
||||
all_ws();
|
||||
var operation = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var ret = {
|
||||
type: "operation"
|
||||
, getter: false
|
||||
@ -478,13 +552,13 @@
|
||||
if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
|
||||
all_ws();
|
||||
ret.idlType = return_type();
|
||||
operation_rest(ret);
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
if (consume(ID, "static")) {
|
||||
ret["static"] = true;
|
||||
ret.idlType = return_type();
|
||||
operation_rest(ret);
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
else if (consume(ID, "stringifier")) {
|
||||
@ -492,7 +566,7 @@
|
||||
all_ws();
|
||||
if (consume(OTHER, ";")) return ret;
|
||||
ret.idlType = return_type();
|
||||
operation_rest(ret);
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
ret.idlType = return_type();
|
||||
@ -513,7 +587,7 @@
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
operation_rest(ret);
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@ -530,8 +604,8 @@
|
||||
}
|
||||
};
|
||||
|
||||
var serialiser = function () {
|
||||
all_ws();
|
||||
var serialiser = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "serializer")) return;
|
||||
var ret = { type: "serializer" };
|
||||
all_ws();
|
||||
@ -589,77 +663,84 @@
|
||||
else {
|
||||
ret.idlType = return_type();
|
||||
all_ws();
|
||||
ret.operation = operation_rest();
|
||||
ret.operation = operation_rest(null, store);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
var interface_ = function (isPartial) {
|
||||
all_ws();
|
||||
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 ret = {
|
||||
var mems = []
|
||||
, ret = {
|
||||
type: "interface"
|
||||
, name: name.value
|
||||
, partial: false
|
||||
, members: []
|
||||
, members: mems
|
||||
};
|
||||
if (!isPartial) ret.inheritance = inheritance() || null;
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("Bodyless interface");
|
||||
while (true) {
|
||||
all_ws();
|
||||
all_ws(store ? mems : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Missing semicolon after interface");
|
||||
return ret;
|
||||
}
|
||||
var ea = extended_attrs();
|
||||
var ea = extended_attrs(store ? mems : null);
|
||||
all_ws();
|
||||
var cnt = const_();
|
||||
var cnt = const_(store ? mems : null);
|
||||
if (cnt) {
|
||||
cnt.extAttrs = ea;
|
||||
ret.members.push(cnt);
|
||||
continue;
|
||||
}
|
||||
var mem = serialiser() || attribute() || operation() || error("Unknown member");
|
||||
var mem = 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 () {
|
||||
all_ws();
|
||||
var partial = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "partial")) return;
|
||||
var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything");
|
||||
var thing = dictionary(true, store) ||
|
||||
interface_(true, store) ||
|
||||
error("Partial doesn't apply to anything");
|
||||
thing.partial = true;
|
||||
return thing;
|
||||
};
|
||||
|
||||
var dictionary = function (isPartial) {
|
||||
all_ws();
|
||||
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 ret = {
|
||||
var mems = []
|
||||
, ret = {
|
||||
type: "dictionary"
|
||||
, name: name.value
|
||||
, partial: false
|
||||
, members: []
|
||||
, members: mems
|
||||
};
|
||||
if (!isPartial) ret.inheritance = inheritance() || null;
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("Bodyless dictionary");
|
||||
while (true) {
|
||||
all_ws();
|
||||
all_ws(store ? mems : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Missing semicolon after dictionary");
|
||||
return ret;
|
||||
}
|
||||
var ea = extended_attrs();
|
||||
all_ws();
|
||||
var ea = extended_attrs(store ? mems : null);
|
||||
all_ws(store ? mems : null, "pea");
|
||||
var typ = type() || error("No type for dictionary member");
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name for dictionary member");
|
||||
@ -675,28 +756,29 @@
|
||||
}
|
||||
};
|
||||
|
||||
var exception = function () {
|
||||
all_ws();
|
||||
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 ret = {
|
||||
var mems = []
|
||||
, ret = {
|
||||
type: "exception"
|
||||
, name: name.value
|
||||
, members: []
|
||||
, members: mems
|
||||
};
|
||||
ret.inheritance = inheritance() || null;
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("Bodyless exception");
|
||||
while (true) {
|
||||
all_ws();
|
||||
all_ws(store ? mems : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Missing semicolon after exception");
|
||||
return ret;
|
||||
}
|
||||
var ea = extended_attrs();
|
||||
all_ws();
|
||||
var ea = extended_attrs(store ? mems : null);
|
||||
all_ws(store ? mems : null, "pea");
|
||||
var cnt = const_();
|
||||
if (cnt) {
|
||||
cnt.extAttrs = ea;
|
||||
@ -718,21 +800,22 @@
|
||||
}
|
||||
};
|
||||
|
||||
var enum_ = function () {
|
||||
all_ws();
|
||||
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 ret = {
|
||||
var vals = []
|
||||
, ret = {
|
||||
type: "enum"
|
||||
, name: name.value
|
||||
, values: []
|
||||
, values: vals
|
||||
};
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("No curly for enum");
|
||||
var saw_comma = false;
|
||||
while (true) {
|
||||
all_ws();
|
||||
all_ws(store ? vals : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
if (saw_comma) error("Trailing comma in enum");
|
||||
@ -741,9 +824,10 @@
|
||||
}
|
||||
var val = consume(STR) || error("Unexpected value in enum");
|
||||
ret.values.push(val.value.replace(/"/g, ""));
|
||||
all_ws();
|
||||
all_ws(store ? vals : null);
|
||||
if (consume(OTHER, ",")) {
|
||||
all_ws();
|
||||
if (store) vals.push({ type: "," });
|
||||
all_ws(store ? vals : null);
|
||||
saw_comma = true;
|
||||
}
|
||||
else {
|
||||
@ -752,15 +836,15 @@
|
||||
}
|
||||
};
|
||||
|
||||
var typedef = function () {
|
||||
all_ws();
|
||||
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();
|
||||
all_ws(store, "tpea");
|
||||
ret.idlType = type() || error("No type in typedef");
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name in typedef");
|
||||
@ -770,8 +854,8 @@
|
||||
return ret;
|
||||
};
|
||||
|
||||
var implements_ = function () {
|
||||
all_ws();
|
||||
var implements_ = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var target = consume(ID);
|
||||
if (!target) return;
|
||||
var w = all_ws();
|
||||
@ -794,24 +878,24 @@
|
||||
}
|
||||
};
|
||||
|
||||
var definition = function () {
|
||||
return callback() ||
|
||||
interface_() ||
|
||||
partial() ||
|
||||
dictionary() ||
|
||||
exception() ||
|
||||
enum_() ||
|
||||
typedef() ||
|
||||
implements_()
|
||||
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 () {
|
||||
var definitions = function (store) {
|
||||
if (!tokens.length) return [];
|
||||
var defs = [];
|
||||
while (true) {
|
||||
var ea = extended_attrs()
|
||||
, def = definition();
|
||||
var ea = extended_attrs(store ? defs : null)
|
||||
, def = definition(store ? defs : null);
|
||||
if (!def) {
|
||||
if (ea.length) error("Stray extended attributes");
|
||||
break;
|
||||
@ -821,21 +905,20 @@
|
||||
}
|
||||
return defs;
|
||||
};
|
||||
var res = definitions();
|
||||
var res = definitions(opt.ws);
|
||||
if (tokens.length) error("Unrecognised tokens");
|
||||
return res;
|
||||
};
|
||||
|
||||
var obj = {
|
||||
parse: function (str) {
|
||||
var tokens = tokenise(str);
|
||||
return parse(tokens);
|
||||
}
|
||||
var inNode = typeof module !== "undefined" && module.exports
|
||||
, obj = {
|
||||
parse: function (str, opt) {
|
||||
if (!opt) opt = {};
|
||||
var tokens = tokenise(str);
|
||||
return parse(tokens, opt);
|
||||
}
|
||||
};
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports = obj;
|
||||
}
|
||||
else {
|
||||
window.WebIDL2 = obj;
|
||||
}
|
||||
|
||||
if (inNode) module.exports = obj;
|
||||
else window.WebIDL2 = obj;
|
||||
}());
|
||||
|
@ -8,131 +8,7 @@ policies and contribution forms [3].
|
||||
[3] http://www.w3.org/2004/10/27-testcases
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file automatically generates browser tests for WebIDL interfaces, using
|
||||
* the testharness.js framework. To use, first include the following:
|
||||
*
|
||||
* <script src=/resources/testharness.js></script>
|
||||
* <script src=/resources/testharnessreport.js></script>
|
||||
* <script src=/resources/WebIDLParser.js></script>
|
||||
* <script src=/resources/idlharness.js></script>
|
||||
*
|
||||
* Then you'll need some type of IDLs. Here's some script that can be run on a
|
||||
* spec written in HTML, which will grab all the elements with class="idl",
|
||||
* concatenate them, and replace the body so you can copy-paste:
|
||||
*
|
||||
var s = "";
|
||||
[].forEach.call(document.getElementsByClassName("idl"), function(idl) {
|
||||
//https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
|
||||
if (!idl.classList.contains("extract"))
|
||||
{
|
||||
s += idl.textContent + "\n\n";
|
||||
}
|
||||
});
|
||||
document.body.innerHTML = '<pre></pre>';
|
||||
document.body.firstChild.textContent = s;
|
||||
*
|
||||
* (TODO: write this in Python or something so that it can be done from the
|
||||
* command line instead.)
|
||||
*
|
||||
* Once you have that, put it in your script somehow. The easiest way is to
|
||||
* embed it literally in an HTML file with <script type=text/plain> or similar,
|
||||
* so that you don't have to do any escaping. Another possibility is to put it
|
||||
* in a separate .idl file that's fetched via XHR or similar. Sample usage:
|
||||
*
|
||||
* var idl_array = new IdlArray();
|
||||
* idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
|
||||
* idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
|
||||
* idl_array.add_objects({Document: ["document"]});
|
||||
* idl_array.test();
|
||||
*
|
||||
* This tests that window.Document exists and meets all the requirements of
|
||||
* WebIDL. It also tests that window.document (the result of evaluating the
|
||||
* string "document") has URL and nodeName properties that behave as they
|
||||
* should, and otherwise meets WebIDL's requirements for an object whose
|
||||
* primary interface is Document. It does not test that window.Node exists,
|
||||
* which is what you want if the Node interface is already tested in some other
|
||||
* specification's suite and your specification only extends or refers to it.
|
||||
* Of course, each IDL string can define many different things, and calls to
|
||||
* add_objects() can register many different objects for different interfaces:
|
||||
* this is a very simple example.
|
||||
*
|
||||
* TODO: Write assert_writable, assert_enumerable, assert_configurable and
|
||||
* their inverses, and use those instead of just checking
|
||||
* getOwnPropertyDescriptor.
|
||||
*
|
||||
* == Public methods of IdlArray ==
|
||||
*
|
||||
* IdlArray objects can be obtained with new IdlArray(). Anything not
|
||||
* documented in this section should be considered an implementation detail,
|
||||
* and outside callers should not use it.
|
||||
*
|
||||
* add_idls(idl_string):
|
||||
* Parses idl_string (throwing on parse error) and adds the results to the
|
||||
* IdlArray. All the definitions will be tested when you run test(). If
|
||||
* some of the definitions refer to other definitions, those must be present
|
||||
* too. For instance, if idl_string says that Document inherits from Node,
|
||||
* the Node interface must also have been provided in some call to add_idls()
|
||||
* or add_untested_idls().
|
||||
*
|
||||
* add_untested_idls(idl_string):
|
||||
* Like add_idls(), but the definitions will not be tested. If an untested
|
||||
* interface is added and then extended with a tested partial interface, the
|
||||
* members of the partial interface will still be tested. Also, all the
|
||||
* members will still be tested for objects added with add_objects(), because
|
||||
* you probably want to test that (for instance) window.document has all the
|
||||
* properties from Node, not just Document, even if the Node interface itself
|
||||
* is tested in a different test suite.
|
||||
*
|
||||
* add_objects(dict):
|
||||
* dict should be an object whose keys are the names of interfaces or
|
||||
* exceptions, and whose values are arrays of strings. When an interface or
|
||||
* exception is tested, every string registered for it with add_objects()
|
||||
* will be evaluated, and tests will be run on the result to verify that it
|
||||
* correctly implements that interface or exception. This is the only way to
|
||||
* test anything about [NoInterfaceObject] interfaces, and there are many
|
||||
* tests that can't be run on any interface without an object to fiddle with.
|
||||
*
|
||||
* The interface has to be the *primary* interface of all the objects
|
||||
* provided. For example, don't pass {Node: ["document"]}, but rather
|
||||
* {Document: ["document"]}. Assuming the Document interface was declared to
|
||||
* inherit from Node, this will automatically test that document implements
|
||||
* the Node interface too.
|
||||
*
|
||||
* Warning: methods will be called on any provided objects, in a manner that
|
||||
* WebIDL requires be safe. For instance, if a method has mandatory
|
||||
* arguments, the test suite will try calling it with too few arguments to
|
||||
* see if it throws an exception. If an implementation incorrectly runs the
|
||||
* function instead of throwing, this might have side effects, possibly even
|
||||
* preventing the test suite from running correctly.
|
||||
*
|
||||
* prevent_multiple_testing(name):
|
||||
* This is a niche method for use in case you're testing many objects that
|
||||
* implement the same interfaces, and don't want to retest the same
|
||||
* interfaces every single time. For instance, HTML defines many interfaces
|
||||
* that all inherit from HTMLElement, so the HTML test suite has something
|
||||
* like
|
||||
* .add_objects({
|
||||
* HTMLHtmlElement: ['document.documentElement'],
|
||||
* HTMLHeadElement: ['document.head'],
|
||||
* HTMLBodyElement: ['document.body'],
|
||||
* ...
|
||||
* })
|
||||
* and so on for dozens of element types. This would mean that it would
|
||||
* retest that each and every one of those elements implements HTMLElement,
|
||||
* Element, and Node, which would be thousands of basically redundant tests.
|
||||
* The test suite therefore calls prevent_multiple_testing("HTMLElement").
|
||||
* This means that once one object has been tested to implement HTMLElement
|
||||
* and its ancestors, no other object will be. Thus in the example code
|
||||
* above, the harness would test that document.documentElement correctly
|
||||
* implements HTMLHtmlElement, HTMLElement, Element, and Node; but
|
||||
* document.head would only be tested for HTMLHeadElement, and so on for
|
||||
* further objects.
|
||||
*
|
||||
* test():
|
||||
* Run all tests. This should be called after you've called all other
|
||||
* methods to add IDLs and objects.
|
||||
*/
|
||||
/* For user documentation see docs/idlharness.md */
|
||||
|
||||
/**
|
||||
* Notes for people who want to edit this file (not just use it as a library):
|
||||
@ -550,6 +426,9 @@ IdlArray.prototype.assert_type_is = function(value, type)
|
||||
return;
|
||||
|
||||
case "DOMString":
|
||||
case "ByteString":
|
||||
case "USVString":
|
||||
// TODO: https://github.com/w3c/testharness.js/issues/92
|
||||
assert_equals(typeof value, "string");
|
||||
return;
|
||||
|
||||
@ -1312,6 +1191,249 @@ IdlInterface.prototype.test_self = function()
|
||||
}.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');
|
||||
};
|
||||
|
||||
//@}
|
||||
IdlInterface.prototype.test_member_const = function(member)
|
||||
//@{
|
||||
{
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
|
||||
// "For each constant defined on an interface A, there must be
|
||||
// a corresponding property on the interface object, if it
|
||||
// exists."
|
||||
assert_own_property(window[this.name], member.name);
|
||||
// "The value of the property is that which is obtained by
|
||||
// converting the constant’s IDL value to an ECMAScript
|
||||
// value."
|
||||
assert_equals(window[this.name][member.name], constValue(member.value),
|
||||
"property has wrong value");
|
||||
// "The property has attributes { [[Writable]]: false,
|
||||
// [[Enumerable]]: true, [[Configurable]]: false }."
|
||||
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
|
||||
assert_false("get" in desc, "property has getter");
|
||||
assert_false("set" in desc, "property has setter");
|
||||
assert_false(desc.writable, "property is writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_false(desc.configurable, "property is configurable");
|
||||
}.bind(this), this.name + " interface: constant " + member.name + " on interface object");
|
||||
// "In addition, a property with the same characteristics must
|
||||
// exist on the interface prototype object."
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
|
||||
if (this.has_extended_attribute("Callback")) {
|
||||
assert_false("prototype" in window[this.name],
|
||||
this.name + ' should not have a "prototype" property');
|
||||
return;
|
||||
}
|
||||
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
|
||||
assert_own_property(window[this.name].prototype, member.name);
|
||||
assert_equals(window[this.name].prototype[member.name], constValue(member.value),
|
||||
"property has wrong value");
|
||||
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
|
||||
assert_false("get" in desc, "property has getter");
|
||||
assert_false("set" in desc, "property has setter");
|
||||
assert_false(desc.writable, "property is writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_false(desc.configurable, "property is configurable");
|
||||
}.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
|
||||
};
|
||||
|
||||
|
||||
//@}
|
||||
IdlInterface.prototype.test_member_attribute = function(member)
|
||||
//@{
|
||||
{
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
|
||||
if (member["static"]) {
|
||||
assert_own_property(window[this.name], member.name,
|
||||
"The interface object must have a property " +
|
||||
format_value(member.name));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert_true(member.name in window[this.name].prototype,
|
||||
"The prototype object must have a property " +
|
||||
format_value(member.name));
|
||||
|
||||
if (!member.has_extended_attribute("LenientThis")) {
|
||||
assert_throws(new TypeError(), function() {
|
||||
window[this.name].prototype[member.name];
|
||||
}.bind(this), "getting property on prototype object must throw TypeError");
|
||||
} else {
|
||||
assert_equals(window[this.name].prototype[member.name], undefined,
|
||||
"getting property on prototype object must return undefined");
|
||||
}
|
||||
do_interface_attribute_asserts(window[this.name].prototype, member);
|
||||
}
|
||||
}.bind(this), this.name + " interface: attribute " + member.name);
|
||||
};
|
||||
|
||||
//@}
|
||||
IdlInterface.prototype.test_member_operation = function(member)
|
||||
//@{
|
||||
{
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
|
||||
if (this.has_extended_attribute("Callback")) {
|
||||
assert_false("prototype" in window[this.name],
|
||||
this.name + ' should not have a "prototype" property');
|
||||
return;
|
||||
}
|
||||
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
|
||||
// "For each unique identifier of an operation defined on the
|
||||
// interface, there must be a corresponding property on the
|
||||
// interface prototype object (if it is a regular operation) or
|
||||
// the interface object (if it is a static operation), unless
|
||||
// the effective overload set for that identifier and operation
|
||||
// and with an argument count of 0 (for the ECMAScript language
|
||||
// binding) has no entries."
|
||||
//
|
||||
var prototypeOrInterfaceObject;
|
||||
if (member["static"]) {
|
||||
assert_own_property(window[this.name], member.name,
|
||||
"interface prototype object missing static operation");
|
||||
prototypeOrInterfaceObject = window[this.name];
|
||||
}
|
||||
else
|
||||
{
|
||||
assert_own_property(window[this.name].prototype, member.name,
|
||||
"interface prototype object missing non-static operation");
|
||||
prototypeOrInterfaceObject = window[this.name].prototype;
|
||||
}
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(prototypeOrInterfaceObject, member.name);
|
||||
// "The property has attributes { [[Writable]]: true,
|
||||
// [[Enumerable]]: true, [[Configurable]]: true }."
|
||||
assert_false("get" in desc, "property has getter");
|
||||
assert_false("set" in desc, "property has setter");
|
||||
assert_true(desc.writable, "property is not writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_true(desc.configurable, "property is not configurable");
|
||||
// "The value of the property is a Function object whose
|
||||
// behavior is as follows . . ."
|
||||
assert_equals(typeof prototypeOrInterfaceObject[member.name], "function",
|
||||
"property must be a function");
|
||||
// "The value of the Function object’s “length” property is
|
||||
// a Number determined as follows:
|
||||
// ". . .
|
||||
// "Return the length of the shortest argument list of the
|
||||
// entries in S."
|
||||
//
|
||||
// TODO: Doesn't handle overloading or variadic arguments.
|
||||
assert_equals(prototypeOrInterfaceObject[member.name].length,
|
||||
member.arguments.filter(function(arg) {
|
||||
return !arg.optional;
|
||||
}).length,
|
||||
"property has wrong .length");
|
||||
|
||||
// Make some suitable arguments
|
||||
var args = member.arguments.map(function(arg) {
|
||||
return create_suitable_object(arg.idlType);
|
||||
});
|
||||
|
||||
// "Let O be a value determined as follows:
|
||||
// ". . .
|
||||
// "Otherwise, throw a TypeError."
|
||||
// This should be hit if the operation is not static, there is
|
||||
// no [ImplicitThis] attribute, and the this value is null.
|
||||
//
|
||||
// TODO: We currently ignore the [ImplicitThis] case.
|
||||
if (!member["static"]) {
|
||||
assert_throws(new TypeError(), function() {
|
||||
window[this.name].prototype[member.name].apply(null, args);
|
||||
}, "calling operation with this = null didn't throw TypeError");
|
||||
}
|
||||
|
||||
// ". . . If O is not null and is also not a platform object
|
||||
// that implements interface I, throw a TypeError."
|
||||
//
|
||||
// TODO: Test a platform object that implements some other
|
||||
// interface. (Have to be sure to get inheritance right.)
|
||||
assert_throws(new TypeError(), function() {
|
||||
window[this.name].prototype[member.name].apply({}, args);
|
||||
}, "calling operation with this = {} didn't throw TypeError");
|
||||
}.bind(this), this.name + " interface: operation " + member.name +
|
||||
"(" + member.arguments.map(function(m) { return m.idlType.idlType; }) +
|
||||
")");
|
||||
};
|
||||
|
||||
//@}
|
||||
IdlInterface.prototype.test_member_stringifier = function(member)
|
||||
//@{
|
||||
{
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
|
||||
if (this.has_extended_attribute("Callback")) {
|
||||
assert_false("prototype" in window[this.name],
|
||||
this.name + ' should not have a "prototype" property');
|
||||
return;
|
||||
}
|
||||
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
|
||||
// ". . . the property exists on the interface prototype object."
|
||||
var interfacePrototypeObject = window[this.name].prototype;
|
||||
assert_own_property(window[this.name].prototype, "toString",
|
||||
"interface prototype object missing non-static operation");
|
||||
|
||||
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_true(desc.writable, "property is not writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_true(desc.configurable, "property is not configurable");
|
||||
// "The value of the property is a Function object, 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() {
|
||||
window[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() {
|
||||
window[this.name].prototype.toString.apply({}, []);
|
||||
}, "calling stringifier with this = {} didn't throw TypeError");
|
||||
}.bind(this), this.name + " interface: stringifier");
|
||||
};
|
||||
|
||||
//@}
|
||||
IdlInterface.prototype.test_members = function()
|
||||
//@{
|
||||
@ -1319,195 +1441,37 @@ IdlInterface.prototype.test_members = function()
|
||||
for (var i = 0; i < this.members.length; i++)
|
||||
{
|
||||
var member = this.members[i];
|
||||
if (member.untested)
|
||||
{
|
||||
if (member.untested) {
|
||||
continue;
|
||||
}
|
||||
if (member.type == "const")
|
||||
{
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
|
||||
// "For each constant defined on an interface A, there must be
|
||||
// a corresponding property on the interface object, if it
|
||||
// exists."
|
||||
assert_own_property(window[this.name], member.name);
|
||||
// "The value of the property is that which is obtained by
|
||||
// converting the constant’s IDL value to an ECMAScript
|
||||
// value."
|
||||
assert_equals(window[this.name][member.name], constValue(member.value),
|
||||
"property has wrong value");
|
||||
// "The property has attributes { [[Writable]]: false,
|
||||
// [[Enumerable]]: true, [[Configurable]]: false }."
|
||||
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
|
||||
assert_false("get" in desc, "property has getter");
|
||||
assert_false("set" in desc, "property has setter");
|
||||
assert_false(desc.writable, "property is writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_false(desc.configurable, "property is configurable");
|
||||
}.bind(this), this.name + " interface: constant " + member.name + " on interface object");
|
||||
// "In addition, a property with the same characteristics must
|
||||
// exist on the interface prototype object."
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
switch (member.type) {
|
||||
case "const":
|
||||
this.test_member_const(member);
|
||||
break;
|
||||
|
||||
if (this.has_extended_attribute("Callback")) {
|
||||
assert_false("prototype" in window[this.name],
|
||||
this.name + ' should not have a "prototype" property');
|
||||
return;
|
||||
}
|
||||
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
|
||||
assert_own_property(window[this.name].prototype, member.name);
|
||||
assert_equals(window[this.name].prototype[member.name], constValue(member.value),
|
||||
"property has wrong value");
|
||||
var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
|
||||
assert_false("get" in desc, "property has getter");
|
||||
assert_false("set" in desc, "property has setter");
|
||||
assert_false(desc.writable, "property is writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_false(desc.configurable, "property is configurable");
|
||||
}.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
|
||||
}
|
||||
else if (member.type == "attribute")
|
||||
{
|
||||
if (member.has_extended_attribute("Unforgeable"))
|
||||
{
|
||||
// We do the checks in test_interface_of instead
|
||||
continue;
|
||||
case "attribute":
|
||||
// For unforgeable attributes, we do the checks in
|
||||
// test_interface_of instead.
|
||||
if (!member.has_extended_attribute("Unforgeable")) {
|
||||
this.test_member_attribute(member);
|
||||
}
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
break;
|
||||
|
||||
if (member["static"]) {
|
||||
assert_own_property(window[this.name], member.name,
|
||||
"The interface object must have a property " +
|
||||
format_value(member.name));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert_true(member.name in window[this.name].prototype,
|
||||
"The prototype object must have a property " +
|
||||
format_value(member.name));
|
||||
|
||||
// TODO: Needs to test for LenientThis.
|
||||
assert_throws(new TypeError(), function() {
|
||||
window[this.name].prototype[member.name];
|
||||
}.bind(this), "getting property on prototype object must throw TypeError");
|
||||
do_interface_attribute_asserts(window[this.name].prototype, member);
|
||||
}
|
||||
}.bind(this), this.name + " interface: attribute " + member.name);
|
||||
}
|
||||
else if (member.type == "operation")
|
||||
{
|
||||
case "operation":
|
||||
// TODO: Need to correctly handle multiple operations with the same
|
||||
// identifier.
|
||||
if (!member.name)
|
||||
{
|
||||
// Unnamed getter or such
|
||||
continue;
|
||||
if (member.name) {
|
||||
this.test_member_operation(member);
|
||||
} else if (member.stringifier) {
|
||||
this.test_member_stringifier(member);
|
||||
}
|
||||
test(function()
|
||||
{
|
||||
assert_own_property(window, this.name,
|
||||
"window does not have own property " + format_value(this.name));
|
||||
break;
|
||||
|
||||
if (this.has_extended_attribute("Callback")) {
|
||||
assert_false("prototype" in window[this.name],
|
||||
this.name + ' should not have a "prototype" property');
|
||||
return;
|
||||
}
|
||||
|
||||
assert_own_property(window[this.name], "prototype",
|
||||
'interface "' + this.name + '" does not have own property "prototype"');
|
||||
|
||||
// "For each unique identifier of an operation defined on the
|
||||
// interface, there must be a corresponding property on the
|
||||
// interface prototype object (if it is a regular operation) or
|
||||
// the interface object (if it is a static operation), unless
|
||||
// the effective overload set for that identifier and operation
|
||||
// and with an argument count of 0 (for the ECMAScript language
|
||||
// binding) has no entries."
|
||||
//
|
||||
var prototypeOrInterfaceObject;
|
||||
if (member["static"]) {
|
||||
assert_own_property(window[this.name], member.name,
|
||||
"interface prototype object missing static operation");
|
||||
prototypeOrInterfaceObject = window[this.name];
|
||||
}
|
||||
else
|
||||
{
|
||||
assert_own_property(window[this.name].prototype, member.name,
|
||||
"interface prototype object missing non-static operation");
|
||||
prototypeOrInterfaceObject = window[this.name].prototype;
|
||||
}
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(prototypeOrInterfaceObject, member.name);
|
||||
// "The property has attributes { [[Writable]]: true,
|
||||
// [[Enumerable]]: true, [[Configurable]]: true }."
|
||||
assert_false("get" in desc, "property has getter");
|
||||
assert_false("set" in desc, "property has setter");
|
||||
assert_true(desc.writable, "property is not writable");
|
||||
assert_true(desc.enumerable, "property is not enumerable");
|
||||
assert_true(desc.configurable, "property is not configurable");
|
||||
// "The value of the property is a Function object whose
|
||||
// behavior is as follows . . ."
|
||||
assert_equals(typeof prototypeOrInterfaceObject[member.name], "function",
|
||||
"property must be a function");
|
||||
// "The value of the Function object’s “length” property is
|
||||
// a Number determined as follows:
|
||||
// ". . .
|
||||
// "Return the length of the shortest argument list of the
|
||||
// entries in S."
|
||||
//
|
||||
// TODO: Doesn't handle overloading or variadic arguments.
|
||||
assert_equals(prototypeOrInterfaceObject[member.name].length,
|
||||
member.arguments.filter(function(arg) {
|
||||
return !arg.optional;
|
||||
}).length,
|
||||
"property has wrong .length");
|
||||
|
||||
// Make some suitable arguments
|
||||
var args = member.arguments.map(function(arg) {
|
||||
return create_suitable_object(arg.idlType);
|
||||
});
|
||||
|
||||
// "Let O be a value determined as follows:
|
||||
// ". . .
|
||||
// "Otherwise, throw a TypeError."
|
||||
// This should be hit if the operation is not static, there is
|
||||
// no [ImplicitThis] attribute, and the this value is null.
|
||||
//
|
||||
// TODO: We currently ignore the [ImplicitThis] case.
|
||||
if (!member["static"]) {
|
||||
assert_throws(new TypeError(), function() {
|
||||
window[this.name].prototype[member.name].apply(null, args);
|
||||
}, "calling operation with this = null didn't throw TypeError");
|
||||
}
|
||||
|
||||
// ". . . If O is not null and is also not a platform object
|
||||
// that implements interface I, throw a TypeError."
|
||||
//
|
||||
// TODO: Test a platform object that implements some other
|
||||
// interface. (Have to be sure to get inheritance right.)
|
||||
assert_throws(new TypeError(), function() {
|
||||
window[this.name].prototype[member.name].apply({}, args);
|
||||
}, "calling operation with this = {} didn't throw TypeError");
|
||||
}.bind(this), this.name + " interface: operation " + member.name +
|
||||
"(" + member.arguments.map(function(m) { return m.idlType.idlType; }) +
|
||||
")");
|
||||
default:
|
||||
// TODO: check more member types.
|
||||
break;
|
||||
}
|
||||
// TODO: check more member types, like stringifier
|
||||
}
|
||||
};
|
||||
|
||||
@ -1748,11 +1712,14 @@ function do_interface_attribute_asserts(obj, member)
|
||||
// value 0."
|
||||
assert_equals(typeof desc.get, "function", "getter must be Function");
|
||||
assert_equals(desc.get.length, 0, "getter length must be 0");
|
||||
// TODO: Account for LenientThis
|
||||
assert_throws(new TypeError(), function()
|
||||
{
|
||||
desc.get.call({});
|
||||
}.bind(this), "calling getter on wrong object type must throw TypeError");
|
||||
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");
|
||||
}
|
||||
|
||||
// TODO: Test calling setter on the interface prototype (should throw
|
||||
// TypeError in most cases).
|
||||
@ -1774,6 +1741,14 @@ function do_interface_attribute_asserts(obj, member)
|
||||
{
|
||||
assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes");
|
||||
assert_equals(desc.set.length, 1, "setter length must be 1");
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
//@}
|
||||
@ -1826,6 +1801,8 @@ function create_suitable_object(type)
|
||||
return 7;
|
||||
|
||||
case "DOMString":
|
||||
case "ByteString":
|
||||
case "USVString":
|
||||
return "foo";
|
||||
|
||||
case "object":
|
||||
|
@ -90,3 +90,18 @@ table#results span.actual {
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
span.ok {
|
||||
color:green;
|
||||
}
|
||||
|
||||
tr.error {
|
||||
color:red;
|
||||
}
|
||||
|
||||
span.timeout {
|
||||
color:red;
|
||||
}
|
||||
|
||||
span.ok, span.timeout, span.error {
|
||||
font-variant:small-caps;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user