Files
sausage/userland/qjs/source/tests/bug1795.js
T
surma d44f1d9677 Build separate native and WASI pipelines with shared multicall names
Checkpoint before integration and package validation.

Assisted-by: SurmAgent:unknown [read] [edit] [bash]
2026-11-12 09:36:27 +00:00

98 lines
3.2 KiB
JavaScript

// https://github.com/quickjs-ng/quickjs/issues/1795
import { assert, assertArrayEquals } from "./assert.js";
// 1. Array.fromAsync must not look up .call on mapper function (iterable source).
{
function mapper(x) { return x * 10; }
mapper.call = function () { return "hijacked"; };
const res = await Array.fromAsync([1, 2], mapper);
assertArrayEquals(res, [10, 20]);
}
// 2. Array.fromAsync must not look up .call on mapper function (array-like source).
{
function mapper(x) { return x * 10; }
mapper.call = function () { return "hijacked"; };
const res = await Array.fromAsync({ length: 2, 0: 1, 1: 2 }, mapper);
assertArrayEquals(res, [10, 20]);
}
// 3. Array.fromAsync must not look up .call on iterator method ([Symbol.iterator]).
{
const method = function () { return [1, 2].values(); };
method.call = function () { return ["hijacked"].values(); };
const res = await Array.fromAsync({ [Symbol.iterator]: method });
assertArrayEquals(res, [1, 2]);
}
// 4. Array.fromAsync must not look up .call on async iterator method ([Symbol.asyncIterator]).
{
const asyncMethod = async function* () { yield 1; yield 2; };
asyncMethod.call = function () { throw new Error("hijacked"); };
const res = await Array.fromAsync({ [Symbol.asyncIterator]: asyncMethod });
assertArrayEquals(res, [1, 2]);
}
// 5. Array.fromAsync works even if mapper.call or method.call is not callable (null or primitive).
{
const mapper = (x) => x + 1;
mapper.call = null;
const res = await Array.fromAsync([10, 20], mapper);
assertArrayEquals(res, [11, 21]);
}
{
const method = function* () { yield 3; yield 4; };
method.call = 123;
const res = await Array.fromAsync({ [Symbol.iterator]: method });
assertArrayEquals(res, [3, 4]);
}
// 6. Verify thisArg and index parameters are passed correctly to mapper.
{
const thisObj = { multiplier: 3 };
const indices = [];
const thisReceivers = [];
function mapper(val, idx) {
indices.push(idx);
thisReceivers.push(this);
return val * this.multiplier;
}
mapper.call = null;
const res = await Array.fromAsync([5, 6], mapper, thisObj);
assertArrayEquals(res, [15, 18]);
assertArrayEquals(indices, [0, 1]);
assert(thisReceivers[0], thisObj);
assert(thisReceivers[1], thisObj);
}
{
const thisObj = { multiplier: 4 };
const indices = [];
const thisReceivers = [];
function mapper(val, idx) {
indices.push(idx);
thisReceivers.push(this);
return val * this.multiplier;
}
mapper.call = null;
const res = await Array.fromAsync({ length: 2, 0: 5, 1: 6 }, mapper, thisObj);
assertArrayEquals(res, [20, 24]);
assertArrayEquals(indices, [0, 1]);
assert(thisReceivers[0], thisObj);
assert(thisReceivers[1], thisObj);
}
// 7. Verify receiver (this) for iterator method is the arrayLike object.
{
let receivedThis = null;
const obj = {
[Symbol.iterator]() {
receivedThis = this;
return [7, 8].values();
}
};
obj[Symbol.iterator].call = null;
const res = await Array.fromAsync(obj);
assertArrayEquals(res, [7, 8]);
assert(receivedThis, obj);
}