forked from tc39/test262
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Array.fromAsync various remaining coverage
This contains a few more tests for Array.fromAsync, in addition to what has already been merged and what is under review at tc39#3791. This covers the following items from the testing plan at tc39#3725: - Success cases - Creates promise - Create new array/arraylike in promise (with length = length property) - Input - Invalid input values - nonconforming object (arraylike without length, missing keys) - Covered by polyfill tests - Result promise rejects if length access fails (non-iterable input) - Unaffected by globalThis.Symbol mutation (non-iterable) - this-value - this-value is a constructor - this-value is not a constructor - If this is a constructor, and items doesn't have a Symbol.iterator, returns a new instance of this - Iterator closed when property creation on this fails - Returned promise rejects when ^ - Other tests - Error is thrown for all CreateDataProperty fails - Non-writable properties are overwritten by CreateDataProperty - Input with missing values
- Loading branch information
Showing
16 changed files
with
610 additions
and
0 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
test/built-ins/Array/fromAsync/asyncitems-arraylike-holes.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: Array-like object with holes treats the holes as undefined | ||
info: | | ||
3.k.vii.2. Let _kValue_ be ? Get(_arrayLike_, _Pk_). | ||
features: [Array.fromAsync] | ||
flags: [async] | ||
includes: [asyncHelpers.js, compareArray.js] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
const arrayLike = Object.create(null); | ||
arrayLike.length = 5; | ||
arrayLike[0] = 0; | ||
arrayLike[1] = 1; | ||
arrayLike[2] = 2; | ||
arrayLike[4] = 4; | ||
|
||
const array = await Array.fromAsync(arrayLike); | ||
assert.compareArray(array, [0, 1, 2, undefined, 4], "holes in array-like treated as undefined"); | ||
}); |
25 changes: 25 additions & 0 deletions
25
test/built-ins/Array/fromAsync/asyncitems-arraylike-length-accessor-throws.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: Rejects on array-like object whose length cannot be gotten | ||
info: | | ||
3.k.iii. Let _len_ be ? LengthOfArrayLike(_arrayLike_). | ||
features: [Array.fromAsync] | ||
flags: [async] | ||
includes: [asyncHelpers.js] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
await assert.throwsAsync(Test262Error, () => Array.fromAsync({ | ||
get length() { | ||
throw new Test262Error('accessing length property fails'); | ||
} | ||
}), "Promise should be rejected if array-like length getter throws"); | ||
|
||
await assert.throwsAsync(TypeError, () => Array.fromAsync({ | ||
length: 1n, | ||
0: 0 | ||
}), "Promise should be rejected if array-like length can't be converted to a number"); | ||
}); |
31 changes: 31 additions & 0 deletions
31
test/built-ins/Array/fromAsync/asyncitems-arraylike-too-long.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Promise is rejected if the length of the array-like to copy is out of range | ||
info: | | ||
j. If _iteratorRecord_ is not *undefined*, then | ||
... | ||
k. Else, | ||
... | ||
iv. If IsConstructor(_C_) is *true*, then | ||
... | ||
v. Else, | ||
1. Let _A_ be ? ArrayCreate(_len_). | ||
ArrayCreate, step 1: | ||
1. If _length_ > 2³² - 1, throw a *RangeError* exception. | ||
includes: [asyncHelpers.js] | ||
flags: [async] | ||
features: [Array.fromAsync] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
const notConstructor = {}; | ||
|
||
await assert.throwsAsync(RangeError, () => Array.fromAsync.call(notConstructor, { | ||
length: 4294967296 // 2³² | ||
}), "Array-like with excessive length"); | ||
}); |
23 changes: 23 additions & 0 deletions
23
test/built-ins/Array/fromAsync/asyncitems-object-not-arraylike.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Treats an asyncItems object that isn't an array-like as a 0-length array-like | ||
info: | | ||
3.k.iii. Let _len_ be ? LengthOfArrayLike(_arrayLike_). | ||
features: [Array.fromAsync] | ||
flags: [async] | ||
includes: [asyncHelpers.js, compareArray.js] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
const notArrayLike = Object.create(null); | ||
notArrayLike[0] = 0; | ||
notArrayLike[1] = 1; | ||
notArrayLike[2] = 2; | ||
|
||
const array = await Array.fromAsync(notArrayLike); | ||
assert.compareArray(array, [], "non-array-like object is treated as 0-length array-like"); | ||
}); |
40 changes: 40 additions & 0 deletions
40
test/built-ins/Array/fromAsync/asyncitems-uses-intrinsic-iterator-symbols.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Use the intrinsic @@iterator and @@asyncIterator to check iterability | ||
includes: [compareArray.js, asyncHelpers.js] | ||
flags: [async] | ||
features: [Array.fromAsync] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
// Replace the user-reachable Symbol.iterator and Symbol.asyncIterator with | ||
// fake symbol keys | ||
const originalSymbol = globalThis.Symbol; | ||
const fakeIteratorSymbol = Symbol("iterator"); | ||
const fakeAsyncIteratorSymbol = Symbol("asyncIterator"); | ||
globalThis.Symbol = { | ||
iterator: fakeIteratorSymbol, | ||
asyncIterator: fakeAsyncIteratorSymbol, | ||
}; | ||
|
||
const input = { | ||
length: 3, | ||
0: 0, | ||
1: 1, | ||
2: 2, | ||
[fakeIteratorSymbol]() { | ||
throw new Test262Error("The fake Symbol.iterator method should not be called"); | ||
}, | ||
[fakeAsyncIteratorSymbol]() { | ||
throw new Test262Error("The fake Symbol.asyncIterator method should not be called"); | ||
} | ||
}; | ||
const output = await Array.fromAsync(input); | ||
assert.compareArray(output, [0, 1, 2]); | ||
|
||
globalThis.Symbol = originalSymbol; | ||
}); |
22 changes: 22 additions & 0 deletions
22
test/built-ins/Array/fromAsync/returned-promise-resolves-to-array.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Array.fromAsync returns a Promise that resolves to an Array in the normal case | ||
info: | | ||
1. Let _C_ be the *this* value. | ||
... | ||
3.e. If IsConstructor(_C_) is *true*, then | ||
i. Let _A_ be ? Construct(_C_). | ||
features: [Array.fromAsync] | ||
flags: [async] | ||
includes: [asyncHelpers.js] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
const promise = Array.fromAsync([0, 1, 2]); | ||
const array = await promise; | ||
assert(Array.isArray(array), "Array.fromAsync returns a Promise that resolves to an Array"); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: Array.fromAsync returns a Promise | ||
info: | | ||
5. Return _promiseCapability_.[[Promise]]. | ||
flags: [async] | ||
includes: [asyncHelpers.js] | ||
features: [Array.fromAsync] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
let p = Array.fromAsync([0, 1, 2]); | ||
|
||
assert(p instanceof Promise, "Array.fromAsync returns a Promise"); | ||
assert.sameValue( | ||
Object.getPrototypeOf(p), | ||
Promise.prototype, | ||
"Array.fromAsync returns an object with prototype Promise.prototype" | ||
); | ||
|
||
p = Array.fromAsync([0, 1, 2], () => { | ||
throw new Test262Error("this will make the Promise reject"); | ||
}) | ||
assert(p instanceof Promise, "Array.fromAsync returns a Promise even on error"); | ||
assert.sameValue( | ||
Object.getPrototypeOf(p), | ||
Promise.prototype, | ||
"Array.fromAsync returns an object with prototype Promise.prototype even on error" | ||
); | ||
|
||
await assert.throwsAsync(Test262Error, () => p, "Prevent unhandled rejection"); | ||
}); |
74 changes: 74 additions & 0 deletions
74
test/built-ins/Array/fromAsync/this-constructor-operations.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Order of user-observable operations on a custom this-value and its instances | ||
includes: [compareArray.js, asyncHelpers.js] | ||
flags: [async] | ||
features: [Array.fromAsync] | ||
---*/ | ||
|
||
function formatPropertyName(propertyKey, objectName = "") { | ||
switch (typeof propertyKey) { | ||
case "symbol": | ||
if (Symbol.keyFor(propertyKey) !== undefined) { | ||
return `${objectName}[Symbol.for('${Symbol.keyFor(propertyKey)}')]`; | ||
} else if (propertyKey.description.startsWith('Symbol.')) { | ||
return `${objectName}[${propertyKey.description}]`; | ||
} else { | ||
return `${objectName}[Symbol('${propertyKey.description}')]` | ||
} | ||
case "string": | ||
if (propertyKey !== String(Number(propertyKey))) | ||
return objectName ? `${objectName}.${propertyKey}` : propertyKey; | ||
// fall through | ||
default: | ||
// integer or string integer-index | ||
return `${objectName}[${propertyKey}]`; | ||
} | ||
} | ||
|
||
asyncTest(async function () { | ||
const expectedCalls = [ | ||
"construct MyArray", | ||
"defineProperty A[0]", | ||
"defineProperty A[1]", | ||
"set A.length" | ||
]; | ||
const actualCalls = []; | ||
|
||
function MyArray(...args) { | ||
actualCalls.push("construct MyArray"); | ||
return new Proxy(Object.create(null), { | ||
set(target, key, value) { | ||
actualCalls.push(`set ${formatPropertyName(key, "A")}`); | ||
return Reflect.set(target, key, value); | ||
}, | ||
defineProperty(target, key, descriptor) { | ||
actualCalls.push(`defineProperty ${formatPropertyName(key, "A")}`); | ||
return Reflect.defineProperty(target, key, descriptor); | ||
} | ||
}); | ||
} | ||
|
||
let result = await Array.fromAsync.call(MyArray, [1, 2]); | ||
assert.compareArray(expectedCalls, actualCalls, "order of operations for array argument"); | ||
|
||
actualCalls.splice(0); // reset | ||
|
||
const expectedCallsForArrayLike = [ | ||
"construct MyArray", | ||
"construct MyArray", | ||
"defineProperty A[0]", | ||
"defineProperty A[1]", | ||
"set A.length" | ||
]; | ||
result = await Array.fromAsync.call(MyArray, { | ||
length: 2, | ||
0: 1, | ||
1: 2 | ||
}); | ||
assert.compareArray(expectedCallsForArrayLike, actualCalls, "order of operations for array-like argument"); | ||
}); |
33 changes: 33 additions & 0 deletions
33
test/built-ins/Array/fromAsync/this-constructor-with-bad-length-setter.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Rejects the promise if setting the length fails on an instance of a custom | ||
this-value | ||
info: | | ||
3.j.ii.4.a. Perform ? Set(_A_, *"length"*, 𝔽(_k_), *true*). | ||
... | ||
3.k.viii. Perform ? Set(_A_, *"length"*, 𝔽(_len_), *true*) | ||
includes: [asyncHelpers.js] | ||
flags: [async] | ||
features: [Array.fromAsync] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
class MyArray { | ||
set length(v) { | ||
throw new Test262Error("setter of length property throws") | ||
} | ||
} | ||
|
||
await assert.throwsAsync(Test262Error, () => Array.fromAsync.call(MyArray, [0, 1, 2]), "Promise rejected if setting length fails"); | ||
|
||
await assert.throwsAsync(Test262Error, () => Array.fromAsync.call(MyArray, { | ||
length: 3, | ||
0: 0, | ||
1: 1, | ||
2: 2 | ||
}), "Promise rejected if setting length from array-like fails"); | ||
}); |
50 changes: 50 additions & 0 deletions
50
test/built-ins/Array/fromAsync/this-constructor-with-readonly-elements.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright (C) 2023 Igalia, S.L. All rights reserved. | ||
// This code is governed by the BSD license found in the LICENSE file. | ||
|
||
/*--- | ||
esid: sec-array.fromasync | ||
description: > | ||
Overwrites non-writable element properties on an instance of a custom | ||
this-value | ||
info: | | ||
3.j.ii.8. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_). | ||
... | ||
3.k.vii.6. Perform ? CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_). | ||
includes: [asyncHelpers.js] | ||
flags: [async] | ||
features: [Array.fromAsync] | ||
---*/ | ||
|
||
asyncTest(async function () { | ||
function MyArray() { | ||
this.length = 4; | ||
for (let ix = 0; ix < this.length; ix++) { | ||
Object.defineProperty(this, ix, { | ||
enumerable: true, | ||
writable: false, | ||
configurable: true, | ||
value: 99 | ||
}); | ||
} | ||
} | ||
|
||
let result = await Array.fromAsync.call(MyArray, [0, 1, 2]); | ||
assert.sameValue(result.length, 3, "Length property is overwritten"); | ||
assert.sameValue(result[0], 0, "Read-only element 0 is overwritten"); | ||
assert.sameValue(result[1], 1, "Read-only element 1 is overwritten"); | ||
assert.sameValue(result[2], 2, "Read-only element 2 is overwritten"); | ||
assert.sameValue(result[3], 99, "Element 3 is not overwritten"); | ||
|
||
result = await Array.fromAsync.call(MyArray, { | ||
length: 3, | ||
0: 0, | ||
1: 1, | ||
2: 2, | ||
3: 3 // ignored | ||
}); | ||
assert.sameValue(result.length, 3, "Length property is overwritten"); | ||
assert.sameValue(result[0], 0, "Read-only element 0 is overwritten"); | ||
assert.sameValue(result[1], 1, "Read-only element 1 is overwritten"); | ||
assert.sameValue(result[2], 2, "Read-only element 2 is overwritten"); | ||
assert.sameValue(result[3], 99, "Element 3 is not overwritten"); | ||
}); |
Oops, something went wrong.