Add tests for the asyncItems argument to Array.fromAsync. (#3754)

Co-authored-by: Philip Chimento <pchimento@igalia.com>
This commit is contained in:
Ms2ger 2023-03-10 11:46:59 +01:00 committed by GitHub
parent 53e5ef817e
commit 9704d7f22f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 691 additions and 0 deletions

View File

@ -20,6 +20,7 @@ function formatPropertyName(propertyKey, objectName = "") {
case "number":
return `${objectName}[${propertyKey}]`;
default:
// TODO: check if propertyKey is an integer index.
return objectName ? `${objectName}.${propertyKey}` : propertyKey;
}
}

View File

@ -0,0 +1,44 @@
// Copyright (C) 2022 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 respects array mutation
info: |
Array.fromAsync
3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
IteratorStep
1. Let result be ? IteratorNext(iteratorRecord).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
%AsyncFromSyncIteratorPrototype%.next
6.a. Let result be Completion(IteratorNext(syncIteratorRecord)).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
Array.prototype [ @@iterator ] ( )
Array.prototype.values ( )
2. Return CreateArrayIterator(O, value).
CreateArrayIterator
1.b.iii. If index len, return NormalCompletion(undefined).
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const items = [];
const promise = Array.fromAsync(items);
// By the time we get here, the first next() call has already happened, and returned
// { done: true }. We then return from the loop in Array.fromAsync 3.j.ii. with the empty array,
// and the following line no longer affects that.
items.push(7);
const result = await promise;
assert.compareArray(result, []);
});

View File

@ -0,0 +1,43 @@
// Copyright (C) 2022 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 respects array mutation
info: |
Array.fromAsync
3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
IteratorStep
1. Let result be ? IteratorNext(iteratorRecord).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
%AsyncFromSyncIteratorPrototype%.next
6.a. Let result be Completion(IteratorNext(syncIteratorRecord)).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
Array.prototype [ @@iterator ] ( )
Array.prototype.values ( )
2. Return CreateArrayIterator(O, value).
CreateArrayIterator
1.b.iii. If index len, return NormalCompletion(undefined).
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const items = [1];
const promise = Array.fromAsync(items);
// At this point, the first element of `items` has been read, but the iterator will take other
// changes into account.
items.push(7);
const result = await promise;
assert.compareArray(result, [1, 7]);
});

View File

@ -0,0 +1,43 @@
// Copyright (C) 2022 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 respects array mutation
info: |
Array.fromAsync
3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
IteratorStep
1. Let result be ? IteratorNext(iteratorRecord).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
%AsyncFromSyncIteratorPrototype%.next
6.a. Let result be Completion(IteratorNext(syncIteratorRecord)).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
Array.prototype [ @@iterator ] ( )
Array.prototype.values ( )
2. Return CreateArrayIterator(O, value).
CreateArrayIterator
1.b.iii. If index len, return NormalCompletion(undefined).
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const items = [1, 2, 3];
const promise = Array.fromAsync(items);
// At this point, the first element of `items` has been read, but the iterator will take other
// changes into account.
items.push(4);
const result = await promise;
assert.compareArray(result, [1, 2, 3, 4]);
});

View File

@ -0,0 +1,44 @@
// Copyright (C) 2022 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 respects array mutation
info: |
Array.fromAsync
3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
IteratorStep
1. Let result be ? IteratorNext(iteratorRecord).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
%AsyncFromSyncIteratorPrototype%.next
6.a. Let result be Completion(IteratorNext(syncIteratorRecord)).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
Array.prototype [ @@iterator ] ( )
Array.prototype.values ( )
2. Return CreateArrayIterator(O, value).
CreateArrayIterator
1.b.iii. If index len, return NormalCompletion(undefined).
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const items = [1, 2, 3];
const promise = Array.fromAsync(items);
// At this point, the first element of `items` has been read, but the iterator will take other
// changes into account.
items[0] = 7;
items[1] = 8;
const result = await promise;
assert.compareArray(result, [1, 8, 3]);
});

View File

@ -0,0 +1,43 @@
// Copyright (C) 2022 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 respects array mutation
info: |
Array.fromAsync
3.j.ii.3. Let next be ? Await(IteratorStep(iteratorRecord)).
IteratorStep
1. Let result be ? IteratorNext(iteratorRecord).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
%AsyncFromSyncIteratorPrototype%.next
6.a. Let result be Completion(IteratorNext(syncIteratorRecord)).
IteratorNext
1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
Array.prototype [ @@iterator ] ( )
Array.prototype.values ( )
2. Return CreateArrayIterator(O, value).
CreateArrayIterator
1.b.iii. If index len, return NormalCompletion(undefined).
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const items = [1, 2, 3];
const promise = Array.fromAsync(items);
// At this point, the first element of `items` has been read, but the iterator will take other
// changes into account.
items.pop();
const result = await promise;
assert.compareArray(result, [1, 2]);
});

View File

@ -0,0 +1,17 @@
// Copyright (C) 2022 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 doesn't special-case ArrayBuffer
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const items = new ArrayBuffer(7);
const result = await Array.fromAsync(items);
assert.compareArray(result, []);
});

View File

@ -0,0 +1,31 @@
// Copyright (C) 2022 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 tries the various properties in order and awaits promises
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const actual = [];
const items = TemporalHelpers.propertyBagObserver(actual, {
length: 2,
0: Promise.resolve(2),
1: Promise.resolve(1),
}, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [2, 1]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
"get items[Symbol.iterator]",
"get items.length",
"get items.length.valueOf",
"call items.length.valueOf",
"get items.0",
"get items.1",
]);
});

View File

@ -0,0 +1,32 @@
// Copyright (C) 2022 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 tries the various properties in order
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
async function * asyncGen() {
for (let i = 0; i < 4; i++) {
yield Promise.resolve(i * 2);
}
}
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, asyncGen, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [0, 2, 4, 6]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
]);
});

View File

@ -0,0 +1,19 @@
// Copyright (C) 2022 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 rejects if the @@asyncIterator property is not callable
includes: [asyncHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
for (const v of [true, "", Symbol(), 1, 1n, {}]) {
await assert.throwsAsync(TypeError,
() => Array.fromAsync({ [Symbol.asyncIterator]: v }),
`@@asyncIterator = ${typeof v}`);
}
});

View File

@ -0,0 +1,30 @@
// Copyright (C) 2022 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 tries the various properties in order
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, null, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [2, 1]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
"get items[Symbol.iterator]",
"get items.length",
"get items[0]",
"get items[1]",
]);
});

View File

@ -0,0 +1,32 @@
// Copyright (C) 2022 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 handles a sync iterator returned from @@asyncIterator
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
function * syncGen() {
for (let i = 0; i < 4; i++) {
yield i * 2;
}
}
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, syncGen, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [0, 2, 4, 6]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
]);
});

View File

@ -0,0 +1,16 @@
// Copyright (C) 2022 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 rejects if getting the @@asyncIterator property throws
includes: [asyncHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
await assert.throwsAsync(Test262Error,
() => Array.fromAsync({ get [Symbol.asyncIterator]() { throw new Test262Error() } }));
});

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 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 treats a BigInt as an array-like
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
BigInt.prototype.length = 2;
BigInt.prototype[0] = 1;
BigInt.prototype[1] = 2;
const result = await Array.fromAsync(1n);
assert.compareArray(result, [1, 2]);
});

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 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 treats a boolean as an array-like
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
Boolean.prototype.length = 2;
Boolean.prototype[0] = 1;
Boolean.prototype[1] = 2;
const result = await Array.fromAsync(true);
assert.compareArray(result, [1, 2]);
});

View File

@ -0,0 +1,21 @@
// Copyright (C) 2022 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 treats a function as an array-like, reading elements up to fn.length
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const fn = function(a, b) {};
fn[0] = 1;
fn[1] = 2;
fn[2] = 3;
const result = await Array.fromAsync(fn);
assert.compareArray(result, [1, 2]);
});

View File

@ -0,0 +1,33 @@
// Copyright (C) 2022 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 handles a sync iterator returned from @@iterator
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
function * syncGen() {
for (let i = 0; i < 4; i++) {
yield i * 2;
}
}
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, syncGen, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [0, 2, 4, 6]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
"get items[Symbol.iterator]",
]);
});

View File

@ -0,0 +1,19 @@
// Copyright (C) 2022 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 rejects if the @@iterator property is not callable
includes: [asyncHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
for (const v of [true, "", Symbol(), 1, 1n, {}]) {
await assert.throwsAsync(TypeError,
() => Array.fromAsync({ [Symbol.iterator]: v }),
`@@iterator = ${typeof v}`);
}
});

View File

@ -0,0 +1,30 @@
// Copyright (C) 2022 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 tries the various properties in order
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, null, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [2, 1]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
"get items[Symbol.iterator]",
"get items.length",
"get items[0]",
"get items[1]",
]);
});

View File

@ -0,0 +1,33 @@
// Copyright (C) 2022 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 handles an async iterator returned from @@iterator
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
function * asyncGen() {
for (let i = 0; i < 4; i++) {
yield Promise.resolve(i * 2);
}
}
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, asyncGen, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [0, 2, 4, 6]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
"get items[Symbol.iterator]",
]);
});

View File

@ -0,0 +1,16 @@
// Copyright (C) 2022 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 rejects if getting the @@iterator property throws
includes: [asyncHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
await assert.throwsAsync(Test262Error,
() => Array.fromAsync({ get [Symbol.iterator]() { throw new Test262Error() } }));
});

View File

@ -0,0 +1,18 @@
// Copyright (C) 2022 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 rejects with a TypeError if the asyncItems argument is null or undefined
info: |
3.c. Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator).
includes: [asyncHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
await assert.throwsAsync(TypeError, () => Array.fromAsync(null), "null asyncItems");
await assert.throwsAsync(TypeError, () => Array.fromAsync(undefined), "undefined asyncItems");
});

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 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 treats a Number as an array-like
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
Number.prototype.length = 2;
Number.prototype[0] = 1;
Number.prototype[1] = 2;
const result = await Array.fromAsync(1);
assert.compareArray(result, [1, 2]);
});

View File

@ -0,0 +1,30 @@
// Copyright (C) 2022 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 tries the various properties in order
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const actual = [];
const items = {};
TemporalHelpers.observeProperty(actual, items, Symbol.asyncIterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, Symbol.iterator, undefined, "items");
TemporalHelpers.observeProperty(actual, items, "length", 2, "items");
TemporalHelpers.observeProperty(actual, items, 0, 2, "items");
TemporalHelpers.observeProperty(actual, items, 1, 1, "items");
const result = await Array.fromAsync(items);
assert.compareArray(result, [2, 1]);
assert.compareArray(actual, [
"get items[Symbol.asyncIterator]",
"get items[Symbol.iterator]",
"get items.length",
"get items[0]",
"get items[1]",
]);
});

View File

@ -0,0 +1,16 @@
// Copyright (C) 2022 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 iterates over a string
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
const result = await Array.fromAsync("test");
assert.compareArray(result, ["t", "e", "s", "t"]);
});

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 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 treats a Symbol as an array-like
includes: [asyncHelpers.js, compareArray.js]
flags: [async]
features: [Array.fromAsync]
---*/
asyncTest(async function () {
Symbol.prototype.length = 2;
Symbol.prototype[0] = 1;
Symbol.prototype[1] = 2;
const result = await Array.fromAsync(Symbol());
assert.compareArray(result, [1, 2]);
});