Skip to content

Commit 8813291

Browse files
authored
test: cover Readable.from() sync iterator errors
Signed-off-by: jakecastelli <38635403+jakecastelli@users.noreply.github.com> PR-URL: #65515 Reviewed-By: Jason Zhang <xzha4350@gmail.com> Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
1 parent 49c87ef commit 8813291

2 files changed

Lines changed: 114 additions & 11 deletions

File tree

test/parallel/test-readable-from-iterator-closing.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,40 @@ async function syncRejectedSupport() {
101101
}
102102
}
103103

104+
async function syncRejectedAfterResolvedSupport() {
105+
const expectedError = new Error('later rejection');
106+
const finallyMustCall = mustCall();
107+
const bodyMustCall = mustCall((chunk) => {
108+
assert.strictEqual(chunk, 'a');
109+
});
110+
const catchMustCall = mustCall((error) => {
111+
assert.strictEqual(error, expectedError);
112+
});
113+
const thirdNextMustNotCall = mustNotCall();
114+
115+
function* generate() {
116+
try {
117+
yield Promise.resolve('a');
118+
yield Promise.reject(expectedError);
119+
thirdNextMustNotCall();
120+
} finally {
121+
finallyMustCall();
122+
}
123+
}
124+
125+
const stream = Readable.from(generate());
126+
127+
try {
128+
for await (const chunk of stream) {
129+
bodyMustCall(chunk);
130+
}
131+
} catch (error) {
132+
catchMustCall(error);
133+
}
134+
135+
assert.strictEqual(stream.destroyed, true);
136+
}
137+
104138
async function noReturnAfterThrow() {
105139
const returnMustNotCall = mustNotCall();
106140
const bodyMustNotCall = mustNotCall();
@@ -187,6 +221,7 @@ Promise.all([
187221
syncSupport(),
188222
syncPromiseSupport(),
189223
syncRejectedSupport(),
224+
syncRejectedAfterResolvedSupport(),
190225
noReturnAfterThrow(),
191226
closeStreamWhileNextIsPending(),
192227
closeAfterNullYielded(),
Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,87 @@
11
'use strict';
2-
const { mustNotCall, expectsError } = require('../common');
2+
const common = require('../common');
3+
const assert = require('assert');
34
const { Readable } = require('stream');
5+
const { finished } = require('stream/promises');
46

5-
async function* generate() {
6-
yield null;
7-
}
8-
9-
const stream = Readable.from(generate());
10-
11-
stream.on('error', expectsError({
7+
const expectedError = {
128
code: 'ERR_STREAM_NULL_VALUES',
139
name: 'TypeError',
1410
message: 'May not write null values to stream'
15-
}));
11+
};
12+
13+
async function rejectsNull(iterable, expectedChunks = []) {
14+
const stream = Readable.from(iterable);
15+
const chunks = [];
16+
const completion = finished(stream);
17+
18+
stream.on('data', (chunk) => chunks.push(chunk));
19+
20+
await assert.rejects(completion, expectedError);
21+
assert.deepStrictEqual(chunks, expectedChunks);
22+
assert.strictEqual(stream.destroyed, true);
23+
}
24+
25+
async function asyncIteratorYieldsNull() {
26+
const cleanup = common.mustCall();
27+
28+
async function* generate() {
29+
try {
30+
yield null;
31+
} finally {
32+
cleanup();
33+
}
34+
}
35+
36+
await rejectsNull(generate());
37+
}
1638

17-
stream.on('data', mustNotCall());
39+
async function syncIteratorYieldsNull() {
40+
const cleanup = common.mustCall();
41+
42+
function* generate() {
43+
try {
44+
yield null;
45+
} finally {
46+
cleanup();
47+
}
48+
}
49+
50+
await rejectsNull(generate());
51+
}
52+
53+
async function firstSyncValueResolvesToNull() {
54+
const cleanup = common.mustCall();
55+
56+
function* generate() {
57+
try {
58+
yield Promise.resolve(null);
59+
} finally {
60+
cleanup();
61+
}
62+
}
63+
64+
await rejectsNull(generate());
65+
}
66+
67+
async function laterSyncValueResolvesToNull() {
68+
const cleanup = common.mustCall();
69+
70+
function* generate() {
71+
try {
72+
yield Promise.resolve('first');
73+
yield Promise.resolve(null);
74+
} finally {
75+
cleanup();
76+
}
77+
}
78+
79+
await rejectsNull(generate(), ['first']);
80+
}
1881

19-
stream.on('end', mustNotCall());
82+
Promise.all([
83+
asyncIteratorYieldsNull(),
84+
syncIteratorYieldsNull(),
85+
firstSyncValueResolvesToNull(),
86+
laterSyncValueResolvesToNull(),
87+
]).then(common.mustCall());

0 commit comments

Comments
 (0)