diff options
Diffstat (limited to 'js/src/tests/non262/Map')
-rw-r--r-- | js/src/tests/non262/Map/NaN-as-key.js | 55 | ||||
-rw-r--r-- | js/src/tests/non262/Map/browser.js | 0 | ||||
-rw-r--r-- | js/src/tests/non262/Map/constructor-iterator-close.js | 293 | ||||
-rw-r--r-- | js/src/tests/non262/Map/constructor-iterator-primitive.js | 34 | ||||
-rw-r--r-- | js/src/tests/non262/Map/forEach-selfhosted-behavior.js | 51 | ||||
-rw-r--r-- | js/src/tests/non262/Map/getter-name.js | 10 | ||||
-rw-r--r-- | js/src/tests/non262/Map/iterable.js | 28 | ||||
-rw-r--r-- | js/src/tests/non262/Map/iterator-thisv-error.js | 24 | ||||
-rw-r--r-- | js/src/tests/non262/Map/record-tuple.js | 42 | ||||
-rw-r--r-- | js/src/tests/non262/Map/shell.js | 0 | ||||
-rw-r--r-- | js/src/tests/non262/Map/symbols.js | 33 |
11 files changed, 570 insertions, 0 deletions
diff --git a/js/src/tests/non262/Map/NaN-as-key.js b/js/src/tests/non262/Map/NaN-as-key.js new file mode 100644 index 0000000000..6fa5ee67e9 --- /dev/null +++ b/js/src/tests/non262/Map/NaN-as-key.js @@ -0,0 +1,55 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 722260; +var summary = 'All NaNs must be treated as identical keys for Map'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +/* Avoid constant-folding that would happen were |undefined| to be used. */ +var key = -/a/g.missingProperty; + +var m = new Map(); +m.set(key, 17); +assertEq(m.get(key), 17); +assertEq(m.get(-key), 17); +assertEq(m.get(NaN), 17); + +m.delete(-key); +assertEq(m.has(key), false); +assertEq(m.has(-key), false); +assertEq(m.has(NaN), false); + +m.set(-key, 17); +assertEq(m.get(key), 17); +assertEq(m.get(-key), 17); +assertEq(m.get(NaN), 17); + +m.delete(NaN); +assertEq(m.has(key), false); +assertEq(m.has(-key), false); +assertEq(m.has(NaN), false); + +m.set(NaN, 17); +assertEq(m.get(key), 17); +assertEq(m.get(-key), 17); +assertEq(m.get(NaN), 17); + +m.delete(key); +assertEq(m.has(key), false); +assertEq(m.has(-key), false); +assertEq(m.has(NaN), false); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/non262/Map/browser.js b/js/src/tests/non262/Map/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/Map/browser.js diff --git a/js/src/tests/non262/Map/constructor-iterator-close.js b/js/src/tests/non262/Map/constructor-iterator-close.js new file mode 100644 index 0000000000..084e6cb257 --- /dev/null +++ b/js/src/tests/non262/Map/constructor-iterator-close.js @@ -0,0 +1,293 @@ +var BUGNUMBER = 1180306; +var summary = 'Map/Set/WeakMap/WeakSet constructor should close iterator on error'; + +print(BUGNUMBER + ": " + summary); + +function test(ctors, { nextVal=undefined, + nextThrowVal=undefined, + modifier=undefined, + exceptionVal=undefined, + exceptionType=undefined, + closed=true }) { + function getIterable() { + let iterable = { + closed: false, + [Symbol.iterator]() { + let iterator = { + first: true, + next() { + if (this.first) { + this.first = false; + if (nextThrowVal) + throw nextThrowVal; + return nextVal; + } + return { value: undefined, done: true }; + }, + return() { + iterable.closed = true; + return {}; + } + }; + if (modifier) + modifier(iterator, iterable); + + return iterator; + } + }; + return iterable; + } + + for (let ctor of ctors) { + let iterable = getIterable(); + if (exceptionVal) { + let caught = false; + try { + new ctor(iterable); + } catch (e) { + assertEq(e, exceptionVal); + caught = true; + } + assertEq(caught, true); + } else if (exceptionType) { + assertThrowsInstanceOf(() => new ctor(iterable), exceptionType); + } else { + new ctor(iterable); + } + assertEq(iterable.closed, closed); + } +} + +// == Error cases with close == + +// ES 2017 draft 23.1.1.1 Map step 8.d.ii. +// ES 2017 draft 23.3.1.1 WeakMap step 8.d.ii. +test([Map, WeakMap], { + nextVal: { value: "non object", done: false }, + exceptionType: TypeError, + closed: true, +}); + +// ES 2017 draft 23.1.1.1 Map step 8.f. +// ES 2017 draft 23.3.1.1 WeakMap step 8.f. +test([Map, WeakMap], { + nextVal: { value: { get 0() { throw "0 getter throws"; } }, done: false }, + exceptionVal: "0 getter throws", + closed: true, +}); + +// ES 2017 draft 23.1.1.1 Map step 8.h. +// ES 2017 draft 23.3.1.1 WeakMap step 8.h. +test([Map, WeakMap], { + nextVal: { value: { 0: {}, get 1() { throw "1 getter throws"; } }, done: false }, + exceptionVal: "1 getter throws", + closed: true, +}); + +// ES 2017 draft 23.1.1.1 Map step 8.j. +// ES 2017 draft 23.3.1.1 WeakMap step 8.j. +class MyMap extends Map { + set(k, v) { + throw "setter throws"; + } +} +class MyWeakMap extends WeakMap { + set(k, v) { + throw "setter throws"; + } +} +test([MyMap, MyWeakMap], { + nextVal: { value: [{}, {}], done: false }, + exceptionVal: "setter throws", + closed: true, +}); + +// ES 2017 draft 23.2.1.1 Set step 8.e. +// ES 2017 draft 23.4.1.1 WeakSet step 8.e. +class MySet extends Set { + add(v) { + throw "adder throws"; + } +} +class MyWeakSet extends WeakSet { + add(v) { + throw "adder throws"; + } +} +test([MySet, MyWeakSet], { + nextVal: { value: {}, done: false }, + exceptionVal: "adder throws", + closed: true, +}); + +// ES 2021 draft 7.4.6 step 5. +// if GetMethod fails, the thrown value should be ignored. +test([MyMap, MyWeakMap], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + Object.defineProperty(iterator, "return", { + get: function() { + iterable.closed = true; + throw "return getter throws"; + } + }); + }, + exceptionVal: "setter throws", + closed: true, +}); +test([MySet, MyWeakSet], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + Object.defineProperty(iterator, "return", { + get: function() { + iterable.closed = true; + throw "return getter throws"; + } + }); + }, + exceptionVal: "adder throws", + closed: true, +}); +test([MyMap, MyWeakMap], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + Object.defineProperty(iterator, "return", { + get: function() { + iterable.closed = true; + return "non object"; + } + }); + }, + exceptionVal: "setter throws", + closed: true, +}); +test([MySet, MyWeakSet], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + Object.defineProperty(iterator, "return", { + get: function() { + iterable.closed = true; + return "non object"; + } + }); + }, + exceptionVal: "adder throws", + closed: true, +}); +test([MyMap, MyWeakMap], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + Object.defineProperty(iterator, "return", { + get: function() { + iterable.closed = true; + // Non callable. + return {}; + } + }); + }, + exceptionVal: "setter throws", + closed: true, +}); +test([MySet, MyWeakSet], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + Object.defineProperty(iterator, "return", { + get: function() { + iterable.closed = true; + // Non callable. + return {}; + } + }); + }, + exceptionVal: "adder throws", + closed: true, +}); + +// ES 2017 draft 7.4.6 steps 6. +// if return method throws, the thrown value should be ignored. +test([MyMap, MyWeakMap], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + iterator.return = function() { + iterable.closed = true; + throw "return throws"; + }; + }, + exceptionVal: "setter throws", + closed: true, +}); +test([MySet, MyWeakSet], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + iterator.return = function() { + iterable.closed = true; + throw "return throws"; + }; + }, + exceptionVal: "adder throws", + closed: true, +}); + +test([MyMap, MyWeakMap], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + iterator.return = function() { + iterable.closed = true; + return "non object"; + }; + }, + exceptionVal: "setter throws", + closed: true, +}); +test([MySet, MyWeakSet], { + nextVal: { value: [{}, {}], done: false }, + modifier: (iterator, iterable) => { + iterator.return = function() { + iterable.closed = true; + return "non object"; + }; + }, + exceptionVal: "adder throws", + closed: true, +}); + +// == Error cases without close == + +// ES 2017 draft 23.1.1.1 Map step 8.a. +// ES 2017 draft 23.3.1.1 WeakMap step 8.a. +// ES 2017 draft 23.2.1.1 Set step 8.a. +// ES 2017 draft 23.4.1.1 WeakSet step 8.a. +test([Map, WeakMap, Set, WeakSet], { + nextThrowVal: "next throws", + exceptionVal: "next throws", + closed: false, +}); +test([Map, WeakMap, Set, WeakSet], { + nextVal: { value: {}, get done() { throw "done getter throws"; } }, + exceptionVal: "done getter throws", + closed: false, +}); + +// ES 2017 draft 23.1.1.1 Map step 8.c. +// ES 2017 draft 23.3.1.1 WeakMap step 8.c. +// ES 2017 draft 23.2.1.1 Set step 8.c. +// ES 2017 draft 23.4.1.1 WeakSet step 8.c. +test([Map, WeakMap, Set, WeakSet], { + nextVal: { get value() { throw "value getter throws"; }, done: false }, + exceptionVal: "value getter throws", + closed: false, +}); + +// == Successful cases == + +test([Map, WeakMap], { + nextVal: { value: [{}, {}], done: false }, + closed: false, +}); +test([Set, WeakSet], { + nextVal: { value: {}, done: false }, + closed: false, +}); + +if (typeof reportCompare === 'function') + reportCompare(true, true); diff --git a/js/src/tests/non262/Map/constructor-iterator-primitive.js b/js/src/tests/non262/Map/constructor-iterator-primitive.js new file mode 100644 index 0000000000..e1fff5c3c9 --- /dev/null +++ b/js/src/tests/non262/Map/constructor-iterator-primitive.js @@ -0,0 +1,34 @@ +var BUGNUMBER = 1021835; +var summary = "Returning non-object from @@iterator should throw"; + +print(BUGNUMBER + ": " + summary); + +let ctors = [ + Map, + Set, + WeakMap, + WeakSet +]; + +let primitives = [ + 1, + true, + undefined, + null, + "foo", + Symbol.iterator +]; + +for (let ctor of ctors) { + for (let primitive of primitives) { + let arg = { + [Symbol.iterator]() { + return primitive; + } + }; + assertThrowsInstanceOf(() => new ctor(arg), TypeError); + } +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/Map/forEach-selfhosted-behavior.js b/js/src/tests/non262/Map/forEach-selfhosted-behavior.js new file mode 100644 index 0000000000..ed4d8b57f8 --- /dev/null +++ b/js/src/tests/non262/Map/forEach-selfhosted-behavior.js @@ -0,0 +1,51 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 987243; +var summary = "Don't use .call(...) in the self-hosted Map.prototype.forEach"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var functionCall = Function.prototype.call; + +function throwSyntaxError() +{ + throw new SyntaxError("Function.prototype.call incorrectly called"); +} + +function lalala() {} + +Function.prototype.call = throwSyntaxError; + +new Map().forEach(throwSyntaxError); +new Map([[1, 2]]).forEach(lalala); +new Map([[1, 2], [3, 4]]).forEach(lalala); + +Function.prototype.call = function() { this.set(42, "fnord"); }; + +new Map().forEach(throwSyntaxError); +new Map([[1, 2]]).forEach(lalala); +new Map([[1, 2], [3, 4]]).forEach(lalala); + +var callCount = 0; +Function.prototype.call = function() { callCount++; }; + +new Map().forEach(throwSyntaxError); +new Map([[1, 2]]).forEach(lalala); +new Map([[1, 2], [3, 4]]).forEach(lalala); + +assertEq(callCount, 0); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/non262/Map/getter-name.js b/js/src/tests/non262/Map/getter-name.js new file mode 100644 index 0000000000..08f7890c75 --- /dev/null +++ b/js/src/tests/non262/Map/getter-name.js @@ -0,0 +1,10 @@ +var BUGNUMBER = 1180290; +var summary = 'Map getters should have get prefix'; + +print(BUGNUMBER + ": " + summary); + +assertEq(Object.getOwnPropertyDescriptor(Map, Symbol.species).get.name, "get [Symbol.species]"); +assertEq(Object.getOwnPropertyDescriptor(Map.prototype, "size").get.name, "get size"); + +if (typeof reportCompare === 'function') + reportCompare(true, true); diff --git a/js/src/tests/non262/Map/iterable.js b/js/src/tests/non262/Map/iterable.js new file mode 100644 index 0000000000..cf6b7228ab --- /dev/null +++ b/js/src/tests/non262/Map/iterable.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +let length; +let iterable = { + [Symbol.iterator]() { return this; }, + next() { length = arguments.length; return {done: true}; } +}; + +new Map(iterable); +// ensure no arguments are passed to next() during construction (Bug 1197095) +assertEq(length, 0); + +let typeofThis; +Object.defineProperty(Number.prototype, Symbol.iterator, { + value() { + "use strict"; + typeofThis = typeof this; + return { next() { return {done: true}; } }; + } +}); + +new Map(0); +// ensure that iterable objects retain their type (Bug 1197094) +assertEq(typeofThis, "number"); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/Map/iterator-thisv-error.js b/js/src/tests/non262/Map/iterator-thisv-error.js new file mode 100644 index 0000000000..cc85c90f25 --- /dev/null +++ b/js/src/tests/non262/Map/iterator-thisv-error.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +function test(fn, thisv) { + var message; + try { + fn.call(thisv); + } catch (e) { + message = e.message; + } + + assertEq(/^\w+ method called on incompatible.+/.test(message), true); + assertEq(message.includes("std_"), false); +} + +for (var thisv of [null, undefined, false, true, 0, ""]) { + test(Map.prototype.values, thisv); + test(Map.prototype.keys, thisv); + test(Map.prototype.entries, thisv); + test(Map.prototype[Symbol.iterator], thisv); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/Map/record-tuple.js b/js/src/tests/non262/Map/record-tuple.js new file mode 100644 index 0000000000..92c9d68414 --- /dev/null +++ b/js/src/tests/non262/Map/record-tuple.js @@ -0,0 +1,42 @@ +// |reftest| skip-if(!this.hasOwnProperty("Record")) + +function test(input, query, same) { + assertEq(set(input).has(query), same); + assertEq(new Map([[input, 1]]).has(query), same); + if (same) assertEq(new Map([[input, 1]]).get(query), 1); +} +function first(it) { + for (const v of it) return v; +} +function set(v) { + return new Set([v]); +} + + +test(#[0, 1], #[0, 1], true); +test(#[0, 1], #[1, 0], false); + +test(#{x: 1}, #{x: 1}, true); +test(#{x: 1}, #{y: 1}, false); +test(#{x: 1}, #{x: 0}, false); +test(#{x: 0, y: 1}, #{x: 0, y: 1}, true); +test(#{x: 0, y: 1}, #{y: 1, x: 0}, true); +test(#{x: 0, y: 1}, #{x: 1, y: 0}, false); +test(#{x: 0, y: 1}, #{x: 0, y: 0}, false); + +test(#[NaN], #[NaN], true); +test(#{x: NaN}, #{x: NaN}, true); +test(#[+0], #[-0], true); +test(#{x: +0}, #{x: -0}, true); +assertEq(Object.is(first(set(#[+0]))[0], +0), true); +assertEq(Object.is(first(set(#[-0]))[0], -0), true); +assertEq(Object.is(first(set(#{x: +0})).x, +0), true); +assertEq(Object.is(first(set(#{x: -0})).x, -0), true); + +// Test ropes. +test(#["ab" + String.fromCodePoint(67)], #["ab" + String.fromCodePoint(67)], true); +test(#{ x: "ab" + String.fromCodePoint(67) }, #{ x: "ab" + String.fromCodePoint(67) }, true); +test(#["ab" + String.fromCodePoint(67)], #["ab" + String.fromCodePoint(68)], false); +test(#{ x: "ab" + String.fromCodePoint(67) }, #{ x: "ab" + String.fromCodePoint(68) }, false); + +if (typeof reportCompare === "function") reportCompare(0, 0); diff --git a/js/src/tests/non262/Map/shell.js b/js/src/tests/non262/Map/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/Map/shell.js diff --git a/js/src/tests/non262/Map/symbols.js b/js/src/tests/non262/Map/symbols.js new file mode 100644 index 0000000000..30589a9732 --- /dev/null +++ b/js/src/tests/non262/Map/symbols.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +var m = new Map; + +// Symbols can be Map keys. +var sym = Symbol(); +m.set(sym, "zero"); +assertEq(m.has(sym), true); +assertEq(m.get(sym), "zero"); +assertEq(m.has(Symbol()), false); +assertEq(m.get(Symbol()), undefined); +assertEq([...m][0][0], sym); +m.set(sym, "replaced"); +assertEq(m.get(sym), "replaced"); +m.delete(sym); +assertEq(m.has(sym), false); +assertEq(m.size, 0); + +// Symbols returned by Symbol.for() can be Map keys. +for (var word of "that that is is that that is not is not is that not it".split(' ')) { + sym = Symbol.for(word); + m.set(sym, (m.get(sym) || 0) + 1); +} +assertDeepEq([...m], [ + [Symbol.for("that"), 5], + [Symbol.for("is"), 5], + [Symbol.for("not"), 3], + [Symbol.for("it"), 1] +]); + +if (typeof reportCompare === "function") + reportCompare(0, 0); |