| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- // Functional WeakSet tests -- verifies the APIs work correctly
- // Note however this does not verify the GC semantics of WeakSet
- WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
- var tests = [
- {
- name: "WeakSet constructor called on undefined or WeakSet.prototype returns new WeakSet object (and throws on null, non-extensible object)",
- body: function () {
- // WeakSet is no longer allowed to be called as a function unless the object it is given
- // for its this argument already has the [[WeakSetData]] property on it.
- // TODO: When we implement @@create support, update this test to reflect it.
- //
- assert.throws(function () { WeakSet.call(undefined); }, TypeError, "WeakSet.call() throws TypeError given undefined");
- assert.throws(function () { WeakSet.call(null); }, TypeError, "WeakSet.call() throws TypeError given null");
- assert.throws(function () { WeakSet.call(WeakSet.prototype); }, TypeError, "WeakSet.call() throws TypeError given WeakSet.prototype");
- /*
- var weakset1 = WeakSet.call(undefined);
- assert.isTrue(weakset1 !== null && weakset1 !== undefined && weakset1 !== WeakSet.prototype, "WeakSet constructor creates new WeakSet object when this is undefined");
- var weakset2 = WeakSet.call(WeakSet.prototype);
- assert.isTrue(weakset2 !== null && weakset2 !== undefined && weakset2 !== WeakSet.prototype, "WeakSet constructor creates new WeakSet object when this is equal to WeakSet.prototype");
- var o = { };
- Object.preventExtensions(o);
- assert.throws(function () { WeakSet.call(null); }, TypeError, "WeakSet constructor throws on null");
- assert.throws(function () { WeakSet.call(o); }, TypeError, "WeakSet constructor throws on non-extensible object");
- */
- }
- },
- {
- name: "WeakSet constructor throws when called on already initialized WeakSet object",
- body: function () {
- var weakset = new WeakSet();
- assert.throws(function () { WeakSet.call(weakset); }, TypeError);
- // WeakSet is no longer allowed to be called as a function unless the object it is given
- // for its this argument already has the [[WeakSetData]] property on it.
- // TODO: When we implement @@create support, update this test to reflect it.
- /*
- var obj = {};
- WeakSet.call(obj);
- assert.throws(function () { WeakSet.call(obj); }, TypeError);
- function MyWeakSet() {
- WeakSet.call(this);
- }
- MyWeakSet.prototype = new WeakSet();
- MyWeakSet.prototype.constructor = MyWeakSet;
- var myweakset = new MyWeakSet();
- assert.throws(function () { WeakSet.call(myweakset); }, TypeError);
- assert.throws(function () { MyWeakSet.call(myweakset); }, TypeError);
- */
- }
- },
- {
- name: "WeakSet constructor populates the weakset with values from given optional iteratable argument",
- body: function () {
- var keys = [ { }, { }, { }, { } ];
- var ws = new WeakSet([ keys[0], keys[1], keys[2] ]);
- assert.isTrue(ws.has(keys[0]), "ws has value keys[0]");
- assert.isTrue(ws.has(keys[1]), "ws has value keys[1]");
- assert.isTrue(ws.has(keys[2]), "ws has value keys[2]");
- var customIterable = {
- [Symbol.iterator]: function () {
- var i = 0;
- return {
- next: function () {
- return {
- done: i > 3,
- value: keys[i++]
- };
- }
- };
- }
- };
- ws = new WeakSet(customIterable);
- assert.isTrue(ws.has(keys[0]), "ws has key keys[0]");
- assert.isTrue(ws.has(keys[1]), "ws has key keys[1]");
- assert.isTrue(ws.has(keys[2]), "ws has key keys[2]");
- assert.isTrue(ws.has(keys[3]), "ws has key keys[3]");
- }
- },
- {
- name: "WeakSet constructor throws exceptions for non- and malformed iterable arguments",
- body: function () {
- var iterableNoIteratorMethod = { [Symbol.iterator]: 123 };
- var iterableBadIteratorMethod = { [Symbol.iterator]: function () { } };
- var iterableNoIteratorNextMethod = { [Symbol.iterator]: function () { return { }; } };
- var iterableBadIteratorNextMethod = { [Symbol.iterator]: function () { return { next: 123 }; } };
- var iterableNoIteratorResultObject = { [Symbol.iterator]: function () { return { next: function () { } }; } };
- assert.throws(function () { new WeakSet(123); }, TypeError, "new WeakSet() throws on non-object", "Function expected");
- assert.throws(function () { new WeakSet({ }); }, TypeError, "new WeakSet() throws on non-iterable object", "Function expected");
- assert.throws(function () { new WeakSet(iterableNoIteratorMethod); }, TypeError, "new WeakSet() throws on non-iterable object where @@iterator property is not a function", "Function expected");
- assert.throws(function () { new WeakSet(iterableBadIteratorMethod); }, TypeError, "new WeakSet() throws on non-iterable object where @@iterator function doesn't return an iterator", "Object expected");
- assert.throws(function () { new WeakSet(iterableNoIteratorNextMethod); }, TypeError, "new WeakSet() throws on iterable object where iterator object does not have next property", "Function expected");
- assert.throws(function () { new WeakSet(iterableBadIteratorNextMethod); }, TypeError, "new WeakSet() throws on iterable object where iterator object's next property is not a function", "Function expected");
- assert.throws(function () { new WeakSet(iterableNoIteratorResultObject); }, TypeError, "new WeakSet() throws on iterable object where iterator object's next method doesn't return an iterator result", "Object expected");
- }
- },
- {
- name: "APIs throw TypeError where specified",
- body: function () {
- function MyWeakSetImposter() { }
- MyWeakSetImposter.prototype = new WeakSet();
- MyWeakSetImposter.prototype.constructor = MyWeakSetImposter;
- var o = new MyWeakSetImposter();
- assert.throws(function () { o.add(o); }, TypeError, "add should throw if this doesn't have WeakSetData property");
- assert.throws(function () { o.delete(o); }, TypeError, "delete should throw if this doesn't have WeakSetData property");
- assert.throws(function () { o.has(o); }, TypeError, "has should throw if this doesn't have WeakSetData property");
- assert.throws(function () { WeakSet.prototype.add.call(); }, TypeError, "add should throw if called with no arguments");
- assert.throws(function () { WeakSet.prototype.delete.call(); }, TypeError, "delete should throw if called with no arguments");
- assert.throws(function () { WeakSet.prototype.has.call(); }, TypeError, "has should throw if called with no arguments");
- assert.throws(function () { WeakSet.prototype.add.call(null, o); }, TypeError, "add should throw if this is null");
- assert.throws(function () { WeakSet.prototype.delete.call(null, o); }, TypeError, "delete should throw if this is null");
- assert.throws(function () { WeakSet.prototype.has.call(null, o); }, TypeError, "has should throw if this is null");
- assert.throws(function () { WeakSet.prototype.add.call(undefined, o); }, TypeError, "add should throw if this is undefined");
- assert.throws(function () { WeakSet.prototype.delete.call(undefined, o); }, TypeError, "delete should throw if this is undefined");
- assert.throws(function () { WeakSet.prototype.has.call(undefined, o); }, TypeError, "has should throw if this is undefined");
- var weakset = new WeakSet();
- assert.throws(function () { weakset.add(null); }, TypeError, "add should throw if key is not an object, e.g. null");
- assert.throws(function () { weakset.add(undefined); }, TypeError, "add should throw if key is not an object, e.g. undefined");
- assert.throws(function () { weakset.add(true); }, TypeError, "add should throw if key is not an object, e.g. a boolean");
- assert.throws(function () { weakset.add(10); }, TypeError, "add should throw if key is not an object, e.g. a number");
- assert.throws(function () { weakset.add("hello"); }, TypeError, "add should throw if key is not an object, e.g. a string");
- }
- },
- {
- name: "Non-object key argument silent fails delete and has",
- body: function () {
- var weakset = new WeakSet();
- assert.isFalse(weakset.has(null), "null is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.has(undefined), "undefined is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.has(true), "boolean is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.has(10), "number is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.has("hello"), "string is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.delete(null), "null is not an object and cannot be a key in a WeakSet; delete returns false");
- assert.isFalse(weakset.delete(undefined), "undefined is not an object and cannot be a key in a WeakSet; delete returns false");
- assert.isFalse(weakset.delete(true), "boolean is not an object and cannot be a key in a WeakSet; delete returns false");
- assert.isFalse(weakset.delete(10), "number is not an object and cannot be a key in a WeakSet; delete returns false");
- assert.isFalse(weakset.delete("hello"), "string is not an object and cannot be a key in a WeakSet; delete returns false");
- var booleanObject = new Boolean(true);
- var numberObject = new Number(10);
- var stringObject = new String("hello");
- weakset.add(booleanObject);
- weakset.add(numberObject);
- weakset.add(stringObject);
- assert.isFalse(weakset.has(true), "boolean is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.has(10), "number is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.has("hello"), "string is not an object and cannot be a key in a WeakSet; has returns false");
- assert.isFalse(weakset.delete(true), "boolean is not an object and cannot be a key in a WeakSet; delete returns false");
- assert.isFalse(weakset.delete(10), "number is not an object and cannot be a key in a WeakSet; delete returns false");
- assert.isFalse(weakset.delete("hello"), "string is not an object and cannot be a key in a WeakSet; delete returns false");
- }
- },
- {
- name: "Basic usage, add, delete, has",
- body: function () {
- var weakset = new WeakSet();
- var o = { };
- var p = { };
- var q = { };
- weakset.add(o);
- weakset.add(p);
- weakset.add(q);
- assert.isTrue(weakset.has(o), "Should contain key o");
- assert.isTrue(weakset.has(p), "Should contain key p");
- assert.isTrue(weakset.has(q), "Should contain key q");
- assert.isFalse(weakset.has(weakset), "Should not contain other keys, 'weakset'");
- assert.isFalse(weakset.has({ }), "Should not contain other keys, '{ }'");
- assert.isTrue(weakset.delete(p), "Should return true after deleting key p");
- assert.isTrue(weakset.has(o), "Should still contain key o");
- assert.isFalse(weakset.has(p), "Should no longer contain key p");
- assert.isTrue(weakset.has(q), "Should still contain key q");
- assert.isFalse(weakset.delete(p), "Should return false, p is no longer a key");
- assert.isTrue(weakset.delete(o), "Should return true after deleting key o");
- assert.isTrue(weakset.delete(q), "Should return true after deleting key q");
- assert.isFalse(weakset.has(o), "Should no longer contain key o");
- assert.isFalse(weakset.has(p), "Should still not contain key p");
- assert.isFalse(weakset.has(q), "Should no longer contain key q");
- }
- },
- {
- name: "Not specifying arguments should default them to undefined",
- body: function () {
- var weakset = new WeakSet();
- assert.throws(function () { weakset.add(); }, TypeError, "Should throw TypeError for implicit undefined; add");
- assert.isFalse(weakset.has(), "Should return false for implicit undefined; has");
- assert.isFalse(weakset.delete(), "Should return false for implicit undefined; delete");
- }
- },
- {
- name: "Extra arguments should be ignored",
- body: function () {
- var weakset = new WeakSet();
- var o = { };
- var p = { };
- var q = { };
- assert.isFalse(weakset.has(o, p, q), "Looks for o, ignores p and q, weak weakset is empty and has should return false");
- assert.isFalse(weakset.delete(o, p, q), "Looks for o, ignores p and q, weak weakset is empty and delete should return false");
- weakset.add(o, p, q);
- assert.isTrue(weakset.has(o), "Should contain o");
- assert.isFalse(weakset.has(p), "Should not contain p");
- assert.isFalse(weakset.has(q), "Should not contain q");
- assert.isTrue(weakset.has(o, p, q), "Ignores p and q, does have o");
- assert.isTrue(weakset.has(o, q, p), "Order of extra arguments has no affect, still has o");
- assert.isFalse(weakset.has(p, o), "Ignores o, does not have p");
- assert.isFalse(weakset.delete(p, o, q), "p is not found so should return false, ignores o and q");
- assert.isFalse(weakset.delete(q, o), "q is not found so should return false, ignores o");
- assert.isTrue(weakset.delete(o, p, q), "o is found and deleted, so should return true, ignores p and q");
- }
- },
- {
- name: "Delete should return true if item was in the WeakSet, false if not",
- body: function () {
- var weakset = new WeakSet();
- var o = { };
- var p = { };
- weakset.add(o);
- assert.isFalse(weakset.delete(p), "p is not a key in the weakset, delete should return false");
- assert.isTrue(weakset.delete(o), "o is a key in the weakset, delete should remove it and return true");
- assert.isFalse(weakset.delete(o), "o is no longer a key in the weakset, delete should now return false");
- }
- },
- {
- name: "Adding the same key twice is valid, having no affect on the second add",
- body: function () {
- var weakset = new WeakSet();
- var o = { };
- var p = { };
- weakset.add(o);
- weakset.add(o);
- weakset.add(p);
- weakset.delete(o);
- weakset.add(p);
- weakset.add(o);
- weakset.add(o);
- weakset.delete(o);
- weakset.delete(p);
- weakset.add(o);
- assert.isTrue(weakset.has(o), "o is in the weakset");
- weakset.add(o);
- assert.isTrue(weakset.has(o), "o is still in the weakset");
- weakset.add(p);
- assert.isTrue(weakset.has(o), "o is still in the weakset");
- assert.isTrue(weakset.has(p), "p is now in the weakset");
- weakset.delete(o);
- assert.isFalse(weakset.has(o), "o is no longer in the weakset");
- assert.isTrue(weakset.has(p), "p is still in the weakset");
- weakset.add(p);
- assert.isTrue(weakset.has(p), "p is still in the weakset");
- }
- },
- {
- name: "add returns the weakset instance itself",
- body: function () {
- var weakset = new WeakSet();
- var o = { };
- assert.areEqual(weakset, weakset.add(o), "Adding a new key should return WeakSet instance");
- assert.areEqual(weakset, weakset.add(o), "Adding an existing key should return WeakSet instance");
- }
- },
- {
- name: "Adding and removing keys from one WeakSet shouldn't affect other WeakSets",
- body: function () {
- var ws1 = new WeakSet();
- var ws2 = new WeakSet();
- var ws3 = new WeakSet();
- var o = { };
- var p = { };
- var q = { };
- ws1.add(o);
- ws1.add(p);
- ws2.add(q);
- assert.isTrue(ws1.has(o), "ws1 has o");
- assert.isFalse(ws2.has(o), "ws2 does not have o");
- assert.isFalse(ws3.has(o), "ws3 does not have o");
- assert.isTrue(ws1.has(p), "ws1 has p");
- assert.isTrue(ws2.has(q), "ws2 has q");
- assert.isFalse(ws1.has(q), "ws1 does not have q");
- assert.isFalse(ws2.has(p), "ws2 does not have p");
- assert.isFalse(ws3.has(p), "ws3 does not have p");
- assert.isFalse(ws3.has(q), "ws3 does not have q");
- ws3.add(p);
- ws3.add(q);
- assert.isTrue(ws3.has(p), "ws3 now has p");
- assert.isTrue(ws3.has(q), "ws3 now has q");
- assert.isTrue(ws1.has(p), "ws1 still has p");
- assert.isFalse(ws2.has(p), "ws2 still does not have p");
- assert.isFalse(ws1.has(q), "ws1 still does not have q");
- assert.isTrue(ws2.has(q), "ws2 still has q");
- assert.isTrue(ws1.delete(p), "p is removed from ws1");
- assert.isFalse(ws1.has(p), "ws1 no longer has p");
- assert.isTrue(ws3.has(p), "ws3 still has p");
- ws3.delete(p);
- ws3.delete(q);
- assert.isFalse(ws3.has(p), "ws3 no longer has p");
- assert.isFalse(ws3.has(q), "ws3 no longer has q");
- assert.isTrue(ws1.has(o), "ws1 still has o");
- assert.isTrue(ws2.has(q), "ws2 still has q");
- }
- },
- {
- name: "Number, Boolean, and String and other special objects should all as keys",
- body: function () {
- var weakset = new WeakSet();
- var n = new Number(1);
- var b = new Boolean(2);
- var s = new String("Hi");
- /*
- Fast DOM and HostDispatch objects are tested in the mshtml test weakset_DOMkey.html
- WinRT objects are still an open issue; they are CustomExternalObjects so they work,
- but they are proxied and the proxies are not kept alive by the outside object, only
- by internal JS references. Further, allowing objects to be linked to the lifetime
- of a WinJS object can cause cycles between JS GC objects and WinRT COM ref counted
- objects, which are not deducible by the GC. Therefore using WinRT objects with
- WeakSet is prone to subtle easy to make memory leak bugs.
- var fd = new FastDOM();
- var hd = new HostDispatch();
- var wrt = new WinRT();
- */
- var ab = new ArrayBuffer(32);
- weakset.add(n);
- weakset.add(b);
- weakset.add(s);
- weakset.add(ab);
- assert.isTrue(weakset.has(n), "weakset has key n which is a Number instance");
- assert.isTrue(weakset.has(b), "weakset has key b which is a Boolean instance");
- assert.isTrue(weakset.has(s), "weakset has key s which is a String instance");
- assert.isTrue(weakset.has(ab), "weakset has key ab which is an ArrayBuffer instance");
- assert.isTrue(weakset.delete(n), "Successfully delete key n which is a Number instance from weakset");
- assert.isTrue(weakset.delete(b), "Successfully delete key b which is a Boolean instance from weakset");
- assert.isTrue(weakset.delete(s), "Successfully delete key s which is a String instance from weakset");
- assert.isTrue(weakset.delete(ab), "Successfully delete key ab which is an ArrayBuffer instance from weakset");
- assert.isFalse(weakset.has(n), "weakset no longer has key n");
- assert.isFalse(weakset.has(b), "weakset no longer has key b");
- assert.isFalse(weakset.has(s), "weakset no longer has key s");
- assert.isFalse(weakset.has(ab), "weakset no longer has key ab");
- }
- },
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|