mirror of https://github.com/tc39/test262.git
Add Set.prototype.union tests (#3816)
* Beginning of adding Set.prototype.union tests * Fix description * Add tests for GetSetRecord Which also allows Set-like objects * Add title to test descriptions * Add test for ensuring values are appended * Add tests for properties of union Also: tests for RequireInternalSlot, Constructor, BuiltIns. Added a test to ensure that -0F is converted to +0F * Ensure Set.prototype.add is not called as part of .union * fix lint issues * Set subclassing and Symbol.species tests * Set.prototype.union tests for arrays and subclass methods * Add the Set-methods frontmatter feature flag * Add additional Set.prototype.union test for edge cases * Update test/built-ins/Set/GetSetRecord/keys-is-callable.js Co-authored-by: Kevin Gibbons <bakkot@gmail.com> * Use compareArray() for assertions * Remove class field syntax * Remove unused args * Update test/built-ins/Set/prototype/union/subclass-receiver-methods.js Co-authored-by: Jordan Harband <ljharb@gmail.com> * Return original 'add' * address comments * add one more mutation in the evil mutating iterator test * address further comments --------- Co-authored-by: Kevin Gibbons <bakkot@gmail.com> Co-authored-by: Jordan Harband <ljharb@gmail.com> Co-authored-by: Ms2ger <Ms2ger@igalia.com>
This commit is contained in:
parent
5962be6d66
commit
60310b70bc
|
@ -210,6 +210,7 @@ regexp-named-groups
|
|||
regexp-unicode-property-escapes
|
||||
rest-parameters
|
||||
Set
|
||||
Set-methods
|
||||
SharedArrayBuffer
|
||||
string-trimming
|
||||
String.fromCodePoint
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union should not call Set.prototype.add
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = new Set([2, 3]);
|
||||
const expected = [1, 2, 3];
|
||||
|
||||
const originalAdd = Set.prototype.add;
|
||||
let count = 0;
|
||||
Set.prototype.add = function (...rest) {
|
||||
count++;
|
||||
return originalAdd.apply(this, rest);
|
||||
};
|
||||
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
assert.sameValue(count, 0, "Add is never called");
|
||||
|
||||
Set.prototype.add = originalAdd;
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: GetSetRecord allows instances of Set-like classes
|
||||
info: |
|
||||
1. If obj is not an Object, throw a TypeError exception.
|
||||
2. Let rawSize be ? Get(obj, "size").
|
||||
...
|
||||
7. Let has be ? Get(obj, "has").
|
||||
...
|
||||
9. Let keys be ? Get(obj, "keys").
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = new class {
|
||||
get size() {
|
||||
return 2;
|
||||
}
|
||||
has() {
|
||||
throw new Test262Error("Set.prototype.union should not invoke .has on its argument");
|
||||
}
|
||||
* keys() {
|
||||
yield 2;
|
||||
yield 3;
|
||||
}
|
||||
};
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: GetSetRecord allows Set-like objects
|
||||
info: |
|
||||
1. If obj is not an Object, throw a TypeError exception.
|
||||
2. Let rawSize be ? Get(obj, "size").
|
||||
...
|
||||
7. Let has be ? Get(obj, "has").
|
||||
...
|
||||
9. Let keys be ? Get(obj, "keys").
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = {
|
||||
size: 2,
|
||||
has: () => {},
|
||||
keys: function* keys() {
|
||||
yield 2;
|
||||
yield 3;
|
||||
},
|
||||
};
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union appends new values to a copy of the original Set
|
||||
info: |
|
||||
7.b.iii.1 Append nextValue to resultSetData.
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = new Set([-1, 0, 3]);
|
||||
const expected = [1, 2, -1, 0, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
|
||||
const s3 = new Set([1, 2, -3]);
|
||||
const s4 = new Set([-1, 0]);
|
||||
const expected2 = [1, 2, -3, -1, 0];
|
||||
const combined2 = s3.union(s4);
|
||||
|
||||
assert.compareArray([...combined2], expected2);
|
||||
assert.sameValue(
|
||||
combined2 instanceof Set,
|
||||
true,
|
||||
"The returned object is a Set"
|
||||
);
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union doesn't work with arrays
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = [3];
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"Throws an error when an array is used"
|
||||
);
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Tests that Set.prototype.union meets the requirements for built-in objects
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
assert.sameValue(
|
||||
Object.isExtensible(Set.prototype.union),
|
||||
true,
|
||||
"Built-in objects must be extensible."
|
||||
);
|
||||
|
||||
assert.sameValue(
|
||||
Object.prototype.toString.call(Set.prototype.union),
|
||||
"[object Function]",
|
||||
"Object.prototype.toString"
|
||||
);
|
||||
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(Set.prototype.union),
|
||||
Function.prototype,
|
||||
"prototype"
|
||||
);
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-getsetrecord
|
||||
description: GetSetRecord throws if obj is not an object
|
||||
info: |
|
||||
1. If obj is not an Object, throw a TypeError exception.
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
let s1 = new Set([1]);
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(1);
|
||||
},
|
||||
"number"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union("");
|
||||
},
|
||||
"string"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(1n);
|
||||
},
|
||||
"bigint"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(false);
|
||||
},
|
||||
"boolean"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(undefined);
|
||||
},
|
||||
"undefined"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(null);
|
||||
},
|
||||
"null"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(Symbol("test"));
|
||||
},
|
||||
"symbol"
|
||||
);
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union combines with Map
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const m1 = new Map([
|
||||
[2, "two"],
|
||||
[3, "three"],
|
||||
]);
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(m1);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union can combine empty Sets
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([]);
|
||||
const s2 = new Set([1, 2]);
|
||||
let expected = [1, 2];
|
||||
let combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
|
||||
const s3 = new Set([1, 2]);
|
||||
const s4 = new Set([]);
|
||||
expected = [1, 2];
|
||||
combined = s3.union(s4);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
|
||||
const s5 = new Set([]);
|
||||
const s6 = new Set([]);
|
||||
expected = [];
|
||||
combined = s5.union(s6);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union is successful when called on itself
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const expected = [1, 2];
|
||||
const combined = s1.union(s1);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union can combine Sets that have the same content
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = new Set([1, 2]);
|
||||
const expected = [1, 2];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union combines Sets
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = new Set([2, 3]);
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union converts -0𝔽 to +0𝔽
|
||||
info: |
|
||||
7.b.ii. If nextValue is -0𝔽, set nextValue to +0𝔽.
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const setlikeWithMinusZero = {
|
||||
size: 1,
|
||||
has: function () {
|
||||
throw new Test262Error("Set.prototype.union should not invoke .has on its argument");
|
||||
},
|
||||
keys: function () {
|
||||
// we use an array here because the Set constructor would normalize away -0
|
||||
return [-0].values();
|
||||
},
|
||||
};
|
||||
|
||||
const s1 = new Set([1]);
|
||||
let expected = [1, +0];
|
||||
let combined = s1.union(setlikeWithMinusZero);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
|
||||
const s2 = new Set([+0]);
|
||||
expected = [+0];
|
||||
combined = s2.union(setlikeWithMinusZero);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-getsetrecord
|
||||
description: GetSetRecord throws an exception if the Set-like object's 'has' property is not callable
|
||||
info: |
|
||||
7. Let has be ? Get(obj, "has").
|
||||
8. If IsCallable(has) is false, throw a TypeError exception.
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = {
|
||||
size: 2,
|
||||
has: undefined,
|
||||
keys: function* keys() {
|
||||
yield 2;
|
||||
yield 3;
|
||||
},
|
||||
};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when has is undefined"
|
||||
);
|
||||
|
||||
s2.has = {};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when has is not callable"
|
||||
);
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-getsetrecord
|
||||
description: GetSetRecord throws an exception if the Set-like object's 'keys' property is not callable
|
||||
info: |
|
||||
9. Let keys be ? Get(obj, "keys").
|
||||
10. If IsCallable(keys) is false, throw a TypeError exception.
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = {
|
||||
size: 2,
|
||||
has: () => {},
|
||||
keys: undefined,
|
||||
};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when keys is undefined"
|
||||
);
|
||||
|
||||
s2.keys = {};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when keys is not callable"
|
||||
);
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union length property
|
||||
info: |
|
||||
Set.prototype.union ( other )]
|
||||
includes: [propertyHelper.js]
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
assert.sameValue(typeof Set.prototype.union, "function");
|
||||
|
||||
verifyProperty(Set.prototype.union, "length", {
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
configurable: true,
|
||||
value: 1,
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union name property
|
||||
info: |
|
||||
Set.prototype.union ( other )]
|
||||
includes: [propertyHelper.js]
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
assert.sameValue(typeof Set.prototype.union, "function");
|
||||
|
||||
verifyProperty(Set.prototype.union, "name", {
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
configurable: true,
|
||||
value: "union",
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union does not implement [[Construct]], is not new-able
|
||||
includes: [isConstructor.js]
|
||||
features: [Reflect.construct, Set-methods]
|
||||
---*/
|
||||
|
||||
assert.sameValue(
|
||||
isConstructor(Set.prototype.union),
|
||||
false,
|
||||
"isConstructor(Set.prototype.union) must return false"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => {
|
||||
new Set.prototype.union();
|
||||
},
|
||||
"`new Set.prototype.union()` throws TypeError"
|
||||
);
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (C) 2023 Kevin Gibbons, Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union throws when receiver is not a Set
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
class MySetLike {
|
||||
constructor() {
|
||||
this.size = 2;
|
||||
this.has = () => {};
|
||||
this.keys = function* keys() {
|
||||
yield 2;
|
||||
yield 3;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const s1 = new MySetLike();
|
||||
const s2 = new Set();
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => {
|
||||
Set.prototype.union.call(s1, s2);
|
||||
},
|
||||
"Set-like class"
|
||||
);
|
||||
|
||||
const s3 = {
|
||||
size: 2,
|
||||
has: () => {},
|
||||
keys: function* keys() {
|
||||
yield 2;
|
||||
yield 3;
|
||||
},
|
||||
};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => {
|
||||
Set.prototype.union.call(s3, s2);
|
||||
},
|
||||
"Set-like object"
|
||||
);
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union RequireInternalSlot
|
||||
info: |
|
||||
2. Perform ? RequireInternalSlot(O, [[SetData]])
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
const union = Set.prototype.union;
|
||||
|
||||
assert.sameValue(typeof union, "function");
|
||||
|
||||
assert.throws(TypeError, () => union.call(undefined), "undefined");
|
||||
assert.throws(TypeError, () => union.call(null), "null");
|
||||
assert.throws(TypeError, () => union.call(true), "true");
|
||||
assert.throws(TypeError, () => union.call(""), "empty string");
|
||||
assert.throws(TypeError, () => union.call(Symbol()), "symbol");
|
||||
assert.throws(TypeError, () => union.call(1), "1");
|
||||
assert.throws(TypeError, () => union.call(1n), "1n");
|
||||
assert.throws(TypeError, () => union.call({}), "plain object");
|
||||
assert.throws(TypeError, () => union.call([]), "array");
|
||||
assert.throws(TypeError, () => union.call(new Map()), "map");
|
||||
assert.throws(TypeError, () => union.call(Set.prototype), "Set.prototype");
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (C) 2023 Kevin Gibbons, Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union consumes a set-like array as a set-like, not an array
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = [5, 6];
|
||||
s2.size = 3;
|
||||
s2.has = function () {
|
||||
throw new Test262Error("Set.prototype.union should not invoke .has on its argument");
|
||||
};
|
||||
s2.keys = function () {
|
||||
return [2, 3, 4].values();
|
||||
};
|
||||
|
||||
const expected = [1, 2, 3, 4];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (C) 2023 Kevin Gibbons, Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union maintains values even when a custom Set-like class mutates the receiver
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const baseSet = new Set(["a", "b", "c", "d", "e"]);
|
||||
|
||||
function mutatingIterator() {
|
||||
let index = 0;
|
||||
let values = ["x", "y"];
|
||||
return {
|
||||
next() {
|
||||
baseSet.delete("b");
|
||||
baseSet.delete("c");
|
||||
baseSet.add("b");
|
||||
baseSet.add("d");
|
||||
return {
|
||||
done: index >= 2,
|
||||
value: values[index++],
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const evilSetLike = {
|
||||
size: 2,
|
||||
get has() {
|
||||
baseSet.add("q");
|
||||
return function () {
|
||||
throw new Test262Error("Set.prototype.union should not invoke .has on its argument");
|
||||
};
|
||||
},
|
||||
keys() {
|
||||
return mutatingIterator();
|
||||
},
|
||||
};
|
||||
|
||||
const combined = baseSet.union(evilSetLike);
|
||||
const expectedCombined = ["a", "b", "c", "d", "e", "q", "x", "y"];
|
||||
assert.compareArray([...combined], expectedCombined);
|
||||
|
||||
const expectedNewBase = ["a", "d", "e", "q", "b"];
|
||||
assert.compareArray([...baseSet], expectedNewBase);
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (C) 2023 Kevin Gibbons, Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union calls a Set-like class's methods in order
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
const observedOrder = [];
|
||||
const expectedOrder = [
|
||||
"getting size",
|
||||
"ToNumber(size)",
|
||||
"getting has",
|
||||
"getting keys",
|
||||
"calling keys",
|
||||
"getting next",
|
||||
// first iteration, has value
|
||||
"calling next",
|
||||
"getting done",
|
||||
"getting value",
|
||||
// second iteration, has value
|
||||
"calling next",
|
||||
"getting done",
|
||||
"getting value",
|
||||
// third iteration, no value; ends
|
||||
"calling next",
|
||||
"getting done",
|
||||
];
|
||||
|
||||
function observableIterator() {
|
||||
let values = ["a", "b"];
|
||||
let index = 0;
|
||||
return {
|
||||
get next() {
|
||||
observedOrder.push("getting next");
|
||||
return function () {
|
||||
observedOrder.push("calling next");
|
||||
return {
|
||||
get done() {
|
||||
observedOrder.push("getting done");
|
||||
return index >= values.length;
|
||||
},
|
||||
get value() {
|
||||
observedOrder.push("getting value");
|
||||
return values[index++];
|
||||
},
|
||||
};
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
class MySetLike {
|
||||
get size() {
|
||||
observedOrder.push("getting size");
|
||||
return {
|
||||
valueOf: function () {
|
||||
observedOrder.push("ToNumber(size)");
|
||||
return 2;
|
||||
},
|
||||
};
|
||||
}
|
||||
get has() {
|
||||
observedOrder.push("getting has");
|
||||
return function () {
|
||||
throw new Test262Error("Set.prototype.union should not invoke .has on its argument");
|
||||
};
|
||||
}
|
||||
get keys() {
|
||||
observedOrder.push("getting keys");
|
||||
return function () {
|
||||
observedOrder.push("calling keys");
|
||||
return observableIterator();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = new MySetLike();
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray(observedOrder, expectedOrder);
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-getsetrecord
|
||||
description: GetSetRecord throws an exception if the Set-like object has a size that is coerced to NaN
|
||||
info: |
|
||||
2. Let rawSize be ? Get(obj, "size").
|
||||
3. Let numSize be ? ToNumber(rawSize).
|
||||
4. NOTE: If rawSize is undefined, then numSize will be NaN.
|
||||
5. If numSize is NaN, throw a TypeError exception.
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
const s1 = new Set([1, 2]);
|
||||
const s2 = {
|
||||
size: undefined,
|
||||
has: () => {},
|
||||
keys: function* keys() {
|
||||
yield 2;
|
||||
yield 3;
|
||||
},
|
||||
};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when size is undefined"
|
||||
);
|
||||
|
||||
s2.size = NaN;
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when size is NaN"
|
||||
);
|
||||
|
||||
let coercionCalls = 0;
|
||||
s2.size = {
|
||||
valueOf: function() {
|
||||
++coercionCalls;
|
||||
return NaN;
|
||||
},
|
||||
};
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when size coerces to NaN"
|
||||
);
|
||||
assert.sameValue(coercionCalls, 1, "GetSetRecord coerces size");
|
||||
|
||||
s2.size = 0n;
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when size is a BigInt"
|
||||
);
|
||||
|
||||
s2.size = "string";
|
||||
assert.throws(
|
||||
TypeError,
|
||||
function () {
|
||||
s1.union(s2);
|
||||
},
|
||||
"GetSetRecord throws an error when size is a non-numeric string"
|
||||
);
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union works on subclasses of Set, but never calls the receiver's size/has/keys methods
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
let sizeCount = 0;
|
||||
let hasCount = 0;
|
||||
let keysCount = 0;
|
||||
|
||||
class MySet extends Set {
|
||||
size(...rest) {
|
||||
sizeCount++;
|
||||
return super.size(...rest);
|
||||
}
|
||||
|
||||
has(...rest) {
|
||||
hasCount++;
|
||||
return super.has(...rest);
|
||||
}
|
||||
|
||||
keys(...rest) {
|
||||
keysCount++;
|
||||
return super.keys(...rest);
|
||||
}
|
||||
}
|
||||
|
||||
const s1 = new MySet([1, 2]);
|
||||
const s2 = new Set([2, 3]);
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
assert.sameValue(
|
||||
combined instanceof MySet,
|
||||
false,
|
||||
"The returned object is a Set, not a subclass"
|
||||
);
|
||||
assert.sameValue(sizeCount, 0, "size should not be called on the receiver");
|
||||
assert.sameValue(hasCount, 0, "has should not be called on the receiver");
|
||||
assert.sameValue(keysCount, 0, "keys should not be called on the receiver");
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union works on subclasses of Set, but returns an instance of Set even when Symbol.species is overridden.
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
var count = 0;
|
||||
class MySet extends Set {
|
||||
static get [Symbol.species]() {
|
||||
count++;
|
||||
return Set;
|
||||
}
|
||||
}
|
||||
|
||||
const s1 = new MySet([1, 2]);
|
||||
const s2 = new Set([2, 3]);
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(count, 0, "Symbol.species is never called");
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
assert.sameValue(
|
||||
combined instanceof MySet,
|
||||
false,
|
||||
"The returned object is a Set, not a subclass"
|
||||
);
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union works on subclasses of Set, but returns an instance of Set
|
||||
features: [Set-methods]
|
||||
includes: [compareArray.js]
|
||||
---*/
|
||||
|
||||
class MySet extends Set {}
|
||||
|
||||
const s1 = new MySet([1, 2]);
|
||||
const s2 = new Set([2, 3]);
|
||||
const expected = [1, 2, 3];
|
||||
const combined = s1.union(s2);
|
||||
|
||||
assert.compareArray([...combined], expected);
|
||||
assert.sameValue(combined instanceof Set, true, "The returned object is a Set");
|
||||
assert.sameValue(
|
||||
combined instanceof MySet,
|
||||
false,
|
||||
"The returned object is a Set, not a subclass"
|
||||
);
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (C) 2023 Anthony Frehner. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-set.prototype.union
|
||||
description: Set.prototype.union properties
|
||||
includes: [propertyHelper.js]
|
||||
features: [Set-methods]
|
||||
---*/
|
||||
|
||||
assert.sameValue(
|
||||
typeof Set.prototype.union,
|
||||
"function",
|
||||
"`typeof Set.prototype.union` is `'function'`"
|
||||
);
|
||||
|
||||
verifyProperty(Set.prototype, "union", {
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
Loading…
Reference in New Issue