From 13b0e2d8d609603b0230ba950404ea21c149f0db Mon Sep 17 00:00:00 2001 From: jugglinmike Date: Fri, 30 Jun 2017 15:22:29 -0400 Subject: [PATCH] [idlharness.js] Expand test coverage (#6262) A previous patch introduced new tests intended to verify that global platform objects were also immutable prototype objects. In actuality, the new tests verified an unrelated condition: that interface prototype objects were also immutable prototype objects. Update idlharness to assert that both types of objects are immutable prototype objects, and modify test expectation strings to correctly describe each type. Introduce "cleanup" logic to avoid sub-test interaction. --- resources/idlharness.js | 199 +++++++---- .../test_immutable_prototype.html | 321 ++++++++++++++++++ 2 files changed, 445 insertions(+), 75 deletions(-) create mode 100644 resources/test/tests/idlharness/IdlInterface/test_immutable_prototype.html diff --git a/resources/idlharness.js b/resources/idlharness.js index 6dd1db3d40aff7..d05745774638b6 100644 --- a/resources/idlharness.js +++ b/resources/idlharness.js @@ -1380,81 +1380,14 @@ IdlInterface.prototype.test_self = function() } }.bind(this), this.name + " interface: existence and properties of interface prototype object"); - if (this.is_global() && typeof Object.setPrototypeOf === "function") { - // These functions test WebIDL as of 2017-06-06. - // https://heycam.github.io/webidl/#platform-object-setprototypeof - test(function() { - var originalValue = Object.getPrototypeOf(self[this.name].prototype); - var newValue = Object.create(null); - - assert_throws(new TypeError(), function() { - Object.setPrototypeOf(self[this.name].prototype, newValue); - }); - - assert_equals( - Object.getPrototypeOf(self[this.name].prototype), - originalValue, - "original value not modified" - ); - }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + - "of global platform object - setting to a new value via Object.setPrototypeOf " + - "should throw a TypeError"); - - test(function() { - var originalValue = Object.getPrototypeOf(self[this.name].prototype); - var newValue = Object.create(null); - - assert_throws(new TypeError(), function() { - self[this.name].prototype.__proto__ = newValue; - }); - - assert_equals( - Object.getPrototypeOf(self[this.name].prototype), - originalValue, - "original value not modified" - ); - }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + - "of global platform object - setting to a new value via __proto__ " + - "should throw a TypeError"); - - test(function() { - var originalValue = Object.getPrototypeOf(self[this.name].prototype); - var newValue = Object.create(null); - - assert_false(Reflect.setPrototypeOf(self[this.name].prototype.__proto__, newValue)); - - assert_equals( - Object.getPrototypeOf(self[this.name].prototype), - originalValue, - "original value not modified" - ); - }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + - "of global platform object - setting to a new value via Reflect.setPrototypeOf " + - "should return false"); - - test(function() { - var originalValue = Object.getPrototypeOf(self[this.name].prototype); - - Object.setPrototypeOf(self[this.name].prototype, originalValue); - }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + - "of global platform object - setting to its original value via Object.setPrototypeOf " + - "should not throw"); - - test(function() { - var originalValue = Object.getPrototypeOf(self[this.name].prototype); - - self[this.name].prototype.__proto__ = originalValue; - }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + - "of global platform object - setting to its original value via __proto__ " + - "should not throw"); - - test(function() { - var originalValue = Object.getPrototypeOf(self[this.name].prototype); - - assert_true(Reflect.setPrototypeOf(self[this.name].prototype, originalValue)); - }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + - "of global platform object - setting to its original value via Reflect.setPrototypeOf " + - "should return true"); + // "If the interface is declared with the [Global] or [PrimaryGlobal] + // extended attribute, or the interface is in the set of inherited + // interfaces for any other interface that is declared with one of these + // attributes, then the interface prototype object must be an immutable + // prototype exotic object." + // https://heycam.github.io/webidl/#interface-prototype-object + if (this.is_global()) { + this.test_immutable_prototype("interface prototype object", self[this.name].prototype); } test(function() @@ -1493,6 +1426,110 @@ IdlInterface.prototype.test_self = function() }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property'); }; +//@} +IdlInterface.prototype.test_immutable_prototype = function(type, obj) +//@{ +{ + if (typeof Object.setPrototypeOf !== "function") { + return; + } + + test(function(t) { + var originalValue = Object.getPrototypeOf(obj); + var newValue = Object.create(null); + + t.add_cleanup(function() { + try { + Object.setPrototypeOf(obj, originalValue); + } catch (err) {} + }); + + assert_throws(new TypeError(), function() { + Object.setPrototypeOf(obj, newValue); + }); + + assert_equals( + Object.getPrototypeOf(obj), + originalValue, + "original value not modified" + ); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to a new value via Object.setPrototypeOf " + + "should throw a TypeError"); + + test(function(t) { + var originalValue = Object.getPrototypeOf(obj); + var newValue = Object.create(null); + + t.add_cleanup(function() { + var setter = Object.getOwnPropertyDescriptor( + Object.prototype, '__proto__' + ).set; + + try { + setter.call(obj, originalValue); + } catch (err) {} + }); + + assert_throws(new TypeError(), function() { + obj.__proto__ = newValue; + }); + + assert_equals( + Object.getPrototypeOf(obj), + originalValue, + "original value not modified" + ); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to a new value via __proto__ " + + "should throw a TypeError"); + + test(function(t) { + var originalValue = Object.getPrototypeOf(obj); + var newValue = Object.create(null); + + t.add_cleanup(function() { + try { + Reflect.setPrototypeOf(obj, originalValue); + } catch (err) {} + }); + + assert_false(Reflect.setPrototypeOf(obj, newValue)); + + assert_equals( + Object.getPrototypeOf(obj), + originalValue, + "original value not modified" + ); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to a new value via Reflect.setPrototypeOf " + + "should return false"); + + test(function() { + var originalValue = Object.getPrototypeOf(obj); + + Object.setPrototypeOf(obj, originalValue); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to its original value via Object.setPrototypeOf " + + "should not throw"); + + test(function() { + var originalValue = Object.getPrototypeOf(obj); + + obj.__proto__ = originalValue; + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to its original value via __proto__ " + + "should not throw"); + + test(function() { + var originalValue = Object.getPrototypeOf(obj); + + assert_true(Reflect.setPrototypeOf(obj, originalValue)); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to its original value via Reflect.setPrototypeOf " + + "should return true"); +}; + //@} IdlInterface.prototype.test_member_const = function(member) //@{ @@ -2042,6 +2079,18 @@ IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception return; } + // "The internal [[SetPrototypeOf]] method of every platform object that + // implements an interface with the [Global] or [PrimaryGlobal] extended + // attribute must execute the same algorithm as is defined for the + // [[SetPrototypeOf]] internal method of an immutable prototype exotic + // object." + // https://heycam.github.io/webidl/#platform-object-setprototypeof + if (this.is_global()) + { + this.test_immutable_prototype("global platform object", obj); + } + + // We can't easily test that its prototype is correct if there's no // interface object, or the object is from a different global environment // (not instanceof Object). TODO: test in this case that its prototype at diff --git a/resources/test/tests/idlharness/IdlInterface/test_immutable_prototype.html b/resources/test/tests/idlharness/IdlInterface/test_immutable_prototype.html new file mode 100644 index 00000000000000..16214c4d24f986 --- /dev/null +++ b/resources/test/tests/idlharness/IdlInterface/test_immutable_prototype.html @@ -0,0 +1,321 @@ + + + + + idlharness: Immutable prototypes + + + + + + + + + +