How to use exposureAttr method in wpt

Best JavaScript code snippet using wpt

idlharness.js

Source:idlharness.js Github

copy

Full Screen

1/*2Distributed under both the W3C Test Suite License [1] and the W3C33-clause BSD License [2]. To contribute to a W3C Test Suite, see the4policies and contribution forms [3].5[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license6[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license7[3] http://www.w3.org/2004/10/27-testcases8*/9/* For user documentation see docs/_writing-tests/idlharness.md */10/**11 * Notes for people who want to edit this file (not just use it as a library):12 *13 * Most of the interesting stuff happens in the derived classes of IdlObject,14 * especially IdlInterface. The entry point for all IdlObjects is .test(),15 * which is called by IdlArray.test(). An IdlObject is conceptually just16 * "thing we want to run tests on", and an IdlArray is an array of IdlObjects17 * with some additional data thrown in.18 *19 * The object model is based on what WebIDLParser.js produces, which is in turn20 * based on its pegjs grammar. If you want to figure out what properties an21 * object will have from WebIDLParser.js, the best way is to look at the22 * grammar:23 *24 * https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg25 *26 * So for instance:27 *28 * // interface definition29 * interface30 * = extAttrs:extendedAttributeList? S? "interface" S name:identifier w herit:ifInheritance? w "{" w mem:ifMember* w "}" w ";" w31 * { return { type: "interface", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; }32 *33 * This means that an "interface" object will have a .type property equal to34 * the string "interface", a .name property equal to the identifier that the35 * parser found, an .inheritance property equal to either null or the result of36 * the "ifInheritance" production found elsewhere in the grammar, and so on.37 * After each grammatical production is a JavaScript function in curly braces38 * that gets called with suitable arguments and returns some JavaScript value.39 *40 * (Note that the version of WebIDLParser.js we use might sometimes be41 * out-of-date or forked.)42 *43 * The members and methods of the classes defined by this file are all at least44 * briefly documented, hopefully.45 */46(function(){47"use strict";48// Support subsetTestByKey from /common/subset-tests-by-key.js, but make it optional49if (!('subsetTestByKey' in self)) {50 self.subsetTestByKey = function(key, callback, ...args) {51 return callback(...args);52 }53 self.shouldRunSubTest = () => true;54}55/// Helpers ///56function constValue (cnt)57//@{58{59 if (cnt.type === "null") return null;60 if (cnt.type === "NaN") return NaN;61 if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity;62 if (cnt.type === "number") return +cnt.value;63 return cnt.value;64}65//@}66function minOverloadLength(overloads)67//@{68{69 // "The value of the Function object’s “length” property is70 // a Number determined as follows:71 // ". . .72 // "Return the length of the shortest argument list of the73 // entries in S."74 if (!overloads.length) {75 return 0;76 }77 return overloads.map(function(attr) {78 return attr.arguments ? attr.arguments.filter(function(arg) {79 return !arg.optional && !arg.variadic;80 }).length : 0;81 })82 .reduce(function(m, n) { return Math.min(m, n); });83}84//@}85function throwOrReject(a_test, operation, fn, obj, args, message, cb)86//@{87{88 if (operation.idlType.generic !== "Promise") {89 assert_throws(new TypeError(), function() {90 fn.apply(obj, args);91 }, message);92 cb();93 } else {94 try {95 promise_rejects(a_test, new TypeError(), fn.apply(obj, args), message).then(cb, cb);96 } catch (e){97 a_test.step(function() {98 assert_unreached("Throws \"" + e + "\" instead of rejecting promise");99 cb();100 });101 }102 }103}104//@}105function awaitNCallbacks(n, cb, ctx)106//@{107{108 var counter = 0;109 return function() {110 counter++;111 if (counter >= n) {112 cb();113 }114 };115}116//@}117var fround =118//@{119(function(){120 if (Math.fround) return Math.fround;121 var arr = new Float32Array(1);122 return function fround(n) {123 arr[0] = n;124 return arr[0];125 };126})();127//@}128/// IdlHarnessError ///129// Entry point130self.IdlHarnessError = function(message)131//@{132{133 /**134 * Message to be printed as the error's toString invocation.135 */136 this.message = message;137};138IdlHarnessError.prototype = Object.create(Error.prototype);139//@}140IdlHarnessError.prototype.toString = function()141//@{142{143 return this.message;144};145//@}146/// IdlArray ///147// Entry point148self.IdlArray = function()149//@{150{151 /**152 * A map from strings to the corresponding named IdlObject, such as153 * IdlInterface or IdlException. These are the things that test() will run154 * tests on.155 */156 this.members = {};157 /**158 * A map from strings to arrays of strings. The keys are interface or159 * exception names, and are expected to also exist as keys in this.members160 * (otherwise they'll be ignored). This is populated by add_objects() --161 * see documentation at the start of the file. The actual tests will be162 * run by calling this.members[name].test_object(obj) for each obj in163 * this.objects[name]. obj is a string that will be eval'd to produce a164 * JavaScript value, which is supposed to be an object implementing the165 * given IdlObject (interface, exception, etc.).166 */167 this.objects = {};168 /**169 * When adding multiple collections of IDLs one at a time, an earlier one170 * might contain a partial interface or implements statement that depends171 * on a later one. Save these up and handle them right before we run172 * tests.173 *174 * .partials is simply an array of objects from WebIDLParser.js'175 * "partialinterface" production. .implements maps strings to arrays of176 * strings, such that177 *178 * A implements B;179 * A implements C;180 * D implements E;181 *182 * results in this["implements"] = { A: ["B", "C"], D: ["E"] }.183 *184 * Similarly,185 *186 * interface A : B {};187 * interface B : C {};188 *189 * results in this["inheritance"] = { A: "B", B: "C" }190 */191 this.partials = [];192 this["implements"] = {};193 this["includes"] = {};194 this["inheritance"] = {};195};196//@}197IdlArray.prototype.add_idls = function(raw_idls, options)198//@{199{200 /** Entry point. See documentation at beginning of file. */201 this.internal_add_idls(WebIDL2.parse(raw_idls), options);202};203//@}204IdlArray.prototype.add_untested_idls = function(raw_idls, options)205//@{206{207 /** Entry point. See documentation at beginning of file. */208 var parsed_idls = WebIDL2.parse(raw_idls);209 this.mark_as_untested(parsed_idls);210 this.internal_add_idls(parsed_idls, options);211};212//@}213IdlArray.prototype.mark_as_untested = function (parsed_idls)214//@{215{216 for (var i = 0; i < parsed_idls.length; i++) {217 parsed_idls[i].untested = true;218 if ("members" in parsed_idls[i]) {219 for (var j = 0; j < parsed_idls[i].members.length; j++) {220 parsed_idls[i].members[j].untested = true;221 }222 }223 }224};225//@}226//@}227IdlArray.prototype.is_excluded_by_options = function (name, options)228//@{229{230 return options &&231 (options.except && options.except.includes(name)232 || options.only && !options.only.includes(name));233};234//@}235//@}236IdlArray.prototype.add_dependency_idls = function(raw_idls, options)237//@{238{239 const parsed_idls = WebIDL2.parse(raw_idls);240 const new_options = { only: [] }241 const all_deps = new Set();242 Object.values(this.inheritance).forEach(v => all_deps.add(v));243 Object.entries(this.implements).forEach(([k, v]) => {244 all_deps.add(k);245 all_deps.add(v);246 });247 // NOTE: If 'A includes B' for B that we care about, then A is also a dep.248 Object.keys(this.includes).forEach(k => {249 all_deps.add(k);250 this.includes[k].forEach(v => all_deps.add(v));251 });252 this.partials.map(p => p.name).forEach(v => all_deps.add(v));253 // Add the attribute idlTypes of all the nested members of all tested idls.254 for (const obj of [this.members, this.partials]) {255 const tested = Object.values(obj).filter(m => !m.untested && m.members);256 for (const parsed of tested) {257 for (const attr of Object.values(parsed.members).filter(m => !m.untested && m.type === 'attribute')) {258 all_deps.add(attr.idlType.idlType);259 }260 }261 }262 if (options && options.except && options.only) {263 throw new IdlHarnessError("The only and except options can't be used together.");264 }265 const should_skip = name => {266 // NOTE: Deps are untested, so we're lenient, and skip re-encountered definitions.267 // e.g. for 'idl' containing A:B, B:C, C:D268 // array.add_idls(idl, {only: ['A','B']}).269 // array.add_dependency_idls(idl);270 // B would be encountered as tested, and encountered as a dep, so we ignore.271 return name in this.members272 || this.is_excluded_by_options(name, options);273 }274 // Record of skipped items, in case we later determine they are a dependency.275 // Maps name -> [parsed_idl, ...]276 const skipped = new Map();277 const process = function(parsed) {278 var deps = [];279 if (parsed.name) {280 deps.push(parsed.name);281 } else if (parsed.type === "implements") {282 deps.push(parsed.target);283 deps.push(parsed.implements);284 } else if (parsed.type === "includes") {285 deps.push(parsed.target);286 deps.push(parsed.includes);287 }288 deps = deps.filter(function(name) {289 if (!name || should_skip(name) || !all_deps.has(name)) {290 // Flag as skipped, if it's not already processed, so we can291 // come back to it later if we retrospectively call it a dep.292 if (name && !(name in this.members)) {293 skipped.has(name)294 ? skipped.get(name).push(parsed)295 : skipped.set(name, [parsed]);296 }297 return false;298 }299 return true;300 }.bind(this));301 deps.forEach(function(name) {302 new_options.only.push(name);303 const follow_up = new Set();304 for (const dep_type of ["inheritance", "implements", "includes"]) {305 if (parsed[dep_type]) {306 const inheriting = parsed[dep_type];307 const inheritor = parsed.name || parsed.target;308 for (const dep of [inheriting, inheritor]) {309 new_options.only.push(dep);310 all_deps.add(dep);311 follow_up.add(dep);312 }313 }314 }315 for (const deferred of follow_up) {316 if (skipped.has(deferred)) {317 const next = skipped.get(deferred);318 skipped.delete(deferred);319 next.forEach(process);320 }321 }322 });323 }.bind(this);324 for (let parsed of parsed_idls) {325 process(parsed);326 }327 this.mark_as_untested(parsed_idls);328 if (new_options.only.length) {329 this.internal_add_idls(parsed_idls, new_options);330 }331}332//@}333IdlArray.prototype.internal_add_idls = function(parsed_idls, options)334//@{335{336 /**337 * Internal helper called by add_idls() and add_untested_idls().338 *339 * parsed_idls is an array of objects that come from WebIDLParser.js's340 * "definitions" production. The add_untested_idls() entry point341 * additionally sets an .untested property on each object (and its342 * .members) so that they'll be skipped by test() -- they'll only be343 * used for base interfaces of tested interfaces, return types, etc.344 *345 * options is a dictionary that can have an only or except member which are346 * arrays. If only is given then only members, partials and interface347 * targets listed will be added, and if except is given only those that348 * aren't listed will be added. Only one of only and except can be used.349 */350 if (options && options.only && options.except)351 {352 throw new IdlHarnessError("The only and except options can't be used together.");353 }354 var should_skip = name => {355 return this.is_excluded_by_options(name, options);356 }357 parsed_idls.forEach(function(parsed_idl)358 {359 var partial_types = [360 "interface",361 "interface mixin",362 "dictionary",363 "namespace",364 ];365 if (parsed_idl.partial && partial_types.includes(parsed_idl.type))366 {367 if (should_skip(parsed_idl.name))368 {369 return;370 }371 this.partials.push(parsed_idl);372 return;373 }374 if (parsed_idl.type == "implements")375 {376 if (should_skip(parsed_idl.target))377 {378 return;379 }380 if (!(parsed_idl.target in this["implements"]))381 {382 this["implements"][parsed_idl.target] = [];383 }384 this["implements"][parsed_idl.target].push(parsed_idl["implements"]);385 return;386 }387 if (parsed_idl.type == "includes")388 {389 if (should_skip(parsed_idl.target))390 {391 return;392 }393 if (!(parsed_idl.target in this["includes"]))394 {395 this["includes"][parsed_idl.target] = [];396 }397 this["includes"][parsed_idl.target].push(parsed_idl["includes"]);398 return;399 }400 parsed_idl.array = this;401 if (should_skip(parsed_idl.name))402 {403 return;404 }405 if (parsed_idl.name in this.members)406 {407 throw new IdlHarnessError("Duplicate identifier " + parsed_idl.name);408 }409 if (parsed_idl["inheritance"]) {410 // NOTE: Clash should be impossible (would require redefinition of parsed_idl.name).411 if (parsed_idl.name in this["inheritance"]412 && parsed_idl["inheritance"] != this["inheritance"][parsed_idl.name]) {413 throw new IdlHarnessError(414 `Inheritance for ${parsed_idl.name} was already defined`);415 }416 this["inheritance"][parsed_idl.name] = parsed_idl["inheritance"];417 }418 switch(parsed_idl.type)419 {420 case "interface":421 this.members[parsed_idl.name] =422 new IdlInterface(parsed_idl, /* is_callback = */ false, /* is_mixin = */ false);423 break;424 case "interface mixin":425 this.members[parsed_idl.name] =426 new IdlInterface(parsed_idl, /* is_callback = */ false, /* is_mixin = */ true);427 break;428 case "dictionary":429 // Nothing to test, but we need the dictionary info around for type430 // checks431 this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);432 break;433 case "typedef":434 this.members[parsed_idl.name] = new IdlTypedef(parsed_idl);435 break;436 case "callback":437 // TODO438 console.log("callback not yet supported");439 break;440 case "enum":441 this.members[parsed_idl.name] = new IdlEnum(parsed_idl);442 break;443 case "callback interface":444 this.members[parsed_idl.name] =445 new IdlInterface(parsed_idl, /* is_callback = */ true, /* is_mixin = */ false);446 break;447 case "namespace":448 this.members[parsed_idl.name] = new IdlNamespace(parsed_idl);449 break;450 default:451 throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported";452 }453 }.bind(this));454};455//@}456IdlArray.prototype.add_objects = function(dict)457//@{458{459 /** Entry point. See documentation at beginning of file. */460 for (var k in dict)461 {462 if (k in this.objects)463 {464 this.objects[k] = this.objects[k].concat(dict[k]);465 }466 else467 {468 this.objects[k] = dict[k];469 }470 }471};472//@}473IdlArray.prototype.prevent_multiple_testing = function(name)474//@{475{476 /** Entry point. See documentation at beginning of file. */477 this.members[name].prevent_multiple_testing = true;478};479//@}480IdlArray.prototype.recursively_get_implements = function(interface_name)481//@{482{483 /**484 * Helper function for test(). Returns an array of things that implement485 * interface_name, so if the IDL contains486 *487 * A implements B;488 * B implements C;489 * B implements D;490 *491 * then recursively_get_implements("A") should return ["B", "C", "D"].492 */493 var ret = this["implements"][interface_name];494 if (ret === undefined)495 {496 return [];497 }498 for (var i = 0; i < this["implements"][interface_name].length; i++)499 {500 ret = ret.concat(this.recursively_get_implements(ret[i]));501 if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i]))502 {503 throw new IdlHarnessError("Circular implements statements involving " + ret[i]);504 }505 }506 return ret;507};508//@}509IdlArray.prototype.recursively_get_includes = function(interface_name)510//@{511{512 /**513 * Helper function for test(). Returns an array of things that implement514 * interface_name, so if the IDL contains515 *516 * A includes B;517 * B includes C;518 * B includes D;519 *520 * then recursively_get_includes("A") should return ["B", "C", "D"].521 */522 var ret = this["includes"][interface_name];523 if (ret === undefined)524 {525 return [];526 }527 for (var i = 0; i < this["includes"][interface_name].length; i++)528 {529 ret = ret.concat(this.recursively_get_includes(ret[i]));530 if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i]))531 {532 throw new IdlHarnessError("Circular includes statements involving " + ret[i]);533 }534 }535 return ret;536};537//@}538IdlArray.prototype.is_json_type = function(type)539//@{540{541 /**542 * Checks whether type is a JSON type as per543 * https://heycam.github.io/webidl/#dfn-json-types544 */545 var idlType = type.idlType;546 if (type.generic == "Promise") { return false; }547 // nullable and annotated types don't need to be handled separately,548 // as webidl2 doesn't represent them wrapped-up (as they're described549 // in WebIDL).550 // union and record types551 if (type.union || type.generic == "record") {552 return idlType.every(this.is_json_type, this);553 }554 // sequence types555 if (type.generic == "sequence" || type.generic == "FrozenArray") {556 return this.is_json_type(idlType);557 }558 if (typeof idlType != "string") { throw new Error("Unexpected type " + JSON.stringify(idlType)); }559 switch (idlType)560 {561 // Numeric types562 case "byte":563 case "octet":564 case "short":565 case "unsigned short":566 case "long":567 case "unsigned long":568 case "long long":569 case "unsigned long long":570 case "float":571 case "double":572 case "unrestricted float":573 case "unrestricted double":574 // boolean575 case "boolean":576 // string types577 case "DOMString":578 case "ByteString":579 case "USVString":580 // object type581 case "object":582 return true;583 case "Error":584 case "DOMException":585 case "Int8Array":586 case "Int16Array":587 case "Int32Array":588 case "Uint8Array":589 case "Uint16Array":590 case "Uint32Array":591 case "Uint8ClampedArray":592 case "Float32Array":593 case "ArrayBuffer":594 case "DataView":595 case "any":596 return false;597 default:598 var thing = this.members[idlType];599 if (!thing) { throw new Error("Type " + idlType + " not found"); }600 if (thing instanceof IdlEnum) { return true; }601 if (thing instanceof IdlTypedef) {602 return this.is_json_type(thing.idlType);603 }604 // dictionaries where all of their members are JSON types605 if (thing instanceof IdlDictionary) {606 var stack = thing.get_inheritance_stack();607 var map = new Map();608 while (stack.length)609 {610 stack.pop().members.forEach(function(m) {611 map.set(m.name, m.idlType)612 });613 }614 return Array.from(map.values()).every(this.is_json_type, this);615 }616 // interface types that have a toJSON operation declared on themselves or617 // one of their inherited or consequential interfaces.618 if (thing instanceof IdlInterface) {619 var base;620 while (thing)621 {622 if (thing.has_to_json_regular_operation()) { return true; }623 var mixins = this.implements[thing.name] || this.includes[thing.name];624 if (mixins) {625 mixins = mixins.map(function(id) {626 var mixin = this.members[id];627 if (!mixin) {628 throw new Error("Interface " + id + " not found (implemented by " + thing.name + ")");629 }630 return mixin;631 }, this);632 if (mixins.some(function(m) { return m.has_to_json_regular_operation() } )) { return true; }633 }634 if (!thing.base) { return false; }635 base = this.members[thing.base];636 if (!base) {637 throw new Error("Interface " + thing.base + " not found (inherited by " + thing.name + ")");638 }639 thing = base;640 }641 return false;642 }643 return false;644 }645};646function exposure_set(object, default_set) {647 var exposed = object.extAttrs && object.extAttrs.filter(a => a.name === "Exposed");648 if (exposed && exposed.length > 1) {649 throw new IdlHarnessError(650 `Multiple 'Exposed' extended attributes on ${object.name}`);651 }652 let result = default_set || ["Window"];653 if (result && !(result instanceof Set)) {654 result = new Set(result);655 }656 if (exposed && exposed.length) {657 var set = exposed[0].rhs.value;658 // Could be a list or a string.659 if (typeof set == "string") {660 set = [ set ];661 }662 result = new Set(set);663 }664 if (result && result.has("Worker")) {665 result.delete("Worker");666 result.add("DedicatedWorker");667 result.add("ServiceWorker");668 result.add("SharedWorker");669 }670 return result;671}672function exposed_in(globals) {673 if ('document' in self) {674 return globals.has("Window");675 }676 if ('DedicatedWorkerGlobalScope' in self &&677 self instanceof DedicatedWorkerGlobalScope) {678 return globals.has("DedicatedWorker");679 }680 if ('SharedWorkerGlobalScope' in self &&681 self instanceof SharedWorkerGlobalScope) {682 return globals.has("SharedWorker");683 }684 if ('ServiceWorkerGlobalScope' in self &&685 self instanceof ServiceWorkerGlobalScope) {686 return globals.has("ServiceWorker");687 }688 throw new IdlHarnessError("Unexpected global object");689}690//@}691/**692 * Asserts that the given error message is thrown for the given function.693 * @param {string|IdlHarnessError} error Expected Error message.694 * @param {Function} idlArrayFunc Function operating on an IdlArray that should throw.695 */696IdlArray.prototype.assert_throws = function(error, idlArrayFunc)697//@{698{699 try {700 idlArrayFunc.call(this, this);701 } catch (e) {702 if (e instanceof AssertionError) {703 throw e;704 }705 // Assertions for behaviour of the idlharness.js engine.706 if (error instanceof IdlHarnessError) {707 error = error.message;708 }709 if (e.message !== error) {710 throw new IdlHarnessError(`${idlArrayFunc} threw "${e}", not the expected IdlHarnessError "${error}"`);711 }712 return;713 }714 throw new IdlHarnessError(`${idlArrayFunc} did not throw the expected IdlHarnessError`);715}716//@}717IdlArray.prototype.test = function()718//@{719{720 /** Entry point. See documentation at beginning of file. */721 // First merge in all the partial interfaces and implements statements we722 // encountered.723 this.collapse_partials();724 for (var lhs in this["implements"])725 {726 this.recursively_get_implements(lhs).forEach(function(rhs)727 {728 var errStr = lhs + " implements " + rhs + ", but ";729 if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";730 if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface.";731 if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";732 if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";733 this.members[rhs].members.forEach(function(member)734 {735 this.members[lhs].members.push(new IdlInterfaceMember(member));736 }.bind(this));737 }.bind(this));738 }739 this["implements"] = {};740 for (var lhs in this["includes"])741 {742 this.recursively_get_includes(lhs).forEach(function(rhs)743 {744 var errStr = lhs + " includes " + rhs + ", but ";745 if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";746 if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface.";747 if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";748 if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";749 this.members[rhs].members.forEach(function(member)750 {751 this.members[lhs].members.push(new IdlInterfaceMember(member));752 }.bind(this));753 }.bind(this));754 }755 this["includes"] = {};756 // Assert B defined for A : B757 for (const member of Object.values(this.members).filter(m => m.base)) {758 const lhs = member.name;759 const rhs = member.base;760 if (!(rhs in this.members)) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is undefined.`);761 const lhs_is_interface = this.members[lhs] instanceof IdlInterface;762 const rhs_is_interface = this.members[rhs] instanceof IdlInterface;763 if (rhs_is_interface != lhs_is_interface) {764 if (!lhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${lhs} is not an interface.`);765 if (!rhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is not an interface.`);766 }767 // Check for circular dependencies.768 member.get_inheritance_stack();769 }770 Object.getOwnPropertyNames(this.members).forEach(function(memberName) {771 var member = this.members[memberName];772 if (!(member instanceof IdlInterface)) {773 return;774 }775 var globals = exposure_set(member);776 member.exposed = exposed_in(globals);777 member.exposureSet = globals;778 }.bind(this));779 // Now run test() on every member, and test_object() for every object.780 for (var name in this.members)781 {782 this.members[name].test();783 if (name in this.objects)784 {785 const objects = this.objects[name];786 if (!objects || !Array.isArray(objects)) {787 throw new IdlHarnessError(`Invalid or empty objects for member ${name}`);788 }789 objects.forEach(function(str)790 {791 if (!this.members[name] || !(this.members[name] instanceof IdlInterface)) {792 throw new IdlHarnessError(`Invalid object member name ${name}`);793 }794 this.members[name].test_object(str);795 }.bind(this));796 }797 }798};799//@}800IdlArray.prototype.collapse_partials = function()801//@{802{803 const testedPartials = new Map();804 this.partials.forEach(function(parsed_idl)805 {806 const originalExists = parsed_idl.name in this.members807 && (this.members[parsed_idl.name] instanceof IdlInterface808 || this.members[parsed_idl.name] instanceof IdlDictionary809 || this.members[parsed_idl.name] instanceof IdlNamespace);810 let partialTestName = parsed_idl.name;811 if (!parsed_idl.untested) {812 // Ensure unique test name in case of multiple partials.813 let partialTestCount = 1;814 if (testedPartials.has(parsed_idl.name)) {815 partialTestCount += testedPartials.get(parsed_idl.name);816 partialTestName = `${partialTestName}[${partialTestCount}]`;817 }818 testedPartials.set(parsed_idl.name, partialTestCount);819 test(function () {820 assert_true(originalExists, `Original ${parsed_idl.type} should be defined`);821 var expected = IdlInterface;822 switch (parsed_idl.type) {823 case 'interface': expected = IdlInterface; break;824 case 'dictionary': expected = IdlDictionary; break;825 case 'namespace': expected = IdlNamespace; break;826 }827 assert_true(828 expected.prototype.isPrototypeOf(this.members[parsed_idl.name]),829 `Original ${parsed_idl.name} definition should have type ${parsed_idl.type}`);830 }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: original ${parsed_idl.type} defined`);831 }832 if (!originalExists) {833 // Not good.. but keep calm and carry on.834 return;835 }836 if (parsed_idl.extAttrs)837 {838 // Special-case "Exposed". Must be a subset of original interface's exposure.839 // Exposed on a partial is the equivalent of having the same Exposed on all nested members.840 // See https://github.com/heycam/webidl/issues/154 for discrepency between Exposed and841 // other extended attributes on partial interfaces.842 const exposureAttr = parsed_idl.extAttrs.find(a => a.name === "Exposed");843 if (exposureAttr) {844 if (!parsed_idl.untested) {845 test(function () {846 const partialExposure = exposure_set(parsed_idl);847 const memberExposure = exposure_set(this.members[parsed_idl.name]);848 partialExposure.forEach(name => {849 if (!memberExposure || !memberExposure.has(name)) {850 throw new IdlHarnessError(851 `Partial ${parsed_idl.name} ${parsed_idl.type} is exposed to '${name}', the original ${parsed_idl.type} is not.`);852 }853 });854 }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: valid exposure set`);855 }856 parsed_idl.members.forEach(function (member) {857 member.extAttrs.push(exposureAttr);858 }.bind(this));859 }860 parsed_idl.extAttrs.forEach(function(extAttr)861 {862 // "Exposed" already handled above.863 if (extAttr.name === "Exposed") {864 return;865 }866 this.members[parsed_idl.name].extAttrs.push(extAttr);867 }.bind(this));868 }869 parsed_idl.members.forEach(function(member)870 {871 this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member));872 }.bind(this));873 }.bind(this));874 this.partials = [];875}876//@}877IdlArray.prototype.assert_type_is = function(value, type)878//@{879{880 if (type.idlType in this.members881 && this.members[type.idlType] instanceof IdlTypedef) {882 this.assert_type_is(value, this.members[type.idlType].idlType);883 return;884 }885 if (type.union) {886 for (var i = 0; i < type.idlType.length; i++) {887 try {888 this.assert_type_is(value, type.idlType[i]);889 // No AssertionError, so we match one type in the union890 return;891 } catch(e) {892 if (e instanceof AssertionError) {893 // We didn't match this type, let's try some others894 continue;895 }896 throw e;897 }898 }899 // TODO: Is there a nice way to list the union's types in the message?900 assert_true(false, "Attribute has value " + format_value(value)901 + " which doesn't match any of the types in the union");902 }903 /**904 * Helper function that tests that value is an instance of type according905 * to the rules of WebIDL. value is any JavaScript value, and type is an906 * object produced by WebIDLParser.js' "type" production. That production907 * is fairly elaborate due to the complexity of WebIDL's types, so it's908 * best to look at the grammar to figure out what properties it might have.909 */910 if (type.idlType == "any")911 {912 // No assertions to make913 return;914 }915 if (type.nullable && value === null)916 {917 // This is fine918 return;919 }920 if (type.array)921 {922 // TODO: not supported yet923 return;924 }925 if (type.generic === "sequence")926 {927 assert_true(Array.isArray(value), "should be an Array");928 if (!value.length)929 {930 // Nothing we can do.931 return;932 }933 this.assert_type_is(value[0], type.idlType);934 return;935 }936 if (type.generic === "Promise") {937 assert_true("then" in value, "Attribute with a Promise type should have a then property");938 // TODO: Ideally, we would check on project fulfillment939 // that we get the right type940 // but that would require making the type check async941 return;942 }943 if (type.generic === "FrozenArray") {944 assert_true(Array.isArray(value), "Value should be array");945 assert_true(Object.isFrozen(value), "Value should be frozen");946 if (!value.length)947 {948 // Nothing we can do.949 return;950 }951 this.assert_type_is(value[0], type.idlType);952 return;953 }954 type = type.idlType;955 switch(type)956 {957 case "void":958 assert_equals(value, undefined);959 return;960 case "boolean":961 assert_equals(typeof value, "boolean");962 return;963 case "byte":964 assert_equals(typeof value, "number");965 assert_equals(value, Math.floor(value), "should be an integer");966 assert_true(-128 <= value && value <= 127, "byte " + value + " should be in range [-128, 127]");967 return;968 case "octet":969 assert_equals(typeof value, "number");970 assert_equals(value, Math.floor(value), "should be an integer");971 assert_true(0 <= value && value <= 255, "octet " + value + " should be in range [0, 255]");972 return;973 case "short":974 assert_equals(typeof value, "number");975 assert_equals(value, Math.floor(value), "should be an integer");976 assert_true(-32768 <= value && value <= 32767, "short " + value + " should be in range [-32768, 32767]");977 return;978 case "unsigned short":979 assert_equals(typeof value, "number");980 assert_equals(value, Math.floor(value), "should be an integer");981 assert_true(0 <= value && value <= 65535, "unsigned short " + value + " should be in range [0, 65535]");982 return;983 case "long":984 assert_equals(typeof value, "number");985 assert_equals(value, Math.floor(value), "should be an integer");986 assert_true(-2147483648 <= value && value <= 2147483647, "long " + value + " should be in range [-2147483648, 2147483647]");987 return;988 case "unsigned long":989 assert_equals(typeof value, "number");990 assert_equals(value, Math.floor(value), "should be an integer");991 assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " should be in range [0, 4294967295]");992 return;993 case "long long":994 assert_equals(typeof value, "number");995 return;996 case "unsigned long long":997 case "DOMTimeStamp":998 assert_equals(typeof value, "number");999 assert_true(0 <= value, "unsigned long long should be positive");1000 return;1001 case "float":1002 assert_equals(typeof value, "number");1003 assert_equals(value, fround(value), "float rounded to 32-bit float should be itself");1004 assert_not_equals(value, Infinity);1005 assert_not_equals(value, -Infinity);1006 assert_not_equals(value, NaN);1007 return;1008 case "DOMHighResTimeStamp":1009 case "double":1010 assert_equals(typeof value, "number");1011 assert_not_equals(value, Infinity);1012 assert_not_equals(value, -Infinity);1013 assert_not_equals(value, NaN);1014 return;1015 case "unrestricted float":1016 assert_equals(typeof value, "number");1017 assert_equals(value, fround(value), "unrestricted float rounded to 32-bit float should be itself");1018 return;1019 case "unrestricted double":1020 assert_equals(typeof value, "number");1021 return;1022 case "DOMString":1023 assert_equals(typeof value, "string");1024 return;1025 case "ByteString":1026 assert_equals(typeof value, "string");1027 assert_regexp_match(value, /^[\x00-\x7F]*$/);1028 return;1029 case "USVString":1030 assert_equals(typeof value, "string");1031 assert_regexp_match(value, /^([\x00-\ud7ff\ue000-\uffff]|[\ud800-\udbff][\udc00-\udfff])*$/);1032 return;1033 case "object":1034 assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function");1035 return;1036 }1037 if (!(type in this.members))1038 {1039 throw new IdlHarnessError("Unrecognized type " + type);1040 }1041 if (this.members[type] instanceof IdlInterface)1042 {1043 // We don't want to run the full1044 // IdlInterface.prototype.test_instance_of, because that could result1045 // in an infinite loop. TODO: This means we don't have tests for1046 // NoInterfaceObject interfaces, and we also can't test objects that1047 // come from another self.1048 assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function");1049 if (value instanceof Object1050 && !this.members[type].has_extended_attribute("NoInterfaceObject")1051 && type in self)1052 {1053 assert_true(value instanceof self[type], "instanceof " + type);1054 }1055 }1056 else if (this.members[type] instanceof IdlEnum)1057 {1058 assert_equals(typeof value, "string");1059 }1060 else if (this.members[type] instanceof IdlDictionary)1061 {1062 // TODO: Test when we actually have something to test this on1063 }1064 else1065 {1066 throw new IdlHarnessError("Type " + type + " isn't an interface or dictionary");1067 }1068};1069//@}1070/// IdlObject ///1071function IdlObject() {}1072IdlObject.prototype.test = function()1073//@{1074{1075 /**1076 * By default, this does nothing, so no actual tests are run for IdlObjects1077 * that don't define any (e.g., IdlDictionary at the time of this writing).1078 */1079};1080//@}1081IdlObject.prototype.has_extended_attribute = function(name)1082//@{1083{1084 /**1085 * This is only meaningful for things that support extended attributes,1086 * such as interfaces, exceptions, and members.1087 */1088 return this.extAttrs.some(function(o)1089 {1090 return o.name == name;1091 });1092};1093//@}1094/// IdlDictionary ///1095// Used for IdlArray.prototype.assert_type_is1096function IdlDictionary(obj)1097//@{1098{1099 /**1100 * obj is an object produced by the WebIDLParser.js "dictionary"1101 * production.1102 */1103 /** Self-explanatory. */1104 this.name = obj.name;1105 /** A back-reference to our IdlArray. */1106 this.array = obj.array;1107 /** An array of objects produced by the "dictionaryMember" production. */1108 this.members = obj.members;1109 /**1110 * The name (as a string) of the dictionary type we inherit from, or null1111 * if there is none.1112 */1113 this.base = obj.inheritance;1114}1115//@}1116IdlDictionary.prototype = Object.create(IdlObject.prototype);1117IdlDictionary.prototype.get_inheritance_stack = function() {1118 return IdlInterface.prototype.get_inheritance_stack.call(this);1119};1120/// IdlInterface ///1121function IdlInterface(obj, is_callback, is_mixin)1122//@{1123{1124 /**1125 * obj is an object produced by the WebIDLParser.js "interface" production.1126 */1127 /** Self-explanatory. */1128 this.name = obj.name;1129 /** A back-reference to our IdlArray. */1130 this.array = obj.array;1131 /**1132 * An indicator of whether we should run tests on the interface object and1133 * interface prototype object. Tests on members are controlled by .untested1134 * on each member, not this.1135 */1136 this.untested = obj.untested;1137 /** An array of objects produced by the "ExtAttr" production. */1138 this.extAttrs = obj.extAttrs;1139 /** An array of IdlInterfaceMembers. */1140 this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); });1141 if (this.has_extended_attribute("Unforgeable")) {1142 this.members1143 .filter(function(m) { return !m["static"] && (m.type == "attribute" || m.type == "operation"); })1144 .forEach(function(m) { return m.isUnforgeable = true; });1145 }1146 /**1147 * The name (as a string) of the type we inherit from, or null if there is1148 * none.1149 */1150 this.base = obj.inheritance;1151 this._is_callback = is_callback;1152 this._is_mixin = is_mixin;1153}1154//@}1155IdlInterface.prototype = Object.create(IdlObject.prototype);1156IdlInterface.prototype.is_callback = function()1157//@{1158{1159 return this._is_callback;1160};1161//@}1162IdlInterface.prototype.is_mixin = function()1163//@{1164{1165 return this._is_mixin;1166};1167//@}1168IdlInterface.prototype.has_constants = function()1169//@{1170{1171 return this.members.some(function(member) {1172 return member.type === "const";1173 });1174};1175//@}1176IdlInterface.prototype.get_unscopables = function()1177{1178 return this.members.filter(function(member) {1179 return member.isUnscopable;1180 });1181};1182IdlInterface.prototype.is_global = function()1183//@{1184{1185 return this.extAttrs.some(function(attribute) {1186 return attribute.name === "Global";1187 });1188};1189//@}1190IdlInterface.prototype.has_to_json_regular_operation = function() {1191 return this.members.some(function(m) {1192 return m.is_to_json_regular_operation();1193 });1194};1195IdlInterface.prototype.has_default_to_json_regular_operation = function() {1196 return this.members.some(function(m) {1197 return m.is_to_json_regular_operation() && m.has_extended_attribute("Default");1198 });1199};1200IdlInterface.prototype.get_inheritance_stack = function() {1201 /**1202 * See https://heycam.github.io/webidl/#create-an-inheritance-stack1203 *1204 * Returns an array of IdlInterface objects which contains itself1205 * and all of its inherited interfaces.1206 *1207 * So given:1208 *1209 * A : B {};1210 * B : C {};1211 * C {};1212 *1213 * then A.get_inheritance_stack() should return [A, B, C],1214 * and B.get_inheritance_stack() should return [B, C].1215 *1216 * Note: as dictionary inheritance is expressed identically by the AST,1217 * this works just as well for getting a stack of inherited dictionaries.1218 */1219 var stack = [this];1220 var idl_interface = this;1221 while (idl_interface.base) {1222 var base = this.array.members[idl_interface.base];1223 if (!base) {1224 throw new Error(idl_interface.type + " " + idl_interface.base + " not found (inherited by " + idl_interface.name + ")");1225 } else if (stack.indexOf(base) > -1) {1226 stack.push(base);1227 let dep_chain = stack.map(i => i.name).join(',');1228 throw new IdlHarnessError(`${this.name} has a circular dependency: ${dep_chain}`);1229 }1230 idl_interface = base;1231 stack.push(idl_interface);1232 }1233 return stack;1234};1235/**1236 * Implementation of1237 * https://heycam.github.io/webidl/#default-tojson-operation1238 * for testing purposes.1239 *1240 * Collects the IDL types of the attributes that meet the criteria1241 * for inclusion in the default toJSON operation for easy1242 * comparison with actual value1243 */1244IdlInterface.prototype.default_to_json_operation = function(callback) {1245 var map = new Map(), isDefault = false;1246 this.traverse_inherited_and_consequential_interfaces(function(I) {1247 if (I.has_default_to_json_regular_operation()) {1248 isDefault = true;1249 I.members.forEach(function(m) {1250 if (!m.static && m.type == "attribute" && I.array.is_json_type(m.idlType)) {1251 map.set(m.name, m.idlType);1252 }1253 });1254 } else if (I.has_to_json_regular_operation()) {1255 isDefault = false;1256 }1257 });1258 return isDefault ? map : null;1259};1260/**1261 * Traverses inherited interfaces from the top down1262 * and imeplemented interfaces inside out.1263 * Invokes |callback| on each interface.1264 *1265 * This is an abstract implementation of the traversal1266 * algorithm specified in:1267 * https://heycam.github.io/webidl/#collect-attribute-values1268 * Given the following inheritance tree:1269 *1270 * F1271 * |1272 * C E - I1273 * | |1274 * B - D1275 * |1276 * G - A - H - J1277 *1278 * Invoking traverse_inherited_and_consequential_interfaces() on A1279 * would traverse the tree in the following order:1280 * C -> B -> F -> E -> I -> D -> A -> G -> H -> J1281 */1282IdlInterface.prototype.traverse_inherited_and_consequential_interfaces = function(callback) {1283 if (typeof callback != "function") {1284 throw new TypeError();1285 }1286 var stack = this.get_inheritance_stack();1287 _traverse_inherited_and_consequential_interfaces(stack, callback);1288};1289function _traverse_inherited_and_consequential_interfaces(stack, callback) {1290 var I = stack.pop();1291 callback(I);1292 var mixins = I.array["implements"][I.name] || I.array["includes"][I.name];1293 if (mixins) {1294 mixins.forEach(function(id) {1295 var mixin = I.array.members[id];1296 if (!mixin) {1297 throw new Error("Interface " + id + " not found (implemented by " + I.name + ")");1298 }1299 var interfaces = mixin.get_inheritance_stack();1300 _traverse_inherited_and_consequential_interfaces(interfaces, callback);1301 });1302 }1303 if (stack.length > 0) {1304 _traverse_inherited_and_consequential_interfaces(stack, callback);1305 }1306}1307IdlInterface.prototype.test = function()1308//@{1309{1310 if (this.has_extended_attribute("NoInterfaceObject") || this.is_mixin())1311 {1312 // No tests to do without an instance. TODO: We should still be able1313 // to run tests on the prototype object, if we obtain one through some1314 // other means.1315 return;1316 }1317 if (!this.exposed) {1318 subsetTestByKey(this.name, test, function() {1319 assert_false(this.name in self);1320 }.bind(this), this.name + " interface: existence and properties of interface object");1321 return;1322 }1323 if (!this.untested)1324 {1325 // First test things to do with the exception/interface object and1326 // exception/interface prototype object.1327 this.test_self();1328 }1329 // Then test things to do with its members (constants, fields, attributes,1330 // operations, . . .). These are run even if .untested is true, because1331 // members might themselves be marked as .untested. This might happen to1332 // interfaces if the interface itself is untested but a partial interface1333 // that extends it is tested -- then the interface itself and its initial1334 // members will be marked as untested, but the members added by the partial1335 // interface are still tested.1336 this.test_members();1337};1338//@}1339IdlInterface.prototype.test_self = function()1340//@{1341{1342 subsetTestByKey(this.name, test, function()1343 {1344 // This function tests WebIDL as of 2015-01-13.1345 // "For every interface that is exposed in a given ECMAScript global1346 // environment and:1347 // * is a callback interface that has constants declared on it, or1348 // * is a non-callback interface that is not declared with the1349 // [NoInterfaceObject] extended attribute,1350 // a corresponding property MUST exist on the ECMAScript global object.1351 // The name of the property is the identifier of the interface, and its1352 // value is an object called the interface object.1353 // The property has the attributes { [[Writable]]: true,1354 // [[Enumerable]]: false, [[Configurable]]: true }."1355 if (this.is_callback() && !this.has_constants()) {1356 return;1357 }1358 // TODO: Should we test here that the property is actually writable1359 // etc., or trust getOwnPropertyDescriptor?1360 assert_own_property(self, this.name,1361 "self does not have own property " + format_value(this.name));1362 var desc = Object.getOwnPropertyDescriptor(self, this.name);1363 assert_false("get" in desc, "self's property " + format_value(this.name) + " should not have a getter");1364 assert_false("set" in desc, "self's property " + format_value(this.name) + " should not have a setter");1365 assert_true(desc.writable, "self's property " + format_value(this.name) + " should be writable");1366 assert_false(desc.enumerable, "self's property " + format_value(this.name) + " should not be enumerable");1367 assert_true(desc.configurable, "self's property " + format_value(this.name) + " should be configurable");1368 if (this.is_callback()) {1369 // "The internal [[Prototype]] property of an interface object for1370 // a callback interface must be the Function.prototype object."1371 assert_equals(Object.getPrototypeOf(self[this.name]), Function.prototype,1372 "prototype of self's property " + format_value(this.name) + " is not Object.prototype");1373 return;1374 }1375 // "The interface object for a given non-callback interface is a1376 // function object."1377 // "If an object is defined to be a function object, then it has1378 // characteristics as follows:"1379 // Its [[Prototype]] internal property is otherwise specified (see1380 // below).1381 // "* Its [[Get]] internal property is set as described in ECMA-2621382 // section 9.1.8."1383 // Not much to test for this.1384 // "* Its [[Construct]] internal property is set as described in1385 // ECMA-262 section 19.2.2.3."1386 // Tested below if no constructor is defined. TODO: test constructors1387 // if defined.1388 // "* Its @@hasInstance property is set as described in ECMA-2621389 // section 19.2.3.8, unless otherwise specified."1390 // TODO1391 // ES6 (rev 30) 19.1.3.6:1392 // "Else, if O has a [[Call]] internal method, then let builtinTag be1393 // "Function"."1394 assert_class_string(self[this.name], "Function", "class string of " + this.name);1395 // "The [[Prototype]] internal property of an interface object for a1396 // non-callback interface is determined as follows:"1397 var prototype = Object.getPrototypeOf(self[this.name]);1398 if (this.base) {1399 // "* If the interface inherits from some other interface, the1400 // value of [[Prototype]] is the interface object for that other1401 // interface."1402 var has_interface_object =1403 !this.array1404 .members[this.base]1405 .has_extended_attribute("NoInterfaceObject");1406 if (has_interface_object) {1407 assert_own_property(self, this.base,1408 'should inherit from ' + this.base +1409 ', but self has no such property');1410 assert_equals(prototype, self[this.base],1411 'prototype of ' + this.name + ' is not ' +1412 this.base);1413 }1414 } else {1415 // "If the interface doesn't inherit from any other interface, the1416 // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262],1417 // section 6.1.7.4)."1418 assert_equals(prototype, Function.prototype,1419 "prototype of self's property " + format_value(this.name) + " is not Function.prototype");1420 }1421 if (!this.has_extended_attribute("Constructor")) {1422 // "The internal [[Call]] method of the interface object behaves as1423 // follows . . .1424 //1425 // "If I was not declared with a [Constructor] extended attribute,1426 // then throw a TypeError."1427 assert_throws(new TypeError(), function() {1428 self[this.name]();1429 }.bind(this), "interface object didn't throw TypeError when called as a function");1430 assert_throws(new TypeError(), function() {1431 new self[this.name]();1432 }.bind(this), "interface object didn't throw TypeError when called as a constructor");1433 }1434 }.bind(this), this.name + " interface: existence and properties of interface object");1435 if (!this.is_callback()) {1436 subsetTestByKey(this.name, test, function() {1437 // This function tests WebIDL as of 2014-10-25.1438 // https://heycam.github.io/webidl/#es-interface-call1439 assert_own_property(self, this.name,1440 "self does not have own property " + format_value(this.name));1441 // "Interface objects for non-callback interfaces MUST have a1442 // property named “length” with attributes { [[Writable]]: false,1443 // [[Enumerable]]: false, [[Configurable]]: true } whose value is1444 // a Number."1445 assert_own_property(self[this.name], "length");1446 var desc = Object.getOwnPropertyDescriptor(self[this.name], "length");1447 assert_false("get" in desc, this.name + ".length should not have a getter");1448 assert_false("set" in desc, this.name + ".length should not have a setter");1449 assert_false(desc.writable, this.name + ".length should not be writable");1450 assert_false(desc.enumerable, this.name + ".length should not be enumerable");1451 assert_true(desc.configurable, this.name + ".length should be configurable");1452 var constructors = this.extAttrs1453 .filter(function(attr) { return attr.name == "Constructor"; });1454 var expected_length = minOverloadLength(constructors);1455 assert_equals(self[this.name].length, expected_length, "wrong value for " + this.name + ".length");1456 }.bind(this), this.name + " interface object length");1457 }1458 if (!this.is_callback() || this.has_constants()) {1459 subsetTestByKey(this.name, test, function() {1460 // This function tests WebIDL as of 2015-11-17.1461 // https://heycam.github.io/webidl/#interface-object1462 assert_own_property(self, this.name,1463 "self does not have own property " + format_value(this.name));1464 // "All interface objects must have a property named “name” with1465 // attributes { [[Writable]]: false, [[Enumerable]]: false,1466 // [[Configurable]]: true } whose value is the identifier of the1467 // corresponding interface."1468 assert_own_property(self[this.name], "name");1469 var desc = Object.getOwnPropertyDescriptor(self[this.name], "name");1470 assert_false("get" in desc, this.name + ".name should not have a getter");1471 assert_false("set" in desc, this.name + ".name should not have a setter");1472 assert_false(desc.writable, this.name + ".name should not be writable");1473 assert_false(desc.enumerable, this.name + ".name should not be enumerable");1474 assert_true(desc.configurable, this.name + ".name should be configurable");1475 assert_equals(self[this.name].name, this.name, "wrong value for " + this.name + ".name");1476 }.bind(this), this.name + " interface object name");1477 }1478 if (this.has_extended_attribute("LegacyWindowAlias")) {1479 subsetTestByKey(this.name, test, function()1480 {1481 var aliasAttrs = this.extAttrs.filter(function(o) { return o.name === "LegacyWindowAlias"; });1482 if (aliasAttrs.length > 1) {1483 throw new IdlHarnessError("Invalid IDL: multiple LegacyWindowAlias extended attributes on " + this.name);1484 }1485 if (this.is_callback()) {1486 throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on non-interface " + this.name);1487 }1488 if (!this.exposureSet.has("Window")) {1489 throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on " + this.name + " which is not exposed in Window");1490 }1491 // TODO: when testing of [NoInterfaceObject] interfaces is supported,1492 // check that it's not specified together with LegacyWindowAlias.1493 // TODO: maybe check that [LegacyWindowAlias] is not specified on a partial interface.1494 var rhs = aliasAttrs[0].rhs;1495 if (!rhs) {1496 throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on " + this.name + " without identifier");1497 }1498 var aliases;1499 if (rhs.type === "identifier-list") {1500 aliases = rhs.value;1501 } else { // rhs.type === identifier1502 aliases = [ rhs.value ];1503 }1504 // OK now actually check the aliases...1505 var alias;1506 if (exposed_in(exposure_set(this, this.exposureSet)) && 'document' in self) {1507 for (alias of aliases) {1508 assert_true(alias in self, alias + " should exist");1509 assert_equals(self[alias], self[this.name], "self." + alias + " should be the same value as self." + this.name);1510 var desc = Object.getOwnPropertyDescriptor(self, alias);1511 assert_equals(desc.value, self[this.name], "wrong value in " + alias + " property descriptor");1512 assert_true(desc.writable, alias + " should be writable");1513 assert_false(desc.enumerable, alias + " should not be enumerable");1514 assert_true(desc.configurable, alias + " should be configurable");1515 assert_false('get' in desc, alias + " should not have a getter");1516 assert_false('set' in desc, alias + " should not have a setter");1517 }1518 } else {1519 for (alias of aliases) {1520 assert_false(alias in self, alias + " should not exist");1521 }1522 }1523 }.bind(this), this.name + " interface: legacy window alias");1524 }1525 // TODO: Test named constructors if I find any interfaces that have them.1526 subsetTestByKey(this.name, test, function()1527 {1528 // This function tests WebIDL as of 2015-01-21.1529 // https://heycam.github.io/webidl/#interface-object1530 if (this.is_callback() && !this.has_constants()) {1531 return;1532 }1533 assert_own_property(self, this.name,1534 "self does not have own property " + format_value(this.name));1535 if (this.is_callback()) {1536 assert_false("prototype" in self[this.name],1537 this.name + ' should not have a "prototype" property');1538 return;1539 }1540 // "An interface object for a non-callback interface must have a1541 // property named “prototype” with attributes { [[Writable]]: false,1542 // [[Enumerable]]: false, [[Configurable]]: false } whose value is an1543 // object called the interface prototype object. This object has1544 // properties that correspond to the regular attributes and regular1545 // operations defined on the interface, and is described in more detail1546 // in section 4.5.4 below."1547 assert_own_property(self[this.name], "prototype",1548 'interface "' + this.name + '" does not have own property "prototype"');1549 var desc = Object.getOwnPropertyDescriptor(self[this.name], "prototype");1550 assert_false("get" in desc, this.name + ".prototype should not have a getter");1551 assert_false("set" in desc, this.name + ".prototype should not have a setter");1552 assert_false(desc.writable, this.name + ".prototype should not be writable");1553 assert_false(desc.enumerable, this.name + ".prototype should not be enumerable");1554 assert_false(desc.configurable, this.name + ".prototype should not be configurable");1555 // Next, test that the [[Prototype]] of the interface prototype object1556 // is correct. (This is made somewhat difficult by the existence of1557 // [NoInterfaceObject].)1558 // TODO: Aryeh thinks there's at least other place in this file where1559 // we try to figure out if an interface prototype object is1560 // correct. Consolidate that code.1561 // "The interface prototype object for a given interface A must have an1562 // internal [[Prototype]] property whose value is returned from the1563 // following steps:1564 // "If A is declared with the [Global] extended1565 // attribute, and A supports named properties, then return the named1566 // properties object for A, as defined in §3.6.4 Named properties1567 // object.1568 // "Otherwise, if A is declared to inherit from another interface, then1569 // return the interface prototype object for the inherited interface.1570 // "Otherwise, return %ObjectPrototype%.1571 //1572 // "In the ECMAScript binding, the DOMException type has some additional1573 // requirements:1574 //1575 // "Unlike normal interface types, the interface prototype object1576 // for DOMException must have as its [[Prototype]] the intrinsic1577 // object %ErrorPrototype%."1578 //1579 if (this.name === "Window") {1580 assert_class_string(Object.getPrototypeOf(self[this.name].prototype),1581 'WindowProperties',1582 'Class name for prototype of Window' +1583 '.prototype is not "WindowProperties"');1584 } else {1585 var inherit_interface, inherit_interface_has_interface_object;1586 if (this.base) {1587 inherit_interface = this.base;1588 inherit_interface_has_interface_object =1589 !this.array1590 .members[inherit_interface]1591 .has_extended_attribute("NoInterfaceObject");1592 } else if (this.name === "DOMException") {1593 inherit_interface = 'Error';1594 inherit_interface_has_interface_object = true;1595 } else {1596 inherit_interface = 'Object';1597 inherit_interface_has_interface_object = true;1598 }1599 if (inherit_interface_has_interface_object) {1600 assert_own_property(self, inherit_interface,1601 'should inherit from ' + inherit_interface + ', but self has no such property');1602 assert_own_property(self[inherit_interface], 'prototype',1603 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property');1604 assert_equals(Object.getPrototypeOf(self[this.name].prototype),1605 self[inherit_interface].prototype,1606 'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype');1607 } else {1608 // We can't test that we get the correct object, because this is the1609 // only way to get our hands on it. We only test that its class1610 // string, at least, is correct.1611 assert_class_string(Object.getPrototypeOf(self[this.name].prototype),1612 inherit_interface + 'Prototype',1613 'Class name for prototype of ' + this.name +1614 '.prototype is not "' + inherit_interface + 'Prototype"');1615 }1616 }1617 // "The class string of an interface prototype object is the1618 // concatenation of the interface’s identifier and the string1619 // “Prototype”."1620 // Skip these tests for now due to a specification issue about1621 // prototype name.1622 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=282441623 // assert_class_string(self[this.name].prototype, this.name + "Prototype",1624 // "class string of " + this.name + ".prototype");1625 // String() should end up calling {}.toString if nothing defines a1626 // stringifier.1627 if (!this.has_stringifier()) {1628 // assert_equals(String(self[this.name].prototype), "[object " + this.name + "Prototype]",1629 // "String(" + this.name + ".prototype)");1630 }1631 }.bind(this), this.name + " interface: existence and properties of interface prototype object");1632 // "If the interface is declared with the [Global]1633 // extended attribute, or the interface is in the set of inherited1634 // interfaces for any other interface that is declared with one of these1635 // attributes, then the interface prototype object must be an immutable1636 // prototype exotic object."1637 // https://heycam.github.io/webidl/#interface-prototype-object1638 if (this.is_global()) {1639 this.test_immutable_prototype("interface prototype object", self[this.name].prototype);1640 }1641 subsetTestByKey(this.name, test, function()1642 {1643 if (this.is_callback() && !this.has_constants()) {1644 return;1645 }1646 assert_own_property(self, this.name,1647 "self does not have own property " + format_value(this.name));1648 if (this.is_callback()) {1649 assert_false("prototype" in self[this.name],1650 this.name + ' should not have a "prototype" property');1651 return;1652 }1653 assert_own_property(self[this.name], "prototype",1654 'interface "' + this.name + '" does not have own property "prototype"');1655 // "If the [NoInterfaceObject] extended attribute was not specified on1656 // the interface, then the interface prototype object must also have a1657 // property named “constructor” with attributes { [[Writable]]: true,1658 // [[Enumerable]]: false, [[Configurable]]: true } whose value is a1659 // reference to the interface object for the interface."1660 assert_own_property(self[this.name].prototype, "constructor",1661 this.name + '.prototype does not have own property "constructor"');1662 var desc = Object.getOwnPropertyDescriptor(self[this.name].prototype, "constructor");1663 assert_false("get" in desc, this.name + ".prototype.constructor should not have a getter");1664 assert_false("set" in desc, this.name + ".prototype.constructor should not have a setter");1665 assert_true(desc.writable, this.name + ".prototype.constructor should be writable");1666 assert_false(desc.enumerable, this.name + ".prototype.constructor should not be enumerable");1667 assert_true(desc.configurable, this.name + ".prototype.constructor should be configurable");1668 assert_equals(self[this.name].prototype.constructor, self[this.name],1669 this.name + '.prototype.constructor is not the same object as ' + this.name);1670 }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');1671 subsetTestByKey(this.name, test, function()1672 {1673 if (this.is_callback() && !this.has_constants()) {1674 return;1675 }1676 assert_own_property(self, this.name,1677 "self does not have own property " + format_value(this.name));1678 if (this.is_callback()) {1679 assert_false("prototype" in self[this.name],1680 this.name + ' should not have a "prototype" property');1681 return;1682 }1683 assert_own_property(self[this.name], "prototype",1684 'interface "' + this.name + '" does not have own property "prototype"');1685 // If the interface has any member declared with the [Unscopable] extended1686 // attribute, then there must be a property on the interface prototype object1687 // whose name is the @@unscopables symbol, which has the attributes1688 // { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true },1689 // and whose value is an object created as follows...1690 var unscopables = this.get_unscopables().map(m => m.name);1691 var proto = self[this.name].prototype;1692 if (unscopables.length != 0) {1693 assert_own_property(1694 proto, Symbol.unscopables,1695 this.name + '.prototype should have an @@unscopables property');1696 var desc = Object.getOwnPropertyDescriptor(proto, Symbol.unscopables);1697 assert_false("get" in desc,1698 this.name + ".prototype[Symbol.unscopables] should not have a getter");1699 assert_false("set" in desc, this.name + ".prototype[Symbol.unscopables] should not have a setter");1700 assert_false(desc.writable, this.name + ".prototype[Symbol.unscopables] should not be writable");1701 assert_false(desc.enumerable, this.name + ".prototype[Symbol.unscopables] should not be enumerable");1702 assert_true(desc.configurable, this.name + ".prototype[Symbol.unscopables] should be configurable");1703 assert_equals(desc.value, proto[Symbol.unscopables],1704 this.name + '.prototype[Symbol.unscopables] should be in the descriptor');1705 assert_equals(typeof desc.value, "object",1706 this.name + '.prototype[Symbol.unscopables] should be an object');1707 assert_equals(Object.getPrototypeOf(desc.value), null,1708 this.name + '.prototype[Symbol.unscopables] should have a null prototype');1709 assert_equals(Object.getOwnPropertySymbols(desc.value).length,1710 0,1711 this.name + '.prototype[Symbol.unscopables] should have the right number of symbol-named properties');1712 // Check that we do not have _extra_ unscopables. Checking that we1713 // have all the ones we should will happen in the per-member tests.1714 var observed = Object.getOwnPropertyNames(desc.value);1715 for (var prop of observed) {1716 assert_not_equals(unscopables.indexOf(prop),1717 -1,1718 this.name + '.prototype[Symbol.unscopables] has unexpected property "' + prop + '"');1719 }1720 } else {1721 assert_equals(Object.getOwnPropertyDescriptor(self[this.name].prototype, Symbol.unscopables),1722 undefined,1723 this.name + '.prototype should not have @@unscopables');1724 }1725 }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s @@unscopables property');1726};1727//@}1728IdlInterface.prototype.test_immutable_prototype = function(type, obj)1729//@{1730{1731 if (typeof Object.setPrototypeOf !== "function") {1732 return;1733 }1734 subsetTestByKey(this.name, test, function(t) {1735 var originalValue = Object.getPrototypeOf(obj);1736 var newValue = Object.create(null);1737 t.add_cleanup(function() {1738 try {1739 Object.setPrototypeOf(obj, originalValue);1740 } catch (err) {}1741 });1742 assert_throws(new TypeError(), function() {1743 Object.setPrototypeOf(obj, newValue);1744 });1745 assert_equals(1746 Object.getPrototypeOf(obj),1747 originalValue,1748 "original value not modified"1749 );1750 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1751 "of " + type + " - setting to a new value via Object.setPrototypeOf " +1752 "should throw a TypeError");1753 subsetTestByKey(this.name, test, function(t) {1754 var originalValue = Object.getPrototypeOf(obj);1755 var newValue = Object.create(null);1756 t.add_cleanup(function() {1757 var setter = Object.getOwnPropertyDescriptor(1758 Object.prototype, '__proto__'1759 ).set;1760 try {1761 setter.call(obj, originalValue);1762 } catch (err) {}1763 });1764 assert_throws(new TypeError(), function() {1765 obj.__proto__ = newValue;1766 });1767 assert_equals(1768 Object.getPrototypeOf(obj),1769 originalValue,1770 "original value not modified"1771 );1772 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1773 "of " + type + " - setting to a new value via __proto__ " +1774 "should throw a TypeError");1775 subsetTestByKey(this.name, test, function(t) {1776 var originalValue = Object.getPrototypeOf(obj);1777 var newValue = Object.create(null);1778 t.add_cleanup(function() {1779 try {1780 Reflect.setPrototypeOf(obj, originalValue);1781 } catch (err) {}1782 });1783 assert_false(Reflect.setPrototypeOf(obj, newValue));1784 assert_equals(1785 Object.getPrototypeOf(obj),1786 originalValue,1787 "original value not modified"1788 );1789 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1790 "of " + type + " - setting to a new value via Reflect.setPrototypeOf " +1791 "should return false");1792 subsetTestByKey(this.name, test, function() {1793 var originalValue = Object.getPrototypeOf(obj);1794 Object.setPrototypeOf(obj, originalValue);1795 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1796 "of " + type + " - setting to its original value via Object.setPrototypeOf " +1797 "should not throw");1798 subsetTestByKey(this.name, test, function() {1799 var originalValue = Object.getPrototypeOf(obj);1800 obj.__proto__ = originalValue;1801 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1802 "of " + type + " - setting to its original value via __proto__ " +1803 "should not throw");1804 subsetTestByKey(this.name, test, function() {1805 var originalValue = Object.getPrototypeOf(obj);1806 assert_true(Reflect.setPrototypeOf(obj, originalValue));1807 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1808 "of " + type + " - setting to its original value via Reflect.setPrototypeOf " +1809 "should return true");1810};1811//@}1812IdlInterface.prototype.test_member_const = function(member)1813//@{1814{1815 if (!this.has_constants()) {1816 throw new IdlHarnessError("Internal error: test_member_const called without any constants");1817 }1818 subsetTestByKey(this.name, test, function()1819 {1820 assert_own_property(self, this.name,1821 "self does not have own property " + format_value(this.name));1822 // "For each constant defined on an interface A, there must be1823 // a corresponding property on the interface object, if it1824 // exists."1825 assert_own_property(self[this.name], member.name);1826 // "The value of the property is that which is obtained by1827 // converting the constant’s IDL value to an ECMAScript1828 // value."1829 assert_equals(self[this.name][member.name], constValue(member.value),1830 "property has wrong value");1831 // "The property has attributes { [[Writable]]: false,1832 // [[Enumerable]]: true, [[Configurable]]: false }."1833 var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);1834 assert_false("get" in desc, "property should not have a getter");1835 assert_false("set" in desc, "property should not have a setter");1836 assert_false(desc.writable, "property should not be writable");1837 assert_true(desc.enumerable, "property should be enumerable");1838 assert_false(desc.configurable, "property should not be configurable");1839 }.bind(this), this.name + " interface: constant " + member.name + " on interface object");1840 // "In addition, a property with the same characteristics must1841 // exist on the interface prototype object."1842 subsetTestByKey(this.name, test, function()1843 {1844 assert_own_property(self, this.name,1845 "self does not have own property " + format_value(this.name));1846 if (this.is_callback()) {1847 assert_false("prototype" in self[this.name],1848 this.name + ' should not have a "prototype" property');1849 return;1850 }1851 assert_own_property(self[this.name], "prototype",1852 'interface "' + this.name + '" does not have own property "prototype"');1853 assert_own_property(self[this.name].prototype, member.name);1854 assert_equals(self[this.name].prototype[member.name], constValue(member.value),1855 "property has wrong value");1856 var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);1857 assert_false("get" in desc, "property should not have a getter");1858 assert_false("set" in desc, "property should not have a setter");1859 assert_false(desc.writable, "property should not be writable");1860 assert_true(desc.enumerable, "property should be enumerable");1861 assert_false(desc.configurable, "property should not be configurable");1862 }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");1863};1864//@}1865IdlInterface.prototype.test_member_attribute = function(member)1866//@{1867 {1868 if (!shouldRunSubTest(this.name)) {1869 return;1870 }1871 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: attribute " + member.name);1872 a_test.step(function()1873 {1874 if (this.is_callback() && !this.has_constants()) {1875 a_test.done()1876 return;1877 }1878 assert_own_property(self, this.name,1879 "self does not have own property " + format_value(this.name));1880 assert_own_property(self[this.name], "prototype",1881 'interface "' + this.name + '" does not have own property "prototype"');1882 if (member["static"]) {1883 assert_own_property(self[this.name], member.name,1884 "The interface object must have a property " +1885 format_value(member.name));1886 a_test.done();1887 return;1888 }1889 this.do_member_unscopable_asserts(member);1890 if (this.is_global()) {1891 assert_own_property(self, member.name,1892 "The global object must have a property " +1893 format_value(member.name));1894 assert_false(member.name in self[this.name].prototype,1895 "The prototype object should not have a property " +1896 format_value(member.name));1897 var getter = Object.getOwnPropertyDescriptor(self, member.name).get;1898 assert_equals(typeof(getter), "function",1899 format_value(member.name) + " must have a getter");1900 // Try/catch around the get here, since it can legitimately throw.1901 // If it does, we obviously can't check for equality with direct1902 // invocation of the getter.1903 var gotValue;1904 var propVal;1905 try {1906 propVal = self[member.name];1907 gotValue = true;1908 } catch (e) {1909 gotValue = false;1910 }1911 if (gotValue) {1912 assert_equals(propVal, getter.call(undefined),1913 "Gets on a global should not require an explicit this");1914 }1915 // do_interface_attribute_asserts must be the last thing we do,1916 // since it will call done() on a_test.1917 this.do_interface_attribute_asserts(self, member, a_test);1918 } else {1919 assert_true(member.name in self[this.name].prototype,1920 "The prototype object must have a property " +1921 format_value(member.name));1922 if (!member.has_extended_attribute("LenientThis")) {1923 if (member.idlType.generic !== "Promise") {1924 assert_throws(new TypeError(), function() {1925 self[this.name].prototype[member.name];1926 }.bind(this), "getting property on prototype object must throw TypeError");1927 // do_interface_attribute_asserts must be the last thing we1928 // do, since it will call done() on a_test.1929 this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);1930 } else {1931 promise_rejects(a_test, new TypeError(),1932 self[this.name].prototype[member.name])1933 .then(function() {1934 // do_interface_attribute_asserts must be the last1935 // thing we do, since it will call done() on a_test.1936 this.do_interface_attribute_asserts(self[this.name].prototype,1937 member, a_test);1938 }.bind(this));1939 }1940 } else {1941 assert_equals(self[this.name].prototype[member.name], undefined,1942 "getting property on prototype object must return undefined");1943 // do_interface_attribute_asserts must be the last thing we do,1944 // since it will call done() on a_test.1945 this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);1946 }1947 }1948 }.bind(this));1949};1950//@}1951IdlInterface.prototype.test_member_operation = function(member)1952//@{1953{1954 if (!shouldRunSubTest(this.name)) {1955 return;1956 }1957 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: operation " + member.name +1958 "(" + member.arguments.map(1959 function(m) {return m.idlType.idlType; } ).join(", ")1960 +")");1961 a_test.step(function()1962 {1963 // This function tests WebIDL as of 2015-12-29.1964 // https://heycam.github.io/webidl/#es-operations1965 if (this.is_callback() && !this.has_constants()) {1966 a_test.done();1967 return;1968 }1969 assert_own_property(self, this.name,1970 "self does not have own property " + format_value(this.name));1971 if (this.is_callback()) {1972 assert_false("prototype" in self[this.name],1973 this.name + ' should not have a "prototype" property');1974 a_test.done();1975 return;1976 }1977 assert_own_property(self[this.name], "prototype",1978 'interface "' + this.name + '" does not have own property "prototype"');1979 // "For each unique identifier of an exposed operation defined on the1980 // interface, there must exist a corresponding property, unless the1981 // effective overload set for that identifier and operation and with an1982 // argument count of 0 has no entries."1983 // TODO: Consider [Exposed].1984 // "The location of the property is determined as follows:"1985 var memberHolderObject;1986 // "* If the operation is static, then the property exists on the1987 // interface object."1988 if (member["static"]) {1989 assert_own_property(self[this.name], member.name,1990 "interface object missing static operation");1991 memberHolderObject = self[this.name];1992 // "* Otherwise, [...] if the interface was declared with the [Global]1993 // extended attribute, then the property exists1994 // on every object that implements the interface."1995 } else if (this.is_global()) {1996 assert_own_property(self, member.name,1997 "global object missing non-static operation");1998 memberHolderObject = self;1999 // "* Otherwise, the property exists solely on the interface’s2000 // interface prototype object."2001 } else {2002 assert_own_property(self[this.name].prototype, member.name,2003 "interface prototype object missing non-static operation");2004 memberHolderObject = self[this.name].prototype;2005 }2006 this.do_member_unscopable_asserts(member);2007 this.do_member_operation_asserts(memberHolderObject, member, a_test);2008 }.bind(this));2009};2010IdlInterface.prototype.do_member_unscopable_asserts = function(member)2011{2012 // Check that if the member is unscopable then it's in the2013 // @@unscopables object properly.2014 if (!member.isUnscopable) {2015 return;2016 }2017 var unscopables = self[this.name].prototype[Symbol.unscopables];2018 var prop = member.name;2019 var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop);2020 assert_equals(typeof propDesc, "object",2021 this.name + '.prototype[Symbol.unscopables].' + prop + ' must exist')2022 assert_false("get" in propDesc,2023 this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no getter');2024 assert_false("set" in propDesc,2025 this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no setter');2026 assert_true(propDesc.writable,2027 this.name + '.prototype[Symbol.unscopables].' + prop + ' must be writable');2028 assert_true(propDesc.enumerable,2029 this.name + '.prototype[Symbol.unscopables].' + prop + ' must be enumerable');2030 assert_true(propDesc.configurable,2031 this.name + '.prototype[Symbol.unscopables].' + prop + ' must be configurable');2032 assert_equals(propDesc.value, true,2033 this.name + '.prototype[Symbol.unscopables].' + prop + ' must have the value `true`');2034};2035//@}2036IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject, member, a_test)2037//@{2038{2039 var done = a_test.done.bind(a_test);2040 var operationUnforgeable = member.isUnforgeable;2041 var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name);2042 // "The property has attributes { [[Writable]]: B,2043 // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the2044 // operation is unforgeable on the interface, and true otherwise".2045 assert_false("get" in desc, "property should not have a getter");2046 assert_false("set" in desc, "property should not have a setter");2047 assert_equals(desc.writable, !operationUnforgeable,2048 "property should be writable if and only if not unforgeable");2049 assert_true(desc.enumerable, "property should be enumerable");2050 assert_equals(desc.configurable, !operationUnforgeable,2051 "property should be configurable if and only if not unforgeable");2052 // "The value of the property is a Function object whose2053 // behavior is as follows . . ."2054 assert_equals(typeof memberHolderObject[member.name], "function",2055 "property must be a function");2056 const ctors = this.members.filter(function(m) {2057 return m.type == "operation" && m.name == member.name;2058 });2059 assert_equals(2060 memberHolderObject[member.name].length,2061 minOverloadLength(ctors),2062 "property has wrong .length");2063 // Make some suitable arguments2064 var args = member.arguments.map(function(arg) {2065 return create_suitable_object(arg.idlType);2066 });2067 // "Let O be a value determined as follows:2068 // ". . .2069 // "Otherwise, throw a TypeError."2070 // This should be hit if the operation is not static, there is2071 // no [ImplicitThis] attribute, and the this value is null.2072 //2073 // TODO: We currently ignore the [ImplicitThis] case. Except we manually2074 // check for globals, since otherwise we'll invoke window.close(). And we2075 // have to skip this test for anything that on the proto chain of "self",2076 // since that does in fact have implicit-this behavior.2077 if (!member["static"]) {2078 var cb;2079 if (!this.is_global() &&2080 memberHolderObject[member.name] != self[member.name])2081 {2082 cb = awaitNCallbacks(2, done);2083 throwOrReject(a_test, member, memberHolderObject[member.name], null, args,2084 "calling operation with this = null didn't throw TypeError", cb);2085 } else {2086 cb = awaitNCallbacks(1, done);2087 }2088 // ". . . If O is not null and is also not a platform object2089 // that implements interface I, throw a TypeError."2090 //2091 // TODO: Test a platform object that implements some other2092 // interface. (Have to be sure to get inheritance right.)2093 throwOrReject(a_test, member, memberHolderObject[member.name], {}, args,2094 "calling operation with this = {} didn't throw TypeError", cb);2095 } else {2096 done();2097 }2098}2099//@}2100IdlInterface.prototype.add_iterable_members = function(member)2101//@{2102{2103 this.members.push(new IdlInterfaceMember(2104 { type: "operation", name: "entries", idlType: "iterator", arguments: []}));2105 this.members.push(new IdlInterfaceMember(2106 { type: "operation", name: "keys", idlType: "iterator", arguments: []}));2107 this.members.push(new IdlInterfaceMember(2108 { type: "operation", name: "values", idlType: "iterator", arguments: []}));2109 this.members.push(new IdlInterfaceMember(2110 { type: "operation", name: "forEach", idlType: "void",2111 arguments:2112 [{ name: "callback", idlType: {idlType: "function"}},2113 { name: "thisValue", idlType: {idlType: "any"}, optional: true}]}));2114};2115IdlInterface.prototype.test_to_json_operation = function(memberHolderObject, member) {2116 var instanceName = memberHolderObject && memberHolderObject.constructor.name2117 || member.name + " object";2118 if (member.has_extended_attribute("Default")) {2119 subsetTestByKey(this.name, test, function() {2120 var map = this.default_to_json_operation();2121 var json = memberHolderObject.toJSON();2122 map.forEach(function(type, k) {2123 assert_true(k in json, "property " + JSON.stringify(k) + " should be present in the output of " + this.name + ".prototype.toJSON()");2124 var descriptor = Object.getOwnPropertyDescriptor(json, k);2125 assert_true(descriptor.writable, "property " + k + " should be writable");2126 assert_true(descriptor.configurable, "property " + k + " should be configurable");2127 assert_true(descriptor.enumerable, "property " + k + " should be enumerable");2128 this.array.assert_type_is(json[k], type);2129 delete json[k];2130 }, this);2131 }.bind(this), "Test default toJSON operation of " + instanceName);2132 } else {2133 subsetTestByKey(this.name, test, function() {2134 assert_true(this.array.is_json_type(member.idlType), JSON.stringify(member.idlType) + " is not an appropriate return value for the toJSON operation of " + instanceName);2135 this.array.assert_type_is(memberHolderObject.toJSON(), member.idlType);2136 }.bind(this), "Test toJSON operation of " + instanceName);2137 }2138};2139//@}2140IdlInterface.prototype.test_member_iterable = function(member)2141//@{2142{2143 var interfaceName = this.name;2144 var isPairIterator = member.idlType.length === 2;2145 subsetTestByKey(this.name, test, function()2146 {2147 var descriptor = Object.getOwnPropertyDescriptor(self[interfaceName].prototype, Symbol.iterator);2148 assert_true(descriptor.writable, "property should be writable");2149 assert_true(descriptor.configurable, "property should be configurable");2150 assert_false(descriptor.enumerable, "property should not be enumerable");2151 assert_equals(self[interfaceName].prototype[Symbol.iterator].name, isPairIterator ? "entries" : "values", "@@iterator function does not have the right name");2152 }, "Testing Symbol.iterator property of iterable interface " + interfaceName);2153 if (isPairIterator) {2154 subsetTestByKey(this.name, test, function() {2155 assert_equals(self[interfaceName].prototype[Symbol.iterator], self[interfaceName].prototype["entries"], "entries method is not the same as @@iterator");2156 }, "Testing pair iterable interface " + interfaceName);2157 } else {2158 subsetTestByKey(this.name, test, function() {2159 ["entries", "keys", "values", "forEach", Symbol.Iterator].forEach(function(property) {2160 assert_equals(self[interfaceName].prototype[property], Array.prototype[property], property + " function is not the same as Array one");2161 });2162 }, "Testing value iterable interface " + interfaceName);2163 }2164};2165//@}2166IdlInterface.prototype.test_member_stringifier = function(member)2167//@{2168{2169 subsetTestByKey(this.name, test, function()2170 {2171 if (this.is_callback() && !this.has_constants()) {2172 return;2173 }2174 assert_own_property(self, this.name,2175 "self does not have own property " + format_value(this.name));2176 if (this.is_callback()) {2177 assert_false("prototype" in self[this.name],2178 this.name + ' should not have a "prototype" property');2179 return;2180 }2181 assert_own_property(self[this.name], "prototype",2182 'interface "' + this.name + '" does not have own property "prototype"');2183 // ". . . the property exists on the interface prototype object."2184 var interfacePrototypeObject = self[this.name].prototype;2185 assert_own_property(self[this.name].prototype, "toString",2186 "interface prototype object missing non-static operation");2187 var stringifierUnforgeable = member.isUnforgeable;2188 var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "toString");2189 // "The property has attributes { [[Writable]]: B,2190 // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the2191 // stringifier is unforgeable on the interface, and true otherwise."2192 assert_false("get" in desc, "property should not have a getter");2193 assert_false("set" in desc, "property should not have a setter");2194 assert_equals(desc.writable, !stringifierUnforgeable,2195 "property should be writable if and only if not unforgeable");2196 assert_true(desc.enumerable, "property should be enumerable");2197 assert_equals(desc.configurable, !stringifierUnforgeable,2198 "property should be configurable if and only if not unforgeable");2199 // "The value of the property is a Function object, which behaves as2200 // follows . . ."2201 assert_equals(typeof interfacePrototypeObject.toString, "function",2202 "property must be a function");2203 // "The value of the Function object’s “length” property is the Number2204 // value 0."2205 assert_equals(interfacePrototypeObject.toString.length, 0,2206 "property has wrong .length");2207 // "Let O be the result of calling ToObject on the this value."2208 assert_throws(new TypeError(), function() {2209 self[this.name].prototype.toString.apply(null, []);2210 }, "calling stringifier with this = null didn't throw TypeError");2211 // "If O is not an object that implements the interface on which the2212 // stringifier was declared, then throw a TypeError."2213 //2214 // TODO: Test a platform object that implements some other2215 // interface. (Have to be sure to get inheritance right.)2216 assert_throws(new TypeError(), function() {2217 self[this.name].prototype.toString.apply({}, []);2218 }, "calling stringifier with this = {} didn't throw TypeError");2219 }.bind(this), this.name + " interface: stringifier");2220};2221//@}2222IdlInterface.prototype.test_members = function()2223//@{2224{2225 for (var i = 0; i < this.members.length; i++)2226 {2227 var member = this.members[i];2228 switch (member.type) {2229 case "iterable":2230 this.add_iterable_members(member);2231 break;2232 // TODO: add setlike and maplike handling.2233 default:2234 break;2235 }2236 }2237 for (var i = 0; i < this.members.length; i++)2238 {2239 var member = this.members[i];2240 if (member.untested) {2241 continue;2242 }2243 if (!exposed_in(exposure_set(member, this.exposureSet))) {2244 subsetTestByKey(this.name, test, function() {2245 // It's not exposed, so we shouldn't find it anywhere.2246 assert_false(member.name in self[this.name],2247 "The interface object must not have a property " +2248 format_value(member.name));2249 assert_false(member.name in self[this.name].prototype,2250 "The prototype object must not have a property " +2251 format_value(member.name));2252 }.bind(this), this.name + " interface: member " + member.name);2253 continue;2254 }2255 switch (member.type) {2256 case "const":2257 this.test_member_const(member);2258 break;2259 case "attribute":2260 // For unforgeable attributes, we do the checks in2261 // test_interface_of instead.2262 if (!member.isUnforgeable)2263 {2264 this.test_member_attribute(member);2265 }2266 if (member.stringifier) {2267 this.test_member_stringifier(member);2268 }2269 break;2270 case "operation":2271 // TODO: Need to correctly handle multiple operations with the same2272 // identifier.2273 // For unforgeable operations, we do the checks in2274 // test_interface_of instead.2275 if (member.name) {2276 if (!member.isUnforgeable)2277 {2278 this.test_member_operation(member);2279 }2280 } else if (member.stringifier) {2281 this.test_member_stringifier(member);2282 }2283 break;2284 case "iterable":2285 this.test_member_iterable(member);2286 break;2287 default:2288 // TODO: check more member types.2289 break;2290 }2291 }2292};2293//@}2294IdlInterface.prototype.test_object = function(desc)2295//@{2296{2297 var obj, exception = null;2298 try2299 {2300 obj = eval(desc);2301 }2302 catch(e)2303 {2304 exception = e;2305 }2306 var expected_typeof =2307 this.members.some(function(member) { return member.legacycaller; })2308 ? "function"2309 : "object";2310 this.test_primary_interface_of(desc, obj, exception, expected_typeof);2311 var current_interface = this;2312 while (current_interface)2313 {2314 if (!(current_interface.name in this.array.members))2315 {2316 throw new IdlHarnessError("Interface " + current_interface.name + " not found (inherited by " + this.name + ")");2317 }2318 if (current_interface.prevent_multiple_testing && current_interface.already_tested)2319 {2320 return;2321 }2322 current_interface.test_interface_of(desc, obj, exception, expected_typeof);2323 current_interface = this.array.members[current_interface.base];2324 }2325};2326//@}2327IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception, expected_typeof)2328//@{2329{2330 // Only the object itself, not its members, are tested here, so if the2331 // interface is untested, there is nothing to do.2332 if (this.untested)2333 {2334 return;2335 }2336 // "The internal [[SetPrototypeOf]] method of every platform object that2337 // implements an interface with the [Global] extended2338 // attribute must execute the same algorithm as is defined for the2339 // [[SetPrototypeOf]] internal method of an immutable prototype exotic2340 // object."2341 // https://heycam.github.io/webidl/#platform-object-setprototypeof2342 if (this.is_global())2343 {2344 this.test_immutable_prototype("global platform object", obj);2345 }2346 // We can't easily test that its prototype is correct if there's no2347 // interface object, or the object is from a different global environment2348 // (not instanceof Object). TODO: test in this case that its prototype at2349 // least looks correct, even if we can't test that it's actually correct.2350 if (!this.has_extended_attribute("NoInterfaceObject")2351 && (typeof obj != expected_typeof || obj instanceof Object))2352 {2353 subsetTestByKey(this.name, test, function()2354 {2355 assert_equals(exception, null, "Unexpected exception when evaluating object");2356 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2357 assert_own_property(self, this.name,2358 "self does not have own property " + format_value(this.name));2359 assert_own_property(self[this.name], "prototype",2360 'interface "' + this.name + '" does not have own property "prototype"');2361 // "The value of the internal [[Prototype]] property of the2362 // platform object is the interface prototype object of the primary2363 // interface from the platform object’s associated global2364 // environment."2365 assert_equals(Object.getPrototypeOf(obj),2366 self[this.name].prototype,2367 desc + "'s prototype is not " + this.name + ".prototype");2368 }.bind(this), this.name + " must be primary interface of " + desc);2369 }2370 // "The class string of a platform object that implements one or more2371 // interfaces must be the identifier of the primary interface of the2372 // platform object."2373 subsetTestByKey(this.name, test, function()2374 {2375 assert_equals(exception, null, "Unexpected exception when evaluating object");2376 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2377 assert_class_string(obj, this.name, "class string of " + desc);2378 if (!this.has_stringifier())2379 {2380 assert_equals(String(obj), "[object " + this.name + "]", "String(" + desc + ")");2381 }2382 }.bind(this), "Stringification of " + desc);2383};2384//@}2385IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof)2386//@{2387{2388 // TODO: Indexed and named properties, more checks on interface members2389 this.already_tested = true;2390 if (!shouldRunSubTest(this.name)) {2391 return;2392 }2393 for (var i = 0; i < this.members.length; i++)2394 {2395 var member = this.members[i];2396 if (member.untested) {2397 continue;2398 }2399 if (!exposed_in(exposure_set(member, this.exposureSet))) {2400 subsetTestByKey(this.name, test, function() {2401 assert_equals(exception, null, "Unexpected exception when evaluating object");2402 assert_false(member.name in obj);2403 }.bind(this), this.name + " interface: " + desc + ' must not have property "' + member.name + '"');2404 continue;2405 }2406 if (member.type == "attribute" && member.isUnforgeable)2407 {2408 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: " + desc + ' must have own property "' + member.name + '"');2409 a_test.step(function() {2410 assert_equals(exception, null, "Unexpected exception when evaluating object");2411 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2412 // Call do_interface_attribute_asserts last, since it will call a_test.done()2413 this.do_interface_attribute_asserts(obj, member, a_test);2414 }.bind(this));2415 }2416 else if (member.type == "operation" &&2417 member.name &&2418 member.isUnforgeable)2419 {2420 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: " + desc + ' must have own property "' + member.name + '"');2421 a_test.step(function()2422 {2423 assert_equals(exception, null, "Unexpected exception when evaluating object");2424 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2425 assert_own_property(obj, member.name,2426 "Doesn't have the unforgeable operation property");2427 this.do_member_operation_asserts(obj, member, a_test);2428 }.bind(this));2429 }2430 else if ((member.type == "const"2431 || member.type == "attribute"2432 || member.type == "operation")2433 && member.name)2434 {2435 var described_name = member.name;2436 if (member.type == "operation")2437 {2438 described_name += "(" + member.arguments.map(arg => arg.idlType.idlType).join(", ") + ")";2439 }2440 subsetTestByKey(this.name, test, function()2441 {2442 assert_equals(exception, null, "Unexpected exception when evaluating object");2443 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2444 if (!member["static"]) {2445 if (!this.is_global()) {2446 assert_inherits(obj, member.name);2447 } else {2448 assert_own_property(obj, member.name);2449 }2450 if (member.type == "const")2451 {2452 assert_equals(obj[member.name], constValue(member.value));2453 }2454 if (member.type == "attribute")2455 {2456 // Attributes are accessor properties, so they might2457 // legitimately throw an exception rather than returning2458 // anything.2459 var property, thrown = false;2460 try2461 {2462 property = obj[member.name];2463 }2464 catch (e)2465 {2466 thrown = true;2467 }2468 if (!thrown)2469 {2470 this.array.assert_type_is(property, member.idlType);2471 }2472 }2473 if (member.type == "operation")2474 {2475 assert_equals(typeof obj[member.name], "function");2476 }2477 }2478 }.bind(this), this.name + " interface: " + desc + ' must inherit property "' + described_name + '" with the proper type');2479 }2480 // TODO: This is wrong if there are multiple operations with the same2481 // identifier.2482 // TODO: Test passing arguments of the wrong type.2483 if (member.type == "operation" && member.name && member.arguments.length)2484 {2485 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: calling " + member.name +2486 "(" + member.arguments.map(function(m) { return m.idlType.idlType; }).join(", ") +2487 ") on " + desc + " with too few arguments must throw TypeError");2488 a_test.step(function()2489 {2490 assert_equals(exception, null, "Unexpected exception when evaluating object");2491 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2492 var fn;2493 if (!member["static"]) {2494 if (!this.is_global() && !member.isUnforgeable) {2495 assert_inherits(obj, member.name);2496 } else {2497 assert_own_property(obj, member.name);2498 }2499 fn = obj[member.name];2500 }2501 else2502 {2503 assert_own_property(obj.constructor, member.name, "interface object must have static operation as own property");2504 fn = obj.constructor[member.name];2505 }2506 var minLength = minOverloadLength(this.members.filter(function(m) {2507 return m.type == "operation" && m.name == member.name;2508 }));2509 var args = [];2510 var cb = awaitNCallbacks(minLength, a_test.done.bind(a_test));2511 for (var i = 0; i < minLength; i++) {2512 throwOrReject(a_test, member, fn, obj, args, "Called with " + i + " arguments", cb);2513 args.push(create_suitable_object(member.arguments[i].idlType));2514 }2515 if (minLength === 0) {2516 cb();2517 }2518 }.bind(this));2519 }2520 if (member.is_to_json_regular_operation()) {2521 this.test_to_json_operation(obj, member);2522 }2523 }2524};2525//@}2526IdlInterface.prototype.has_stringifier = function()2527//@{2528{2529 if (this.name === "DOMException") {2530 // toString is inherited from Error, so don't assume we have the2531 // default stringifer2532 return true;2533 }2534 if (this.members.some(function(member) { return member.stringifier; })) {2535 return true;2536 }2537 if (this.base &&2538 this.array.members[this.base].has_stringifier()) {2539 return true;2540 }2541 return false;2542};2543//@}2544IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member, a_test)2545//@{2546{2547 // This function tests WebIDL as of 2015-01-27.2548 // TODO: Consider [Exposed].2549 // This is called by test_member_attribute() with the prototype as obj if2550 // it is not a global, and the global otherwise, and by test_interface_of()2551 // with the object as obj.2552 var pendingPromises = [];2553 // "For each exposed attribute of the interface, whether it was declared on2554 // the interface itself or one of its consequential interfaces, there MUST2555 // exist a corresponding property. The characteristics of this property are2556 // as follows:"2557 // "The name of the property is the identifier of the attribute."2558 assert_own_property(obj, member.name);2559 // "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]:2560 // true, [[Configurable]]: configurable }, where:2561 // "configurable is false if the attribute was declared with the2562 // [Unforgeable] extended attribute and true otherwise;2563 // "G is the attribute getter, defined below; and2564 // "S is the attribute setter, also defined below."2565 var desc = Object.getOwnPropertyDescriptor(obj, member.name);2566 assert_false("value" in desc, 'property descriptor should not have a "value" field');2567 assert_false("writable" in desc, 'property descriptor should not have a "writable" field');2568 assert_true(desc.enumerable, "property should be enumerable");2569 if (member.isUnforgeable)2570 {2571 assert_false(desc.configurable, "[Unforgeable] property must not be configurable");2572 }2573 else2574 {2575 assert_true(desc.configurable, "property must be configurable");2576 }2577 // "The attribute getter is a Function object whose behavior when invoked2578 // is as follows:"2579 assert_equals(typeof desc.get, "function", "getter must be Function");2580 // "If the attribute is a regular attribute, then:"2581 if (!member["static"]) {2582 // "If O is not a platform object that implements I, then:2583 // "If the attribute was specified with the [LenientThis] extended2584 // attribute, then return undefined.2585 // "Otherwise, throw a TypeError."2586 if (!member.has_extended_attribute("LenientThis")) {2587 if (member.idlType.generic !== "Promise") {2588 assert_throws(new TypeError(), function() {2589 desc.get.call({});2590 }.bind(this), "calling getter on wrong object type must throw TypeError");2591 } else {2592 pendingPromises.push(2593 promise_rejects(a_test, new TypeError(), desc.get.call({}),2594 "calling getter on wrong object type must reject the return promise with TypeError"));2595 }2596 } else {2597 assert_equals(desc.get.call({}), undefined,2598 "calling getter on wrong object type must return undefined");2599 }2600 }2601 // "The value of the Function object’s “length” property is the Number2602 // value 0."2603 assert_equals(desc.get.length, 0, "getter length must be 0");2604 // TODO: Test calling setter on the interface prototype (should throw2605 // TypeError in most cases).2606 if (member.readonly2607 && !member.has_extended_attribute("LenientSetter")2608 && !member.has_extended_attribute("PutForwards")2609 && !member.has_extended_attribute("Replaceable"))2610 {2611 // "The attribute setter is undefined if the attribute is declared2612 // readonly and has neither a [PutForwards] nor a [Replaceable]2613 // extended attribute declared on it."2614 assert_equals(desc.set, undefined, "setter must be undefined for readonly attributes");2615 }2616 else2617 {2618 // "Otherwise, it is a Function object whose behavior when2619 // invoked is as follows:"2620 assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes");2621 // "If the attribute is a regular attribute, then:"2622 if (!member["static"]) {2623 // "If /validThis/ is false and the attribute was not specified2624 // with the [LenientThis] extended attribute, then throw a2625 // TypeError."2626 // "If the attribute is declared with a [Replaceable] extended2627 // attribute, then: ..."2628 // "If validThis is false, then return."2629 if (!member.has_extended_attribute("LenientThis")) {2630 assert_throws(new TypeError(), function() {2631 desc.set.call({});2632 }.bind(this), "calling setter on wrong object type must throw TypeError");2633 } else {2634 assert_equals(desc.set.call({}), undefined,2635 "calling setter on wrong object type must return undefined");2636 }2637 }2638 // "The value of the Function object’s “length” property is the Number2639 // value 1."2640 assert_equals(desc.set.length, 1, "setter length must be 1");2641 }2642 Promise.all(pendingPromises).then(a_test.done.bind(a_test));2643}2644//@}2645/// IdlInterfaceMember ///2646function IdlInterfaceMember(obj)2647//@{2648{2649 /**2650 * obj is an object produced by the WebIDLParser.js "ifMember" production.2651 * We just forward all properties to this object without modification,2652 * except for special extAttrs handling.2653 */2654 for (var k in obj)2655 {2656 this[k] = obj[k];2657 }2658 if (!("extAttrs" in this))2659 {2660 this.extAttrs = [];2661 }2662 this.isUnforgeable = this.has_extended_attribute("Unforgeable");2663 this.isUnscopable = this.has_extended_attribute("Unscopable");2664}2665//@}2666IdlInterfaceMember.prototype = Object.create(IdlObject.prototype);2667IdlInterfaceMember.prototype.is_to_json_regular_operation = function() {2668 return this.type == "operation" && !this.static && this.name == "toJSON";2669};2670/// Internal helper functions ///2671function create_suitable_object(type)2672//@{2673{2674 /**2675 * type is an object produced by the WebIDLParser.js "type" production. We2676 * return a JavaScript value that matches the type, if we can figure out2677 * how.2678 */2679 if (type.nullable)2680 {2681 return null;2682 }2683 switch (type.idlType)2684 {2685 case "any":2686 case "boolean":2687 return true;2688 case "byte": case "octet": case "short": case "unsigned short":2689 case "long": case "unsigned long": case "long long":2690 case "unsigned long long": case "float": case "double":2691 case "unrestricted float": case "unrestricted double":2692 return 7;2693 case "DOMString":2694 case "ByteString":2695 case "USVString":2696 return "foo";2697 case "object":2698 return {a: "b"};2699 case "Node":2700 return document.createTextNode("abc");2701 }2702 return null;2703}2704//@}2705/// IdlEnum ///2706// Used for IdlArray.prototype.assert_type_is2707function IdlEnum(obj)2708//@{2709{2710 /**2711 * obj is an object produced by the WebIDLParser.js "dictionary"2712 * production.2713 */2714 /** Self-explanatory. */2715 this.name = obj.name;2716 /** An array of values produced by the "enum" production. */2717 this.values = obj.values;2718}2719//@}2720IdlEnum.prototype = Object.create(IdlObject.prototype);2721/// IdlTypedef ///2722// Used for IdlArray.prototype.assert_type_is2723function IdlTypedef(obj)2724//@{2725{2726 /**2727 * obj is an object produced by the WebIDLParser.js "typedef"2728 * production.2729 */2730 /** Self-explanatory. */2731 this.name = obj.name;2732 /** The idlType that we are supposed to be typedeffing to. */2733 this.idlType = obj.idlType;2734}2735//@}2736IdlTypedef.prototype = Object.create(IdlObject.prototype);2737/// IdlNamespace ///2738function IdlNamespace(obj)2739//@{2740{2741 this.name = obj.name;2742 this.extAttrs = obj.extAttrs;2743 this.untested = obj.untested;2744 /** A back-reference to our IdlArray. */2745 this.array = obj.array;2746 /** An array of IdlInterfaceMembers. */2747 this.members = obj.members.map(m => new IdlInterfaceMember(m));2748}2749//@}2750IdlNamespace.prototype = Object.create(IdlObject.prototype);2751IdlNamespace.prototype.do_member_operation_asserts = function (memberHolderObject, member, a_test)2752//@{2753{2754 var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name);2755 assert_false("get" in desc, "property should not have a getter");2756 assert_false("set" in desc, "property should not have a setter");2757 assert_equals(2758 desc.writable,2759 !member.isUnforgeable,2760 "property should be writable if and only if not unforgeable");2761 assert_true(desc.enumerable, "property should be enumerable");2762 assert_equals(2763 desc.configurable,2764 !member.isUnforgeable,2765 "property should be configurable if and only if not unforgeable");2766 assert_equals(2767 typeof memberHolderObject[member.name],2768 "function",2769 "property must be a function");2770 assert_equals(2771 memberHolderObject[member.name].length,2772 minOverloadLength(this.members.filter(function(m) {2773 return m.type == "operation" && m.name == member.name;2774 })),2775 "operation has wrong .length");2776 a_test.done();2777}2778//@}2779IdlNamespace.prototype.test_member_operation = function(member)2780//@{2781{2782 if (!shouldRunSubTest(this.name)) {2783 return;2784 }2785 var args = member.arguments.map(function(a) {2786 var s = a.idlType.idlType;2787 if (a.variadic) {2788 s += '...';2789 }2790 return s;2791 }).join(", ");2792 var a_test = subsetTestByKey(2793 this.name,2794 async_test,2795 this.name + ' namespace: operation ' + member.name + '(' + args + ')');2796 a_test.step(function() {2797 assert_own_property(2798 self[this.name],2799 member.name,2800 'namespace object missing operation ' + format_value(member.name));2801 this.do_member_operation_asserts(self[this.name], member, a_test);2802 }.bind(this));2803};2804//@}2805IdlNamespace.prototype.test_member_attribute = function (member)2806//@{2807{2808 if (!shouldRunSubTest(this.name)) {2809 return;2810 }2811 var a_test = subsetTestByKey(2812 this.name,2813 async_test,2814 this.name + ' namespace: attribute ' + member.name);2815 a_test.step(function()2816 {2817 assert_own_property(2818 self[this.name],2819 member.name,2820 this.name + ' does not have property ' + format_value(member.name));2821 var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);2822 assert_equals(desc.set, undefined, "setter must be undefined for namespace members");2823 a_test.done();2824 }.bind(this));2825};2826//@}2827IdlNamespace.prototype.test = function ()2828//@{2829{2830 /**2831 * TODO(lukebjerring): Assert:2832 * - "Note that unlike interfaces or dictionaries, namespaces do not create types."2833 * - "Of the extended attributes defined in this specification, only the2834 * [Exposed] and [SecureContext] extended attributes are applicable to namespaces."2835 * - "Namespaces must be annotated with the [Exposed] extended attribute."2836 */2837 for (const v of Object.values(this.members)) {2838 switch (v.type) {2839 case 'operation':2840 this.test_member_operation(v);2841 break;2842 case 'attribute':2843 this.test_member_attribute(v);2844 break;2845 default:2846 throw 'Invalid namespace member ' + v.name + ': ' + v.type + ' not supported';2847 }2848 };2849};2850//@}2851}());2852/**2853 * idl_test is a promise_test wrapper that handles the fetching of the IDL,2854 * avoiding repetitive boilerplate.2855 *2856 * @param {String|String[]} srcs Spec name(s) for source idl files (fetched from2857 * /interfaces/{name}.idl).2858 * @param {String|String[]} deps Spec name(s) for dependency idl files (fetched2859 * from /interfaces/{name}.idl). Order is important - dependencies from2860 * each source will only be included if they're already know to be a2861 * dependency (i.e. have already been seen).2862 * @param {Function} setup_func Function for extra setup of the idl_array, such2863 * as adding objects. Do not call idl_array.test() in the setup; it is2864 * called by this function (idl_test).2865 */2866function idl_test(srcs, deps, idl_setup_func) {2867 return promise_test(function (t) {2868 var idl_array = new IdlArray();2869 srcs = (srcs instanceof Array) ? srcs : [srcs] || [];2870 deps = (deps instanceof Array) ? deps : [deps] || [];2871 var setup_error = null;2872 return Promise.all(2873 srcs.concat(deps).map(function(spec) {2874 return fetch_spec(spec);2875 }))2876 .then(function(idls) {2877 for (var i = 0; i < srcs.length; i++) {2878 idl_array.add_idls(idls[i]);2879 }2880 for (var i = srcs.length; i < srcs.length + deps.length; i++) {2881 idl_array.add_dependency_idls(idls[i]);2882 }2883 })2884 .then(function() {2885 if (idl_setup_func) {2886 return idl_setup_func(idl_array, t);2887 }2888 })2889 .catch(function(e) { setup_error = e || 'IDL setup failed.'; })2890 .then(function () {2891 var error = setup_error;2892 try {2893 idl_array.test(); // Test what we can.2894 } catch (e) {2895 // If testing fails hard here, the original setup error2896 // is more likely to be the real cause.2897 error = error || e;2898 }2899 if (error) {2900 throw error;2901 }2902 });2903 }, 'idl_test setup');2904}2905/**2906 * fetch_spec is a shorthand for a Promise that fetches the spec's content.2907 */2908function fetch_spec(spec) {2909 return fetch('/interfaces/' + spec + '.idl').then(function (r) {2910 return r.text();2911 });2912}...

Full Screen

Full Screen

aflprep_idlharness.js

Source:aflprep_idlharness.js Github

copy

Full Screen

1 * Notes for people who want to edit this file (not just use it as a library):2 *3 * Most of the interesting stuff happens in the derived classes of IdlObject,4 * especially IdlInterface. The entry point for all IdlObjects is .test(),5 * which is called by IdlArray.test(). An IdlObject is conceptually just6 * "thing we want to run tests on", and an IdlArray is an array of IdlObjects7 * with some additional data thrown in.8 *9 * The object model is based on what WebIDLParser.js produces, which is in turn10 * based on its pegjs grammar. If you want to figure out what properties an11 * object will have from WebIDLParser.js, the best way is to look at the12 * grammar:13 *14 *15 * So for instance:16 *17 * interface18 * = extAttrs:extendedAttributeList? S? "interface" S name:identifier w herit:ifInheritance? w "{" w mem:ifMember* w "}" w ";" w19 * { return { type: "interface", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; }20 *21 * This means that an "interface" object will have a .type property equal to22 * the string "interface", a .name property equal to the identifier that the23 * parser found, an .inheritance property equal to either null or the result of24 * the "ifInheritance" production found elsewhere in the grammar, and so on.25 * After each grammatical production is a JavaScript function in curly braces26 * that gets called with suitable arguments and returns some JavaScript value.27 *28 * (Note that the version of WebIDLParser.js we use might sometimes be29 * out-of-date or forked.)30 *31 * The members and methods of the classes defined by this file are all at least32 * briefly documented, hopefully.33(function(){34"use strict";35if (!('subsetTestByKey' in self)) {36 self.subsetTestByKey = function(key, callback, ...args) {37 return callback(...args);38 }39 self.shouldRunSubTest = () => true;40}41function constValue (cnt)42{43 if (cnt.type === "null") return null;44 if (cnt.type === "NaN") return NaN;45 if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity;46 if (cnt.type === "number") return +cnt.value;47 return cnt.value;48}49function minOverloadLength(overloads)50{51 if (!overloads.length) {52 return 0;53 }54 return overloads.map(function(attr) {55 return attr.arguments ? attr.arguments.filter(function(arg) {56 return !arg.optional && !arg.variadic;57 }).length : 0;58 })59 .reduce(function(m, n) { return Math.min(m, n); });60}61function globalOf(func)62{63 try {64 return func.constructor("return this;")();65 } catch (e) {66 }67 return self;68}69function isConstructor(o) {70 try {71 new (new Proxy(o, {construct: () => ({})}));72 return true;73 } catch(e) {74 return false;75 }76}77function throwOrReject(a_test, operation, fn, obj, args, message, cb)78{79 if (operation.idlType.generic !== "Promise") {80 assert_throws_js(globalOf(fn).TypeError, function() {81 fn.apply(obj, args);82 }, message);83 cb();84 } else {85 try {86 promise_rejects_js(a_test, TypeError, fn.apply(obj, args), message).then(cb, cb);87 } catch (e){88 a_test.step(function() {89 assert_unreached("Throws \"" + e + "\" instead of rejecting promise");90 cb();91 });92 }93 }94}95function awaitNCallbacks(n, cb, ctx)96{97 var counter = 0;98 return function() {99 counter++;100 if (counter >= n) {101 cb();102 }103 };104}105self.IdlHarnessError = function(message)106{107 * Message to be printed as the error's toString invocation.108 this.message = message;109};110IdlHarnessError.prototype = Object.create(Error.prototype);111IdlHarnessError.prototype.toString = function()112{113 return this.message;114};115self.IdlArray = function()116{117 * A map from strings to the corresponding named IdlObject, such as118 * IdlInterface or IdlException. These are the things that test() will run119 * tests on.120 this.members = {};121 * A map from strings to arrays of strings. The keys are interface or122 * exception names, and are expected to also exist as keys in this.members123 * (otherwise they'll be ignored). This is populated by add_objects() --124 * see documentation at the start of the file. The actual tests will be125 * run by calling this.members[name].test_object(obj) for each obj in126 * this.objects[name]. obj is a string that will be eval'd to produce a127 * JavaScript value, which is supposed to be an object implementing the128 * given IdlObject (interface, exception, etc.).129 this.objects = {};130 * When adding multiple collections of IDLs one at a time, an earlier one131 * might contain a partial interface or includes statement that depends132 * on a later one. Save these up and handle them right before we run133 * tests.134 *135 * Both this.partials and this.includes will be the objects as parsed by136 * WebIDLParser.js, not wrapped in IdlInterface or similar.137 this.partials = [];138 this.includes = [];139 * Record of skipped IDL items, in case we later realize that they are a140 * dependency (to retroactively process them).141 this.skipped = new Map();142};143IdlArray.prototype.add_idls = function(raw_idls, options)144{145 this.internal_add_idls(WebIDL2.parse(raw_idls), options);146};147IdlArray.prototype.add_untested_idls = function(raw_idls, options)148{149 var parsed_idls = WebIDL2.parse(raw_idls);150 this.mark_as_untested(parsed_idls);151 this.internal_add_idls(parsed_idls, options);152};153IdlArray.prototype.mark_as_untested = function (parsed_idls)154{155 for (var i = 0; i < parsed_idls.length; i++) {156 parsed_idls[i].untested = true;157 if ("members" in parsed_idls[i]) {158 for (var j = 0; j < parsed_idls[i].members.length; j++) {159 parsed_idls[i].members[j].untested = true;160 }161 }162 }163};164IdlArray.prototype.is_excluded_by_options = function (name, options)165{166 return options &&167 (options.except && options.except.includes(name)168 || options.only && !options.only.includes(name));169};170IdlArray.prototype.add_dependency_idls = function(raw_idls, options)171{172 return this.internal_add_dependency_idls(WebIDL2.parse(raw_idls), options);173};174IdlArray.prototype.internal_add_dependency_idls = function(parsed_idls, options)175{176 const new_options = { only: [] }177 const all_deps = new Set();178 Object.values(this.members).forEach(v => {179 if (v.base) {180 all_deps.add(v.base);181 }182 });183 this.includes.forEach(i => {184 all_deps.add(i.target);185 all_deps.add(i.includes);186 });187 this.partials.forEach(p => all_deps.add(p.name));188 Object.entries(this.members).forEach(([k, v]) => {189 if (v instanceof IdlTypedef) {190 let defs = v.idlType.union191 ? v.idlType.idlType.map(t => t.idlType)192 : [v.idlType.idlType];193 defs.forEach(d => all_deps.add(d));194 }195 });196 const attrDeps = parsedIdls => {197 return parsedIdls.reduce((deps, parsed) => {198 if (parsed.members) {199 for (const attr of Object.values(parsed.members).filter(m => m.type === 'attribute')) {200 let attrType = attr.idlType;201 if (attrType.generic) {202 deps.add(attrType.generic);203 attrType = attrType.idlType;204 }205 deps.add(attrType.idlType);206 }207 }208 if (parsed.base in this.members) {209 attrDeps([this.members[parsed.base]]).forEach(dep => deps.add(dep));210 }211 return deps;212 }, new Set());213 };214 const testedMembers = Object.values(this.members).filter(m => !m.untested && m.members);215 attrDeps(testedMembers).forEach(dep => all_deps.add(dep));216 const testedPartials = this.partials.filter(m => !m.untested && m.members);217 attrDeps(testedPartials).forEach(dep => all_deps.add(dep));218 if (options && options.except && options.only) {219 throw new IdlHarnessError("The only and except options can't be used together.");220 }221 const defined_or_untested = name => {222 return name in this.members223 || this.is_excluded_by_options(name, options);224 }225 const process = function(parsed) {226 var deps = [];227 if (parsed.name) {228 deps.push(parsed.name);229 } else if (parsed.type === "includes") {230 deps.push(parsed.target);231 deps.push(parsed.includes);232 }233 deps = deps.filter(function(name) {234 if (!name235 || name === parsed.name && defined_or_untested(name)236 || !all_deps.has(name)) {237 if (name && !(name in this.members)) {238 this.skipped.has(name)239 ? this.skipped.get(name).push(parsed)240 : this.skipped.set(name, [parsed]);241 }242 return false;243 }244 return true;245 }.bind(this));246 deps.forEach(function(name) {247 if (!new_options.only.includes(name)) {248 new_options.only.push(name);249 }250 const follow_up = new Set();251 for (const dep_type of ["inheritance", "includes"]) {252 if (parsed[dep_type]) {253 const inheriting = parsed[dep_type];254 const inheritor = parsed.name || parsed.target;255 const deps = [inheriting];256 if (dep_type !== "includes"257 || inheriting in this.members && !this.members[inheriting].untested258 || this.partials.some(function(p) {259 return p.name === inheriting;260 })) {261 deps.push(inheritor);262 }263 for (const dep of deps) {264 if (!new_options.only.includes(dep)) {265 new_options.only.push(dep);266 }267 all_deps.add(dep);268 follow_up.add(dep);269 }270 }271 }272 for (const deferred of follow_up) {273 if (this.skipped.has(deferred)) {274 const next = this.skipped.get(deferred);275 this.skipped.delete(deferred);276 next.forEach(process);277 }278 }279 }.bind(this));280 }.bind(this);281 for (let parsed of parsed_idls) {282 process(parsed);283 }284 this.mark_as_untested(parsed_idls);285 if (new_options.only.length) {286 this.internal_add_idls(parsed_idls, new_options);287 }288}289IdlArray.prototype.internal_add_idls = function(parsed_idls, options)290{291 * Internal helper called by add_idls() and add_untested_idls().292 *293 * parsed_idls is an array of objects that come from WebIDLParser.js's294 * "definitions" production. The add_untested_idls() entry point295 * additionally sets an .untested property on each object (and its296 * .members) so that they'll be skipped by test() -- they'll only be297 * used for base interfaces of tested interfaces, return types, etc.298 *299 * options is a dictionary that can have an only or except member which are300 * arrays. If only is given then only members, partials and interface301 * targets listed will be added, and if except is given only those that302 * aren't listed will be added. Only one of only and except can be used.303 if (options && options.only && options.except)304 {305 throw new IdlHarnessError("The only and except options can't be used together.");306 }307 var should_skip = name => {308 return this.is_excluded_by_options(name, options);309 }310 parsed_idls.forEach(function(parsed_idl)311 {312 var partial_types = [313 "interface",314 "interface mixin",315 "dictionary",316 "namespace",317 ];318 if (parsed_idl.partial && partial_types.includes(parsed_idl.type))319 {320 if (should_skip(parsed_idl.name))321 {322 return;323 }324 this.partials.push(parsed_idl);325 return;326 }327 if (parsed_idl.type == "includes")328 {329 if (should_skip(parsed_idl.target))330 {331 return;332 }333 this.includes.push(parsed_idl);334 return;335 }336 parsed_idl.array = this;337 if (should_skip(parsed_idl.name))338 {339 return;340 }341 if (parsed_idl.name in this.members)342 {343 throw new IdlHarnessError("Duplicate identifier " + parsed_idl.name);344 }345 switch(parsed_idl.type)346 {347 case "interface":348 this.members[parsed_idl.name] =349 break;350 case "interface mixin":351 this.members[parsed_idl.name] =352 break;353 case "dictionary":354 this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);355 break;356 case "typedef":357 this.members[parsed_idl.name] = new IdlTypedef(parsed_idl);358 break;359 case "callback":360 this.members[parsed_idl.name] = new IdlCallback(parsed_idl);361 break;362 case "enum":363 this.members[parsed_idl.name] = new IdlEnum(parsed_idl);364 break;365 case "callback interface":366 this.members[parsed_idl.name] =367 break;368 case "namespace":369 this.members[parsed_idl.name] = new IdlNamespace(parsed_idl);370 break;371 default:372 throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported";373 }374 }.bind(this));375};376IdlArray.prototype.add_objects = function(dict)377{378 for (var k in dict)379 {380 if (k in this.objects)381 {382 this.objects[k] = this.objects[k].concat(dict[k]);383 }384 else385 {386 this.objects[k] = dict[k];387 }388 }389};390IdlArray.prototype.prevent_multiple_testing = function(name)391{392 this.members[name].prevent_multiple_testing = true;393};394IdlArray.prototype.is_json_type = function(type)395{396 * Checks whether type is a JSON type as per397 var idlType = type.idlType;398 if (type.generic == "Promise") { return false; }399 if (type.union || type.generic == "record") {400 return idlType.every(this.is_json_type, this);401 }402 if (type.generic == "sequence" || type.generic == "FrozenArray") {403 return this.is_json_type(idlType[0]);404 }405 if (typeof idlType != "string") { throw new Error("Unexpected type " + JSON.stringify(idlType)); }406 switch (idlType)407 {408 case "byte":409 case "octet":410 case "short":411 case "unsigned short":412 case "long":413 case "unsigned long":414 case "long long":415 case "unsigned long long":416 case "float":417 case "double":418 case "unrestricted float":419 case "unrestricted double":420 case "boolean":421 case "DOMString":422 case "ByteString":423 case "USVString":424 case "object":425 return true;426 case "Error":427 case "DOMException":428 case "Int8Array":429 case "Int16Array":430 case "Int32Array":431 case "Uint8Array":432 case "Uint16Array":433 case "Uint32Array":434 case "Uint8ClampedArray":435 case "BigInt64Array":436 case "BigUint64Array":437 case "Float32Array":438 case "Float64Array":439 case "ArrayBuffer":440 case "DataView":441 case "any":442 return false;443 default:444 var thing = this.members[idlType];445 if (!thing) { throw new Error("Type " + idlType + " not found"); }446 if (thing instanceof IdlEnum) { return true; }447 if (thing instanceof IdlTypedef) {448 return this.is_json_type(thing.idlType);449 }450 if (thing instanceof IdlDictionary) {451 const map = new Map();452 for (const dict of thing.get_reverse_inheritance_stack()) {453 for (const m of dict.members) {454 map.set(m.name, m.idlType);455 }456 }457 return Array.from(map.values()).every(this.is_json_type, this);458 }459 if (thing instanceof IdlInterface) {460 var base;461 while (thing)462 {463 if (thing.has_to_json_regular_operation()) { return true; }464 var mixins = this.includes[thing.name];465 if (mixins) {466 mixins = mixins.map(function(id) {467 var mixin = this.members[id];468 if (!mixin) {469 throw new Error("Interface " + id + " not found (implemented by " + thing.name + ")");470 }471 return mixin;472 }, this);473 if (mixins.some(function(m) { return m.has_to_json_regular_operation() } )) { return true; }474 }475 if (!thing.base) { return false; }476 base = this.members[thing.base];477 if (!base) {478 throw new Error("Interface " + thing.base + " not found (inherited by " + thing.name + ")");479 }480 thing = base;481 }482 return false;483 }484 return false;485 }486};487function exposure_set(object, default_set) {488 var exposed = object.extAttrs && object.extAttrs.filter(a => a.name === "Exposed");489 if (exposed && exposed.length > 1) {490 throw new IdlHarnessError(491 `Multiple 'Exposed' extended attributes on ${object.name}`);492 }493 let result = default_set || ["Window"];494 if (result && !(result instanceof Set)) {495 result = new Set(result);496 }497 if (exposed && exposed.length) {498 const { rhs } = exposed[0];499 const set = rhs.type === "identifier-list" ?500 rhs.value.map(id => id.value) :501 [ rhs.value ];502 result = new Set(set);503 }504 if (result && result.has("Worker")) {505 result.delete("Worker");506 result.add("DedicatedWorker");507 result.add("ServiceWorker");508 result.add("SharedWorker");509 }510 return result;511}512function exposed_in(globals) {513 if ('Window' in self) {514 return globals.has("Window");515 }516 if ('DedicatedWorkerGlobalScope' in self &&517 self instanceof DedicatedWorkerGlobalScope) {518 return globals.has("DedicatedWorker");519 }520 if ('SharedWorkerGlobalScope' in self &&521 self instanceof SharedWorkerGlobalScope) {522 return globals.has("SharedWorker");523 }524 if ('ServiceWorkerGlobalScope' in self &&525 self instanceof ServiceWorkerGlobalScope) {526 return globals.has("ServiceWorker");527 }528 throw new IdlHarnessError("Unexpected global object");529}530 * Asserts that the given error message is thrown for the given function.531 * @param {string|IdlHarnessError} error Expected Error message.532 * @param {Function} idlArrayFunc Function operating on an IdlArray that should throw.533IdlArray.prototype.assert_throws = function(error, idlArrayFunc)534{535 try {536 idlArrayFunc.call(this, this);537 } catch (e) {538 if (e instanceof AssertionError) {539 throw e;540 }541 if (error instanceof IdlHarnessError) {542 error = error.message;543 }544 if (e.message !== error) {545 throw new IdlHarnessError(`${idlArrayFunc} threw "${e}", not the expected IdlHarnessError "${error}"`);546 }547 return;548 }549 throw new IdlHarnessError(`${idlArrayFunc} did not throw the expected IdlHarnessError`);550}551IdlArray.prototype.test = function()552{553 this.merge_partials();554 this.merge_mixins();555 for (const member of Object.values(this.members).filter(m => m.base)) {556 const lhs = member.name;557 const rhs = member.base;558 if (!(rhs in this.members)) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is undefined.`);559 const lhs_is_interface = this.members[lhs] instanceof IdlInterface;560 const rhs_is_interface = this.members[rhs] instanceof IdlInterface;561 if (rhs_is_interface != lhs_is_interface) {562 if (!lhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${lhs} is not an interface.`);563 if (!rhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is not an interface.`);564 }565 member.get_reverse_inheritance_stack();566 }567 Object.getOwnPropertyNames(this.members).forEach(function(memberName) {568 var member = this.members[memberName];569 if (!(member instanceof IdlInterface)) {570 return;571 }572 var globals = exposure_set(member);573 member.exposed = exposed_in(globals);574 member.exposureSet = globals;575 }.bind(this));576 for (var name in this.members)577 {578 this.members[name].test();579 if (name in this.objects)580 {581 const objects = this.objects[name];582 if (!objects || !Array.isArray(objects)) {583 throw new IdlHarnessError(`Invalid or empty objects for member ${name}`);584 }585 objects.forEach(function(str)586 {587 if (!this.members[name] || !(this.members[name] instanceof IdlInterface)) {588 throw new IdlHarnessError(`Invalid object member name ${name}`);589 }590 this.members[name].test_object(str);591 }.bind(this));592 }593 }594};595IdlArray.prototype.merge_partials = function()596{597 const testedPartials = new Map();598 this.partials.forEach(function(parsed_idl)599 {600 const originalExists = parsed_idl.name in this.members601 && (this.members[parsed_idl.name] instanceof IdlInterface602 || this.members[parsed_idl.name] instanceof IdlDictionary603 || this.members[parsed_idl.name] instanceof IdlNamespace);604 let partialTestName = parsed_idl.name;605 let partialTestCount = 1;606 if (testedPartials.has(parsed_idl.name)) {607 partialTestCount += testedPartials.get(parsed_idl.name);608 partialTestName = `${partialTestName}[${partialTestCount}]`;609 }610 testedPartials.set(parsed_idl.name, partialTestCount);611 if (!parsed_idl.untested) {612 test(function () {613 assert_true(originalExists, `Original ${parsed_idl.type} should be defined`);614 var expected;615 switch (parsed_idl.type) {616 case 'dictionary': expected = IdlDictionary; break;617 case 'namespace': expected = IdlNamespace; break;618 case 'interface':619 case 'interface mixin':620 default:621 expected = IdlInterface; break;622 }623 assert_true(624 expected.prototype.isPrototypeOf(this.members[parsed_idl.name]),625 `Original ${parsed_idl.name} definition should have type ${parsed_idl.type}`);626 }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: original ${parsed_idl.type} defined`);627 }628 if (!originalExists) {629 return;630 }631 if (parsed_idl.extAttrs)632 {633 const exposureAttr = parsed_idl.extAttrs.find(a => a.name === "Exposed");634 if (exposureAttr) {635 if (!parsed_idl.untested) {636 test(function () {637 const partialExposure = exposure_set(parsed_idl);638 const memberExposure = exposure_set(this.members[parsed_idl.name]);639 partialExposure.forEach(name => {640 if (!memberExposure || !memberExposure.has(name)) {641 throw new IdlHarnessError(642 `Partial ${parsed_idl.name} ${parsed_idl.type} is exposed to '${name}', the original ${parsed_idl.type} is not.`);643 }644 });645 }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: valid exposure set`);646 }647 parsed_idl.members.forEach(function (member) {648 member.extAttrs.push(exposureAttr);649 }.bind(this));650 }651 parsed_idl.extAttrs.forEach(function(extAttr)652 {653 if (extAttr.name === "Exposed") {654 return;655 }656 this.members[parsed_idl.name].extAttrs.push(extAttr);657 }.bind(this));658 }659 if (parsed_idl.members.length) {660 test(function () {661 var clash = parsed_idl.members.find(function(member) {662 return this.members[parsed_idl.name].members.find(function(m) {663 return this.are_duplicate_members(m, member);664 }.bind(this));665 }.bind(this));666 parsed_idl.members.forEach(function(member)667 {668 this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member));669 }.bind(this));670 assert_true(!clash, "member " + (clash && clash.name) + " is unique");671 }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: member names are unique`);672 }673 }.bind(this));674 this.partials = [];675}676IdlArray.prototype.merge_mixins = function()677{678 for (const parsed_idl of this.includes)679 {680 const lhs = parsed_idl.target;681 const rhs = parsed_idl.includes;682 var errStr = lhs + " includes " + rhs + ", but ";683 if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";684 if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface.";685 if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";686 if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";687 if (this.members[rhs].members.length) {688 test(function () {689 var clash = this.members[rhs].members.find(function(member) {690 return this.members[lhs].members.find(function(m) {691 return this.are_duplicate_members(m, member);692 }.bind(this));693 }.bind(this));694 this.members[rhs].members.forEach(function(member) {695 assert_true(696 this.members[lhs].members.every(m => !this.are_duplicate_members(m, member)),697 "member " + member.name + " is unique");698 this.members[lhs].members.push(new IdlInterfaceMember(member));699 }.bind(this));700 assert_true(!clash, "member " + (clash && clash.name) + " is unique");701 }.bind(this), lhs + " includes " + rhs + ": member names are unique");702 }703 }704 this.includes = [];705}706IdlArray.prototype.are_duplicate_members = function(m1, m2) {707 if (m1.name !== m2.name) {708 return false;709 }710 if (m1.type === 'operation' && m2.type === 'operation'711 && m1.arguments.length !== m2.arguments.length) {712 return false;713 }714 return true;715}716IdlArray.prototype.assert_type_is = function(value, type)717{718 if (type.idlType in this.members719 && this.members[type.idlType] instanceof IdlTypedef) {720 this.assert_type_is(value, this.members[type.idlType].idlType);721 return;722 }723 if (type.nullable && value === null)724 {725 return;726 }727 if (type.union) {728 for (var i = 0; i < type.idlType.length; i++) {729 try {730 this.assert_type_is(value, type.idlType[i]);731 return;732 } catch(e) {733 if (e instanceof AssertionError) {734 continue;735 }736 throw e;737 }738 }739 assert_true(false, "Attribute has value " + format_value(value)740 + " which doesn't match any of the types in the union");741 }742 * Helper function that tests that value is an instance of type according743 * to the rules of WebIDL. value is any JavaScript value, and type is an744 * object produced by WebIDLParser.js' "type" production. That production745 * is fairly elaborate due to the complexity of WebIDL's types, so it's746 * best to look at the grammar to figure out what properties it might have.747 if (type.idlType == "any")748 {749 return;750 }751 if (type.array)752 {753 return;754 }755 if (type.generic === "sequence")756 {757 assert_true(Array.isArray(value), "should be an Array");758 if (!value.length)759 {760 return;761 }762 this.assert_type_is(value[0], type.idlType[0]);763 return;764 }765 if (type.generic === "Promise") {766 assert_true("then" in value, "Attribute with a Promise type should have a then property");767 return;768 }769 if (type.generic === "FrozenArray") {770 assert_true(Array.isArray(value), "Value should be array");771 assert_true(Object.isFrozen(value), "Value should be frozen");772 if (!value.length)773 {774 return;775 }776 this.assert_type_is(value[0], type.idlType[0]);777 return;778 }779 type = Array.isArray(type.idlType) ? type.idlType[0] : type.idlType;780 switch(type)781 {782 case "undefined":783 assert_equals(value, undefined);784 return;785 case "boolean":786 assert_equals(typeof value, "boolean");787 return;788 case "byte":789 assert_equals(typeof value, "number");790 assert_equals(value, Math.floor(value), "should be an integer");791 assert_true(-128 <= value && value <= 127, "byte " + value + " should be in range [-128, 127]");792 return;793 case "octet":794 assert_equals(typeof value, "number");795 assert_equals(value, Math.floor(value), "should be an integer");796 assert_true(0 <= value && value <= 255, "octet " + value + " should be in range [0, 255]");797 return;798 case "short":799 assert_equals(typeof value, "number");800 assert_equals(value, Math.floor(value), "should be an integer");801 assert_true(-32768 <= value && value <= 32767, "short " + value + " should be in range [-32768, 32767]");802 return;803 case "unsigned short":804 assert_equals(typeof value, "number");805 assert_equals(value, Math.floor(value), "should be an integer");806 assert_true(0 <= value && value <= 65535, "unsigned short " + value + " should be in range [0, 65535]");807 return;808 case "long":809 assert_equals(typeof value, "number");810 assert_equals(value, Math.floor(value), "should be an integer");811 assert_true(-2147483648 <= value && value <= 2147483647, "long " + value + " should be in range [-2147483648, 2147483647]");812 return;813 case "unsigned long":814 assert_equals(typeof value, "number");815 assert_equals(value, Math.floor(value), "should be an integer");816 assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " should be in range [0, 4294967295]");817 return;818 case "long long":819 assert_equals(typeof value, "number");820 return;821 case "unsigned long long":822 case "DOMTimeStamp":823 assert_equals(typeof value, "number");824 assert_true(0 <= value, "unsigned long long should be positive");825 return;826 case "float":827 assert_equals(typeof value, "number");828 assert_equals(value, Math.fround(value), "float rounded to 32-bit float should be itself");829 assert_not_equals(value, Infinity);830 assert_not_equals(value, -Infinity);831 assert_not_equals(value, NaN);832 return;833 case "DOMHighResTimeStamp":834 case "double":835 assert_equals(typeof value, "number");836 assert_not_equals(value, Infinity);837 assert_not_equals(value, -Infinity);838 assert_not_equals(value, NaN);839 return;840 case "unrestricted float":841 assert_equals(typeof value, "number");842 assert_equals(value, Math.fround(value), "unrestricted float rounded to 32-bit float should be itself");843 return;844 case "unrestricted double":845 assert_equals(typeof value, "number");846 return;847 case "DOMString":848 assert_equals(typeof value, "string");849 return;850 case "ByteString":851 assert_equals(typeof value, "string");852 return;853 case "USVString":854 assert_equals(typeof value, "string");855 return;856 case "ArrayBufferView":857 assert_true(ArrayBuffer.isView(value));858 return;859 case "object":860 assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function");861 return;862 }863 if (!(type in this.members))864 {865 assert_true(value instanceof self[type], "wrong type: not a " + type);866 return;867 }868 if (this.members[type] instanceof IdlInterface)869 {870 assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function");871 if (value instanceof Object872 && !this.members[type].has_extended_attribute("LegacyNoInterfaceObject")873 && type in self)874 {875 assert_true(value instanceof self[type], "instanceof " + type);876 }877 }878 else if (this.members[type] instanceof IdlEnum)879 {880 assert_equals(typeof value, "string");881 }882 else if (this.members[type] instanceof IdlDictionary)883 {884 }885 else if (this.members[type] instanceof IdlCallback)886 {887 assert_equals(typeof value, "function");888 }889 else890 {891 throw new IdlHarnessError("Type " + type + " isn't an interface, callback or dictionary");892 }893};894function IdlObject() {}895IdlObject.prototype.test = function()896{897 * By default, this does nothing, so no actual tests are run for IdlObjects898 * that don't define any (e.g., IdlDictionary at the time of this writing).899};900IdlObject.prototype.has_extended_attribute = function(name)901{902 * This is only meaningful for things that support extended attributes,903 * such as interfaces, exceptions, and members.904 return this.extAttrs.some(function(o)905 {906 return o.name == name;907 });908};909function IdlDictionary(obj)910{911 * obj is an object produced by the WebIDLParser.js "dictionary"912 * production.913 this.name = obj.name;914 this.array = obj.array;915 this.members = obj.members;916 * The name (as a string) of the dictionary type we inherit from, or null917 * if there is none.918 this.base = obj.inheritance;919}920IdlDictionary.prototype = Object.create(IdlObject.prototype);921IdlDictionary.prototype.get_reverse_inheritance_stack = function() {922 return IdlInterface.prototype.get_reverse_inheritance_stack.call(this);923};924function IdlInterface(obj, is_callback, is_mixin)925{926 * obj is an object produced by the WebIDLParser.js "interface" production.927 this.name = obj.name;928 this.array = obj.array;929 * An indicator of whether we should run tests on the interface object and930 * interface prototype object. Tests on members are controlled by .untested931 * on each member, not this.932 this.untested = obj.untested;933 this.extAttrs = obj.extAttrs;934 this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); });935 if (this.has_extended_attribute("LegacyUnforgeable")) {936 this.members937 .filter(function(m) { return m.special !== "static" && (m.type == "attribute" || m.type == "operation"); })938 .forEach(function(m) { return m.isUnforgeable = true; });939 }940 * The name (as a string) of the type we inherit from, or null if there is941 * none.942 this.base = obj.inheritance;943 this._is_callback = is_callback;944 this._is_mixin = is_mixin;945}946IdlInterface.prototype = Object.create(IdlObject.prototype);947IdlInterface.prototype.is_callback = function()948{949 return this._is_callback;950};951IdlInterface.prototype.is_mixin = function()952{953 return this._is_mixin;954};955IdlInterface.prototype.has_constants = function()956{957 return this.members.some(function(member) {958 return member.type === "const";959 });960};961IdlInterface.prototype.get_unscopables = function()962{963 return this.members.filter(function(member) {964 return member.isUnscopable;965 });966};967IdlInterface.prototype.is_global = function()968{969 return this.extAttrs.some(function(attribute) {970 return attribute.name === "Global";971 });972};973 * Value of the LegacyNamespace extended attribute, if any.974 *975IdlInterface.prototype.get_legacy_namespace = function()976{977 var legacyNamespace = this.extAttrs.find(function(attribute) {978 return attribute.name === "LegacyNamespace";979 });980 return legacyNamespace ? legacyNamespace.rhs.value : undefined;981};982IdlInterface.prototype.get_interface_object_owner = function()983{984 var legacyNamespace = this.get_legacy_namespace();985 return legacyNamespace ? self[legacyNamespace] : self;986};987IdlInterface.prototype.should_have_interface_object = function()988{989 return this.is_callback() ? this.has_constants() : !this.has_extended_attribute("LegacyNoInterfaceObject");990};991IdlInterface.prototype.assert_interface_object_exists = function()992{993 var owner = this.get_legacy_namespace() || "self";994 assert_own_property(self[owner], this.name, owner + " does not have own property " + format_value(this.name));995};996IdlInterface.prototype.get_interface_object = function() {997 if (!this.should_have_interface_object()) {998 var reason = this.is_callback() ? "lack of declared constants" : "declared [LegacyNoInterfaceObject] attribute";999 throw new IdlHarnessError(this.name + " has no interface object due to " + reason);1000 }1001 return this.get_interface_object_owner()[this.name];1002};1003IdlInterface.prototype.get_qualified_name = function() {1004 var legacyNamespace = this.get_legacy_namespace();1005 if (legacyNamespace) {1006 return legacyNamespace + "." + this.name;1007 }1008 return this.name;1009};1010IdlInterface.prototype.has_to_json_regular_operation = function() {1011 return this.members.some(function(m) {1012 return m.is_to_json_regular_operation();1013 });1014};1015IdlInterface.prototype.has_default_to_json_regular_operation = function() {1016 return this.members.some(function(m) {1017 return m.is_to_json_regular_operation() && m.has_extended_attribute("Default");1018 });1019};1020 * with the order reversed.1021 *1022 * The order is reversed so that the base class comes first in the list, because1023 * this is what all call sites need.1024 *1025 * So given:1026 *1027 * A : B {};1028 * B : C {};1029 * C {};1030 *1031 * then A.get_reverse_inheritance_stack() returns [C, B, A],1032 * and B.get_reverse_inheritance_stack() returns [C, B].1033 *1034 * Note: as dictionary inheritance is expressed identically by the AST,1035 * this works just as well for getting a stack of inherited dictionaries.1036IdlInterface.prototype.get_reverse_inheritance_stack = function() {1037 const stack = [this];1038 let idl_interface = this;1039 while (idl_interface.base) {1040 const base = this.array.members[idl_interface.base];1041 if (!base) {1042 throw new Error(idl_interface.type + " " + idl_interface.base + " not found (inherited by " + idl_interface.name + ")");1043 } else if (stack.indexOf(base) > -1) {1044 stack.unshift(base);1045 const dep_chain = stack.map(i => i.name).join(',');1046 throw new IdlHarnessError(`${this.name} has a circular dependency: ${dep_chain}`);1047 }1048 idl_interface = base;1049 stack.unshift(idl_interface);1050 }1051 return stack;1052};1053 * Implementation of1054 * for testing purposes.1055 *1056 * Collects the IDL types of the attributes that meet the criteria1057 * for inclusion in the default toJSON operation for easy1058 * comparison with actual value1059IdlInterface.prototype.default_to_json_operation = function() {1060 const map = new Map()1061 let isDefault = false;1062 for (const I of this.get_reverse_inheritance_stack()) {1063 if (I.has_default_to_json_regular_operation()) {1064 isDefault = true;1065 for (const m of I.members) {1066 if (m.special !== "static" && m.type == "attribute" && I.array.is_json_type(m.idlType)) {1067 map.set(m.name, m.idlType);1068 }1069 }1070 } else if (I.has_to_json_regular_operation()) {1071 isDefault = false;1072 }1073 }1074 return isDefault ? map : null;1075};1076IdlInterface.prototype.test = function()1077{1078 if (this.has_extended_attribute("LegacyNoInterfaceObject") || this.is_mixin())1079 {1080 return;1081 }1082 if (!this.exposed)1083 {1084 if (!this.untested)1085 {1086 subsetTestByKey(this.name, test, function() {1087 assert_false(this.name in self);1088 }.bind(this), this.name + " interface: existence and properties of interface object");1089 }1090 return;1091 }1092 if (!this.untested)1093 {1094 this.test_self();1095 }1096 this.test_members();1097};1098IdlInterface.prototype.constructors = function()1099{1100 return this.members1101 .filter(function(m) { return m.type == "constructor"; });1102}1103IdlInterface.prototype.test_self = function()1104{1105 subsetTestByKey(this.name, test, function()1106 {1107 if (!this.should_have_interface_object()) {1108 return;1109 }1110 this.assert_interface_object_exists();1111 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object_owner(), this.name);1112 assert_false("get" in desc, "self's property " + format_value(this.name) + " should not have a getter");1113 assert_false("set" in desc, "self's property " + format_value(this.name) + " should not have a setter");1114 assert_true(desc.writable, "self's property " + format_value(this.name) + " should be writable");1115 assert_false(desc.enumerable, "self's property " + format_value(this.name) + " should not be enumerable");1116 assert_true(desc.configurable, "self's property " + format_value(this.name) + " should be configurable");1117 if (this.is_callback()) {1118 assert_equals(Object.getPrototypeOf(this.get_interface_object()), Function.prototype,1119 "prototype of self's property " + format_value(this.name) + " is not Object.prototype");1120 return;1121 }1122 assert_class_string(this.get_interface_object(), "Function", "class string of " + this.name);1123 var prototype = Object.getPrototypeOf(this.get_interface_object());1124 if (this.base) {1125 var inherited_interface = this.array.members[this.base];1126 if (!inherited_interface.has_extended_attribute("LegacyNoInterfaceObject")) {1127 inherited_interface.assert_interface_object_exists();1128 assert_equals(prototype, inherited_interface.get_interface_object(),1129 'prototype of ' + this.name + ' is not ' +1130 this.base);1131 }1132 } else {1133 assert_equals(prototype, Function.prototype,1134 "prototype of self's property " + format_value(this.name) + " is not Function.prototype");1135 }1136 assert_true(isConstructor(this.get_interface_object()), "interface object must pass IsConstructor check");1137 if (!this.constructors().length) {1138 var interface_object = this.get_interface_object();1139 assert_throws_js(globalOf(interface_object).TypeError, function() {1140 interface_object();1141 }, "interface object didn't throw TypeError when called as a function");1142 assert_throws_js(globalOf(interface_object).TypeError, function() {1143 new interface_object();1144 }, "interface object didn't throw TypeError when called as a constructor");1145 }1146 }.bind(this), this.name + " interface: existence and properties of interface object");1147 if (this.should_have_interface_object() && !this.is_callback()) {1148 subsetTestByKey(this.name, test, function() {1149 this.assert_interface_object_exists();1150 assert_own_property(this.get_interface_object(), "length");1151 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "length");1152 assert_false("get" in desc, this.name + ".length should not have a getter");1153 assert_false("set" in desc, this.name + ".length should not have a setter");1154 assert_false(desc.writable, this.name + ".length should not be writable");1155 assert_false(desc.enumerable, this.name + ".length should not be enumerable");1156 assert_true(desc.configurable, this.name + ".length should be configurable");1157 var constructors = this.constructors();1158 var expected_length = minOverloadLength(constructors);1159 assert_equals(this.get_interface_object().length, expected_length, "wrong value for " + this.name + ".length");1160 }.bind(this), this.name + " interface object length");1161 }1162 if (this.should_have_interface_object()) {1163 subsetTestByKey(this.name, test, function() {1164 this.assert_interface_object_exists();1165 assert_own_property(this.get_interface_object(), "name");1166 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "name");1167 assert_false("get" in desc, this.name + ".name should not have a getter");1168 assert_false("set" in desc, this.name + ".name should not have a setter");1169 assert_false(desc.writable, this.name + ".name should not be writable");1170 assert_false(desc.enumerable, this.name + ".name should not be enumerable");1171 assert_true(desc.configurable, this.name + ".name should be configurable");1172 assert_equals(this.get_interface_object().name, this.name, "wrong value for " + this.name + ".name");1173 }.bind(this), this.name + " interface object name");1174 }1175 if (this.has_extended_attribute("LegacyWindowAlias")) {1176 subsetTestByKey(this.name, test, function()1177 {1178 var aliasAttrs = this.extAttrs.filter(function(o) { return o.name === "LegacyWindowAlias"; });1179 if (aliasAttrs.length > 1) {1180 throw new IdlHarnessError("Invalid IDL: multiple LegacyWindowAlias extended attributes on " + this.name);1181 }1182 if (this.is_callback()) {1183 throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on non-interface " + this.name);1184 }1185 if (!this.exposureSet.has("Window")) {1186 throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on " + this.name + " which is not exposed in Window");1187 }1188 var rhs = aliasAttrs[0].rhs;1189 if (!rhs) {1190 throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on " + this.name + " without identifier");1191 }1192 var aliases;1193 if (rhs.type === "identifier-list") {1194 aliases = rhs.value.map(id => id.value);1195 aliases = [ rhs.value ];1196 }1197 var alias;1198 if (exposed_in(exposure_set(this, this.exposureSet)) && 'document' in self) {1199 for (alias of aliases) {1200 assert_true(alias in self, alias + " should exist");1201 assert_equals(self[alias], this.get_interface_object(), "self." + alias + " should be the same value as self." + this.get_qualified_name());1202 var desc = Object.getOwnPropertyDescriptor(self, alias);1203 assert_equals(desc.value, this.get_interface_object(), "wrong value in " + alias + " property descriptor");1204 assert_true(desc.writable, alias + " should be writable");1205 assert_false(desc.enumerable, alias + " should not be enumerable");1206 assert_true(desc.configurable, alias + " should be configurable");1207 assert_false('get' in desc, alias + " should not have a getter");1208 assert_false('set' in desc, alias + " should not have a setter");1209 }1210 } else {1211 for (alias of aliases) {1212 assert_false(alias in self, alias + " should not exist");1213 }1214 }1215 }.bind(this), this.name + " interface: legacy window alias");1216 }1217 if (this.has_extended_attribute("LegacyFactoryFunction")) {1218 var constructors = this.extAttrs1219 .filter(function(attr) { return attr.name == "LegacyFactoryFunction"; });1220 if (constructors.length !== 1) {1221 throw new IdlHarnessError("Internal error: missing support for multiple LegacyFactoryFunction extended attributes");1222 }1223 var constructor = constructors[0];1224 var min_length = minOverloadLength([constructor]);1225 subsetTestByKey(this.name, test, function()1226 {1227 var name = constructor.rhs.value;1228 assert_own_property(self, name);1229 var desc = Object.getOwnPropertyDescriptor(self, name);1230 assert_equals(desc.value, self[name], "wrong value in " + name + " property descriptor");1231 assert_true(desc.writable, name + " should be writable");1232 assert_false(desc.enumerable, name + " should not be enumerable");1233 assert_true(desc.configurable, name + " should be configurable");1234 assert_false("get" in desc, name + " should not have a getter");1235 assert_false("set" in desc, name + " should not have a setter");1236 }.bind(this), this.name + " interface: named constructor");1237 subsetTestByKey(this.name, test, function()1238 {1239 var name = constructor.rhs.value;1240 var value = self[name];1241 assert_equals(typeof value, "function", "type of value in " + name + " property descriptor");1242 assert_not_equals(value, this.get_interface_object(), "wrong value in " + name + " property descriptor");1243 assert_equals(Object.getPrototypeOf(value), Function.prototype, "wrong value for " + name + "'s prototype");1244 }.bind(this), this.name + " interface: named constructor object");1245 subsetTestByKey(this.name, test, function()1246 {1247 var name = constructor.rhs.value;1248 var expected = this.get_interface_object().prototype;1249 var desc = Object.getOwnPropertyDescriptor(self[name], "prototype");1250 assert_equals(desc.value, expected, "wrong value for " + name + ".prototype");1251 assert_false(desc.writable, "prototype should not be writable");1252 assert_false(desc.enumerable, "prototype should not be enumerable");1253 assert_false(desc.configurable, "prototype should not be configurable");1254 assert_false("get" in desc, "prototype should not have a getter");1255 assert_false("set" in desc, "prototype should not have a setter");1256 }.bind(this), this.name + " interface: named constructor prototype property");1257 subsetTestByKey(this.name, test, function()1258 {1259 var name = constructor.rhs.value;1260 var desc = Object.getOwnPropertyDescriptor(self[name], "name");1261 assert_equals(desc.value, name, "wrong value for " + name + ".name");1262 assert_false(desc.writable, "name should not be writable");1263 assert_false(desc.enumerable, "name should not be enumerable");1264 assert_true(desc.configurable, "name should be configurable");1265 assert_false("get" in desc, "name should not have a getter");1266 assert_false("set" in desc, "name should not have a setter");1267 }.bind(this), this.name + " interface: named constructor name");1268 subsetTestByKey(this.name, test, function()1269 {1270 var name = constructor.rhs.value;1271 var desc = Object.getOwnPropertyDescriptor(self[name], "length");1272 assert_equals(desc.value, min_length, "wrong value for " + name + ".length");1273 assert_false(desc.writable, "length should not be writable");1274 assert_false(desc.enumerable, "length should not be enumerable");1275 assert_true(desc.configurable, "length should be configurable");1276 assert_false("get" in desc, "length should not have a getter");1277 assert_false("set" in desc, "length should not have a setter");1278 }.bind(this), this.name + " interface: named constructor length");1279 subsetTestByKey(this.name, test, function()1280 {1281 var name = constructor.rhs.value;1282 var args = constructor.arguments.map(function(arg) {1283 return create_suitable_object(arg.idlType);1284 });1285 assert_throws_js(globalOf(self[name]).TypeError, function() {1286 self[name](...args);1287 }.bind(this));1288 }.bind(this), this.name + " interface: named constructor without 'new'");1289 }1290 subsetTestByKey(this.name, test, function()1291 {1292 if (!this.should_have_interface_object()) {1293 return;1294 }1295 this.assert_interface_object_exists();1296 if (this.is_callback()) {1297 assert_false("prototype" in this.get_interface_object(),1298 this.name + ' should not have a "prototype" property');1299 return;1300 }1301 assert_own_property(this.get_interface_object(), "prototype",1302 'interface "' + this.name + '" does not have own property "prototype"');1303 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "prototype");1304 assert_false("get" in desc, this.name + ".prototype should not have a getter");1305 assert_false("set" in desc, this.name + ".prototype should not have a setter");1306 assert_false(desc.writable, this.name + ".prototype should not be writable");1307 assert_false(desc.enumerable, this.name + ".prototype should not be enumerable");1308 assert_false(desc.configurable, this.name + ".prototype should not be configurable");1309 if (this.name === "Window") {1310 assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype),1311 'WindowProperties',1312 'Class name for prototype of Window' +1313 '.prototype is not "WindowProperties"');1314 } else {1315 var inherit_interface, inherit_interface_interface_object;1316 if (this.base) {1317 inherit_interface = this.base;1318 var parent = this.array.members[inherit_interface];1319 if (!parent.has_extended_attribute("LegacyNoInterfaceObject")) {1320 parent.assert_interface_object_exists();1321 inherit_interface_interface_object = parent.get_interface_object();1322 }1323 } else if (this.name === "DOMException") {1324 inherit_interface = 'Error';1325 inherit_interface_interface_object = self.Error;1326 } else {1327 inherit_interface = 'Object';1328 inherit_interface_interface_object = self.Object;1329 }1330 if (inherit_interface_interface_object) {1331 assert_not_equals(inherit_interface_interface_object, undefined,1332 'should inherit from ' + inherit_interface + ', but there is no such property');1333 assert_own_property(inherit_interface_interface_object, 'prototype',1334 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property');1335 assert_equals(Object.getPrototypeOf(this.get_interface_object().prototype),1336 inherit_interface_interface_object.prototype,1337 'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype');1338 } else {1339 assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype),1340 inherit_interface + 'Prototype',1341 'Class name for prototype of ' + this.name +1342 '.prototype is not "' + inherit_interface + 'Prototype"');1343 }1344 }1345 if (!this.has_stringifier()) {1346 }1347 }.bind(this), this.name + " interface: existence and properties of interface prototype object");1348 if (this.is_global()) {1349 this.test_immutable_prototype("interface prototype object", this.get_interface_object().prototype);1350 }1351 subsetTestByKey(this.name, test, function()1352 {1353 if (!this.should_have_interface_object()) {1354 return;1355 }1356 this.assert_interface_object_exists();1357 if (this.is_callback()) {1358 assert_false("prototype" in this.get_interface_object(),1359 this.name + ' should not have a "prototype" property');1360 return;1361 }1362 assert_own_property(this.get_interface_object(), "prototype",1363 'interface "' + this.name + '" does not have own property "prototype"');1364 assert_own_property(this.get_interface_object().prototype, "constructor",1365 this.name + '.prototype does not have own property "constructor"');1366 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, "constructor");1367 assert_false("get" in desc, this.name + ".prototype.constructor should not have a getter");1368 assert_false("set" in desc, this.name + ".prototype.constructor should not have a setter");1369 assert_true(desc.writable, this.name + ".prototype.constructor should be writable");1370 assert_false(desc.enumerable, this.name + ".prototype.constructor should not be enumerable");1371 assert_true(desc.configurable, this.name + ".prototype.constructor should be configurable");1372 assert_equals(this.get_interface_object().prototype.constructor, this.get_interface_object(),1373 this.name + '.prototype.constructor is not the same object as ' + this.name);1374 }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');1375 subsetTestByKey(this.name, test, function()1376 {1377 if (!this.should_have_interface_object()) {1378 return;1379 }1380 this.assert_interface_object_exists();1381 if (this.is_callback()) {1382 assert_false("prototype" in this.get_interface_object(),1383 this.name + ' should not have a "prototype" property');1384 return;1385 }1386 assert_own_property(this.get_interface_object(), "prototype",1387 'interface "' + this.name + '" does not have own property "prototype"');1388 var unscopables = this.get_unscopables().map(m => m.name);1389 var proto = this.get_interface_object().prototype;1390 if (unscopables.length != 0) {1391 assert_own_property(1392 proto, Symbol.unscopables,1393 this.name + '.prototype should have an @@unscopables property');1394 var desc = Object.getOwnPropertyDescriptor(proto, Symbol.unscopables);1395 assert_false("get" in desc,1396 this.name + ".prototype[Symbol.unscopables] should not have a getter");1397 assert_false("set" in desc, this.name + ".prototype[Symbol.unscopables] should not have a setter");1398 assert_false(desc.writable, this.name + ".prototype[Symbol.unscopables] should not be writable");1399 assert_false(desc.enumerable, this.name + ".prototype[Symbol.unscopables] should not be enumerable");1400 assert_true(desc.configurable, this.name + ".prototype[Symbol.unscopables] should be configurable");1401 assert_equals(desc.value, proto[Symbol.unscopables],1402 this.name + '.prototype[Symbol.unscopables] should be in the descriptor');1403 assert_equals(typeof desc.value, "object",1404 this.name + '.prototype[Symbol.unscopables] should be an object');1405 assert_equals(Object.getPrototypeOf(desc.value), null,1406 this.name + '.prototype[Symbol.unscopables] should have a null prototype');1407 assert_equals(Object.getOwnPropertySymbols(desc.value).length,1408 0,1409 this.name + '.prototype[Symbol.unscopables] should have the right number of symbol-named properties');1410 var observed = Object.getOwnPropertyNames(desc.value);1411 for (var prop of observed) {1412 assert_not_equals(unscopables.indexOf(prop),1413 -1,1414 this.name + '.prototype[Symbol.unscopables] has unexpected property "' + prop + '"');1415 }1416 } else {1417 assert_equals(Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.unscopables),1418 undefined,1419 this.name + '.prototype should not have @@unscopables');1420 }1421 }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s @@unscopables property');1422};1423IdlInterface.prototype.test_immutable_prototype = function(type, obj)1424{1425 if (typeof Object.setPrototypeOf !== "function") {1426 return;1427 }1428 subsetTestByKey(this.name, test, function(t) {1429 var originalValue = Object.getPrototypeOf(obj);1430 var newValue = Object.create(null);1431 t.add_cleanup(function() {1432 try {1433 Object.setPrototypeOf(obj, originalValue);1434 } catch (err) {}1435 });1436 assert_throws_js(TypeError, function() {1437 Object.setPrototypeOf(obj, newValue);1438 });1439 assert_equals(1440 Object.getPrototypeOf(obj),1441 originalValue,1442 "original value not modified"1443 );1444 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1445 "of " + type + " - setting to a new value via Object.setPrototypeOf " +1446 "should throw a TypeError");1447 subsetTestByKey(this.name, test, function(t) {1448 var originalValue = Object.getPrototypeOf(obj);1449 var newValue = Object.create(null);1450 t.add_cleanup(function() {1451 let setter = Object.getOwnPropertyDescriptor(1452 Object.prototype, '__proto__'1453 ).set;1454 try {1455 setter.call(obj, originalValue);1456 } catch (err) {}1457 });1458 let setter;1459 {1460 let cur = obj;1461 while (cur) {1462 const desc = Object.getOwnPropertyDescriptor(cur, "__proto__");1463 if (desc) {1464 setter = desc.set;1465 break;1466 }1467 cur = Object.getPrototypeOf(cur);1468 }1469 }1470 assert_throws_js(globalOf(setter).TypeError, function() {1471 obj.__proto__ = newValue;1472 });1473 assert_equals(1474 Object.getPrototypeOf(obj),1475 originalValue,1476 "original value not modified"1477 );1478 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1479 "of " + type + " - setting to a new value via __proto__ " +1480 "should throw a TypeError");1481 subsetTestByKey(this.name, test, function(t) {1482 var originalValue = Object.getPrototypeOf(obj);1483 var newValue = Object.create(null);1484 t.add_cleanup(function() {1485 try {1486 Reflect.setPrototypeOf(obj, originalValue);1487 } catch (err) {}1488 });1489 assert_false(Reflect.setPrototypeOf(obj, newValue));1490 assert_equals(1491 Object.getPrototypeOf(obj),1492 originalValue,1493 "original value not modified"1494 );1495 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1496 "of " + type + " - setting to a new value via Reflect.setPrototypeOf " +1497 "should return false");1498 subsetTestByKey(this.name, test, function() {1499 var originalValue = Object.getPrototypeOf(obj);1500 Object.setPrototypeOf(obj, originalValue);1501 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1502 "of " + type + " - setting to its original value via Object.setPrototypeOf " +1503 "should not throw");1504 subsetTestByKey(this.name, test, function() {1505 var originalValue = Object.getPrototypeOf(obj);1506 obj.__proto__ = originalValue;1507 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1508 "of " + type + " - setting to its original value via __proto__ " +1509 "should not throw");1510 subsetTestByKey(this.name, test, function() {1511 var originalValue = Object.getPrototypeOf(obj);1512 assert_true(Reflect.setPrototypeOf(obj, originalValue));1513 }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " +1514 "of " + type + " - setting to its original value via Reflect.setPrototypeOf " +1515 "should return true");1516};1517IdlInterface.prototype.test_member_const = function(member)1518{1519 if (!this.has_constants()) {1520 throw new IdlHarnessError("Internal error: test_member_const called without any constants");1521 }1522 subsetTestByKey(this.name, test, function()1523 {1524 this.assert_interface_object_exists();1525 assert_own_property(this.get_interface_object(), member.name);1526 assert_equals(this.get_interface_object()[member.name], constValue(member.value),1527 "property has wrong value");1528 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name);1529 assert_false("get" in desc, "property should not have a getter");1530 assert_false("set" in desc, "property should not have a setter");1531 assert_false(desc.writable, "property should not be writable");1532 assert_true(desc.enumerable, "property should be enumerable");1533 assert_false(desc.configurable, "property should not be configurable");1534 }.bind(this), this.name + " interface: constant " + member.name + " on interface object");1535 subsetTestByKey(this.name, test, function()1536 {1537 this.assert_interface_object_exists();1538 if (this.is_callback()) {1539 assert_false("prototype" in this.get_interface_object(),1540 this.name + ' should not have a "prototype" property');1541 return;1542 }1543 assert_own_property(this.get_interface_object(), "prototype",1544 'interface "' + this.name + '" does not have own property "prototype"');1545 assert_own_property(this.get_interface_object().prototype, member.name);1546 assert_equals(this.get_interface_object().prototype[member.name], constValue(member.value),1547 "property has wrong value");1548 var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name);1549 assert_false("get" in desc, "property should not have a getter");1550 assert_false("set" in desc, "property should not have a setter");1551 assert_false(desc.writable, "property should not be writable");1552 assert_true(desc.enumerable, "property should be enumerable");1553 assert_false(desc.configurable, "property should not be configurable");1554 }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");1555};1556IdlInterface.prototype.test_member_attribute = function(member)1557 {1558 if (!shouldRunSubTest(this.name)) {1559 return;1560 }1561 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: attribute " + member.name);1562 a_test.step(function()1563 {1564 if (!this.should_have_interface_object()) {1565 a_test.done();1566 return;1567 }1568 this.assert_interface_object_exists();1569 assert_own_property(this.get_interface_object(), "prototype",1570 'interface "' + this.name + '" does not have own property "prototype"');1571 if (member.special === "static") {1572 assert_own_property(this.get_interface_object(), member.name,1573 "The interface object must have a property " +1574 format_value(member.name));1575 a_test.done();1576 return;1577 }1578 this.do_member_unscopable_asserts(member);1579 if (this.is_global()) {1580 assert_own_property(self, member.name,1581 "The global object must have a property " +1582 format_value(member.name));1583 assert_false(member.name in this.get_interface_object().prototype,1584 "The prototype object should not have a property " +1585 format_value(member.name));1586 var getter = Object.getOwnPropertyDescriptor(self, member.name).get;1587 assert_equals(typeof(getter), "function",1588 format_value(member.name) + " must have a getter");1589 var gotValue;1590 var propVal;1591 try {1592 propVal = self[member.name];1593 gotValue = true;1594 } catch (e) {1595 gotValue = false;1596 }1597 if (gotValue) {1598 assert_equals(propVal, getter.call(undefined),1599 "Gets on a global should not require an explicit this");1600 }1601 this.do_interface_attribute_asserts(self, member, a_test);1602 } else {1603 assert_true(member.name in this.get_interface_object().prototype,1604 "The prototype object must have a property " +1605 format_value(member.name));1606 if (!member.has_extended_attribute("LegacyLenientThis")) {1607 if (member.idlType.generic !== "Promise") {1608 assert_throws_js(TypeError, function() {1609 this.get_interface_object().prototype[member.name];1610 }.bind(this), "getting property on prototype object must throw TypeError");1611 this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test);1612 } else {1613 promise_rejects_js(a_test, TypeError,1614 this.get_interface_object().prototype[member.name])1615 .then(a_test.step_func(function() {1616 this.do_interface_attribute_asserts(this.get_interface_object().prototype,1617 member, a_test);1618 }.bind(this)));1619 }1620 } else {1621 assert_equals(this.get_interface_object().prototype[member.name], undefined,1622 "getting property on prototype object must return undefined");1623 this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test);1624 }1625 }1626 }.bind(this));1627};1628IdlInterface.prototype.test_member_operation = function(member)1629{1630 if (!shouldRunSubTest(this.name)) {1631 return;1632 }1633 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: operation " + member);1634 a_test.step(function()1635 {1636 if (!this.should_have_interface_object()) {1637 a_test.done();1638 return;1639 }1640 this.assert_interface_object_exists();1641 if (this.is_callback()) {1642 assert_false("prototype" in this.get_interface_object(),1643 this.name + ' should not have a "prototype" property');1644 a_test.done();1645 return;1646 }1647 assert_own_property(this.get_interface_object(), "prototype",1648 'interface "' + this.name + '" does not have own property "prototype"');1649 var memberHolderObject;1650 if (member.special === "static") {1651 assert_own_property(this.get_interface_object(), member.name,1652 "interface object missing static operation");1653 memberHolderObject = this.get_interface_object();1654 } else if (this.is_global()) {1655 assert_own_property(self, member.name,1656 "global object missing non-static operation");1657 memberHolderObject = self;1658 } else {1659 assert_own_property(this.get_interface_object().prototype, member.name,1660 "interface prototype object missing non-static operation");1661 memberHolderObject = this.get_interface_object().prototype;1662 }1663 this.do_member_unscopable_asserts(member);1664 this.do_member_operation_asserts(memberHolderObject, member, a_test);1665 }.bind(this));1666};1667IdlInterface.prototype.do_member_unscopable_asserts = function(member)1668{1669 if (!member.isUnscopable) {1670 return;1671 }1672 var unscopables = this.get_interface_object().prototype[Symbol.unscopables];1673 var prop = member.name;1674 var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop);1675 assert_equals(typeof propDesc, "object",1676 this.name + '.prototype[Symbol.unscopables].' + prop + ' must exist')1677 assert_false("get" in propDesc,1678 this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no getter');1679 assert_false("set" in propDesc,1680 this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no setter');1681 assert_true(propDesc.writable,1682 this.name + '.prototype[Symbol.unscopables].' + prop + ' must be writable');1683 assert_true(propDesc.enumerable,1684 this.name + '.prototype[Symbol.unscopables].' + prop + ' must be enumerable');1685 assert_true(propDesc.configurable,1686 this.name + '.prototype[Symbol.unscopables].' + prop + ' must be configurable');1687 assert_equals(propDesc.value, true,1688 this.name + '.prototype[Symbol.unscopables].' + prop + ' must have the value `true`');1689};1690IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject, member, a_test)1691{1692 var done = a_test.done.bind(a_test);1693 var operationUnforgeable = member.isUnforgeable;1694 var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name);1695 assert_false("get" in desc, "property should not have a getter");1696 assert_false("set" in desc, "property should not have a setter");1697 assert_equals(desc.writable, !operationUnforgeable,1698 "property should be writable if and only if not unforgeable");1699 assert_true(desc.enumerable, "property should be enumerable");1700 assert_equals(desc.configurable, !operationUnforgeable,1701 "property should be configurable if and only if not unforgeable");1702 assert_equals(typeof memberHolderObject[member.name], "function",1703 "property must be a function");1704 const ctors = this.members.filter(function(m) {1705 return m.type == "operation" && m.name == member.name;1706 });1707 assert_equals(1708 memberHolderObject[member.name].length,1709 minOverloadLength(ctors),1710 "property has wrong .length");1711 assert_equals(1712 memberHolderObject[member.name].name,1713 member.name,1714 "property has wrong .name");1715 var args = member.arguments.map(function(arg) {1716 return create_suitable_object(arg.idlType);1717 });1718 if (member.special !== "static") {1719 var cb;1720 if (!this.is_global() &&1721 memberHolderObject[member.name] != self[member.name])1722 {1723 cb = awaitNCallbacks(2, done);1724 throwOrReject(a_test, member, memberHolderObject[member.name], null, args,1725 "calling operation with this = null didn't throw TypeError", cb);1726 } else {1727 cb = awaitNCallbacks(1, done);1728 }1729 throwOrReject(a_test, member, memberHolderObject[member.name], {}, args,1730 "calling operation with this = {} didn't throw TypeError", cb);1731 } else {1732 done();1733 }1734}1735IdlInterface.prototype.test_to_json_operation = function(desc, memberHolderObject, member) {1736 var instanceName = memberHolderObject && memberHolderObject.constructor.name1737 || member.name + " object";1738 if (member.has_extended_attribute("Default")) {1739 subsetTestByKey(this.name, test, function() {1740 var map = this.default_to_json_operation();1741 var json = memberHolderObject.toJSON();1742 map.forEach(function(type, k) {1743 assert_true(k in json, "property " + JSON.stringify(k) + " should be present in the output of " + this.name + ".prototype.toJSON()");1744 var descriptor = Object.getOwnPropertyDescriptor(json, k);1745 assert_true(descriptor.writable, "property " + k + " should be writable");1746 assert_true(descriptor.configurable, "property " + k + " should be configurable");1747 assert_true(descriptor.enumerable, "property " + k + " should be enumerable");1748 this.array.assert_type_is(json[k], type);1749 delete json[k];1750 }, this);1751 }.bind(this), this.name + " interface: default toJSON operation on " + desc);1752 } else {1753 subsetTestByKey(this.name, test, function() {1754 assert_true(this.array.is_json_type(member.idlType), JSON.stringify(member.idlType) + " is not an appropriate return value for the toJSON operation of " + instanceName);1755 this.array.assert_type_is(memberHolderObject.toJSON(), member.idlType);1756 }.bind(this), this.name + " interface: toJSON operation on " + desc);1757 }1758};1759IdlInterface.prototype.test_member_iterable = function(member)1760{1761 subsetTestByKey(this.name, test, function()1762 {1763 var isPairIterator = member.idlType.length === 2;1764 var proto = this.get_interface_object().prototype;1765 var iteratorDesc = Object.getOwnPropertyDescriptor(proto, Symbol.iterator);1766 assert_true(iteratorDesc.writable, "@@iterator property should be writable");1767 assert_true(iteratorDesc.configurable, "@@iterator property should be configurable");1768 assert_false(iteratorDesc.enumerable, "@@iterator property should not be enumerable");1769 assert_equals(typeof iteratorDesc.value, "function", "@@iterator property should be a function");1770 assert_equals(iteratorDesc.value.length, 0, "@@iterator function object length should be 0");1771 assert_equals(iteratorDesc.value.name, isPairIterator ? "entries" : "values", "@@iterator function object should have the right name");1772 if (isPairIterator) {1773 assert_equals(proto["entries"], proto[Symbol.iterator], "entries method should be the same as @@iterator method");1774 [1775 ["entries", 0],1776 ["keys", 0],1777 ["values", 0],1778 ["forEach", 1]1779 ].forEach(([property, length]) => {1780 var desc = Object.getOwnPropertyDescriptor(proto, property);1781 assert_equals(typeof desc.value, "function", property + " property should be a function");1782 assert_equals(desc.value.length, length, property + " function object length should be " + length);1783 assert_equals(desc.value.name, property, property + " function object should have the right name");1784 });1785 } else {1786 assert_equals(proto[Symbol.iterator], Array.prototype[Symbol.iterator], "@@iterator method should be the same as Array prototype's");1787 ["entries", "keys", "values", "forEach", Symbol.iterator].forEach(property => {1788 var propertyName = property === Symbol.iterator ? "@@iterator" : property;1789 assert_equals(proto[property], Array.prototype[property], propertyName + " method should be the same as Array prototype's");1790 });1791 }1792 }.bind(this), this.name + " interface: iterable<" + member.idlType.map(function(t) { return t.idlType; }).join(", ") + ">");1793};1794IdlInterface.prototype.test_member_async_iterable = function(member)1795{1796 subsetTestByKey(this.name, test, function()1797 {1798 var isPairIterator = member.idlType.length === 2;1799 var proto = this.get_interface_object().prototype;1800 var iteratorDesc = Object.getOwnPropertyDescriptor(proto, Symbol.asyncIterator);1801 assert_true(iteratorDesc.writable, "@@asyncIterator property should be writable");1802 assert_true(iteratorDesc.configurable, "@@asyncIterator property should be configurable");1803 assert_false(iteratorDesc.enumerable, "@@asyncIterator property should not be enumerable");1804 assert_equals(typeof iteratorDesc.value, "function", "@@asyncIterator property should be a function");1805 assert_equals(iteratorDesc.value.length, 0, "@@asyncIterator function object length should be 0");1806 assert_equals(iteratorDesc.value.name, isPairIterator ? "entries" : "values", "@@asyncIterator function object should have the right name");1807 if (isPairIterator) {1808 assert_equals(proto["entries"], proto[Symbol.asyncIterator], "entries method should be the same as @@asyncIterator method");1809 ["entries", "keys", "values"].forEach(property => {1810 var desc = Object.getOwnPropertyDescriptor(proto, property);1811 assert_equals(typeof desc.value, "function", property + " property should be a function");1812 assert_equals(desc.value.length, 0, property + " function object length should be 0");1813 assert_equals(desc.value.name, property, property + " function object should have the right name");1814 });1815 } else {1816 assert_equals(proto["values"], proto[Symbol.asyncIterator], "values method should be the same as @@asyncIterator method");1817 assert_false("entries" in proto, "should not have an entries method");1818 assert_false("keys" in proto, "should not have a keys method");1819 }1820 }.bind(this), this.name + " interface: async iterable<" + member.idlType.map(function(t) { return t.idlType; }).join(", ") + ">");1821};1822IdlInterface.prototype.test_member_stringifier = function(member)1823{1824 subsetTestByKey(this.name, test, function()1825 {1826 if (!this.should_have_interface_object()) {1827 return;1828 }1829 this.assert_interface_object_exists();1830 if (this.is_callback()) {1831 assert_false("prototype" in this.get_interface_object(),1832 this.name + ' should not have a "prototype" property');1833 return;1834 }1835 assert_own_property(this.get_interface_object(), "prototype",1836 'interface "' + this.name + '" does not have own property "prototype"');1837 var interfacePrototypeObject = this.get_interface_object().prototype;1838 assert_own_property(interfacePrototypeObject, "toString",1839 "interface prototype object missing non-static operation");1840 var stringifierUnforgeable = member.isUnforgeable;1841 var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "toString");1842 assert_false("get" in desc, "property should not have a getter");1843 assert_false("set" in desc, "property should not have a setter");1844 assert_equals(desc.writable, !stringifierUnforgeable,1845 "property should be writable if and only if not unforgeable");1846 assert_true(desc.enumerable, "property should be enumerable");1847 assert_equals(desc.configurable, !stringifierUnforgeable,1848 "property should be configurable if and only if not unforgeable");1849 assert_equals(typeof interfacePrototypeObject.toString, "function",1850 "property must be a function");1851 assert_equals(interfacePrototypeObject.toString.length, 0,1852 "property has wrong .length");1853 assert_throws_js(globalOf(interfacePrototypeObject.toString).TypeError, function() {1854 interfacePrototypeObject.toString.apply(null, []);1855 }, "calling stringifier with this = null didn't throw TypeError");1856 assert_throws_js(globalOf(interfacePrototypeObject.toString).TypeError, function() {1857 interfacePrototypeObject.toString.apply({}, []);1858 }, "calling stringifier with this = {} didn't throw TypeError");1859 }.bind(this), this.name + " interface: stringifier");1860};1861IdlInterface.prototype.test_members = function()1862{1863 for (var i = 0; i < this.members.length; i++)1864 {1865 var member = this.members[i];1866 if (member.untested) {1867 continue;1868 }1869 if (!exposed_in(exposure_set(member, this.exposureSet))) {1870 subsetTestByKey(this.name, test, function() {1871 assert_false(member.name in this.get_interface_object(),1872 "The interface object must not have a property " +1873 format_value(member.name));1874 assert_false(member.name in this.get_interface_object().prototype,1875 "The prototype object must not have a property " +1876 format_value(member.name));1877 }.bind(this), this.name + " interface: member " + member.name);1878 continue;1879 }1880 switch (member.type) {1881 case "const":1882 this.test_member_const(member);1883 break;1884 case "attribute":1885 if (!member.isUnforgeable)1886 {1887 this.test_member_attribute(member);1888 }1889 if (member.special === "stringifier") {1890 this.test_member_stringifier(member);1891 }1892 break;1893 case "operation":1894 if (member.name) {1895 if (!member.isUnforgeable)1896 {1897 this.test_member_operation(member);1898 }1899 } else if (member.special === "stringifier") {1900 this.test_member_stringifier(member);1901 }1902 break;1903 case "iterable":1904 if (member.async) {1905 this.test_member_async_iterable(member);1906 } else {1907 this.test_member_iterable(member);1908 }1909 break;1910 default:1911 break;1912 }1913 }1914};1915IdlInterface.prototype.test_object = function(desc)1916{1917 var obj, exception = null;1918 try1919 {1920 obj = eval(desc);1921 }1922 catch(e)1923 {1924 exception = e;1925 }1926 var expected_typeof;1927 if (this.name == "HTMLAllCollection")1928 {1929 expected_typeof = "undefined";1930 }1931 else1932 {1933 expected_typeof = "object";1934 }1935 this.test_primary_interface_of(desc, obj, exception, expected_typeof);1936 var current_interface = this;1937 while (current_interface)1938 {1939 if (!(current_interface.name in this.array.members))1940 {1941 throw new IdlHarnessError("Interface " + current_interface.name + " not found (inherited by " + this.name + ")");1942 }1943 if (current_interface.prevent_multiple_testing && current_interface.already_tested)1944 {1945 return;1946 }1947 current_interface.test_interface_of(desc, obj, exception, expected_typeof);1948 current_interface = this.array.members[current_interface.base];1949 }1950};1951IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception, expected_typeof)1952{1953 if (this.untested)1954 {1955 return;1956 }1957 if (this.is_global())1958 {1959 this.test_immutable_prototype("global platform object", obj);1960 }1961 if (this.should_have_interface_object()1962 && (typeof obj != expected_typeof || obj instanceof Object))1963 {1964 subsetTestByKey(this.name, test, function()1965 {1966 assert_equals(exception, null, "Unexpected exception when evaluating object");1967 assert_equals(typeof obj, expected_typeof, "wrong typeof object");1968 this.assert_interface_object_exists();1969 assert_own_property(this.get_interface_object(), "prototype",1970 'interface "' + this.name + '" does not have own property "prototype"');1971 assert_equals(Object.getPrototypeOf(obj),1972 this.get_interface_object().prototype,1973 desc + "'s prototype is not " + this.name + ".prototype");1974 }.bind(this), this.name + " must be primary interface of " + desc);1975 }1976 subsetTestByKey(this.name, test, function()1977 {1978 assert_equals(exception, null, "Unexpected exception when evaluating object");1979 assert_equals(typeof obj, expected_typeof, "wrong typeof object");1980 assert_class_string(obj, this.get_qualified_name(), "class string of " + desc);1981 if (!this.has_stringifier())1982 {1983 assert_equals(String(obj), "[object " + this.get_qualified_name() + "]", "String(" + desc + ")");1984 }1985 }.bind(this), "Stringification of " + desc);1986};1987IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof)1988{1989 this.already_tested = true;1990 if (!shouldRunSubTest(this.name)) {1991 return;1992 }1993 for (var i = 0; i < this.members.length; i++)1994 {1995 var member = this.members[i];1996 if (member.untested) {1997 continue;1998 }1999 if (!exposed_in(exposure_set(member, this.exposureSet))) {2000 subsetTestByKey(this.name, test, function() {2001 assert_equals(exception, null, "Unexpected exception when evaluating object");2002 assert_false(member.name in obj);2003 }.bind(this), this.name + " interface: " + desc + ' must not have property "' + member.name + '"');2004 continue;2005 }2006 if (member.type == "attribute" && member.isUnforgeable)2007 {2008 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: " + desc + ' must have own property "' + member.name + '"');2009 a_test.step(function() {2010 assert_equals(exception, null, "Unexpected exception when evaluating object");2011 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2012 this.do_interface_attribute_asserts(obj, member, a_test);2013 }.bind(this));2014 }2015 else if (member.type == "operation" &&2016 member.name &&2017 member.isUnforgeable)2018 {2019 var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: " + desc + ' must have own property "' + member.name + '"');2020 a_test.step(function()2021 {2022 assert_equals(exception, null, "Unexpected exception when evaluating object");2023 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2024 assert_own_property(obj, member.name,2025 "Doesn't have the unforgeable operation property");2026 this.do_member_operation_asserts(obj, member, a_test);2027 }.bind(this));2028 }2029 else if ((member.type == "const"2030 || member.type == "attribute"2031 || member.type == "operation")2032 && member.name)2033 {2034 subsetTestByKey(this.name, test, function()2035 {2036 assert_equals(exception, null, "Unexpected exception when evaluating object");2037 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2038 if (member.special !== "static") {2039 if (!this.is_global()) {2040 assert_inherits(obj, member.name);2041 } else {2042 assert_own_property(obj, member.name);2043 }2044 if (member.type == "const")2045 {2046 assert_equals(obj[member.name], constValue(member.value));2047 }2048 if (member.type == "attribute")2049 {2050 var property, thrown = false;2051 try2052 {2053 property = obj[member.name];2054 }2055 catch (e)2056 {2057 thrown = true;2058 }2059 if (!thrown)2060 {2061 if (this.name == "Document" && member.name == "all")2062 {2063 assert_equals(typeof property, "undefined");2064 }2065 else2066 {2067 this.array.assert_type_is(property, member.idlType);2068 }2069 }2070 }2071 if (member.type == "operation")2072 {2073 assert_equals(typeof obj[member.name], "function");2074 }2075 }2076 }.bind(this), this.name + " interface: " + desc + ' must inherit property "' + member + '" with the proper type');2077 }2078 if (member.type == "operation" && member.name && member.arguments.length)2079 {2080 var description =2081 this.name + " interface: calling " + member + " on " + desc +2082 " with too few arguments must throw TypeError";2083 var a_test = subsetTestByKey(this.name, async_test, description);2084 a_test.step(function()2085 {2086 assert_equals(exception, null, "Unexpected exception when evaluating object");2087 assert_equals(typeof obj, expected_typeof, "wrong typeof object");2088 var fn;2089 if (member.special !== "static") {2090 if (!this.is_global() && !member.isUnforgeable) {2091 assert_inherits(obj, member.name);2092 } else {2093 assert_own_property(obj, member.name);2094 }2095 fn = obj[member.name];2096 }2097 else2098 {2099 assert_own_property(obj.constructor, member.name, "interface object must have static operation as own property");2100 fn = obj.constructor[member.name];2101 }2102 var minLength = minOverloadLength(this.members.filter(function(m) {2103 return m.type == "operation" && m.name == member.name;2104 }));2105 var args = [];2106 var cb = awaitNCallbacks(minLength, a_test.done.bind(a_test));2107 for (var i = 0; i < minLength; i++) {2108 throwOrReject(a_test, member, fn, obj, args, "Called with " + i + " arguments", cb);2109 args.push(create_suitable_object(member.arguments[i].idlType));2110 }2111 if (minLength === 0) {2112 cb();2113 }2114 }.bind(this));2115 }2116 if (member.is_to_json_regular_operation()) {2117 this.test_to_json_operation(desc, obj, member);2118 }2119 }2120};2121IdlInterface.prototype.has_stringifier = function()2122{2123 if (this.name === "DOMException") {2124 return true;2125 }2126 if (this.members.some(function(member) { return member.special === "stringifier"; })) {2127 return true;2128 }2129 if (this.base &&2130 this.array.members[this.base].has_stringifier()) {2131 return true;2132 }2133 return false;2134};2135IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member, a_test)2136{2137 var pendingPromises = [];2138 assert_own_property(obj, member.name);2139 var desc = Object.getOwnPropertyDescriptor(obj, member.name);2140 assert_false("value" in desc, 'property descriptor should not have a "value" field');2141 assert_false("writable" in desc, 'property descriptor should not have a "writable" field');2142 assert_true(desc.enumerable, "property should be enumerable");2143 if (member.isUnforgeable)2144 {2145 assert_false(desc.configurable, "[LegacyUnforgeable] property must not be configurable");2146 }2147 else2148 {2149 assert_true(desc.configurable, "property must be configurable");2150 }2151 assert_equals(typeof desc.get, "function", "getter must be Function");2152 if (member.special !== "static") {2153 if (!member.has_extended_attribute("LegacyLenientThis")) {2154 if (member.idlType.generic !== "Promise") {2155 assert_throws_js(globalOf(desc.get).TypeError, function() {2156 desc.get.call({});2157 }.bind(this), "calling getter on wrong object type must throw TypeError");2158 } else {2159 pendingPromises.push(2160 promise_rejects_js(a_test, TypeError, desc.get.call({}),2161 "calling getter on wrong object type must reject the return promise with TypeError"));2162 }2163 } else {2164 assert_equals(desc.get.call({}), undefined,2165 "calling getter on wrong object type must return undefined");2166 }2167 }2168 assert_equals(desc.get.length, 0, "getter length must be 0");2169 assert_equals(desc.get.name, "get " + member.name,2170 "getter must have the name 'get " + member.name + "'");2171 if (member.readonly2172 && !member.has_extended_attribute("LegacyLenientSetter")2173 && !member.has_extended_attribute("PutForwards")2174 && !member.has_extended_attribute("Replaceable"))2175 {2176 assert_equals(desc.set, undefined, "setter must be undefined for readonly attributes");2177 }2178 else2179 {2180 assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes");2181 if (member.special !== "static") {2182 if (!member.has_extended_attribute("LegacyLenientThis")) {2183 assert_throws_js(globalOf(desc.set).TypeError, function() {2184 desc.set.call({});2185 }.bind(this), "calling setter on wrong object type must throw TypeError");2186 } else {2187 assert_equals(desc.set.call({}), undefined,2188 "calling setter on wrong object type must return undefined");2189 }2190 }2191 assert_equals(desc.set.length, 1, "setter length must be 1");2192 assert_equals(desc.set.name, "set " + member.name,2193 "The attribute setter must have the name 'set " + member.name + "'");2194 }2195 Promise.all(pendingPromises).then(a_test.done.bind(a_test));2196}2197function IdlInterfaceMember(obj)2198{2199 * obj is an object produced by the WebIDLParser.js "ifMember" production.2200 * We just forward all properties to this object without modification,2201 * except for special extAttrs handling.2202 for (var k in obj.toJSON())2203 {2204 this[k] = obj[k];2205 }2206 if (!("extAttrs" in this))2207 {2208 this.extAttrs = [];2209 }2210 this.isUnforgeable = this.has_extended_attribute("LegacyUnforgeable");2211 this.isUnscopable = this.has_extended_attribute("Unscopable");2212}2213IdlInterfaceMember.prototype = Object.create(IdlObject.prototype);2214IdlInterfaceMember.prototype.toJSON = function() {2215 return this;2216};2217IdlInterfaceMember.prototype.is_to_json_regular_operation = function() {2218 return this.type == "operation" && this.special !== "static" && this.name == "toJSON";2219};2220IdlInterfaceMember.prototype.toString = function() {2221 function formatType(type) {2222 var result;2223 if (type.generic) {2224 result = type.generic + "<" + type.idlType.map(formatType).join(", ") + ">";2225 } else if (type.union) {2226 result = "(" + type.subtype.map(formatType).join(" or ") + ")";2227 } else {2228 result = type.idlType;2229 }2230 if (type.nullable) {2231 result += "?"2232 }2233 return result;2234 }2235 if (this.type === "operation") {2236 var args = this.arguments.map(function(m) {2237 return [2238 m.optional ? "optional " : "",2239 formatType(m.idlType),2240 m.variadic ? "..." : "",2241 ].join("");2242 }).join(", ");2243 return this.name + "(" + args + ")";2244 }2245 return this.name;2246}2247function create_suitable_object(type)2248{2249 * type is an object produced by the WebIDLParser.js "type" production. We2250 * return a JavaScript value that matches the type, if we can figure out2251 * how.2252 if (type.nullable)2253 {2254 return null;2255 }2256 switch (type.idlType)2257 {2258 case "any":2259 case "boolean":2260 return true;2261 case "byte": case "octet": case "short": case "unsigned short":2262 case "long": case "unsigned long": case "long long":2263 case "unsigned long long": case "float": case "double":2264 case "unrestricted float": case "unrestricted double":2265 return 7;2266 case "DOMString":2267 case "ByteString":2268 case "USVString":2269 return "foo";2270 case "object":2271 return {a: "b"};2272 case "Node":2273 return document.createTextNode("abc");2274 }2275 return null;2276}2277function IdlEnum(obj)2278{2279 * obj is an object produced by the WebIDLParser.js "dictionary"2280 * production.2281 this.name = obj.name;2282 this.values = obj.values;2283}2284IdlEnum.prototype = Object.create(IdlObject.prototype);2285function IdlCallback(obj)2286{2287 * obj is an object produced by the WebIDLParser.js "callback"2288 * production.2289 this.name = obj.name;2290 this.arguments = obj.arguments;2291}2292IdlCallback.prototype = Object.create(IdlObject.prototype);2293function IdlTypedef(obj)2294{2295 * obj is an object produced by the WebIDLParser.js "typedef"2296 * production.2297 this.name = obj.name;2298 this.idlType = obj.idlType;2299}2300IdlTypedef.prototype = Object.create(IdlObject.prototype);2301function IdlNamespace(obj)2302{2303 this.name = obj.name;2304 this.extAttrs = obj.extAttrs;2305 this.untested = obj.untested;2306 this.array = obj.array;2307 this.members = obj.members.map(m => new IdlInterfaceMember(m));2308}2309IdlNamespace.prototype = Object.create(IdlObject.prototype);2310IdlNamespace.prototype.do_member_operation_asserts = function (memberHolderObject, member, a_test)2311{2312 var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name);2313 assert_false("get" in desc, "property should not have a getter");2314 assert_false("set" in desc, "property should not have a setter");2315 assert_equals(2316 desc.writable,2317 !member.isUnforgeable,2318 "property should be writable if and only if not unforgeable");2319 assert_true(desc.enumerable, "property should be enumerable");2320 assert_equals(2321 desc.configurable,2322 !member.isUnforgeable,2323 "property should be configurable if and only if not unforgeable");2324 assert_equals(2325 typeof memberHolderObject[member.name],2326 "function",2327 "property must be a function");2328 assert_equals(2329 memberHolderObject[member.name].length,2330 minOverloadLength(this.members.filter(function(m) {2331 return m.type == "operation" && m.name == member.name;2332 })),2333 "operation has wrong .length");2334 a_test.done();2335}2336IdlNamespace.prototype.test_member_operation = function(member)2337{2338 if (!shouldRunSubTest(this.name)) {2339 return;2340 }2341 var a_test = subsetTestByKey(2342 this.name,2343 async_test,2344 this.name + ' namespace: operation ' + member);2345 a_test.step(function() {2346 assert_own_property(2347 self[this.name],2348 member.name,2349 'namespace object missing operation ' + format_value(member.name));2350 this.do_member_operation_asserts(self[this.name], member, a_test);2351 }.bind(this));2352};2353IdlNamespace.prototype.test_member_attribute = function (member)2354{2355 if (!shouldRunSubTest(this.name)) {2356 return;2357 }2358 var a_test = subsetTestByKey(2359 this.name,2360 async_test,2361 this.name + ' namespace: attribute ' + member.name);2362 a_test.step(function()2363 {2364 assert_own_property(2365 self[this.name],2366 member.name,2367 this.name + ' does not have property ' + format_value(member.name));2368 var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);2369 assert_equals(desc.set, undefined, "setter must be undefined for namespace members");2370 a_test.done();2371 }.bind(this));2372};2373IdlNamespace.prototype.test_self = function ()2374{2375 * TODO(lukebjerring): Assert:2376 * - "Note that unlike interfaces or dictionaries, namespaces do not create types."2377 subsetTestByKey(this.name, test, () => {2378 assert_true(this.extAttrs.every(o => o.name === "Exposed" || o.name === "SecureContext"),2379 "Only the [Exposed] and [SecureContext] extended attributes are applicable to namespaces");2380 assert_true(this.has_extended_attribute("Exposed"),2381 "Namespaces must be annotated with the [Exposed] extended attribute");2382 }, `${this.name} namespace: extended attributes`);2383 const namespaceObject = self[this.name];2384 subsetTestByKey(this.name, test, () => {2385 const desc = Object.getOwnPropertyDescriptor(self, this.name);2386 assert_equals(desc.value, namespaceObject, `wrong value for ${this.name} namespace object`);2387 assert_true(desc.writable, "namespace object should be writable");2388 assert_false(desc.enumerable, "namespace object should not be enumerable");2389 assert_true(desc.configurable, "namespace object should be configurable");2390 assert_false("get" in desc, "namespace object should not have a getter");2391 assert_false("set" in desc, "namespace object should not have a setter");2392 }, `${this.name} namespace: property descriptor`);2393 subsetTestByKey(this.name, test, () => {2394 assert_true(Object.isExtensible(namespaceObject));2395 }, `${this.name} namespace: [[Extensible]] is true`);2396 subsetTestByKey(this.name, test, () => {2397 assert_true(namespaceObject instanceof Object);2398 if (this.name === "console") {2399 const namespacePrototype = Object.getPrototypeOf(namespaceObject);2400 assert_equals(Reflect.ownKeys(namespacePrototype).length, 0);2401 assert_equals(Object.getPrototypeOf(namespacePrototype), Object.prototype);2402 } else {2403 assert_equals(Object.getPrototypeOf(namespaceObject), Object.prototype);2404 }2405 }, `${this.name} namespace: [[Prototype]] is Object.prototype`);2406 subsetTestByKey(this.name, test, () => {2407 assert_equals(typeof namespaceObject, "object");2408 }, `${this.name} namespace: typeof is "object"`);2409 subsetTestByKey(this.name, test, () => {2410 assert_equals(2411 Object.getOwnPropertyDescriptor(namespaceObject, "length"),2412 undefined,2413 "length property must be undefined"2414 );2415 }, `${this.name} namespace: has no length property`);2416 subsetTestByKey(this.name, test, () => {2417 assert_equals(2418 Object.getOwnPropertyDescriptor(namespaceObject, "name"),2419 undefined,2420 "name property must be undefined"2421 );2422 }, `${this.name} namespace: has no name property`);2423};2424IdlNamespace.prototype.test = function ()2425{2426 if (!this.untested) {2427 this.test_self();2428 }2429 for (const v of Object.values(this.members)) {2430 switch (v.type) {2431 case 'operation':2432 this.test_member_operation(v);2433 break;2434 case 'attribute':2435 this.test_member_attribute(v);2436 break;2437 default:2438 throw 'Invalid namespace member ' + v.name + ': ' + v.type + ' not supported';2439 }2440 };2441};2442}());2443 * idl_test is a promise_test wrapper that handles the fetching of the IDL,2444 * avoiding repetitive boilerplate.2445 *2446 * @param {String|String[]} srcs Spec name(s) for source idl files (fetched from2447 * @param {String|String[]} deps Spec name(s) for dependency idl files (fetched2448 * each source will only be included if they're already know to be a2449 * dependency (i.e. have already been seen).2450 * @param {Function} setup_func Function for extra setup of the idl_array, such2451 * as adding objects. Do not call idl_array.test() in the setup; it is2452 * called by this function (idl_test).2453function idl_test(srcs, deps, idl_setup_func) {2454 return promise_test(function (t) {2455 var idl_array = new IdlArray();2456 var setup_error = null;2457 const validationIgnored = [2458 "constructor-member",2459 "dict-arg-default",2460 "require-exposed"2461 ];2462 return Promise.all(2463 srcs.concat(deps).map(fetch_spec))2464 .then(function(results) {2465 const astArray = results.map(result =>2466 WebIDL2.parse(result.idl, { sourceName: result.spec })2467 );2468 test(() => {2469 const validations = WebIDL2.validate(astArray)2470 .filter(v => !validationIgnored.includes(v.ruleName));2471 if (validations.length) {2472 const message = validations.map(v => v.message).join("\n\n");2473 throw new Error(message);2474 }2475 }, "idl_test validation");2476 for (var i = 0; i < srcs.length; i++) {2477 idl_array.internal_add_idls(astArray[i]);2478 }2479 for (var i = srcs.length; i < srcs.length + deps.length; i++) {2480 idl_array.internal_add_dependency_idls(astArray[i]);2481 }2482 })2483 .then(function() {2484 if (idl_setup_func) {2485 return idl_setup_func(idl_array, t);2486 }2487 })2488 .catch(function(e) { setup_error = e || 'IDL setup failed.'; })2489 .then(function () {2490 var error = setup_error;2491 try {2492 } catch (e) {2493 error = error || e;2494 }2495 if (error) {2496 throw error;2497 }2498 });2499 }, 'idl_test setup');2500}2501 * fetch_spec is a shorthand for a Promise that fetches the spec's content.2502function fetch_spec(spec) {2503 return fetch(url).then(function (r) {2504 if (!r.ok) {2505 throw new IdlHarnessError("Error fetching " + url + ".");2506 }2507 return r.text();2508 }).then(idl => ({ spec, idl }));...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('webpagetest');2var client = wpt('www.webpagetest.org');3 if (err) return console.error(err);4 console.log(data);5});6#### wpt(apiKey, [options])7#### .getTestStatus(testId, callback)8##### callback(err, data)9#### .getTestResults(testId, callback)10##### callback(err, data)11#### .runTest(url, [options], callback)

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('webpagetest');2var client = wpt('www.webpagetest.org');3 if (err) return console.error(err);4 console.log(data);5});6var wpt = require('webpagetest');7var client = wpt('www.webpagetest.org');8client.getLocations(function(err, data) {9 if (err) return console.error(err);10 console.log(data);11});12var wpt = require('webpagetest');13var client = wpt('www.webpagetest.org');14client.getTesters(function(err, data) {15 if (err) return console.error(err);16 console.log(data);17});18var wpt = require('webpagetest');19var client = wpt('www.webpagetest.org');20client.getTestStatus('141107_XG_1d1f5c1e2c7f2d9f9e7e9a3e3d3c3f1', function(err, data) {21 if (err) return console.error(err);22 console.log(data);23});24var wpt = require('webpagetest');25var client = wpt('www.webpagetest.org');26client.getTestResults('141107_XG_1d1f5c1e2c7f2d9f9e7e9a3e3d3c3f1', function(err, data) {27 if (err) return console.error(err);28 console.log(data);29});30var wpt = require('webpagetest');31var client = wpt('www.webpagetest.org');32client.getLocations(function(err, data) {33 if (err) return console.error(err);34 console.log(data);35});36var wpt = require('webpagetest');37var client = wpt('www.webpagetest.org');

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('webpagetest');2var wpt = new WebPageTest('www.webpagetest.org');3var options = { location: 'Dulles:Chrome', connectivity: 'Cable' };4 if (err) return console.error(err);5 wpt.getTestStatus(data.data.testId, function(err, data) {6 if (err) return console.error(err);7 wpt.getTestResults(data.data.testId, function(err, data) {8 if (err) return console.error(err);9 wpt.exposureAttr(data.data.testId, function(err, data) {10 if (err) return console.error(err);11 console.log(data);12 });13 });14 });15});16### runTest(url, options, callback)17### getTestStatus(testId, callback)

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('./wpt.js');2var fs = require('fs');3var test = function() {4 var wpt = new Wpt();5 wpt.exposureAttr(url, function(err, data) {6 if (err) {7 console.log(err);8 } else {9 console.log(data);10 fs.writeFile('exposure.json', JSON.stringify(data, null, 2), function(err) {11 if (err) {12 console.log(err);13 } else {14 console.log('exposure.json written');15 }16 });17 }18 });19};20test();

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('webpagetest');2var options = {3};4var test = new wpt(options);5 if (err) return console.log(err);6 console.log('Test submitted. Polling for results.');7 test.pollTestUntilDone(data.data.testId, 5000, function(err, data) {8 if (err) return console.log(err);9 console.log('Test complete!');10 console.log(data.data.runs[1].firstView.exposureAttr);11 });12});13### new WPT(options)

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful