summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/Set/is-disjoint-from.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/Set/is-disjoint-from.js')
-rw-r--r--js/src/tests/non262/Set/is-disjoint-from.js448
1 files changed, 448 insertions, 0 deletions
diff --git a/js/src/tests/non262/Set/is-disjoint-from.js b/js/src/tests/non262/Set/is-disjoint-from.js
new file mode 100644
index 0000000000..e518accda4
--- /dev/null
+++ b/js/src/tests/non262/Set/is-disjoint-from.js
@@ -0,0 +1,448 @@
+// |reftest| shell-option(--enable-new-set-methods) skip-if(!Set.prototype.isDisjointFrom)
+
+assertEq(typeof Set.prototype.isDisjointFrom, "function");
+assertDeepEq(Object.getOwnPropertyDescriptor(Set.prototype.isDisjointFrom, "length"), {
+ value: 1, writable: false, enumerable: false, configurable: true,
+});
+assertDeepEq(Object.getOwnPropertyDescriptor(Set.prototype.isDisjointFrom, "name"), {
+ value: "isDisjointFrom", writable: false, enumerable: false, configurable: true,
+});
+
+const emptySet = new Set();
+const emptySetLike = new SetLike();
+const emptyMap = new Map();
+
+function asMap(values) {
+ return new Map(values.map(v => [v, v]));
+}
+
+// Empty set is disjoint from the empty set.
+assertEq(emptySet.isDisjointFrom(emptySet), true);
+assertEq(emptySet.isDisjointFrom(emptySetLike), true);
+assertEq(emptySet.isDisjointFrom(emptyMap), true);
+
+// Test native Set, Set-like, and Map objects.
+for (let values of [
+ [], [1], [1, 2], [1, true, null, {}],
+]) {
+ // Disjoint operation with an empty set.
+ assertEq(new Set(values).isDisjointFrom(emptySet), true);
+ assertEq(new Set(values).isDisjointFrom(emptySetLike), true);
+ assertEq(new Set(values).isDisjointFrom(emptyMap), true);
+ assertEq(emptySet.isDisjointFrom(new Set(values)), true);
+ assertEq(emptySet.isDisjointFrom(new SetLike(values)), true);
+ assertEq(emptySet.isDisjointFrom(asMap(values)), true);
+
+ // Two sets with the exact same values.
+ assertEq(new Set(values).isDisjointFrom(new Set(values)), values.length === 0);
+ assertEq(new Set(values).isDisjointFrom(new SetLike(values)), values.length === 0);
+ assertEq(new Set(values).isDisjointFrom(asMap(values)), values.length === 0);
+
+ // Disjoint operation of the same set object.
+ let set = new Set(values);
+ assertEq(set.isDisjointFrom(set), values.length === 0);
+}
+
+// Check property accesses are in the correct order.
+{
+ let log = [];
+
+ let sizeValue = 0;
+
+ let {proxy: keysIter} = LoggingProxy({
+ next() {
+ log.push("next()");
+ return {done: true};
+ }
+ }, log);
+
+ let {proxy: setLike} = LoggingProxy({
+ size: {
+ valueOf() {
+ log.push("valueOf()");
+ return sizeValue;
+ }
+ },
+ has() {
+ throw new Error("Unexpected call to |has| method");
+ },
+ keys() {
+ log.push("keys()");
+ return keysIter;
+ },
+ }, log);
+
+ assertEq(emptySet.isDisjointFrom(setLike), true);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ ]);
+
+ // |keys| is called when the this-value has more elements.
+
+ log.length = 0;
+ assertEq(new Set([1]).isDisjointFrom(setLike), true);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ "keys()",
+ "[[get]]", "next",
+ "next()",
+ ]);
+}
+
+// Check input validation.
+{
+ let log = [];
+
+ const nonCallable = {};
+ let sizeValue = 0;
+
+ let {proxy: keysIter} = LoggingProxy({
+ next: nonCallable,
+ }, log);
+
+ let {proxy: setLike, obj: setLikeObj} = LoggingProxy({
+ size: {
+ valueOf() {
+ log.push("valueOf()");
+ return sizeValue;
+ }
+ },
+ has() {
+ throw new Error("Unexpected call to |has| method");
+ },
+ keys() {
+ log.push("keys()");
+ return keysIter;
+ },
+ }, log);
+
+ log.length = 0;
+ assertEq(emptySet.isDisjointFrom(setLike), true);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ ]);
+
+ log.length = 0;
+ assertThrowsInstanceOf(() => new Set([1]).isDisjointFrom(setLike), TypeError);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ "keys()",
+ "[[get]]", "next",
+ ]);
+
+ // Change |keys| to return a non-object value.
+ setLikeObj.keys = () => 123;
+
+ log.length = 0;
+ assertEq(emptySet.isDisjointFrom(setLike), true);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ ]);
+
+ log.length = 0;
+ assertThrowsInstanceOf(() => new Set([1]).isDisjointFrom(setLike), TypeError);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ ]);
+
+ // Change |keys| to a non-callable value.
+ setLikeObj.keys = nonCallable;
+
+ log.length = 0;
+ assertThrowsInstanceOf(() => emptySet.isDisjointFrom(setLike), TypeError);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ "[[get]]", "keys",
+ ]);
+
+ // Change |has| to a non-callable value.
+ setLikeObj.has = nonCallable;
+
+ log.length = 0;
+ assertThrowsInstanceOf(() => emptySet.isDisjointFrom(setLike), TypeError);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ "[[get]]", "has",
+ ]);
+
+ // Change |size| to NaN.
+ sizeValue = NaN;
+
+ log.length = 0;
+ assertThrowsInstanceOf(() => emptySet.isDisjointFrom(setLike), TypeError);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ ]);
+
+ // Change |size| to undefined.
+ sizeValue = undefined;
+
+ log.length = 0;
+ assertThrowsInstanceOf(() => emptySet.isDisjointFrom(setLike), TypeError);
+
+ assertEqArray(log, [
+ "[[get]]", "size",
+ "valueOf()",
+ ]);
+}
+
+// Doesn't accept Array as an input.
+assertThrowsInstanceOf(() => emptySet.isDisjointFrom([]), TypeError);
+
+// Works with Set subclasses.
+{
+ class MySet extends Set {}
+
+ let myEmptySet = new MySet;
+
+ assertEq(emptySet.isDisjointFrom(myEmptySet), true);
+ assertEq(myEmptySet.isDisjointFrom(myEmptySet), true);
+ assertEq(myEmptySet.isDisjointFrom(emptySet), true);
+}
+
+// Doesn't access any properties on the this-value.
+{
+ let log = [];
+
+ let {proxy: setProto} = LoggingProxy(Set.prototype, log);
+
+ let set = new Set([]);
+ Object.setPrototypeOf(set, setProto);
+
+ assertEq(Set.prototype.isDisjointFrom.call(set, emptySet), true);
+
+ assertEqArray(log, []);
+}
+
+// Throws a TypeError when the this-value isn't a Set object.
+for (let thisValue of [
+ null, undefined, true, "", {}, new Map, new Proxy(new Set, {}),
+]) {
+ assertThrowsInstanceOf(() => Set.prototype.isDisjointFrom.call(thisValue, emptySet), TypeError);
+}
+
+// Calls |has| when the this-value has fewer keys.
+{
+ const keys = [1, 2, 3];
+
+ for (let size of [keys.length, 100, Infinity]) {
+ let i = 0;
+
+ let setLike = {
+ size,
+ has(v) {
+ assertEq(this, setLike);
+ assertEq(arguments.length, 1);
+ assertEq(i < keys.length, true);
+ assertEq(v, keys[i++]);
+ return false;
+ },
+ keys() {
+ throw new Error("Unexpected call to |keys| method");
+ },
+ };
+
+ assertEq(new Set([1, 2, 3]).isDisjointFrom(setLike), true);
+ }
+}
+
+// Calls |keys| when the this-value has more keys.
+{
+ const keys = [1, 2, 3];
+
+ for (let size of [0, 1, 2]) {
+ let setLike = {
+ size,
+ has() {
+ throw new Error("Unexpected call to |has| method");
+ },
+ *keys() {
+ yield* [4, 5, 6];
+ },
+ };
+
+ assertEq(new Set(keys).isDisjointFrom(setLike), true);
+ }
+
+ // Also test early return after first match.
+ for (let size of [0, 1, 2]) {
+ let setLike = {
+ size,
+ has() {
+ throw new Error("Unexpected call to |has| method");
+ },
+ *keys() {
+ yield keys[0];
+
+ throw new Error("keys iterator called too many times");
+ },
+ };
+
+ assertEq(new Set(keys).isDisjointFrom(setLike), false);
+ }
+}
+
+// Test when this-value is modified during iteration.
+{
+ let set = new Set([]);
+
+ // |setLike| has more entries than |set|.
+ let setLike = {
+ size: 100,
+ has(v) {
+ assertEq(set.has(v), true);
+ set.delete(v);
+ return false;
+ },
+ keys() {
+ throw new Error("Unexpected call to |keys| method");
+ },
+ };
+
+ assertEq(set.isDisjointFrom(setLike), true);
+ assertSetContainsExactOrderedItems(set, []);
+}
+{
+ let set = new Set([0]);
+
+ let keys = [1, 2, 3];
+
+ let lastValue;
+ let keysIter = {
+ next() {
+ if (lastValue !== undefined) {
+ assertEq(set.has(lastValue), false);
+ set.add(lastValue);
+
+ lastValue = undefined;
+ }
+
+ if (keys.length) {
+ let value = keys.shift();
+ lastValue = value;
+ return {
+ done: false,
+ get value() {
+ return value;
+ }
+ };
+ }
+ return {
+ done: true,
+ get value() {
+ throw new Error("Unexpected call to |value| getter");
+ }
+ };
+ }
+ };
+
+ // |setLike| has fewer entries than |set|.
+ let setLike = {
+ size: 0,
+ has() {
+ throw new Error("Unexpected call to |has| method");
+ },
+ keys() {
+ return keysIter;
+ },
+ };
+
+ assertEq(set.isDisjointFrom(setLike), true);
+ assertSetContainsExactOrderedItems(set, [0, 1, 2, 3]);
+}
+
+// IteratorClose is called for early returns.
+{
+ let log = [];
+
+ let keysIter = {
+ next() {
+ log.push("next");
+ return {done: false, value: 1};
+ },
+ return() {
+ log.push("return");
+ return {
+ get value() { throw new Error("Unexpected call to |value| getter"); },
+ get done() { throw new Error("Unexpected call to |done| getter"); },
+ };
+ }
+ };
+
+ let setLike = {
+ size: 0,
+ has() {
+ throw new Error("Unexpected call to |has| method");
+ },
+ keys() {
+ return keysIter;
+ },
+ };
+
+ assertEq(new Set([1, 2, 3]).isDisjointFrom(setLike), false);
+
+ assertEqArray(log, ["next", "return"]);
+}
+
+// IteratorClose isn't called for non-early returns.
+{
+ let setLike = new SetLike([4, 5, 6]);
+
+ assertEq(new Set([1, 2, 3]).isDisjointFrom(setLike), true);
+}
+
+// Tests which modify any built-ins should appear last, because modifications may disable
+// optimised code paths.
+
+// Doesn't call the built-in |Set.prototype.{has, keys, size}| functions.
+const SetPrototypeHas = Object.getOwnPropertyDescriptor(Set.prototype, "has");
+const SetPrototypeKeys = Object.getOwnPropertyDescriptor(Set.prototype, "keys");
+const SetPrototypeSize = Object.getOwnPropertyDescriptor(Set.prototype, "size");
+
+delete Set.prototype.has;
+delete Set.prototype.keys;
+delete Set.prototype.size;
+
+try {
+ let set = new Set([1, 2, 3]);
+ let other = new SetLike([1, 2, 3]);
+ assertEq(set.isDisjointFrom(other), false);
+} finally {
+ Object.defineProperty(Set.prototype, "has", SetPrototypeHas);
+ Object.defineProperty(Set.prototype, "keys", SetPrototypeKeys);
+ Object.defineProperty(Set.prototype, "size", SetPrototypeSize);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);