Skip to content

Commit 986de0b

Browse files
committed
Test IteratorZip iteration for zip
1 parent 1d71d90 commit 986de0b

8 files changed

+1024
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright (C) 2025 André Bargull. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-iterator.zip
6+
description: >
7+
Handle abrupt completion from IteratorStep in IteratorZip.
8+
info: |
9+
Iterator.zip ( iterables [ , options ] )
10+
...
11+
16. Return IteratorZip(iters, mode, padding, finishResults).
12+
13+
IteratorZip ( iters, mode, padding, finishResults )
14+
3. Let closure be a new Abstract Closure with no parameters that captures
15+
iters, iterCount, openIters, mode, padding, and finishResults, and
16+
performs the following steps when called:
17+
...
18+
b. Repeat,
19+
...
20+
v. Let completion be Completion(Yield(results)).
21+
vi. If completion is an abrupt completion, then
22+
1. Return ? IteratorCloseAll(openIters, completion).
23+
...
24+
25+
IteratorCloseAll ( iters, completion )
26+
1. For each element iter of iters, in reverse List order, do
27+
a. Set completion to Completion(IteratorClose(iter, completion)).
28+
2. Return ? completion.
29+
30+
IteratorClose ( iteratorRecord, completion )
31+
1. Assert: iteratorRecord.[[Iterator]] is an Object.
32+
2. Let iterator be iteratorRecord.[[Iterator]].
33+
3. Let innerResult be Completion(GetMethod(iterator, "return")).
34+
4. If innerResult is a normal completion, then
35+
a. Let return be innerResult.[[Value]].
36+
b. If return is undefined, return ? completion.
37+
c. Set innerResult to Completion(Call(return, iterator)).
38+
5. If completion is a throw completion, return ? completion.
39+
...
40+
includes: [compareArray.js]
41+
features: [joint-iteration]
42+
---*/
43+
44+
function ExpectedError() {}
45+
46+
var log = [];
47+
48+
var first = {
49+
next() {
50+
log.push("call first next");
51+
return {done: false};
52+
},
53+
return() {
54+
// Called with the correct receiver and no arguments.
55+
assert.sameValue(this, first);
56+
assert.sameValue(arguments.length, 0);
57+
58+
// NB: Log after above asserts, because failures aren't propagated.
59+
log.push("call first return");
60+
61+
// IteratorClose ignores new exceptions when called with a Throw completion.
62+
throw new Test262Error();
63+
}
64+
};
65+
66+
var second = {
67+
next() {
68+
log.push("call second next");
69+
return {done: false};
70+
},
71+
return() {
72+
// Called with the correct receiver and no arguments.
73+
assert.sameValue(this, second);
74+
assert.sameValue(arguments.length, 0);
75+
76+
// NB: Log after above asserts, because failures aren't propagated.
77+
log.push("call second return");
78+
79+
throw new ExpectedError();
80+
}
81+
};
82+
83+
var third = {
84+
next() {
85+
log.push("call third next");
86+
return {done: false};
87+
},
88+
return() {
89+
// Called with the correct receiver and no arguments.
90+
assert.sameValue(this, third);
91+
assert.sameValue(arguments.length, 0);
92+
93+
// NB: Log after above asserts, because failures aren't propagated.
94+
log.push("call third return");
95+
96+
return {};
97+
}
98+
};
99+
100+
var it = Iterator.zip([first, second, third]);
101+
102+
it.next();
103+
104+
assert.throws(ExpectedError, function() {
105+
it.return();
106+
});
107+
108+
assert.compareArray(log, [
109+
"call first next",
110+
"call second next",
111+
"call third next",
112+
113+
"call third return",
114+
"call second return",
115+
"call first return",
116+
]);
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright (C) 2025 André Bargull. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-iterator.zip
6+
description: >
7+
Handle abrupt completion from IteratorStepValue in IteratorZip.
8+
info: |
9+
Iterator.zip ( iterables [ , options ] )
10+
...
11+
16. Return IteratorZip(iters, mode, padding, finishResults).
12+
13+
IteratorZip ( iters, mode, padding, finishResults )
14+
3. Let closure be a new Abstract Closure with no parameters that captures
15+
iters, iterCount, openIters, mode, padding, and finishResults, and
16+
performs the following steps when called:
17+
...
18+
b. Repeat,
19+
...
20+
iii. For each integer i such that 0 ≤ i < iterCount, in ascending order, do
21+
...
22+
3. Else,
23+
a. Let result be Completion(IteratorStepValue(iter)).
24+
b. If result is an abrupt completion, then
25+
i. Remove iter from openIters.
26+
ii. Return ? IteratorCloseAll(openIters, result).
27+
...
28+
d. If result is done, then
29+
i. Remove iter from openIters.
30+
...
31+
32+
IteratorCloseAll ( iters, completion )
33+
1. For each element iter of iters, in reverse List order, do
34+
a. Set completion to Completion(IteratorClose(iter, completion)).
35+
2. Return ? completion.
36+
37+
IteratorClose ( iteratorRecord, completion )
38+
1. Assert: iteratorRecord.[[Iterator]] is an Object.
39+
2. Let iterator be iteratorRecord.[[Iterator]].
40+
3. Let innerResult be Completion(GetMethod(iterator, "return")).
41+
4. If innerResult is a normal completion, then
42+
a. Let return be innerResult.[[Value]].
43+
b. If return is undefined, return ? completion.
44+
c. Set innerResult to Completion(Call(return, iterator)).
45+
5. If completion is a throw completion, return ? completion.
46+
...
47+
includes: [compareArray.js]
48+
features: [joint-iteration]
49+
---*/
50+
51+
var modes = [
52+
"shortest",
53+
"longest",
54+
"strict",
55+
];
56+
57+
function ExpectedError() {}
58+
59+
var log = [];
60+
61+
var first = {
62+
next() {
63+
log.push("call first next");
64+
throw new ExpectedError();
65+
},
66+
return() {
67+
log.push("unexpected call first return");
68+
}
69+
};
70+
71+
var second = {
72+
next() {
73+
log.push("unexpected call second next");
74+
},
75+
return() {
76+
// Called with the correct receiver and no arguments.
77+
assert.sameValue(this, second);
78+
assert.sameValue(arguments.length, 0);
79+
80+
// NB: Log after above asserts, because failures aren't propagated.
81+
log.push("call second return");
82+
83+
// IteratorClose ignores new exceptions when called with a Throw completion.
84+
throw new Test262Error();
85+
}
86+
};
87+
88+
var third = {
89+
next() {
90+
log.push("unexpected call third next");
91+
},
92+
return() {
93+
// Called with the correct receiver and no arguments.
94+
assert.sameValue(this, third);
95+
assert.sameValue(arguments.length, 0);
96+
97+
// NB: Log after above asserts, because failures aren't propagated.
98+
log.push("call third return");
99+
100+
// IteratorClose ignores new exceptions when called with a Throw completion.
101+
throw new Test262Error();
102+
}
103+
};
104+
105+
// Empty iterator to ensure |return| is not called for closed iterators.
106+
var empty = {
107+
next() {
108+
log.push("call empty next");
109+
return {done: true};
110+
},
111+
return() {
112+
log.push("unexpected call empty return");
113+
}
114+
};
115+
116+
for (var mode of modes) {
117+
var it = Iterator.zip([first, second, third], {mode});
118+
119+
assert.throws(ExpectedError, function() {
120+
it.next();
121+
});
122+
123+
assert.compareArray(log, [
124+
"call first next",
125+
"call third return",
126+
"call second return",
127+
]);
128+
129+
// Clear log.
130+
log.length = 0;
131+
}
132+
133+
// This case applies only when mode is "longest".
134+
var it = Iterator.zip([empty, first, second, third], {mode: "longest"});
135+
136+
assert.throws(ExpectedError, function() {
137+
it.next();
138+
});
139+
140+
assert.compareArray(log, [
141+
"call empty next",
142+
"call first next",
143+
"call third return",
144+
"call second return",
145+
]);
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright (C) 2025 André Bargull. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-iterator.zip
6+
description: >
7+
Handle abrupt completion from IteratorStep in IteratorZip.
8+
info: |
9+
Iterator.zip ( iterables [ , options ] )
10+
...
11+
16. Return IteratorZip(iters, mode, padding, finishResults).
12+
13+
IteratorZip ( iters, mode, padding, finishResults )
14+
3. Let closure be a new Abstract Closure with no parameters that captures
15+
iters, iterCount, openIters, mode, padding, and finishResults, and
16+
performs the following steps when called:
17+
...
18+
b. Repeat,
19+
...
20+
v. Let completion be Completion(Yield(results)).
21+
vi. If completion is an abrupt completion, then
22+
1. Return ? IteratorCloseAll(openIters, completion).
23+
...
24+
25+
IteratorCloseAll ( iters, completion )
26+
1. For each element iter of iters, in reverse List order, do
27+
a. Set completion to Completion(IteratorClose(iter, completion)).
28+
2. Return ? completion.
29+
30+
IteratorClose ( iteratorRecord, completion )
31+
1. Assert: iteratorRecord.[[Iterator]] is an Object.
32+
2. Let iterator be iteratorRecord.[[Iterator]].
33+
3. Let innerResult be Completion(GetMethod(iterator, "return")).
34+
4. If innerResult is a normal completion, then
35+
a. Let return be innerResult.[[Value]].
36+
b. If return is undefined, return ? completion.
37+
c. Set innerResult to Completion(Call(return, iterator)).
38+
5. If completion is a throw completion, return ? completion.
39+
...
40+
includes: [compareArray.js]
41+
features: [joint-iteration]
42+
---*/
43+
44+
function ExpectedError() {}
45+
46+
var log = [];
47+
48+
var first = {
49+
next() {
50+
log.push("call first next");
51+
return {done: false};
52+
},
53+
return() {
54+
// Called with the correct receiver and no arguments.
55+
assert.sameValue(this, first);
56+
assert.sameValue(arguments.length, 0);
57+
58+
// NB: Log after above asserts, because failures aren't propagated.
59+
log.push("call first return");
60+
61+
// IteratorClose ignores new exceptions when called with a Throw completion.
62+
throw new Test262Error();
63+
}
64+
};
65+
66+
var second = {
67+
next() {
68+
log.push("call second next");
69+
return {done: false};
70+
},
71+
return() {
72+
// Called with the correct receiver and no arguments.
73+
assert.sameValue(this, second);
74+
assert.sameValue(arguments.length, 0);
75+
76+
// NB: Log after above asserts, because failures aren't propagated.
77+
log.push("call second return");
78+
79+
throw new ExpectedError();
80+
}
81+
};
82+
83+
var third = {
84+
next() {
85+
log.push("call third next");
86+
return {done: false};
87+
},
88+
return() {
89+
// Called with the correct receiver and no arguments.
90+
assert.sameValue(this, third);
91+
assert.sameValue(arguments.length, 0);
92+
93+
// NB: Log after above asserts, because failures aren't propagated.
94+
log.push("call third return");
95+
96+
return {};
97+
}
98+
};
99+
100+
var fourth = {
101+
next() {
102+
log.push("call fourth next");
103+
return {done: true};
104+
},
105+
return() {
106+
log.push("unexpected call fourth return");
107+
}
108+
};
109+
110+
var it = Iterator.zip([first, second, third, fourth], {mode: "longest"});
111+
112+
it.next();
113+
114+
assert.throws(ExpectedError, function() {
115+
it.return();
116+
});
117+
118+
assert.compareArray(log, [
119+
"call first next",
120+
"call second next",
121+
"call third next",
122+
"call fourth next",
123+
124+
"call third return",
125+
"call second return",
126+
"call first return",
127+
]);

0 commit comments

Comments
 (0)