diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js new file mode 100644 index 0000000000..5e832ae5be --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js @@ -0,0 +1,116 @@ +// 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: > + Handle abrupt completion from IteratorStep in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + v. Let completion be Completion(Yield(results)). + vi. If completion is an abrupt completion, then + 1. Return ? IteratorCloseAll(openIters, completion). + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +function ExpectedError() {} + +var log = []; + +var first = { + next() { + log.push("call first next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, first); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call first return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var second = { + next() { + log.push("call second next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, second); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call second return"); + + throw new ExpectedError(); + } +}; + +var third = { + next() { + log.push("call third next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + return {}; + } +}; + +var it = Iterator.zip([first, second, third]); + +it.next(); + +assert.throws(ExpectedError, function() { + it.return(); +}); + +assert.compareArray(log, [ + "call first next", + "call second next", + "call third next", + + "call third return", + "call second return", + "call first return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js new file mode 100644 index 0000000000..b1972c4e91 --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js @@ -0,0 +1,145 @@ +// 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: > + Handle abrupt completion from IteratorStepValue in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do + ... + 3. Else, + a. Let result be Completion(IteratorStepValue(iter)). + b. If result is an abrupt completion, then + i. Remove iter from openIters. + ii. Return ? IteratorCloseAll(openIters, result). + ... + d. If result is done, then + i. Remove iter from openIters. + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +var modes = [ + "shortest", + "longest", + "strict", +]; + +function ExpectedError() {} + +var log = []; + +var first = { + next() { + log.push("call first next"); + throw new ExpectedError(); + }, + return() { + log.push("unexpected call first return"); + } +}; + +var second = { + next() { + log.push("unexpected call second next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, second); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call second return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var third = { + next() { + log.push("unexpected call third next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +// Empty iterator to ensure |return| is not called for closed iterators. +var empty = { + next() { + log.push("call empty next"); + return {done: true}; + }, + return() { + log.push("unexpected call empty return"); + } +}; + +for (var mode of modes) { + var it = Iterator.zip([first, second, third], {mode}); + + assert.throws(ExpectedError, function() { + it.next(); + }); + + assert.compareArray(log, [ + "call first next", + "call third return", + "call second return", + ]); + + // Clear log. + log.length = 0; +} + +// This case applies only when mode is "longest". +var it = Iterator.zip([empty, first, second, third], {mode: "longest"}); + +assert.throws(ExpectedError, function() { + it.next(); +}); + +assert.compareArray(log, [ + "call empty next", + "call first next", + "call third return", + "call second return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js new file mode 100644 index 0000000000..14e9446ea0 --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js @@ -0,0 +1,127 @@ +// 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: > + Handle abrupt completion from IteratorStep in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + v. Let completion be Completion(Yield(results)). + vi. If completion is an abrupt completion, then + 1. Return ? IteratorCloseAll(openIters, completion). + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +function ExpectedError() {} + +var log = []; + +var first = { + next() { + log.push("call first next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, first); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call first return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var second = { + next() { + log.push("call second next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, second); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call second return"); + + throw new ExpectedError(); + } +}; + +var third = { + next() { + log.push("call third next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + return {}; + } +}; + +var fourth = { + next() { + log.push("call fourth next"); + return {done: true}; + }, + return() { + log.push("unexpected call fourth return"); + } +}; + +var it = Iterator.zip([first, second, third, fourth], {mode: "longest"}); + +it.next(); + +assert.throws(ExpectedError, function() { + it.return(); +}); + +assert.compareArray(log, [ + "call first next", + "call second next", + "call third next", + "call fourth next", + + "call third return", + "call second return", + "call first return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js new file mode 100644 index 0000000000..0ea88a04e5 --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js @@ -0,0 +1,125 @@ +// 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: > + Handle abrupt completion from IteratorCloseAll in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do + ... + 3. Else, + ... + d. If result is done, then + i. Remove iter from openIters. + ii. If mode is "shortest", then + i. Return ? IteratorCloseAll(openIters, ReturnCompletion(undefined)). + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +function ExpectedError() {} + +var log = []; + +var first = { + next() { + log.push("call first next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, first); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call first return"); + + return {}; + } +}; + +var second = { + next() { + log.push("call second next"); + return {done: true}; + }, + return() { + log.push("unexpected call second return"); + } +}; + +var third = { + next() { + log.push("unexpected call third next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var fourth = { + next() { + log.push("unexpected call fourth next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, fourth); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call fourth return"); + + throw new ExpectedError(); + } +}; + +var it = Iterator.zip([first, second, third, fourth], {mode: "shortest"}); + +assert.throws(ExpectedError, function() { + it.next(); +}); + +assert.compareArray(log, [ + "call first next", + "call second next", + "call fourth return", + "call third return", + "call first return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js new file mode 100644 index 0000000000..883a6dff0b --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js @@ -0,0 +1,108 @@ +// 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: > + Handle abrupt completion from IteratorCloseAll in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do + ... + 3. Else, + ... + d. If result is done, then + i. Remove iter from openIters. + ... + iii. Else if mode is "strict", then + i. If i ≠ 0, then + i. Return ? IteratorCloseAll(openIters, ThrowCompletion(a newly created TypeError object)). + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +var log = []; + +var first = { + next() { + log.push("call first next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, first); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call first return"); + + return {}; + } +}; + +var second = { + next() { + log.push("call second next"); + return {done: true}; + }, + return() { + log.push("unexpected call second return"); + } +}; + +var third = { + next() { + log.push("unexpected call third next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var it = Iterator.zip([first, second, third], {mode: "strict"}); + +assert.throws(TypeError, function() { + it.next(); +}); + +assert.compareArray(log, [ + "call first next", + "call second next", + "call third return", + "call first return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js new file mode 100644 index 0000000000..63646bd924 --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js @@ -0,0 +1,123 @@ +// 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: > + Handle abrupt completion from IteratorCloseAll in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do + ... + 3. Else, + ... + d. If result is done, then + i. Remove iter from openIters. + ... + iii. Else if mode is "strict", then + ... + ii. For each integer k such that 1 ≤ k < iterCount, in ascending order, do + ... + iv. Else, + i. Return ? IteratorCloseAll(openIters, ThrowCompletion(a newly created TypeError object)). + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +var log = []; + +var first = { + next() { + log.push("call first next"); + return {done: true}; + }, + return() { + log.push("unexpected call first return"); + } +}; + +var second = { + next() { + log.push("call second next"); + return {done: true}; + }, + return() { + log.push("unexpected call second return"); + } +}; + +var third = { + next() { + log.push("call third next"); + return {done: false}; + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var fourth = { + next() { + log.push("unexpected call fourth next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, fourth); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call fourth return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var it = Iterator.zip([first, second, third, fourth], {mode: "strict"}); + +assert.throws(TypeError, function() { + it.next(); +}); + +assert.compareArray(log, [ + "call first next", + "call second next", + "call third next", + "call fourth return", + "call third return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js b/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js new file mode 100644 index 0000000000..9ef82da6a6 --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js @@ -0,0 +1,125 @@ +// 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: > + Handle abrupt completion from IteratorStep in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do + ... + 3. Else, + ... + d. If result is done, then + i. Remove iter from openIters. + ... + iii. Else if mode is "strict", then + ... + ii. For each integer k such that 1 ≤ k < iterCount, in ascending order, do + ... + ii. Let open be Completion(IteratorStep(iters[k])). + iii. If open is an abrupt completion, then + i. Remove iters[k] from openIters. + ii. Return ? IteratorCloseAll(openIters, open). + ... + + IteratorCloseAll ( iters, completion ) + 1. For each element iter of iters, in reverse List order, do + a. Set completion to Completion(IteratorClose(iter, completion)). + 2. Return ? completion. + + IteratorClose ( iteratorRecord, completion ) + 1. Assert: iteratorRecord.[[Iterator]] is an Object. + 2. Let iterator be iteratorRecord.[[Iterator]]. + 3. Let innerResult be Completion(GetMethod(iterator, "return")). + 4. If innerResult is a normal completion, then + a. Let return be innerResult.[[Value]]. + b. If return is undefined, return ? completion. + c. Set innerResult to Completion(Call(return, iterator)). + 5. If completion is a throw completion, return ? completion. + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +function ExpectedError() {} + +var log = []; + +var first = { + next() { + log.push("call first next"); + return {done: true}; + }, + return() { + log.push("unexpected call first return"); + } +}; + +var second = { + next() { + log.push("call second next"); + throw new ExpectedError(); + }, + return() { + log.push("unexpected call second return"); + } +}; + +var third = { + next() { + log.push("unexpected call third next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, third); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call third return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var fourth = { + next() { + log.push("unexpected call fourth next"); + }, + return() { + // Called with the correct receiver and no arguments. + assert.sameValue(this, fourth); + assert.sameValue(arguments.length, 0); + + // NB: Log after above asserts, because failures aren't propagated. + log.push("call fourth return"); + + // IteratorClose ignores new exceptions when called with a Throw completion. + throw new Test262Error(); + } +}; + +var it = Iterator.zip([first, second, third, fourth], {mode: "strict"}); + +assert.throws(ExpectedError, function() { + it.next(); +}); + +assert.compareArray(log, [ + "call first next", + "call second next", + "call fourth return", + "call third return", +]); diff --git a/test/built-ins/Iterator/zip/iterator-zip-iteration.js b/test/built-ins/Iterator/zip/iterator-zip-iteration.js new file mode 100644 index 0000000000..7d4a2d33ae --- /dev/null +++ b/test/built-ins/Iterator/zip/iterator-zip-iteration.js @@ -0,0 +1,155 @@ +// 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: > + Perform iteration in IteratorZip. +info: | + Iterator.zip ( iterables [ , options ] ) + ... + 16. Return IteratorZip(iters, mode, padding, finishResults). + + IteratorZip ( iters, mode, padding, finishResults ) + 3. Let closure be a new Abstract Closure with no parameters that captures + iters, iterCount, openIters, mode, padding, and finishResults, and + performs the following steps when called: + ... + b. Repeat, + ... + iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do + ... + 3. Else, + a. Let result be Completion(IteratorStepValue(iter)). + ... +includes: [compareArray.js] +features: [joint-iteration] +---*/ + +var modes = [ + "shortest", + "longest", + "strict", +]; + +function makeIterator(log, name, elements) { + var elementsIter = elements.values(); + var iterator = { + next() { + log.push(`call ${name} next`); + + // Called with the correct receiver and no arguments. + assert.sameValue(this, iterator); + assert.sameValue(arguments.length, 0); + + var result = elementsIter.next(); + return { + get done() { + log.push(`get ${name}.result.done`); + return result.done; + }, + get value() { + log.push(`get ${name}.result.value`); + return result.value; + }, + }; + }, + return() { + log.push(`call ${name} return`); + + // Called with the correct receiver and no arguments. + assert.sameValue(this, iterator); + assert.sameValue(arguments.length, 0); + + return { + get done() { + log.push(`unexpected get ${name}.result.done`); + return result.done; + }, + get value() { + log.push(`unexpected get ${name}.result.value`); + return result.value; + }, + }; + } + }; + return iterator; +} + +for (var mode of modes) { + var log = []; + var iterables = [ + makeIterator(log, "first", [1, 2, 3]), + makeIterator(log, "second", [4, 5, 6]), + makeIterator(log, "third", [7, 8, 9]), + ]; + var it = Iterator.zip(iterables, {mode}); + + log.push("start"); + for (var v of it) { + log.push("loop"); + } + + var expected = [ + "start", + + "call first next", + "get first.result.done", + "get first.result.value", + "call second next", + "get second.result.done", + "get second.result.value", + "call third next", + "get third.result.done", + "get third.result.value", + "loop", + + "call first next", + "get first.result.done", + "get first.result.value", + "call second next", + "get second.result.done", + "get second.result.value", + "call third next", + "get third.result.done", + "get third.result.value", + "loop", + + "call first next", + "get first.result.done", + "get first.result.value", + "call second next", + "get second.result.done", + "get second.result.value", + "call third next", + "get third.result.done", + "get third.result.value", + "loop", + ]; + + switch (mode) { + case "shortest": { + expected.push( + "call first next", + "get first.result.done", + "call third return", + "call second return", + ); + break; + } + case "longest": + case "strict": { + expected.push( + "call first next", + "get first.result.done", + "call second next", + "get second.result.done", + "call third next", + "get third.result.done", + ); + break; + } + } + + assert.compareArray(log, expected); +}