mirror of
https://github.com/tc39/test262.git
synced 2025-11-28 17:43:19 +01:00
split basic.js into harness+tests, add some more tests
This commit is contained in:
parent
004b7337af
commit
e0738ee1ca
223
harness/iteratorZipUtils.js
Normal file
223
harness/iteratorZipUtils.js
Normal file
@ -0,0 +1,223 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
description: |
|
||||
Utility functions for testing Iterator.prototype.zip and Iterator.prototype.zipKeyed. Requires inclusion of propertyHelper.js.
|
||||
defines:
|
||||
- forEachSequenceCombination
|
||||
- forEachSequenceCombinationKeyed
|
||||
- assertZipped
|
||||
- assertZippedKeyed
|
||||
- assertIteratorResult
|
||||
- assertIsPackedArray
|
||||
---*/
|
||||
|
||||
// Assert |result| is an object created by CreateIteratorResultObject.
|
||||
function assertIteratorResult(result, value, done, label) {
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(result),
|
||||
Object.prototype,
|
||||
label + ": [[Prototype]] of iterator result is Object.prototype"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(result), label + ": iterator result is extensible");
|
||||
|
||||
var ownKeys = Reflect.ownKeys(result);
|
||||
assert.compareArray(ownKeys, ["value", "done"], label + ": iterator result properties");
|
||||
|
||||
verifyProperty(result, "value", {
|
||||
value: value,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
verifyProperty(result, "done", {
|
||||
value: done,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Assert |array| is a packed array with default property attributes.
|
||||
function assertIsPackedArray(array, label) {
|
||||
assert(Array.isArray(array), label + ": array is an array exotic object");
|
||||
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(array),
|
||||
Array.prototype,
|
||||
label + ": [[Prototype]] of array is Array.prototype"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(array), label + ": array is extensible");
|
||||
|
||||
// Ensure "length" property has its default property attributes.
|
||||
verifyProperty(array, "length", {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
// Ensure no holes and all elements have the default property attributes.
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
verifyProperty(array, i, {
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Assert |array| is an extensible null-prototype object with default property attributes.
|
||||
function _assertIsNullProtoMutableObject(object, label) {
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(object),
|
||||
null,
|
||||
label + ": [[Prototype]] of object is null"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(object), label + ": object is extensible");
|
||||
|
||||
// Ensure all properties have the default property attributes.
|
||||
var keys = Object.getOwnPropertyNames(object);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
verifyProperty(object, keys[i], {
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that the `zipped` iterator results as for Iterator.zip for the first `count` elements.
|
||||
// Assumes inputs is an array of arrays of length >= count.
|
||||
// Advances `zipped` by `count` steps.
|
||||
function assertZipped(zipped, inputs, count, label) {
|
||||
// Last returned elements array.
|
||||
var last = null;
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
var itemLabel = label + ", step " + i;
|
||||
|
||||
var result = zipped.next();
|
||||
var value = result.value;
|
||||
|
||||
// Test IteratorResult structure.
|
||||
assertIteratorResult(result, value, false, itemLabel);
|
||||
|
||||
// Ensure value is a new array.
|
||||
assert.notSameValue(value, last, itemLabel + ": returns a new array");
|
||||
last = value;
|
||||
|
||||
// Ensure all array elements have the expected value.
|
||||
var expected = inputs.map(function (array) {
|
||||
return array[i];
|
||||
});
|
||||
assert.compareArray(value, expected, itemLabel + ": values");
|
||||
|
||||
// Ensure value is a packed array with default data properties.
|
||||
//
|
||||
// This operation is destructive, so it has to happen last.
|
||||
assertIsPackedArray(value, itemLabel);
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that the `zipped` iterator results as for Iterator.zipKeyed for the first `count` elements.
|
||||
// Assumes inputs is an object whose values are arrays of length >= count.
|
||||
// Advances `zipped` by `count` steps.
|
||||
function assertZippedKeyed(zipped, inputs, count, label) {
|
||||
// Last returned elements array.
|
||||
var last = null;
|
||||
|
||||
var expectedKeys = Object.keys(inputs);
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
var itemLabel = label + ", step " + i;
|
||||
|
||||
var result = zipped.next();
|
||||
var value = result.value;
|
||||
|
||||
// Test IteratorResult structure.
|
||||
assertIteratorResult(result, value, false, itemLabel);
|
||||
|
||||
// Ensure resulting object is a new object.
|
||||
assert.notSameValue(value, last, itemLabel + ": returns a new object");
|
||||
last = value;
|
||||
|
||||
// Ensure resulting object has the expected keys and values.
|
||||
assert.compareArray(Reflect.ownKeys(value), expectedKeys, itemLabel + ": result object keys");
|
||||
|
||||
var expectedValues = Object.values(inputs).map(function (array) {
|
||||
return array[i];
|
||||
});
|
||||
assert.compareArray(Object.values(value), expectedValues, itemLabel + ": result object values");
|
||||
|
||||
// Ensure resulting object is a null-prototype mutable object with default data properties.
|
||||
//
|
||||
// This operation is destructive, so it has to happen last.
|
||||
_assertIsNullProtoMutableObject(value, itemLabel);
|
||||
}
|
||||
}
|
||||
|
||||
function forEachSequenceCombinationKeyed(callback) {
|
||||
return forEachSequenceCombination(function(inputs, inputsLabel, min, max) {
|
||||
var object = {};
|
||||
for (var i = 0; i < inputs.length; ++i) {
|
||||
object["prop_" + i] = inputs[i];
|
||||
}
|
||||
inputsLabel = "inputs = " + JSON.stringify(object);
|
||||
callback(object, inputsLabel, min, max);
|
||||
});
|
||||
}
|
||||
|
||||
function forEachSequenceCombination(callback) {
|
||||
function test(inputs) {
|
||||
if (inputs.length === 0) {
|
||||
callback(inputs, "inputs = []", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var lengths = inputs.map(function(array) {
|
||||
return array.length;
|
||||
});
|
||||
|
||||
var min = Math.min.apply(null, lengths);
|
||||
var max = Math.max.apply(null, lengths);
|
||||
|
||||
var inputsLabel = "inputs = " + JSON.stringify(inputs);
|
||||
|
||||
callback(inputs, inputsLabel, min, max);
|
||||
}
|
||||
|
||||
// Yield all prefixes of the string |s|.
|
||||
function* prefixes(s) {
|
||||
for (var i = 0; i <= s.length; ++i) {
|
||||
yield s.slice(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Zip an empty iterable.
|
||||
test([]);
|
||||
|
||||
// Zip a single iterator.
|
||||
for (var prefix of prefixes("abcd")) {
|
||||
test([prefix.split("")]);
|
||||
}
|
||||
|
||||
// Zip two iterators.
|
||||
for (var prefix1 of prefixes("abcd")) {
|
||||
for (var prefix2 of prefixes("efgh")) {
|
||||
test([prefix1.split(""), prefix2.split("")]);
|
||||
}
|
||||
}
|
||||
|
||||
// Zip three iterators.
|
||||
for (var prefix1 of prefixes("abcd")) {
|
||||
for (var prefix2 of prefixes("efgh")) {
|
||||
for (var prefix3 of prefixes("ijkl")) {
|
||||
test([prefix1.split(""), prefix2.split(""), prefix3.split("")]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
test/built-ins/Iterator/zip/basic-longest.js
Normal file
85
test/built-ins/Iterator/zip/basic-longest.js
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zip
|
||||
description: >
|
||||
Basic Iterator.zip test with "longest" mode.
|
||||
includes: [compareArray.js, propertyHelper.js, iteratorZipUtils.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
function testSequence(inputs, inputsLabel, minLength, maxLength) {
|
||||
function test(options, optionsLabel, getPaddingForInput) {
|
||||
var label = optionsLabel + ", " + inputsLabel;
|
||||
var it = Iterator.zip(inputs, options);
|
||||
assertZipped(it, inputs, minLength, label);
|
||||
|
||||
for (var i = minLength; i < maxLength; i++) {
|
||||
var itemLabel = label + ", step " + i;
|
||||
|
||||
var result = it.next();
|
||||
var value = result.value;
|
||||
|
||||
// Test IteratorResult structure.
|
||||
assertIteratorResult(result, value, false, itemLabel);
|
||||
|
||||
var expected = inputs.map(function (input, j) {
|
||||
return i < input.length ? input[i] : getPaddingForInput(j);
|
||||
});
|
||||
assert.compareArray(value, expected, itemLabel + ": values");
|
||||
}
|
||||
assertIteratorResult(it.next(), undefined, true, label + ": after completion");
|
||||
}
|
||||
|
||||
test(
|
||||
{ mode: "longest" },
|
||||
"options = { mode: 'longest' }",
|
||||
function () {
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
{ mode: "longest", padding: [] },
|
||||
"options = { mode: 'longest', padding: [] }",
|
||||
function () {
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
{ mode: "longest", padding: ["pad"] },
|
||||
"options = { mode: 'longest', padding: ['pad'] }",
|
||||
function (idx) {
|
||||
return idx === 0 ? "pad" : undefined;
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
{ mode: "longest", padding: Array(inputs.length).fill("pad") },
|
||||
"options = { mode: 'longest', padding: ['pad', 'pad', ..., 'pad'] }",
|
||||
function (idx) {
|
||||
return "pad";
|
||||
},
|
||||
);
|
||||
|
||||
// Yield an infinite amount of numbers.
|
||||
var numbers = {
|
||||
*[Symbol.iterator]() {
|
||||
var i = 0;
|
||||
while (true) {
|
||||
yield 100 + i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
test(
|
||||
{ mode: "longest", padding: numbers },
|
||||
"options = { mode: 'longest', padding: numbers }",
|
||||
function (idx) {
|
||||
return 100 + idx;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
forEachSequenceCombination(testSequence);
|
||||
29
test/built-ins/Iterator/zip/basic-shortest.js
Normal file
29
test/built-ins/Iterator/zip/basic-shortest.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zip
|
||||
description: >
|
||||
Basic Iterator.zip test with "shortest" mode.
|
||||
includes: [compareArray.js, propertyHelper.js, iteratorZipUtils.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
function testSequence(inputs, inputsLabel, minLength, maxLength) {
|
||||
function test(options, optionsLabel) {
|
||||
var label = optionsLabel + ", " + inputsLabel;
|
||||
var it = Iterator.zip(inputs, options);
|
||||
assertZipped(it, inputs, minLength, label);
|
||||
|
||||
// Iterator is closed after `minLength` items.
|
||||
assertIteratorResult(it.next(), undefined, true, label + ": after completion");
|
||||
}
|
||||
|
||||
test(undefined, "options = undefined");
|
||||
|
||||
test({}, "options = {}");
|
||||
|
||||
test({ mode: "shortest" }, "options = { mode: 'shortest' }");
|
||||
}
|
||||
|
||||
forEachSequenceCombination(testSequence);
|
||||
30
test/built-ins/Iterator/zip/basic-strict.js
Normal file
30
test/built-ins/Iterator/zip/basic-strict.js
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zip
|
||||
description: >
|
||||
Basic Iterator.zip test with "strict" mode.
|
||||
includes: [compareArray.js, propertyHelper.js, iteratorZipUtils.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
function testSequence(inputs, inputsLabel, minLength, maxLength) {
|
||||
function test(options, optionsLabel) {
|
||||
var label = optionsLabel + ", " + inputsLabel;
|
||||
var it = Iterator.zip(inputs, options);
|
||||
assertZipped(it, inputs, minLength, label);
|
||||
|
||||
if (minLength === maxLength) {
|
||||
assertIteratorResult(it.next(), undefined, true, label + ": after completion");
|
||||
} else {
|
||||
assert.throws(TypeError, function() {
|
||||
it.next();
|
||||
}, label + " should throw after " + minLength + " items.");
|
||||
}
|
||||
}
|
||||
|
||||
test({ mode: "strict" }, "options = { mode: 'strict' }");
|
||||
}
|
||||
|
||||
forEachSequenceCombination(testSequence);
|
||||
@ -1,236 +0,0 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zip
|
||||
description: >
|
||||
Basic Iterator.zip test using all three possible modes.
|
||||
includes: [compareArray.js, propertyHelper.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
// Assert |result| is an object created by CreateIteratorResultObject.
|
||||
function assertIteratorResult(result, value, done) {
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(result),
|
||||
Object.prototype,
|
||||
"[[Prototype]] of iterator result is Object.prototype"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(result), "iterator result is extensible");
|
||||
|
||||
var ownKeys = Reflect.ownKeys(result);
|
||||
assert.sameValue(ownKeys.length, 2, "iterator result has two own properties");
|
||||
assert.sameValue(ownKeys[0], "value", "first property is 'value'");
|
||||
assert.sameValue(ownKeys[1], "done", "second property is 'done'");
|
||||
|
||||
verifyProperty(result, "value", {
|
||||
value: value,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
verifyProperty(result, "done", {
|
||||
value: done,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Assert |array| is a packed array with default property attributes.
|
||||
function assertIsPackedArray(array) {
|
||||
assert(Array.isArray(array), "array is an array exotic object");
|
||||
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(array),
|
||||
Array.prototype,
|
||||
"[[Prototype]] of array is Array.prototype"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(array), "array is extensible");
|
||||
|
||||
// Ensure "length" property has its default property attributes.
|
||||
verifyProperty(array, "length", {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
// Ensure no holes and all elements have the default property attributes.
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
verifyProperty(array, i, {
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Yield all prefixes of the string |s|.
|
||||
function* prefixes(s) {
|
||||
for (var i = 0; i <= s.length; ++i) {
|
||||
yield s.slice(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty iterable doesn't yield any values.
|
||||
var empty = {
|
||||
*[Symbol.iterator]() {
|
||||
}
|
||||
};
|
||||
|
||||
// Yield a single value.
|
||||
var single = {
|
||||
*[Symbol.iterator]() {
|
||||
yield 1000;
|
||||
}
|
||||
};
|
||||
|
||||
// Yield an infinite amount of numbers.
|
||||
var numbers = {
|
||||
*[Symbol.iterator]() {
|
||||
var i = 0;
|
||||
while (true) {
|
||||
yield 100 + i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// |iterables| is an array whose elements are array(-like) objects. Pass it as
|
||||
// the "iterables" argument to |Iterator.zip|, using |options| as the "options"
|
||||
// argument.
|
||||
//
|
||||
// Then iterate over the returned |Iterator.zip| iterator and check all
|
||||
// returned iteration values have the expected values.
|
||||
function test(iterables, options) {
|
||||
var mode = (options && options.mode) || "shortest";
|
||||
var padding = options && options.padding;
|
||||
|
||||
var lengths = iterables.map(function(array) {
|
||||
return array.length;
|
||||
});
|
||||
|
||||
var min = Math.min.apply(null, lengths);
|
||||
var max = Math.max.apply(null, lengths);
|
||||
|
||||
// Expected number of iterations.
|
||||
var count;
|
||||
switch (mode) {
|
||||
case "shortest":
|
||||
count = min;
|
||||
break;
|
||||
case "longest":
|
||||
count = max;
|
||||
break;
|
||||
case "strict":
|
||||
count = max;
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute padding array when |mode| is "longest".
|
||||
if (mode === "longest") {
|
||||
if (padding) {
|
||||
padding = Iterator.from(padding).take(iterables.length).toArray();
|
||||
} else {
|
||||
padding = [];
|
||||
}
|
||||
|
||||
// Fill with undefined until there are exactly |iterables.length| elements.
|
||||
padding = padding.concat(Array(iterables.length - padding.length).fill(undefined));
|
||||
assert.sameValue(padding.length, iterables.length);
|
||||
}
|
||||
|
||||
// Last returned elements array.
|
||||
var last = null;
|
||||
|
||||
var it = Iterator.zip(iterables, options);
|
||||
for (var i = 0; i < count; i++) {
|
||||
// "strict" mode throws an error if number of elements don't match.
|
||||
if (mode === "strict" && min < max && i === min) {
|
||||
assert.throws(TypeError, function() {
|
||||
it.next();
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
var result = it.next();
|
||||
var value = result.value;
|
||||
|
||||
// Test IteratorResult structure.
|
||||
assertIteratorResult(result, value, false);
|
||||
|
||||
// Ensure value is a new array.
|
||||
assert.notSameValue(value, last, "returns a new array");
|
||||
last = value;
|
||||
|
||||
// Ensure all array elements have the expected value.
|
||||
var expected = iterables.map(function(array, k) {
|
||||
if (i < array.length) {
|
||||
return array[i];
|
||||
}
|
||||
assert.sameValue(mode, "longest", "padding is only used for 'longest' mode");
|
||||
return padding[k];
|
||||
});
|
||||
assert.compareArray(value, expected);
|
||||
|
||||
// Ensure value is a packed array with default data properties.
|
||||
//
|
||||
// This operation is destructive, so it has to happen last.
|
||||
assertIsPackedArray(value);
|
||||
}
|
||||
|
||||
// Iterator is closed.
|
||||
assertIteratorResult(it.next(), undefined, true);
|
||||
}
|
||||
|
||||
var validOptions = [
|
||||
undefined,
|
||||
{},
|
||||
{mode: "shortest"},
|
||||
{mode: "longest"},
|
||||
{mode: "longest", padding: empty},
|
||||
{mode: "longest", padding: single},
|
||||
{mode: "longest", padding: numbers},
|
||||
{mode: "strict"},
|
||||
];
|
||||
|
||||
for (var options of validOptions) {
|
||||
// Zip an empty iterable.
|
||||
var it = Iterator.zip([], options);
|
||||
assertIteratorResult(it.next(), undefined, true);
|
||||
|
||||
// Zip a single iterator.
|
||||
for (var prefix of prefixes("abcd")) {
|
||||
// Split prefix into an array.
|
||||
test([prefix.split("")], options);
|
||||
|
||||
// Use String wrapper as the iterable.
|
||||
test([new String(prefix)], options);
|
||||
}
|
||||
|
||||
// Zip two iterators.
|
||||
for (var prefix1 of prefixes("abcd")) {
|
||||
for (var prefix2 of prefixes("efgh")) {
|
||||
// Split prefixes into arrays.
|
||||
test([prefix1.split(""), prefix2.split("")], options);
|
||||
|
||||
// Use String wrappers as the iterables.
|
||||
test([new String(prefix1), new String(prefix2)], options);
|
||||
}
|
||||
}
|
||||
|
||||
// Zip three iterators.
|
||||
for (var prefix1 of prefixes("abcd")) {
|
||||
for (var prefix2 of prefixes("efgh")) {
|
||||
for (var prefix3 of prefixes("ijkl")) {
|
||||
// Split prefixes into arrays.
|
||||
test([prefix1.split(""), prefix2.split(""), prefix3.split("")], options);
|
||||
|
||||
// Use String wrappers as the iterables.
|
||||
test([new String(prefix1), new String(prefix2), new String(prefix3)], options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
// Copyright (C) 2025 Kevin Gibbons. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zip
|
||||
description: >
|
||||
Accepts String objects as inputs.
|
||||
includes: [compareArray.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
var result = Array.from(Iterator.zip([Object("abc"), Object("123")]));
|
||||
|
||||
assert.sameValue(result.length, 3);
|
||||
assert.compareArray(result[0], ["a", "1"]);
|
||||
assert.compareArray(result[1], ["b", "2"]);
|
||||
assert.compareArray(result[2], ["c", "3"]);
|
||||
22
test/built-ins/Iterator/zip/iterator-non-iterable.js
Normal file
22
test/built-ins/Iterator/zip/iterator-non-iterable.js
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2025 Kevin Gibbons. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zip
|
||||
description: >
|
||||
Throws a TypeError when the "iterables" argument is not iterable.
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
var invalidIterables = [
|
||||
{},
|
||||
{ next() {}, return() {} },
|
||||
function() {}
|
||||
];
|
||||
|
||||
// Throws a TypeError for invalid iterables values.
|
||||
for (var iterables of invalidIterables) {
|
||||
assert.throws(TypeError, function() {
|
||||
Iterator.zip(iterables);
|
||||
});
|
||||
}
|
||||
105
test/built-ins/Iterator/zipKeyed/basic-longest.js
Normal file
105
test/built-ins/Iterator/zipKeyed/basic-longest.js
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
Basic Iterator.zipKeyed test with "longest" mode.
|
||||
includes: [compareArray.js, propertyHelper.js, iteratorZipUtils.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
function testSequence(inputs, inputsLabel, minLength, maxLength) {
|
||||
function test(options, optionsLabel, getPaddingForInput) {
|
||||
var label = optionsLabel + ", " + inputsLabel;
|
||||
var it = Iterator.zipKeyed(inputs, options);
|
||||
assertZippedKeyed(it, inputs, minLength, label);
|
||||
|
||||
var expectedKeys = Object.keys(inputs);
|
||||
|
||||
for (var i = minLength; i < maxLength; i++) {
|
||||
var itemLabel = label + ", step " + i;
|
||||
|
||||
var result = it.next();
|
||||
var value = result.value;
|
||||
|
||||
// Test IteratorResult structure.
|
||||
assertIteratorResult(result, value, false, itemLabel);
|
||||
|
||||
// Ensure resulting object has the expected keys and values.
|
||||
assert.compareArray(Object.keys(value), expectedKeys, itemLabel + ": result object keys");
|
||||
|
||||
var expectedValues = Object.values(inputs).map(function (input, j) {
|
||||
return i < input.length ? input[i] : getPaddingForInput(j);
|
||||
});
|
||||
assert.compareArray(Object.values(value), expectedValues, itemLabel + ": result object values");
|
||||
}
|
||||
assertIteratorResult(it.next(), undefined, true, label + ": after completion");
|
||||
}
|
||||
|
||||
test(
|
||||
{ mode: "longest" },
|
||||
"options = { mode: 'longest' }",
|
||||
function () {
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
{ mode: "longest", padding: {} },
|
||||
"options = { mode: 'longest', padding: {} }",
|
||||
function () {
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
{ mode: "longest", padding: { prop_0: "pad" } },
|
||||
"options = { mode: 'longest', padding: { prop_0: 'pad' } }",
|
||||
function (idx) {
|
||||
return idx === 0 ? "pad" : undefined;
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
{ mode: "longest", padding: { prop_1: "pad" } },
|
||||
"options = { mode: 'longest', padding: { prop_1: 'pad' } }",
|
||||
function (idx) {
|
||||
return idx === 1 ? "pad" : undefined;
|
||||
},
|
||||
);
|
||||
|
||||
var padding = {};
|
||||
for (var key in inputs) {
|
||||
padding[key] = "pad";
|
||||
}
|
||||
test(
|
||||
{ mode: "longest", padding: padding },
|
||||
"options = { mode: 'longest', padding: { prop_0: 'pad', ..., prop_N: 'pad' } }",
|
||||
function (idx) {
|
||||
return "pad";
|
||||
},
|
||||
);
|
||||
|
||||
// Object with many properties.
|
||||
padding = new Proxy({}, {
|
||||
has(target, key) {
|
||||
return key.indexOf('_') !== -1;
|
||||
},
|
||||
get(target, key, receiver) {
|
||||
var split = key.split('_');
|
||||
if (split.length !== 2) return undefined;
|
||||
return 'pad_' + split[1];
|
||||
}
|
||||
});
|
||||
test(
|
||||
{ mode: "longest", padding: padding },
|
||||
"options = { mode: 'longest', padding: { prop_0: 'pad_1', ..., prop_N: 'pad_N' } }",
|
||||
function (idx) {
|
||||
return 'pad_' + idx;
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
forEachSequenceCombinationKeyed(testSequence);
|
||||
29
test/built-ins/Iterator/zipKeyed/basic-shortest.js
Normal file
29
test/built-ins/Iterator/zipKeyed/basic-shortest.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
Basic Iterator.zipkeyed test with "shortest" mode.
|
||||
includes: [compareArray.js, propertyHelper.js, iteratorZipUtils.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
function testSequence(inputs, inputsLabel, minLength, maxLength) {
|
||||
function test(options, optionsLabel) {
|
||||
var label = optionsLabel + ", " + inputsLabel;
|
||||
var it = Iterator.zipKeyed(inputs, options);
|
||||
assertZippedKeyed(it, inputs, minLength, label);
|
||||
|
||||
// Iterator is closed after `minLength` items.
|
||||
assertIteratorResult(it.next(), undefined, true, label + ": after completion");
|
||||
}
|
||||
|
||||
test(undefined, "options = undefined");
|
||||
|
||||
test({}, "options = {}");
|
||||
|
||||
test({ mode: "shortest" }, "options = { mode: 'shortest' }");
|
||||
}
|
||||
|
||||
forEachSequenceCombinationKeyed(testSequence);
|
||||
30
test/built-ins/Iterator/zipKeyed/basic-strict.js
Normal file
30
test/built-ins/Iterator/zipKeyed/basic-strict.js
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
Basic Iterator.zipkeyed test with "strict" mode.
|
||||
includes: [compareArray.js, propertyHelper.js, iteratorZipUtils.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
function testSequence(inputs, inputsLabel, minLength, maxLength) {
|
||||
function test(options, optionsLabel) {
|
||||
var label = optionsLabel + ", " + inputsLabel;
|
||||
var it = Iterator.zipKeyed(inputs, options);
|
||||
assertZippedKeyed(it, inputs, minLength, label);
|
||||
|
||||
if (minLength === maxLength) {
|
||||
assertIteratorResult(it.next(), undefined, true, label + ": after completion");
|
||||
} else {
|
||||
assert.throws(TypeError, function() {
|
||||
it.next();
|
||||
}, label + " should throw after " + minLength + " items.");
|
||||
}
|
||||
}
|
||||
|
||||
test({ mode: "strict" }, "options = { mode: 'strict' }");
|
||||
}
|
||||
|
||||
forEachSequenceCombinationKeyed(testSequence);
|
||||
@ -1,270 +0,0 @@
|
||||
// Copyright (C) 2025 André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
Basic Iterator.zipKeyed test using all three possible modes.
|
||||
includes: [compareArray.js, propertyHelper.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
// Assert |result| is an object created by CreateIteratorResultObject.
|
||||
function assertIteratorResult(result, value, done) {
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(result),
|
||||
Object.prototype,
|
||||
"[[Prototype]] of iterator result is Object.prototype"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(result), "iterator result is extensible");
|
||||
|
||||
var ownKeys = Reflect.ownKeys(result);
|
||||
assert.sameValue(ownKeys.length, 2, "iterator result has two own properties");
|
||||
assert.sameValue(ownKeys[0], "value", "first property is 'value'");
|
||||
assert.sameValue(ownKeys[1], "done", "second property is 'done'");
|
||||
|
||||
verifyProperty(result, "value", {
|
||||
value: value,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
verifyProperty(result, "done", {
|
||||
value: done,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Assert |actual| is a plain object equal to |expected| with default property attributes.
|
||||
function assertPlainObject(actual, expected) {
|
||||
assert.sameValue(
|
||||
Object.getPrototypeOf(actual),
|
||||
null,
|
||||
"[[Prototype]] of actual is null"
|
||||
);
|
||||
|
||||
assert(Object.isExtensible(actual), "actual is extensible");
|
||||
|
||||
var actualKeys = Reflect.ownKeys(actual);
|
||||
var expectedKeys = Reflect.ownKeys(expected);
|
||||
|
||||
// All expected property keys are present.
|
||||
assert.compareArray(actualKeys, expectedKeys);
|
||||
|
||||
// All expected property values are equal.
|
||||
for (var key of expectedKeys) {
|
||||
assert.sameValue(actual[key], expected[key], "with key: " + String(key));
|
||||
}
|
||||
|
||||
// Ensure all properties have the default property attributes.
|
||||
for (var key of expectedKeys) {
|
||||
verifyProperty(actual, key, {
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Yield all prefixes of the string |s|.
|
||||
function* prefixes(s) {
|
||||
for (var i = 0; i <= s.length; ++i) {
|
||||
yield s.slice(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty object.
|
||||
var empty = {};
|
||||
|
||||
// Object with a single property.
|
||||
var single = {
|
||||
a: 1000,
|
||||
};
|
||||
|
||||
// Object with many properties.
|
||||
var numbers = new Proxy({}, {
|
||||
has(target, key) {
|
||||
if (typeof key === "symbol") {
|
||||
key = key.description;
|
||||
}
|
||||
assert.sameValue(key.length, 1, "unsupported key length");
|
||||
return true;
|
||||
},
|
||||
get(target, key, receiver) {
|
||||
if (typeof key === "symbol") {
|
||||
key = key.description;
|
||||
}
|
||||
assert.sameValue(key.length, 1, "unsupported key length");
|
||||
return key.charCodeAt(0);
|
||||
}
|
||||
});
|
||||
|
||||
// |iterables| is an object whose properties are array(-like) objects. Pass it
|
||||
// as the "iterables" argument to |Iterator.zipKeyed|, using |options| as the
|
||||
// "options" argument.
|
||||
//
|
||||
// Then iterate over the returned |Iterator.zipKeyed| iterator and check all
|
||||
// returned iteration values have the expected values.
|
||||
function test(iterables, options) {
|
||||
var mode = (options && options.mode) || "shortest";
|
||||
var padding = options && options.padding;
|
||||
|
||||
// Not Object.entries to allow symbol property keys.
|
||||
var entries = Reflect.ownKeys(iterables).map(function(key) {
|
||||
return [key, iterables[key]];
|
||||
});
|
||||
|
||||
var lengths = entries.map(function([key, array]) {
|
||||
return array.length;
|
||||
});
|
||||
|
||||
var min = Math.min.apply(null, lengths);
|
||||
var max = Math.max.apply(null, lengths);
|
||||
|
||||
// Expected number of iterations.
|
||||
var count;
|
||||
switch (mode) {
|
||||
case "shortest":
|
||||
count = min;
|
||||
break;
|
||||
case "longest":
|
||||
count = max;
|
||||
break;
|
||||
case "strict":
|
||||
count = max;
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute padding array when |mode| is "longest".
|
||||
if (mode === "longest") {
|
||||
padding = entries.map(function([key, array]) {
|
||||
if (padding !== undefined && key in padding) {
|
||||
return padding[key];
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
// Last returned results object.
|
||||
var last = null;
|
||||
|
||||
var it = Iterator.zipKeyed(iterables, options);
|
||||
for (var i = 0; i < count; i++) {
|
||||
// "strict" mode throws an error if number of elements don't match.
|
||||
if (mode === "strict" && min < max && i === min) {
|
||||
assert.throws(TypeError, function() {
|
||||
it.next();
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
var result = it.next();
|
||||
var value = result.value;
|
||||
|
||||
// Test IteratorResult structure.
|
||||
assertIteratorResult(result, value, false);
|
||||
|
||||
// Ensure value is a new object.
|
||||
assert.notSameValue(value, last, "returns a new object");
|
||||
last = value;
|
||||
|
||||
var expected = Object.fromEntries(entries.map(function([key, array], k) {
|
||||
if (i < array.length) {
|
||||
return [key, array[i]];
|
||||
}
|
||||
assert.sameValue(mode, "longest", "padding is only used for 'longest' mode");
|
||||
return [key, padding[k]];
|
||||
}));
|
||||
|
||||
// Ensure all properties have the expected value.
|
||||
// Ensure value is a plain with default data properties.
|
||||
assertPlainObject(value, expected);
|
||||
}
|
||||
|
||||
// Iterator is closed.
|
||||
assertIteratorResult(it.next(), undefined, true);
|
||||
}
|
||||
|
||||
var validOptions = [
|
||||
undefined,
|
||||
{},
|
||||
{mode: "shortest"},
|
||||
{mode: "longest"},
|
||||
{mode: "longest", padding: empty},
|
||||
{mode: "longest", padding: single},
|
||||
{mode: "longest", padding: numbers},
|
||||
{mode: "strict"},
|
||||
];
|
||||
|
||||
for (var options of validOptions) {
|
||||
// Zip an empty object.
|
||||
var it = Iterator.zipKeyed({}, options);
|
||||
assertIteratorResult(it.next(), undefined, true);
|
||||
|
||||
// Zip a single key.
|
||||
for (var prefix of prefixes("abcd")) {
|
||||
// Split prefix into an array.
|
||||
test({
|
||||
a: prefix.split(""),
|
||||
}, options);
|
||||
test({
|
||||
[Symbol("a")]: prefix.split(""),
|
||||
}, options);
|
||||
|
||||
// Use String wrapper as the iterable.
|
||||
test({
|
||||
a: new String(prefix),
|
||||
}, options);
|
||||
}
|
||||
|
||||
// Zip two keys.
|
||||
for (var prefix1 of prefixes("abcd")) {
|
||||
for (var prefix2 of prefixes("efgh")) {
|
||||
// Split prefixes into arrays.
|
||||
test({
|
||||
a: prefix1.split(""),
|
||||
b: prefix2.split(""),
|
||||
}, options);
|
||||
test({
|
||||
[Symbol("a")]: prefix1.split(""),
|
||||
[Symbol("b")]: prefix2.split(""),
|
||||
}, options);
|
||||
|
||||
// Use String wrappers as the iterables.
|
||||
test({
|
||||
a: new String(prefix1),
|
||||
b: new String(prefix2),
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
|
||||
// Zip three keys.
|
||||
for (var prefix1 of prefixes("abcd")) {
|
||||
for (var prefix2 of prefixes("efgh")) {
|
||||
for (var prefix3 of prefixes("ijkl")) {
|
||||
// Split prefixes into arrays.
|
||||
test({
|
||||
a: prefix1.split(""),
|
||||
b: prefix2.split(""),
|
||||
c: prefix3.split(""),
|
||||
}, options);
|
||||
test({
|
||||
[Symbol("a")]: prefix1.split(""),
|
||||
[Symbol("b")]: prefix2.split(""),
|
||||
[Symbol("c")]: prefix3.split(""),
|
||||
}, options);
|
||||
|
||||
// Use String wrappers as the iterables.
|
||||
test({
|
||||
a: new String(prefix1),
|
||||
b: new String(prefix2),
|
||||
c: new String(prefix3),
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2025 Kevin Gibbons. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipKeyed
|
||||
description: >
|
||||
Accepts String objects as inputs.
|
||||
includes: [compareArray.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
var result = Array.from(Iterator.zipKeyed({
|
||||
a: Object("abc"),
|
||||
b: Object("123"),
|
||||
}));
|
||||
|
||||
assert.sameValue(result.length, 3);
|
||||
result.forEach(function (object) {
|
||||
assert.compareArray(Object.keys(object), ["a", "b"]);
|
||||
});
|
||||
assert.compareArray(Object.values(result[0]), ["a", "1"]);
|
||||
assert.compareArray(Object.values(result[1]), ["b", "2"]);
|
||||
assert.compareArray(Object.values(result[2]), ["c", "3"]);
|
||||
@ -38,7 +38,7 @@ var iterables = Object.create(null, {
|
||||
enumerable: false,
|
||||
});
|
||||
|
||||
return [];
|
||||
return ['value for b'];
|
||||
}
|
||||
},
|
||||
c: {
|
||||
@ -58,7 +58,7 @@ var iterables = Object.create(null, {
|
||||
enumerable: true,
|
||||
});
|
||||
|
||||
return [];
|
||||
return ['value for d'];
|
||||
}
|
||||
},
|
||||
e: {
|
||||
@ -66,15 +66,19 @@ var iterables = Object.create(null, {
|
||||
configurable: true,
|
||||
get() {
|
||||
log.push("get e");
|
||||
return [];
|
||||
return ['value for e'];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Iterator.zipKeyed(iterables);
|
||||
var result = Array.from(Iterator.zipKeyed(iterables));
|
||||
|
||||
assert.compareArray(log, [
|
||||
"get b",
|
||||
"get d",
|
||||
"get e",
|
||||
]);
|
||||
|
||||
assert.sameValue(result.length, 1);
|
||||
assert.compareArray(Object.keys(result[0]), ["b", "d", "e"]);
|
||||
assert.compareArray(Object.values(result[0]), ["value for b", "value for d", "value for e"]);
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2025 Kevin Gibbons. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
Inherited properties are skipped in "iterables" iteration.
|
||||
includes: [compareArray.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
var parent = {
|
||||
get a() {
|
||||
throw new Test262Error("inherited properties should not be examined");
|
||||
},
|
||||
}
|
||||
|
||||
var iterables = {
|
||||
__proto__: parent,
|
||||
b: ['value for b'],
|
||||
};
|
||||
|
||||
var result = Array.from(Iterator.zipKeyed(iterables));
|
||||
|
||||
assert.sameValue(result.length, 1);
|
||||
assert.compareArray(Object.keys(result[0]), ["b"]);
|
||||
assert.compareArray(Object.values(result[0]), ["value for b"]);
|
||||
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2025 Kevin Gibbons. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
Symbol properties are used during "iterables" iteration.
|
||||
includes: [compareArray.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
var symbolA = Symbol('a');
|
||||
|
||||
var iterables = {
|
||||
[symbolA]: ['value for a'],
|
||||
b: ['value for b'],
|
||||
};
|
||||
|
||||
var result = Array.from(Iterator.zipKeyed(iterables));
|
||||
|
||||
assert.sameValue(result.length, 1);
|
||||
assert.compareArray(Reflect.ownKeys(result[0]), ["b", symbolA]);
|
||||
assert.sameValue(result[0].b, "value for b");
|
||||
assert.sameValue(result[0][symbolA], "value for a");
|
||||
@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2025 Kevin Gibbons. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-iterator.zipkeyed
|
||||
description: >
|
||||
undefined-valued properties are skipped in "iterables" iteration.
|
||||
includes: [compareArray.js]
|
||||
features: [joint-iteration]
|
||||
---*/
|
||||
|
||||
|
||||
var iterables = {
|
||||
a: undefined,
|
||||
b: ['value for b'],
|
||||
};
|
||||
|
||||
var result = Array.from(Iterator.zipKeyed(iterables));
|
||||
|
||||
assert.sameValue(result.length, 1);
|
||||
assert.compareArray(Reflect.ownKeys(result[0]), ["b"]);
|
||||
assert.compareArray(Object.values(result[0]), ["value for b"]);
|
||||
@ -42,11 +42,6 @@ var iterableReturningThrowingIterator = {
|
||||
}
|
||||
};
|
||||
|
||||
// |undefined| values are ignored.
|
||||
Iterator.zipKeyed({
|
||||
a: undefined,
|
||||
});
|
||||
|
||||
// GetIteratorFlattenable accepts both iterables and iterators.
|
||||
Iterator.zipKeyed({
|
||||
a: throwingIterator,
|
||||
@ -61,6 +56,7 @@ var badIterators = [
|
||||
Symbol(),
|
||||
0,
|
||||
0n,
|
||||
// undefined is handled separately
|
||||
];
|
||||
|
||||
for (var iterator of badIterators) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user