Skip to content
File

Blob: src/workerd/api/node/tests/streams-test.js

javascript11499 lines
1// Copyright (c) 2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import {
5 deepStrictEqual,
6 fail,
7 ifError,
8 notStrictEqual,
9 ok,
10 rejects,
11 strictEqual,
12 throws,
13} from 'node:assert';
14 
15import { Buffer } from 'node:buffer';
16 
17import {
18 Readable,
19 Writable,
20 Duplex,
21 Stream,
22 Transform,
23 PassThrough,
24 addAbortSignal,
25 destroy,
26 finished,
27 isDisturbed,
28 isErrored,
29 promises,
30 duplexPair,
31} from 'node:stream';
32 
33import { ByteLengthQueuingStrategy } from 'node:stream/web';
34strictEqual(ByteLengthQueuingStrategy, globalThis.ByteLengthQueuingStrategy);
35 
36import { EventEmitter } from 'node:events';
37 
38function countedDeferred(n, action) {
39 let resolve;
40 const promise = new Promise((a) => {
41 resolve = a;
42 });
43 return {
44 promise,
45 resolve(...args) {
46 action(...args);
47 if (--n === 0) resolve();
48 },
49 };
50}
51 
52export const legacyAliases = {
53 async test(ctrl, env, ctx) {
54 strictEqual(Readable, (await import('node:_stream_readable')).Readable);
55 strictEqual(Writable, (await import('node:_stream_writable')).Writable);
56 strictEqual(Duplex, (await import('node:_stream_duplex')).Duplex);
57 strictEqual(Transform, (await import('node:_stream_transform')).Transform);
58 strictEqual(
59 PassThrough,
60 (await import('node:_stream_passthrough')).PassThrough
61 );
62 },
63};
64 
65export const addAbortSignalTest = {
66 test(ctrl, env, ctx) {
67 const ac = new AbortController();
68 addAbortSignal(ac.signal, new Readable());
69 
70 {
71 throws(() => {
72 addAbortSignal('INVALID_SIGNAL');
73 }, /ERR_INVALID_ARG_TYPE/);
74 
75 throws(() => {
76 addAbortSignal(ac.signal, 'INVALID_STREAM');
77 }, /ERR_INVALID_ARG_TYPE/);
78 }
79 },
80};
81 
82export const autoDestroy = {
83 async test(ctrl, env, ctx) {
84 {
85 const rDestroyed = Promise.withResolvers();
86 const rEnded = Promise.withResolvers();
87 const rClosed = Promise.withResolvers();
88 
89 const r = new Readable({
90 autoDestroy: true,
91 read() {
92 this.push('hello');
93 this.push('world');
94 this.push(null);
95 },
96 destroy(err, cb) {
97 rDestroyed.resolve();
98 cb();
99 },
100 });
101 
102 let _ended = false;
103 r.resume();
104 r.on('end', rEnded.resolve);
105 r.on('close', rClosed.resolve);
106 
107 await Promise.all([rDestroyed.promise, rEnded.promise, rClosed.promise]);
108 }
109 
110 {
111 const rDestroyed = Promise.withResolvers();
112 const rFinished = Promise.withResolvers();
113 const rClosed = Promise.withResolvers();
114 
115 const w = new Writable({
116 autoDestroy: true,
117 write(data, enc, cb) {
118 cb(null);
119 },
120 destroy(err, cb) {
121 rDestroyed.resolve();
122 cb();
123 },
124 });
125 
126 w.write('hello');
127 w.write('world');
128 w.end();
129 
130 w.on('finish', rFinished.resolve);
131 w.on('close', rClosed.resolve);
132 
133 await Promise.all([
134 rDestroyed.promise,
135 rFinished.promise,
136 rClosed.promise,
137 ]);
138 }
139 
140 {
141 const rDestroyed = Promise.withResolvers();
142 const rEnded = Promise.withResolvers();
143 const rFinished = Promise.withResolvers();
144 const rClosed = Promise.withResolvers();
145 
146 const t = new Transform({
147 autoDestroy: true,
148 transform(data, enc, cb) {
149 cb(null, data);
150 },
151 destroy(err, cb) {
152 rDestroyed.resolve();
153 cb();
154 },
155 });
156 
157 t.write('hello');
158 t.write('world');
159 t.end();
160 
161 t.resume();
162 
163 t.on('end', rEnded.resolve);
164 t.on('finish', rFinished.resolve);
165 t.on('close', rClosed.resolve);
166 
167 await Promise.all([
168 rDestroyed.promise,
169 rEnded.promise,
170 rFinished.promise,
171 rClosed.promise,
172 ]);
173 }
174 
175 {
176 const rDestroyed = Promise.withResolvers();
177 
178 const err = new Error('fail');
179 
180 const r = new Readable({
181 read() {
182 r2.emit('error', err);
183 },
184 });
185 const r2 = new Readable({
186 autoDestroy: true,
187 destroy(err, cb) {
188 rDestroyed.resolve(err);
189 },
190 });
191 
192 r.pipe(r2);
193 
194 const check = await rDestroyed.promise;
195 strictEqual(check, err);
196 }
197 
198 {
199 const rDestroyed = Promise.withResolvers();
200 const err = new Error('fail');
201 const r = new Readable({
202 read() {
203 w.emit('error', err);
204 },
205 });
206 
207 const w = new Writable({
208 autoDestroy: true,
209 destroy(err, cb) {
210 rDestroyed.resolve(err);
211 cb();
212 },
213 });
214 
215 r.pipe(w);
216 
217 const check = await rDestroyed.promise;
218 strictEqual(check, err);
219 }
220 },
221};
222 
223export const awaitDrainWritersInSyncRecursionWrite = {
224 async test(ctrl, env, ctx) {
225 const encode = new PassThrough({
226 highWaterMark: 1,
227 });
228 
229 const decode = new PassThrough({
230 highWaterMark: 1,
231 });
232 
233 const send = countedDeferred(4, (buf) => {
234 encode.write(buf);
235 });
236 
237 let i = 0;
238 const onData = () => {
239 if (++i === 2) {
240 send.resolve(Buffer.from([0x3]));
241 send.resolve(Buffer.from([0x4]));
242 }
243 };
244 
245 encode.pipe(decode).on('data', onData);
246 
247 send.resolve(Buffer.from([0x1]));
248 send.resolve(Buffer.from([0x2]));
249 
250 await send.promise;
251 },
252};
253 
254export const backpressure = {
255 async test(ctrl, env, ctx) {
256 let pushes = 0;
257 const total = 65500 + 40 * 1024;
258 let reads = 0;
259 let writes = 0;
260 const rs = new Readable({
261 read() {
262 if (++reads > 11) throw new Error('incorrect number of reads');
263 if (pushes++ === 10) {
264 this.push(null);
265 return;
266 }
267 
268 const length = this._readableState.length;
269 
270 // We are at most doing two full runs of _reads
271 // before stopping, because Readable is greedy
272 // to keep its buffer full
273 ok(length <= total);
274 
275 this.push(Buffer.alloc(65500));
276 for (let i = 0; i < 40; i++) {
277 this.push(Buffer.alloc(1024));
278 }
279 
280 // We will be over highWaterMark at this point
281 // but a new call to _read is scheduled anyway.
282 },
283 });
284 
285 const closed = Promise.withResolvers();
286 
287 const ws = Writable({
288 write(data, enc, cb) {
289 queueMicrotask(cb);
290 if (++writes === 410) closed.resolve();
291 },
292 });
293 
294 rs.pipe(ws);
295 
296 await closed.promise;
297 },
298};
299 
300export const bigPacket = {
301 async test(ctrl, env, ctx) {
302 const rPassed = Promise.withResolvers();
303 
304 class TestStream extends Transform {
305 _transform(chunk, encoding, done) {
306 // Char 'a' only exists in the last write
307 if (chunk.includes('a')) rPassed.resolve();
308 done();
309 }
310 }
311 
312 const s1 = new Transform({
313 transform(chunk, encoding, cb) {
314 queueMicrotask(() => cb(null, chunk));
315 },
316 });
317 const s2 = new PassThrough();
318 const s3 = new TestStream();
319 s1.pipe(s3);
320 // Don't let s2 auto close which may close s3
321 s2.pipe(s3, { end: false });
322 
323 // We must write a buffer larger than highWaterMark
324 const big = Buffer.alloc(s1.writableHighWaterMark + 1, 'x');
325 
326 // Since big is larger than highWaterMark, it will be buffered internally.
327 ok(!s1.write(big));
328 // 'tiny' is small enough to pass through internal buffer.
329 ok(s2.write('tiny'));
330 
331 // Write some small data in next IO loop, which will never be written to s3
332 // Because 'drain' event is not emitted from s1 and s1 is still paused
333 queueMicrotask(() => s1.write('later'));
334 
335 await rPassed.promise;
336 },
337};
338 
339export const bigPush = {
340 async test(ctrl, env, ctx) {
341 const str = 'asdfasdfasdfasdfasdf';
342 
343 const r = new Readable({
344 highWaterMark: 5,
345 encoding: 'utf8',
346 });
347 
348 let reads = 0;
349 
350 function _read() {
351 if (reads === 0) {
352 setTimeout(() => {
353 r.push(str);
354 }, 1);
355 reads++;
356 } else if (reads === 1) {
357 const ret = r.push(str);
358 strictEqual(ret, false);
359 reads++;
360 } else {
361 r.push(null);
362 }
363 }
364 
365 const read = countedDeferred(3, _read);
366 const ended = Promise.withResolvers();
367 
368 r._read = read.resolve;
369 r.on('end', ended.resolve);
370 
371 // Push some data in to start.
372 // We've never gotten any read event at this point.
373 const ret = r.push(str);
374 // Should be false. > hwm
375 ok(!ret);
376 let chunk = r.read();
377 strictEqual(chunk, str);
378 chunk = r.read();
379 strictEqual(chunk, null);
380 
381 r.once('readable', () => {
382 // This time, we'll get *all* the remaining data, because
383 // it's been added synchronously, as the read WOULD take
384 // us below the hwm, and so it triggered a _read() again,
385 // which synchronously added more, which we then return.
386 chunk = r.read();
387 strictEqual(chunk, str + str);
388 
389 chunk = r.read();
390 strictEqual(chunk, null);
391 });
392 
393 await Promise.all([read.promise, ended.promise]);
394 },
395};
396 
397export const catchRejections = {
398 async test(ctrl, env, ctx) {
399 {
400 const rErrored = Promise.withResolvers();
401 
402 const r = new Readable({
403 captureRejections: true,
404 read() {},
405 });
406 r.push('hello');
407 r.push('world');
408 
409 const err = new Error('kaboom');
410 
411 r.on('error', (_err) => {
412 strictEqual(err, _err);
413 strictEqual(r.destroyed, true);
414 rErrored.resolve();
415 });
416 
417 r.on('data', async () => {
418 throw err;
419 });
420 
421 await rErrored.promise;
422 }
423 
424 {
425 const wErrored = Promise.withResolvers();
426 
427 const w = new Writable({
428 captureRejections: true,
429 highWaterMark: 1,
430 write(chunk, enc, cb) {
431 queueMicrotask(cb);
432 },
433 });
434 
435 const err = new Error('kaboom');
436 
437 w.write('hello', () => {
438 w.write('world');
439 });
440 
441 w.on('error', (_err) => {
442 strictEqual(err, _err);
443 strictEqual(w.destroyed, true);
444 wErrored.resolve();
445 });
446 
447 w.on('drain', async () => {
448 throw err;
449 });
450 
451 await wErrored.promise;
452 }
453 },
454};
455 
456export const construct = {
457 async test(ctrl, env, ctx) {
458 {
459 const errored = Promise.withResolvers();
460 // Multiple callback.
461 new Writable({
462 construct: (callback) => {
463 callback();
464 callback();
465 },
466 }).on('error', (err) => {
467 errored.resolve(err);
468 });
469 
470 const check = await errored.promise;
471 strictEqual(check.message, 'Callback called multiple times');
472 }
473 
474 {
475 const errored = Promise.withResolvers();
476 // Multiple callback.
477 new Readable({
478 construct: (callback) => {
479 callback();
480 callback();
481 },
482 }).on('error', (err) => {
483 errored.resolve(err);
484 });
485 
486 const check = await errored.promise;
487 strictEqual(check.message, 'Callback called multiple times');
488 }
489 
490 {
491 // Synchronous error.
492 const errored = Promise.withResolvers();
493 const err = new Error('test');
494 new Writable({
495 construct: (callback) => {
496 callback(err);
497 },
498 }).on('error', (err) => {
499 errored.resolve(err);
500 });
501 
502 const check = await errored.promise;
503 strictEqual(check, err);
504 }
505 
506 {
507 const errored = Promise.withResolvers();
508 const err = new Error('test');
509 
510 new Readable({
511 construct: (callback) => {
512 callback(err);
513 },
514 }).on('error', (err) => {
515 errored.resolve(err);
516 });
517 
518 const check = await errored.promise;
519 strictEqual(check, err);
520 }
521 
522 {
523 // Asynchronous error.
524 const errored = Promise.withResolvers();
525 const err = new Error('test');
526 
527 new Writable({
528 construct: (callback) => {
529 queueMicrotask(() => callback(err));
530 },
531 }).on('error', (err) => {
532 errored.resolve(err);
533 });
534 
535 const check = await errored.promise;
536 strictEqual(check, err);
537 }
538 
539 {
540 // Asynchronous error.
541 const errored = Promise.withResolvers();
542 const err = new Error('test');
543 
544 new Readable({
545 construct: (callback) => {
546 queueMicrotask(() => callback(err));
547 },
548 }).on('error', errored.resolve);
549 
550 const check = await errored.promise;
551 strictEqual(check, err);
552 }
553 
554 async function testDestroy(factory) {
555 {
556 const constructed = Promise.withResolvers();
557 const closed = Promise.withResolvers();
558 const s = factory({
559 construct: (cb) => {
560 constructed.resolve();
561 queueMicrotask(cb);
562 },
563 });
564 s.on('close', closed.resolve);
565 s.destroy();
566 await Promise.all([constructed.promise, closed.promise]);
567 }
568 
569 {
570 const constructed = Promise.withResolvers();
571 const closed = Promise.withResolvers();
572 const destroyed = Promise.withResolvers();
573 const s = factory({
574 construct: (cb) => {
575 constructed.resolve();
576 queueMicrotask(cb);
577 },
578 });
579 s.on('close', closed.resolve);
580 s.destroy(null, () => {
581 destroyed.resolve();
582 });
583 
584 await Promise.all([
585 constructed.promise,
586 closed.promise,
587 destroyed.promise,
588 ]);
589 }
590 
591 {
592 const constructed = Promise.withResolvers();
593 const closed = Promise.withResolvers();
594 const s = factory({
595 construct: (cb) => {
596 constructed.resolve();
597 queueMicrotask(cb);
598 },
599 });
600 s.on('close', closed.resolve);
601 s.destroy();
602 await Promise.all([constructed.promise, closed.promise]);
603 }
604 
605 {
606 const constructed = Promise.withResolvers();
607 const closed = Promise.withResolvers();
608 const errored = Promise.withResolvers();
609 
610 const s = factory({
611 construct: (cb) => {
612 constructed.resolve();
613 queueMicrotask(cb);
614 },
615 });
616 s.on('close', closed.resolve);
617 s.on('error', (err) => {
618 strictEqual(err.message, 'kaboom');
619 errored.resolve();
620 });
621 s.destroy(new Error('kaboom'), (err) => {
622 strictEqual(err.message, 'kaboom');
623 });
624 await Promise.all([
625 constructed.promise,
626 closed.promise,
627 errored.promise,
628 ]);
629 }
630 
631 {
632 const constructed = Promise.withResolvers();
633 const errored = Promise.withResolvers();
634 const closed = Promise.withResolvers();
635 const s = factory({
636 construct: (cb) => {
637 constructed.resolve();
638 queueMicrotask(cb);
639 },
640 });
641 s.on('error', errored.resolve);
642 s.on('close', closed.resolve);
643 s.destroy(new Error());
644 
645 await Promise.all([
646 constructed.promise,
647 closed.promise,
648 errored.promise,
649 ]);
650 }
651 }
652 await testDestroy(
653 (opts) =>
654 new Readable({
655 read: () => {
656 throw new Error('must not call');
657 },
658 ...opts,
659 })
660 );
661 await testDestroy(
662 (opts) =>
663 new Writable({
664 write: () => {
665 throw new Error('must not call');
666 },
667 final: () => {
668 throw new Error('must not call');
669 },
670 ...opts,
671 })
672 );
673 
674 {
675 const constructed = Promise.withResolvers();
676 const read = Promise.withResolvers();
677 const closed = Promise.withResolvers();
678 
679 const r = new Readable({
680 autoDestroy: true,
681 construct: (cb) => {
682 constructed.resolve();
683 queueMicrotask(cb);
684 },
685 read: () => {
686 r.push(null);
687 read.resolve();
688 },
689 });
690 r.on('close', closed.resolve);
691 r.on('data', () => {
692 throw new Error('should not call');
693 });
694 
695 await Promise.all([constructed.promise, read.promise, closed.promise]);
696 }
697 
698 {
699 const constructed = Promise.withResolvers();
700 const write = Promise.withResolvers();
701 const final = Promise.withResolvers();
702 const closed = Promise.withResolvers();
703 
704 const w = new Writable({
705 autoDestroy: true,
706 construct: (cb) => {
707 constructed.resolve();
708 queueMicrotask(cb);
709 },
710 write: (chunk, encoding, cb) => {
711 write.resolve();
712 queueMicrotask(cb);
713 },
714 final: (cb) => {
715 final.resolve();
716 queueMicrotask(cb);
717 },
718 });
719 w.on('close', closed.resolve);
720 w.end('data');
721 
722 await Promise.all([
723 constructed.promise,
724 write.promise,
725 final.promise,
726 closed.promise,
727 ]);
728 }
729 
730 {
731 const constructed = Promise.withResolvers();
732 const final = Promise.withResolvers();
733 const closed = Promise.withResolvers();
734 const w = new Writable({
735 autoDestroy: true,
736 construct: (cb) => {
737 constructed.resolve();
738 queueMicrotask(cb);
739 },
740 write: () => {
741 throw new Error('should not call');
742 },
743 final: (cb) => {
744 final.resolve();
745 queueMicrotask(cb);
746 },
747 });
748 w.on('close', closed.resolve);
749 w.end();
750 
751 await Promise.all([constructed.promise, final.promise, closed.promise]);
752 }
753 
754 {
755 let constructed = true;
756 new Duplex({
757 construct() {
758 constructed = true;
759 },
760 });
761 ok(constructed);
762 }
763 
764 {
765 // https://github.com/nodejs/node/issues/34448
766 
767 const constructed = Promise.withResolvers();
768 const closed = Promise.withResolvers();
769 const d = new Duplex({
770 readable: false,
771 construct: (callback) => {
772 queueMicrotask(() => {
773 constructed.resolve();
774 callback();
775 });
776 },
777 write(chunk, encoding, callback) {
778 callback();
779 },
780 read() {
781 this.push(null);
782 },
783 });
784 d.resume();
785 d.end('foo');
786 d.on('close', closed.resolve);
787 
788 await Promise.all([constructed.promise, closed.promise]);
789 }
790 
791 {
792 // Construct should not cause stream to read.
793 new Readable({
794 construct: (callback) => {
795 callback();
796 },
797 read() {
798 throw new Error('should not call');
799 },
800 });
801 }
802 },
803};
804 
805export const decoderObjectMode = {
806 test(ctrl, env, ctx) {
807 const readable = new Readable({
808 read: () => {},
809 encoding: 'utf16le',
810 objectMode: true,
811 });
812 
813 readable.push(Buffer.from('abc', 'utf16le'));
814 readable.push(Buffer.from('def', 'utf16le'));
815 readable.push(null);
816 
817 // Without object mode, these would be concatenated into a single chunk.
818 strictEqual(readable.read(), 'abc');
819 strictEqual(readable.read(), 'def');
820 strictEqual(readable.read(), null);
821 },
822};
823 
824export const destroyEventOrder = {
825 async test(ctrl, env, ctx) {
826 const destroyed = Promise.withResolvers();
827 const events = [];
828 const rs = new Readable({
829 read() {},
830 });
831 
832 let _closed = false;
833 let _errored = false;
834 
835 rs.on('close', () => events.push('close'));
836 
837 rs.on('error', (err) => events.push('errored'));
838 
839 rs.destroy(new Error('kaboom'), () => {
840 strictEqual(events, ['errored', 'close']);
841 destroyed.resolve();
842 });
843 
844 await destroyed;
845 },
846};
847 
848export const destroyTests = {
849 async test(ctrl, env, ctx) {
850 {
851 const errored = Promise.withResolvers();
852 const closed = Promise.withResolvers();
853 const r = new Readable({ read() {} });
854 destroy(r);
855 strictEqual(r.destroyed, true);
856 r.on('error', errored.resolve);
857 r.on('close', closed.resolve);
858 const check = await errored.promise;
859 strictEqual(check.name, 'AbortError');
860 await closed.promise;
861 }
862 
863 {
864 const errored = Promise.withResolvers();
865 const closed = Promise.withResolvers();
866 const err = new Error('asd');
867 const r = new Readable({ read() {} });
868 destroy(r, err);
869 strictEqual(r.destroyed, true);
870 r.on('error', errored.resolve);
871 r.on('close', closed.resolve);
872 const check = await errored.promise;
873 strictEqual(check, err);
874 await closed.promise;
875 }
876 
877 {
878 const errored = Promise.withResolvers();
879 const closed = Promise.withResolvers();
880 const w = new Writable({ write() {} });
881 destroy(w);
882 strictEqual(w.destroyed, true);
883 w.on('error', errored.resolve);
884 w.on('close', closed.resolve);
885 const check = await errored.promise;
886 strictEqual(check.name, 'AbortError');
887 await closed.promise;
888 }
889 
890 {
891 const errored = Promise.withResolvers();
892 const closed = Promise.withResolvers();
893 const err = new Error('asd');
894 const w = new Writable({ write() {} });
895 destroy(w, err);
896 strictEqual(w.destroyed, true);
897 w.on('error', errored.resolve);
898 w.on('close', closed.resolve);
899 const check = await errored.promise;
900 strictEqual(check, err);
901 await closed.promise;
902 }
903 },
904};
905 
906export const duplexDestroy = {
907 async test(ctrl, env, ctx) {
908 {
909 const closed = Promise.withResolvers();
910 
911 const duplex = new Duplex({
912 write(chunk, enc, cb) {
913 cb();
914 },
915 read() {},
916 });
917 
918 duplex.resume();
919 
920 duplex.on('end', () => {
921 throw new Error('should not call');
922 });
923 duplex.on('finish', () => {
924 throw new Error('should not call');
925 });
926 duplex.on('close', closed.resolve);
927 
928 duplex.destroy();
929 strictEqual(duplex.destroyed, true);
930 await closed.promise;
931 }
932 
933 {
934 const errored = Promise.withResolvers();
935 const closed = Promise.withResolvers();
936 const duplex = new Duplex({
937 write(chunk, enc, cb) {
938 cb();
939 },
940 read() {},
941 });
942 duplex.resume();
943 
944 const expected = new Error('kaboom');
945 
946 duplex.on('end', closed.reject);
947 duplex.on('finish', closed.reject);
948 duplex.on('close', closed.resolve);
949 duplex.on('error', errored.resolve);
950 
951 duplex.destroy(expected);
952 strictEqual(duplex.destroyed, true);
953 const check = await errored.promise;
954 strictEqual(check, expected);
955 await closed.promise;
956 }
957 
958 {
959 const errored = Promise.withResolvers();
960 const destroyCalled = Promise.withResolvers();
961 const duplex = new Duplex({
962 write(chunk, enc, cb) {
963 cb();
964 },
965 read() {},
966 });
967 
968 const expected = new Error('kaboom');
969 
970 duplex._destroy = function (err, cb) {
971 strictEqual(err, expected);
972 cb(err);
973 destroyCalled.resolve();
974 };
975 
976 duplex.on('finish', errored.reject);
977 duplex.on('error', errored.resolve);
978 
979 duplex.destroy(expected);
980 strictEqual(duplex.destroyed, true);
981 const check = await errored.promise;
982 strictEqual(check, expected);
983 await destroyCalled.promise;
984 }
985 
986 {
987 const closed = Promise.withResolvers();
988 const destroyCalled = Promise.withResolvers();
989 const expected = new Error('kaboom');
990 const duplex = new Duplex({
991 write(chunk, enc, cb) {
992 cb();
993 },
994 read() {},
995 destroy: function (err, cb) {
996 strictEqual(err, expected);
997 cb();
998 destroyCalled.resolve();
999 },
1000 });
1001 duplex.resume();
1002 
1003 duplex.on('end', closed.reject);
1004 duplex.on('finish', closed.reject);
1005 
1006 // Error is swallowed by the custom _destroy
1007 duplex.on('error', closed.reject);
1008 duplex.on('close', closed.resolve);
1009 
1010 duplex.destroy(expected);
1011 strictEqual(duplex.destroyed, true);
1012 await Promise.all([closed.promise, destroyCalled.promise]);
1013 }
1014 
1015 {
1016 const destroyCalled = Promise.withResolvers();
1017 const duplex = new Duplex({
1018 write(chunk, enc, cb) {
1019 cb();
1020 },
1021 read() {},
1022 });
1023 
1024 duplex._destroy = function (err, cb) {
1025 strictEqual(err, null);
1026 cb();
1027 destroyCalled.resolve();
1028 };
1029 
1030 duplex.destroy();
1031 strictEqual(duplex.destroyed, true);
1032 await destroyCalled.promise;
1033 }
1034 
1035 {
1036 const destroyCalled = Promise.withResolvers();
1037 const closed = Promise.withResolvers();
1038 const duplex = new Duplex({
1039 write(chunk, enc, cb) {
1040 cb();
1041 },
1042 read() {},
1043 });
1044 duplex.resume();
1045 
1046 duplex._destroy = function (err, cb) {
1047 strictEqual(err, null);
1048 queueMicrotask(() => {
1049 this.push(null);
1050 this.end();
1051 cb();
1052 destroyCalled.resolve();
1053 });
1054 };
1055 
1056 const fail = closed.reject;
1057 
1058 duplex.on('finish', fail);
1059 duplex.on('end', fail);
1060 
1061 duplex.destroy();
1062 
1063 duplex.removeListener('end', fail);
1064 duplex.removeListener('finish', fail);
1065 duplex.on('end', fail);
1066 duplex.on('finish', fail);
1067 duplex.on('close', closed.resolve);
1068 strictEqual(duplex.destroyed, true);
1069 await Promise.all([closed.promise, destroyCalled.promise]);
1070 }
1071 
1072 {
1073 const destroyCalled = Promise.withResolvers();
1074 const errored = Promise.withResolvers();
1075 const duplex = new Duplex({
1076 write(chunk, enc, cb) {
1077 cb();
1078 },
1079 read() {},
1080 });
1081 
1082 const expected = new Error('kaboom');
1083 
1084 duplex._destroy = function (err, cb) {
1085 strictEqual(err, null);
1086 cb(expected);
1087 destroyCalled.resolve();
1088 };
1089 
1090 duplex.on('error', errored.resolve);
1091 
1092 duplex.destroy();
1093 strictEqual(duplex.destroyed, true);
1094 const check = await errored.promise;
1095 strictEqual(check, expected);
1096 await destroyCalled.promise;
1097 }
1098 
1099 {
1100 const closed = Promise.withResolvers();
1101 const duplex = new Duplex({
1102 write(chunk, enc, cb) {
1103 cb();
1104 },
1105 read() {},
1106 allowHalfOpen: true,
1107 });
1108 duplex.resume();
1109 
1110 duplex.on('finish', closed.reject);
1111 duplex.on('end', closed.reject);
1112 duplex.on('close', closed.resolve);
1113 
1114 duplex.destroy();
1115 strictEqual(duplex.destroyed, true);
1116 await closed.promise;
1117 }
1118 
1119 {
1120 const _closed = Promise.withResolvers();
1121 const duplex = new Duplex({
1122 write(chunk, enc, cb) {
1123 cb();
1124 },
1125 read() {},
1126 destroy() {
1127 throw new Error('should not be called');
1128 },
1129 });
1130 
1131 duplex.destroyed = true;
1132 strictEqual(duplex.destroyed, true);
1133 
1134 duplex.destroy();
1135 }
1136 
1137 {
1138 function MyDuplex() {
1139 strictEqual(this.destroyed, false);
1140 this.destroyed = false;
1141 Duplex.call(this);
1142 }
1143 
1144 Object.setPrototypeOf(MyDuplex.prototype, Duplex.prototype);
1145 Object.setPrototypeOf(MyDuplex, Duplex);
1146 
1147 new MyDuplex();
1148 }
1149 
1150 {
1151 const closed = Promise.withResolvers();
1152 const duplex = new Duplex({
1153 writable: false,
1154 autoDestroy: true,
1155 write(chunk, enc, cb) {
1156 cb();
1157 },
1158 read() {},
1159 });
1160 duplex.push(null);
1161 duplex.resume();
1162 duplex.on('close', closed.resolve);
1163 await closed.promise;
1164 }
1165 
1166 {
1167 const closed = Promise.withResolvers();
1168 const duplex = new Duplex({
1169 readable: false,
1170 autoDestroy: true,
1171 write(chunk, enc, cb) {
1172 cb();
1173 },
1174 read() {},
1175 });
1176 duplex.end();
1177 duplex.on('close', closed.resolve);
1178 await closed.promise;
1179 }
1180 
1181 {
1182 const closed = Promise.withResolvers();
1183 const duplex = new Duplex({
1184 allowHalfOpen: false,
1185 autoDestroy: true,
1186 write(chunk, enc, cb) {
1187 cb();
1188 },
1189 read() {},
1190 });
1191 duplex.push(null);
1192 duplex.resume();
1193 const orgEnd = duplex.end;
1194 duplex.end = closed.reject;
1195 duplex.on('end', () => {
1196 // Ensure end() is called in next tick to allow
1197 // any pending writes to be invoked first.
1198 queueMicrotask(() => {
1199 duplex.end = orgEnd;
1200 });
1201 });
1202 duplex.on('close', closed.resolve);
1203 await closed.promise;
1204 }
1205 
1206 {
1207 // Check abort signal
1208 const closed = Promise.withResolvers();
1209 const errored = Promise.withResolvers();
1210 const controller = new AbortController();
1211 const { signal } = controller;
1212 const duplex = new Duplex({
1213 write(chunk, enc, cb) {
1214 cb();
1215 },
1216 read() {},
1217 signal,
1218 });
1219 let count = 0;
1220 duplex.on('error', (e) => {
1221 strictEqual(count++, 0); // Ensure not called twice
1222 strictEqual(e.name, 'AbortError');
1223 errored.resolve();
1224 });
1225 duplex.on('close', closed.resolve);
1226 controller.abort();
1227 await Promise.all([errored.promise, closed.promise]);
1228 }
1229 },
1230};
1231 
1232export const duplexEnd = {
1233 async test(ctrl, env, ctx) {
1234 {
1235 const stream = new Duplex({
1236 read() {},
1237 });
1238 strictEqual(stream.allowHalfOpen, true);
1239 stream.on('finish', () => {
1240 throw new Error('should not have been called');
1241 });
1242 strictEqual(stream.listenerCount('end'), 0);
1243 stream.resume();
1244 stream.push(null);
1245 }
1246 
1247 {
1248 const finishedCalled = Promise.withResolvers();
1249 const stream = new Duplex({
1250 read() {},
1251 allowHalfOpen: false,
1252 });
1253 strictEqual(stream.allowHalfOpen, false);
1254 stream.on('finish', finishedCalled.resolve);
1255 strictEqual(stream.listenerCount('end'), 0);
1256 stream.resume();
1257 stream.push(null);
1258 await finishedCalled.promise;
1259 }
1260 
1261 {
1262 const stream = new Duplex({
1263 read() {},
1264 allowHalfOpen: false,
1265 });
1266 strictEqual(stream.allowHalfOpen, false);
1267 stream._writableState.ended = true;
1268 stream.on('finish', () => {
1269 throw new Error('Should not have been called');
1270 });
1271 strictEqual(stream.listenerCount('end'), 0);
1272 stream.resume();
1273 stream.push(null);
1274 }
1275 },
1276};
1277 
1278export const duplexProps = {
1279 test(ctrl, env, ctx) {
1280 {
1281 const d = new Duplex({
1282 objectMode: true,
1283 highWaterMark: 100,
1284 });
1285 
1286 strictEqual(d.writableObjectMode, true);
1287 strictEqual(d.writableHighWaterMark, 100);
1288 strictEqual(d.readableObjectMode, true);
1289 strictEqual(d.readableHighWaterMark, 100);
1290 }
1291 
1292 {
1293 const d = new Duplex({
1294 readableObjectMode: false,
1295 readableHighWaterMark: 10,
1296 writableObjectMode: true,
1297 writableHighWaterMark: 100,
1298 });
1299 
1300 strictEqual(d.writableObjectMode, true);
1301 strictEqual(d.writableHighWaterMark, 100);
1302 strictEqual(d.readableObjectMode, false);
1303 strictEqual(d.readableHighWaterMark, 10);
1304 }
1305 },
1306};
1307 
1308export const duplexReadableEnd = {
1309 async test(ctrl, env, ctx) {
1310 const ended = Promise.withResolvers();
1311 let loops = 5;
1312 
1313 const src = new Readable({
1314 read() {
1315 if (loops--) this.push(Buffer.alloc(80000));
1316 },
1317 });
1318 
1319 const dst = new Transform({
1320 transform(chunk, output, fn) {
1321 this.push(null);
1322 fn();
1323 },
1324 });
1325 
1326 src.pipe(dst);
1327 
1328 dst.on('data', () => {});
1329 dst.on('end', () => {
1330 strictEqual(loops, 3);
1331 ok(src.isPaused());
1332 ended.resolve();
1333 });
1334 
1335 await ended.promise;
1336 },
1337};
1338 
1339export const duplexReadableWritable = {
1340 async test(ctrl, env, ctx) {
1341 {
1342 const errored = Promise.withResolvers();
1343 const duplex = new Duplex({
1344 readable: false,
1345 });
1346 strictEqual(duplex.readable, false);
1347 duplex.push('asd');
1348 duplex.on('error', (err) => {
1349 strictEqual(err.code, 'ERR_STREAM_PUSH_AFTER_EOF');
1350 errored.resolve();
1351 });
1352 duplex.on('data', errored.reject);
1353 duplex.on('end', errored.reject);
1354 await errored.promise;
1355 }
1356 
1357 {
1358 const closed = Promise.withResolvers();
1359 const errored = Promise.withResolvers();
1360 const duplex = new Duplex({
1361 writable: false,
1362 write: closed.reject,
1363 });
1364 strictEqual(duplex.writable, false);
1365 duplex.write('asd');
1366 duplex.on('error', (err) => {
1367 strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
1368 errored.resolve();
1369 });
1370 duplex.on('finish', closed.reject);
1371 duplex.on('close', closed.resolve);
1372 await Promise.all([closed.promise, errored.promise]);
1373 }
1374 
1375 {
1376 const closed = Promise.withResolvers();
1377 const duplex = new Duplex({
1378 readable: false,
1379 });
1380 strictEqual(duplex.readable, false);
1381 duplex.on('data', closed.reject);
1382 duplex.on('end', closed.reject);
1383 duplex.on('close', closed.resolve);
1384 async function run() {
1385 for await (const chunk of duplex) {
1386 ok(false, chunk);
1387 }
1388 }
1389 await Promise.all([run(), closed.promise]);
1390 }
1391 },
1392};
1393 
1394export const duplexWritableFinished = {
1395 async test(ctrl, env, ctx) {
1396 {
1397 // Find it on Duplex.prototype
1398 ok(Object.hasOwn(Duplex.prototype, 'writableFinished'));
1399 }
1400 
1401 // event
1402 {
1403 const finishedCalled = Promise.withResolvers();
1404 const ended = Promise.withResolvers();
1405 const duplex = new Duplex();
1406 
1407 duplex._write = (chunk, encoding, cb) => {
1408 // The state finished should start in false.
1409 strictEqual(duplex.writableFinished, false);
1410 cb();
1411 };
1412 
1413 duplex.on('finish', () => {
1414 strictEqual(duplex.writableFinished, true);
1415 finishedCalled.resolve();
1416 });
1417 
1418 duplex.end('testing finished state', () => {
1419 strictEqual(duplex.writableFinished, true);
1420 ended.resolve();
1421 });
1422 
1423 await Promise.all([finishedCalled.promise, ended.promise]);
1424 }
1425 },
1426};
1427 
1428export const duplex = {
1429 async test(ctrl, env, ctx) {
1430 const stream = new Duplex({ objectMode: true });
1431 
1432 ok(Duplex() instanceof Duplex);
1433 ok(stream._readableState.objectMode);
1434 ok(stream._writableState.objectMode);
1435 ok(stream.allowHalfOpen);
1436 strictEqual(stream.listenerCount('end'), 0);
1437 
1438 let _written;
1439 let _read;
1440 
1441 stream._write = (obj, _, cb) => {
1442 _written = obj;
1443 cb();
1444 };
1445 
1446 stream._read = () => {};
1447 
1448 stream.on('data', (obj) => {
1449 _read = obj;
1450 });
1451 
1452 stream.push({ val: 1 });
1453 stream.end({ val: 2 });
1454 
1455 // We have no equivalent for on('exit') ... should we?
1456 // process.on('exit', () => {
1457 // strictEqual(read.val, 1);
1458 // strictEqual(written.val, 2);
1459 // });
1460 
1461 // Duplex.fromWeb
1462 {
1463 const dataToRead = Buffer.from('hello');
1464 const dataToWrite = Buffer.from('world');
1465 
1466 const readable = new ReadableStream({
1467 start(controller) {
1468 controller.enqueue(dataToRead);
1469 },
1470 });
1471 
1472 const writable = new WritableStream({
1473 write: (chunk) => {
1474 strictEqual(chunk, dataToWrite);
1475 },
1476 });
1477 
1478 const pair = { readable, writable };
1479 const duplex = Duplex.fromWeb(pair);
1480 
1481 duplex.write(dataToWrite);
1482 const p = Promise.withResolvers();
1483 duplex.once('data', (chunk) => {
1484 strictEqual(chunk, dataToRead);
1485 p.resolve();
1486 });
1487 await p.promise;
1488 }
1489 
1490 // Duplex.fromWeb - using utf8 and objectMode
1491 {
1492 const dataToRead = 'hello';
1493 const dataToWrite = 'world';
1494 
1495 const readable = new ReadableStream({
1496 start(controller) {
1497 controller.enqueue(dataToRead);
1498 },
1499 });
1500 
1501 const writable = new WritableStream({
1502 write: (chunk) => {
1503 strictEqual(chunk, dataToWrite);
1504 },
1505 });
1506 
1507 const pair = {
1508 readable,
1509 writable,
1510 };
1511 const duplex = Duplex.fromWeb(pair, {
1512 encoding: 'utf8',
1513 objectMode: true,
1514 });
1515 
1516 duplex.write(dataToWrite);
1517 const p = Promise.withResolvers();
1518 duplex.once('data', (chunk) => {
1519 strictEqual(chunk, dataToRead);
1520 p.resolve();
1521 });
1522 await p.promise;
1523 }
1524 
1525 // Duplex.toWeb
1526 {
1527 const dataToRead = Buffer.from('hello');
1528 const dataToWrite = Buffer.from('world');
1529 
1530 const duplex = Duplex({
1531 read() {
1532 this.push(dataToRead);
1533 this.push(null);
1534 },
1535 write: (chunk) => {
1536 strictEqual(chunk, dataToWrite);
1537 },
1538 });
1539 
1540 const { writable, readable } = Duplex.toWeb(duplex);
1541 writable.getWriter().write(dataToWrite);
1542 
1543 const p = Promise.withResolvers();
1544 readable
1545 .getReader()
1546 .read()
1547 .then((result) => {
1548 deepStrictEqual(Buffer.from(result.value), dataToRead);
1549 p.resolve();
1550 });
1551 await p.promise;
1552 }
1553 },
1554};
1555 
1556export const end_of_streams = {
1557 async test(ctrl, env, ctx) {
1558 throws(
1559 () => {
1560 // Passing empty object to mock invalid stream
1561 // should throw error
1562 finished({}, () => {});
1563 },
1564 { code: 'ERR_INVALID_ARG_TYPE' }
1565 );
1566 
1567 const streamObj = new Duplex();
1568 streamObj.end();
1569 // Below code should not throw any errors as the
1570 // streamObj is `Stream`
1571 finished(streamObj, () => {});
1572 },
1573};
1574 
1575export const end_paused = {
1576 async test(ctrl, env, ctx) {
1577 const calledRead = Promise.withResolvers();
1578 const ended = Promise.withResolvers();
1579 const stream = new Readable();
1580 stream._read = function () {
1581 this.push(null);
1582 calledRead.resolve();
1583 };
1584 
1585 stream.on('data', ended.reject);
1586 stream.on('end', ended.resolve);
1587 stream.pause();
1588 
1589 setTimeout(function () {
1590 stream.resume();
1591 });
1592 
1593 await Promise.all([calledRead.promise, ended.promise]);
1594 },
1595};
1596 
1597export const error_once = {
1598 async test(ctrl, env, ctx) {
1599 {
1600 const errored = Promise.withResolvers();
1601 const writable = new Writable();
1602 writable.on('error', errored.resolve);
1603 writable.end();
1604 writable.write('h');
1605 writable.write('h');
1606 await errored.promise;
1607 }
1608 
1609 {
1610 const errored = Promise.withResolvers();
1611 const readable = new Readable();
1612 readable.on('error', errored.resolve);
1613 readable.push(null);
1614 readable.push('h');
1615 readable.push('h');
1616 await errored.promise;
1617 }
1618 },
1619};
1620 
1621export const finishedTest = {
1622 async test(ctrl, env, ctx) {
1623 const promisify = (await import('node:util')).promisify;
1624 {
1625 const finishedOk = Promise.withResolvers();
1626 const rs = new Readable({
1627 read() {},
1628 });
1629 
1630 finished(rs, (err) => {
1631 if (err == null) finishedOk.resolve();
1632 else finishedOk.reject(err);
1633 });
1634 
1635 rs.push(null);
1636 rs.resume();
1637 
1638 await finishedOk.promise;
1639 }
1640 
1641 {
1642 const finishedOk = Promise.withResolvers();
1643 
1644 const ws = new Writable({
1645 write(data, enc, cb) {
1646 cb();
1647 },
1648 });
1649 
1650 finished(ws, (err) => {
1651 if (err == null) finishedOk.resolve();
1652 else finishedOk.reject(err);
1653 });
1654 
1655 ws.end();
1656 
1657 await finishedOk.promise;
1658 }
1659 
1660 {
1661 const finishedOk = Promise.withResolvers();
1662 const tr = new Transform({
1663 transform(data, enc, cb) {
1664 cb();
1665 },
1666 });
1667 
1668 let finish = false;
1669 let ended = false;
1670 
1671 tr.on('end', () => {
1672 ended = true;
1673 });
1674 
1675 tr.on('finish', () => {
1676 finish = true;
1677 });
1678 
1679 finished(tr, (err) => {
1680 ok(finish);
1681 ok(ended);
1682 if (err == null) finishedOk.resolve();
1683 else finishedOk.reject(err);
1684 });
1685 
1686 tr.end();
1687 tr.resume();
1688 
1689 await finishedOk.promise;
1690 }
1691 
1692 {
1693 const finishedCalled = Promise.withResolvers();
1694 const enc = new TextEncoder();
1695 const rs = new Readable({
1696 read() {
1697 this.push(enc.encode('a'));
1698 this.push(enc.encode('b'));
1699 this.push(null);
1700 },
1701 });
1702 
1703 rs.resume();
1704 finished(rs, finishedCalled.resolve);
1705 await finishedCalled.promise;
1706 }
1707 
1708 {
1709 const finishedPromise = promisify(finished);
1710 
1711 async function run() {
1712 const enc = new TextEncoder();
1713 const rs = new Readable({
1714 read() {
1715 this.push(enc.encode('a'));
1716 this.push(enc.encode('b'));
1717 this.push(null);
1718 },
1719 });
1720 
1721 let ended = false;
1722 rs.resume();
1723 rs.on('end', () => {
1724 ended = true;
1725 });
1726 await finishedPromise(rs);
1727 ok(ended);
1728 }
1729 
1730 await run();
1731 }
1732 
1733 {
1734 // Check pre-cancelled
1735 const signal = new EventTarget();
1736 signal.aborted = true;
1737 
1738 const rs = Readable.from((function* () {})());
1739 const errored = Promise.withResolvers();
1740 finished(rs, { signal }, errored.resolve);
1741 const check = await errored.promise;
1742 strictEqual(check.name, 'AbortError');
1743 }
1744 
1745 {
1746 // Check cancelled before the stream ends sync.
1747 const ac = new AbortController();
1748 const { signal } = ac;
1749 
1750 const errored = Promise.withResolvers();
1751 const rs = Readable.from((function* () {})());
1752 finished(rs, { signal }, errored.resolve);
1753 ac.abort();
1754 const check = await errored.promise;
1755 strictEqual(check.name, 'AbortError');
1756 }
1757 
1758 {
1759 // Check cancelled before the stream ends async.
1760 const ac = new AbortController();
1761 const { signal } = ac;
1762 
1763 const rs = Readable.from((function* () {})());
1764 setTimeout(() => ac.abort(), 1);
1765 const errored = Promise.withResolvers();
1766 finished(rs, { signal }, errored.resolve);
1767 const check = await errored.promise;
1768 strictEqual(check.name, 'AbortError');
1769 }
1770 
1771 {
1772 // Check cancelled after doesn't throw.
1773 const ac = new AbortController();
1774 const { signal } = ac;
1775 
1776 const rs = Readable.from(
1777 (function* () {
1778 yield 5;
1779 queueMicrotask(() => ac.abort());
1780 })()
1781 );
1782 rs.resume();
1783 const finishedOk = Promise.withResolvers();
1784 finished(rs, { signal }, finishedOk.resolve);
1785 const check = await finishedOk.promise;
1786 strictEqual(check.name, 'AbortError');
1787 }
1788 
1789 {
1790 // Promisified abort works
1791 const finishedPromise = promisify(finished);
1792 async function run() {
1793 const ac = new AbortController();
1794 const { signal } = ac;
1795 const rs = Readable.from((function* () {})());
1796 queueMicrotask(() => ac.abort());
1797 await finishedPromise(rs, { signal });
1798 }
1799 
1800 await rejects(run, { name: 'AbortError' });
1801 }
1802 
1803 {
1804 // Promisified pre-aborted works
1805 const finishedPromise = promisify(finished);
1806 async function run() {
1807 const signal = new EventTarget();
1808 signal.aborted = true;
1809 const rs = Readable.from((function* () {})());
1810 await finishedPromise(rs, { signal });
1811 }
1812 
1813 await rejects(run, { name: 'AbortError' });
1814 }
1815 
1816 {
1817 const rs = new Readable();
1818 
1819 const finishedOk = Promise.withResolvers();
1820 
1821 finished(rs, finishedOk.resolve);
1822 
1823 rs.push(null);
1824 rs.emit('close'); // Should not trigger an error
1825 rs.resume();
1826 
1827 const check = await finishedOk.promise;
1828 ifError(check);
1829 }
1830 
1831 {
1832 const rs = new Readable();
1833 const errored = Promise.withResolvers();
1834 
1835 finished(rs, errored.resolve);
1836 
1837 rs.emit('close'); // Should trigger error
1838 rs.push(null);
1839 rs.resume();
1840 
1841 const check = await errored.promise;
1842 ok(check);
1843 }
1844 
1845 // Test faulty input values and options.
1846 {
1847 const rs = new Readable({
1848 read() {},
1849 });
1850 
1851 throws(() => finished(rs, 'foo'), {
1852 code: 'ERR_INVALID_ARG_TYPE',
1853 message: /callback/,
1854 });
1855 throws(() => finished(rs, 'foo', () => {}), {
1856 code: 'ERR_INVALID_ARG_TYPE',
1857 message: /options/,
1858 });
1859 throws(() => finished(rs, {}, 'foo'), {
1860 code: 'ERR_INVALID_ARG_TYPE',
1861 message: /callback/,
1862 });
1863 
1864 const finishedOk = Promise.withResolvers();
1865 finished(rs, null, finishedOk.resolve);
1866 
1867 rs.push(null);
1868 rs.resume();
1869 
1870 const check = await finishedOk.promise;
1871 ifError(check);
1872 }
1873 
1874 // Test that calling returned function removes listeners
1875 {
1876 const ws = new Writable({
1877 write(data, env, cb) {
1878 cb();
1879 },
1880 });
1881 const removeListener = finished(ws, () => {
1882 throw new Error('should not have been called');
1883 });
1884 removeListener();
1885 ws.end();
1886 }
1887 
1888 {
1889 const rs = new Readable();
1890 const removeListeners = finished(rs, () => {
1891 throw new Error('should not have been called');
1892 });
1893 removeListeners();
1894 
1895 rs.emit('close');
1896 rs.push(null);
1897 rs.resume();
1898 }
1899 
1900 {
1901 const EventEmitter = (await import('node:events')).EventEmitter;
1902 const streamLike = new EventEmitter();
1903 streamLike.readableEnded = true;
1904 streamLike.readable = true;
1905 throws(
1906 () => {
1907 finished(streamLike, () => {});
1908 },
1909 { code: 'ERR_INVALID_ARG_TYPE' }
1910 );
1911 streamLike.emit('close');
1912 }
1913 
1914 {
1915 const writable = new Writable({ write() {} });
1916 writable.writable = false;
1917 writable.destroy();
1918 const errored = Promise.withResolvers();
1919 finished(writable, errored.resolve);
1920 const check = await errored.promise;
1921 strictEqual(check.code, 'ERR_STREAM_PREMATURE_CLOSE');
1922 }
1923 
1924 {
1925 const readable = new Readable();
1926 readable.readable = false;
1927 readable.destroy();
1928 const errored = Promise.withResolvers();
1929 finished(readable, errored.resolve);
1930 const check = await errored.promise;
1931 strictEqual(check.code, 'ERR_STREAM_PREMATURE_CLOSE');
1932 }
1933 },
1934};
1935 
1936export const highWaterMark = {
1937 async test(ctrl, env, ctx) {
1938 {
1939 // This test ensures that the stream implementation correctly handles values
1940 // for highWaterMark which exceed the range of signed 32 bit integers and
1941 // rejects invalid values.
1942 
1943 // This number exceeds the range of 32 bit integer arithmetic but should still
1944 // be handled correctly.
1945 const ovfl = Number.MAX_SAFE_INTEGER;
1946 const readable = Readable({
1947 highWaterMark: ovfl,
1948 });
1949 strictEqual(readable._readableState.highWaterMark, ovfl);
1950 const writable = Writable({
1951 highWaterMark: ovfl,
1952 });
1953 strictEqual(writable._writableState.highWaterMark, ovfl);
1954 for (const invalidHwm of [true, false, '5', {}, -5, NaN]) {
1955 for (const type of [Readable, Writable]) {
1956 throws(
1957 () => {
1958 type({
1959 highWaterMark: invalidHwm,
1960 });
1961 },
1962 {
1963 name: 'TypeError',
1964 code: 'ERR_INVALID_ARG_VALUE',
1965 }
1966 );
1967 }
1968 }
1969 }
1970 {
1971 // This test ensures that the push method's implementation
1972 // correctly handles the edge case where the highWaterMark and
1973 // the state.length are both zero
1974 
1975 const readable = Readable({
1976 highWaterMark: 0,
1977 });
1978 for (let i = 0; i < 3; i++) {
1979 const needMoreData = readable.push();
1980 strictEqual(needMoreData, true);
1981 }
1982 }
1983 {
1984 // This test ensures that the read(n) method's implementation
1985 // correctly handles the edge case where the highWaterMark, state.length
1986 // and n are all zero
1987 
1988 const readable = Readable({
1989 highWaterMark: 0,
1990 });
1991 const readCalled = Promise.withResolvers();
1992 readable._read = readCalled.resolve;
1993 readable.read(0);
1994 await readCalled.promise;
1995 }
1996 {
1997 const readCalled = Promise.withResolvers();
1998 // Parse size as decimal integer
1999 await Promise.all(
2000 ['1', '1.0', 1].map(async (size) => {
2001 const readable = new Readable({
2002 read: readCalled.resolve,
2003 highWaterMark: 0,
2004 });
2005 readable.read(size);
2006 strictEqual(readable._readableState.highWaterMark, Number(size));
2007 await readCalled.promise;
2008 })
2009 );
2010 }
2011 {
2012 // Test highwatermark limit
2013 const hwm = 0x40000000 + 1;
2014 const readable = Readable({
2015 read() {},
2016 });
2017 throws(() => readable.read(hwm), {
2018 code: 'ERR_OUT_OF_RANGE',
2019 });
2020 }
2021 },
2022};
2023 
2024export const pauseThenRead = {
2025 async test(ctrl, env, ctx) {
2026 const totalChunks = 100;
2027 const chunkSize = 99;
2028 const expectTotalData = totalChunks * chunkSize;
2029 let expectEndingData = expectTotalData;
2030 const closed = Promise.withResolvers();
2031 const r = new Readable({
2032 highWaterMark: 1000,
2033 });
2034 r.on('close', closed.resolve);
2035 let chunks = totalChunks;
2036 r._read = function (n) {
2037 if (!(chunks % 2)) queueMicrotask(push);
2038 else if (!(chunks % 3)) queueMicrotask(push);
2039 else push();
2040 };
2041 let totalPushed = 0;
2042 function push() {
2043 const chunk = chunks-- > 0 ? Buffer.alloc(chunkSize, 'x') : null;
2044 if (chunk) {
2045 totalPushed += chunk.length;
2046 }
2047 r.push(chunk);
2048 }
2049 read100();
2050 await closed.promise;
2051 
2052 // First we read 100 bytes.
2053 function read100() {
2054 readn(100, onData);
2055 }
2056 function readn(n, then) {
2057 expectEndingData -= n;
2058 (function read() {
2059 const c = r.read(n);
2060 if (!c) r.once('readable', read);
2061 else {
2062 strictEqual(c.length, n);
2063 ok(!r.readableFlowing);
2064 then();
2065 }
2066 })();
2067 }
2068 
2069 // Then we listen to some data events.
2070 function onData() {
2071 expectEndingData -= 100;
2072 let seen = 0;
2073 r.on('data', function od(c) {
2074 seen += c.length;
2075 if (seen >= 100) {
2076 // Seen enough
2077 r.removeListener('data', od);
2078 r.pause();
2079 if (seen > 100) {
2080 // Oh no, seen too much!
2081 // Put the extra back.
2082 const diff = seen - 100;
2083 r.unshift(c.slice(c.length - diff));
2084 }
2085 
2086 // Nothing should be lost in-between.
2087 queueMicrotask(pipeLittle);
2088 }
2089 });
2090 }
2091 
2092 // Just pipe 200 bytes, then unshift the extra and unpipe.
2093 function pipeLittle() {
2094 expectEndingData -= 200;
2095 const w = new Writable();
2096 let written = 0;
2097 w.on('finish', () => {
2098 strictEqual(written, 200);
2099 queueMicrotask(read1234);
2100 });
2101 w._write = function (chunk, encoding, cb) {
2102 written += chunk.length;
2103 if (written >= 200) {
2104 r.unpipe(w);
2105 w.end();
2106 cb();
2107 if (written > 200) {
2108 const diff = written - 200;
2109 written -= diff;
2110 r.unshift(chunk.slice(chunk.length - diff));
2111 }
2112 } else {
2113 queueMicrotask(cb);
2114 }
2115 };
2116 r.pipe(w);
2117 }
2118 
2119 // Now read 1234 more bytes.
2120 function read1234() {
2121 readn(1234, resumePause);
2122 }
2123 function resumePause() {
2124 // Don't read anything, just resume and re-pause a whole bunch.
2125 r.resume();
2126 r.pause();
2127 r.resume();
2128 r.pause();
2129 r.resume();
2130 r.pause();
2131 r.resume();
2132 r.pause();
2133 r.resume();
2134 r.pause();
2135 queueMicrotask(pipe);
2136 }
2137 function pipe() {
2138 const w = new Writable();
2139 let written = 0;
2140 w._write = function (chunk, encoding, cb) {
2141 written += chunk.length;
2142 cb();
2143 };
2144 w.on('finish', () => {
2145 strictEqual(written, expectEndingData);
2146 strictEqual(totalPushed, expectTotalData);
2147 });
2148 r.pipe(w);
2149 }
2150 },
2151};
2152 
2153export const corkUncork = {
2154 async test(ctrl, env, ctx) {
2155 // Test the buffering behavior of Writable streams.
2156 //
2157 // The call to cork() triggers storing chunks which are flushed
2158 // on calling uncork() in the same tick.
2159 //
2160 // node version target: 0.12
2161 
2162 const closed = Promise.withResolvers();
2163 const expectedChunks = ['please', 'buffer', 'me', 'kindly'];
2164 const inputChunks = expectedChunks.slice(0);
2165 let seenChunks = [];
2166 let seenEnd = false;
2167 const w = new Writable();
2168 // Let's arrange to store the chunks.
2169 w._write = function (chunk, encoding, cb) {
2170 // Default encoding given none was specified.
2171 strictEqual(encoding, 'buffer');
2172 seenChunks.push(chunk);
2173 cb();
2174 };
2175 // Let's record the stream end event.
2176 w.on('finish', () => {
2177 seenEnd = true;
2178 });
2179 
2180 w.on('close', closed.resolve);
2181 
2182 function writeChunks(remainingChunks, callback) {
2183 const writeChunk = remainingChunks.shift();
2184 let writeState;
2185 if (writeChunk) {
2186 queueMicrotask(() => {
2187 writeState = w.write(writeChunk);
2188 // We were not told to stop writing.
2189 ok(writeState);
2190 writeChunks(remainingChunks, callback);
2191 });
2192 } else {
2193 callback();
2194 }
2195 }
2196 
2197 // Do an initial write.
2198 w.write('stuff');
2199 // The write was immediate.
2200 strictEqual(seenChunks.length, 1);
2201 // Reset the chunks seen so far.
2202 seenChunks = [];
2203 
2204 // Trigger stream buffering.
2205 w.cork();
2206 
2207 // Write the bufferedChunks.
2208 writeChunks(inputChunks, () => {
2209 // Should not have seen anything yet.
2210 strictEqual(seenChunks.length, 0);
2211 
2212 // Trigger writing out the buffer.
2213 w.uncork();
2214 
2215 // Buffered bytes should be seen in current tick.
2216 strictEqual(seenChunks.length, 4);
2217 
2218 // Did the chunks match.
2219 for (let i = 0, l = expectedChunks.length; i < l; i++) {
2220 const seen = seenChunks[i];
2221 // There was a chunk.
2222 ok(seen);
2223 const expected = Buffer.from(expectedChunks[i]);
2224 // It was what we expected.
2225 ok(seen.equals(expected));
2226 }
2227 queueMicrotask(() => {
2228 // The stream should not have been ended.
2229 ok(!seenEnd);
2230 w.end();
2231 });
2232 });
2233 
2234 await closed.promise;
2235 },
2236};
2237 
2238export const corkEnd = {
2239 async test(ctrl, env, ctx) {
2240 // Test the buffering behavior of Writable streams.
2241 //
2242 // The call to cork() triggers storing chunks which are flushed
2243 // on calling end() and the stream subsequently ended.
2244 //
2245 // node version target: 0.12
2246 
2247 const closed = Promise.withResolvers();
2248 const expectedChunks = ['please', 'buffer', 'me', 'kindly'];
2249 const inputChunks = expectedChunks.slice(0);
2250 let seenChunks = [];
2251 let seenEnd = false;
2252 const w = new Writable();
2253 // Let's arrange to store the chunks.
2254 w._write = function (chunk, encoding, cb) {
2255 // Stream end event is not seen before the last write.
2256 ok(!seenEnd);
2257 // Default encoding given none was specified.
2258 strictEqual(encoding, 'buffer');
2259 seenChunks.push(chunk);
2260 cb();
2261 };
2262 // Let's record the stream end event.
2263 w.on('finish', () => {
2264 seenEnd = true;
2265 });
2266 function writeChunks(remainingChunks, callback) {
2267 const writeChunk = remainingChunks.shift();
2268 let writeState;
2269 if (writeChunk) {
2270 queueMicrotask(() => {
2271 writeState = w.write(writeChunk);
2272 // We were not told to stop writing.
2273 ok(writeState);
2274 writeChunks(remainingChunks, callback);
2275 });
2276 } else {
2277 callback();
2278 }
2279 }
2280 
2281 w.on('close', closed.resolve);
2282 
2283 // Do an initial write.
2284 w.write('stuff');
2285 // The write was immediate.
2286 strictEqual(seenChunks.length, 1);
2287 // Reset the seen chunks.
2288 seenChunks = [];
2289 
2290 // Trigger stream buffering.
2291 w.cork();
2292 
2293 // Write the bufferedChunks.
2294 writeChunks(inputChunks, () => {
2295 // Should not have seen anything yet.
2296 strictEqual(seenChunks.length, 0);
2297 
2298 // Trigger flush and ending the stream.
2299 w.end();
2300 
2301 // Stream should not ended in current tick.
2302 ok(!seenEnd);
2303 
2304 // Buffered bytes should be seen in current tick.
2305 strictEqual(seenChunks.length, 4);
2306 
2307 // Did the chunks match.
2308 for (let i = 0, l = expectedChunks.length; i < l; i++) {
2309 const seen = seenChunks[i];
2310 // There was a chunk.
2311 ok(seen);
2312 const expected = Buffer.from(expectedChunks[i]);
2313 // It was what we expected.
2314 ok(seen.equals(expected));
2315 }
2316 queueMicrotask(() => {
2317 // Stream should have ended in next tick.
2318 ok(seenEnd);
2319 });
2320 });
2321 
2322 await closed.promise;
2323 },
2324};
2325 
2326export const writable2Writable = {
2327 async test(ctrl, env, ctx) {
2328 class TestWriter extends Writable {
2329 constructor(opts) {
2330 super(opts);
2331 this.buffer = [];
2332 this.written = 0;
2333 }
2334 _write(chunk, encoding, cb) {
2335 // Simulate a small unpredictable latency
2336 queueMicrotask(
2337 () => {
2338 this.buffer.push(chunk.toString());
2339 this.written += chunk.length;
2340 cb();
2341 },
2342 Math.floor(Math.random() * 10)
2343 );
2344 }
2345 }
2346 const chunks = Array.from({ length: 50 }, (_, i) => 'x'.repeat(i));
2347 {
2348 // Verify fast writing
2349 const tw = new TestWriter({
2350 highWaterMark: 100,
2351 });
2352 const finishCalled = Promise.withResolvers();
2353 tw.on('finish', function () {
2354 // Got chunks in the right order
2355 deepStrictEqual(tw.buffer, chunks);
2356 finishCalled.resolve();
2357 });
2358 chunks.forEach(function (chunk) {
2359 // Ignore backpressure. Just buffer it all up.
2360 tw.write(chunk);
2361 });
2362 tw.end();
2363 await finishCalled.promise;
2364 }
2365 {
2366 // Verify slow writing
2367 const tw = new TestWriter({
2368 highWaterMark: 100,
2369 });
2370 const finishedCalled = Promise.withResolvers();
2371 tw.on('finish', function () {
2372 // Got chunks in the right order
2373 deepStrictEqual(tw.buffer, chunks);
2374 finishedCalled.resolve();
2375 });
2376 let i = 0;
2377 (function W() {
2378 tw.write(chunks[i++]);
2379 if (i < chunks.length) setTimeout(W, 10);
2380 else tw.end();
2381 })();
2382 await finishedCalled.promise;
2383 }
2384 {
2385 // Verify write backpressure
2386 const tw = new TestWriter({
2387 highWaterMark: 50,
2388 });
2389 let drains = 0;
2390 const finishCalled = Promise.withResolvers();
2391 tw.on('finish', function () {
2392 // Got chunks in the right order
2393 deepStrictEqual(tw.buffer, chunks);
2394 strictEqual(drains, 17);
2395 finishCalled.resolve();
2396 });
2397 tw.on('drain', function () {
2398 drains++;
2399 });
2400 let i = 0;
2401 (function W() {
2402 let ret;
2403 do {
2404 ret = tw.write(chunks[i++]);
2405 } while (ret !== false && i < chunks.length);
2406 if (i < chunks.length) {
2407 ok(tw.writableLength >= 50);
2408 tw.once('drain', W);
2409 } else {
2410 tw.end();
2411 }
2412 })();
2413 await finishCalled.promise;
2414 }
2415 {
2416 // Verify write callbacks
2417 const callbacks = chunks
2418 .map(function (chunk, i) {
2419 return [
2420 i,
2421 function () {
2422 callbacks._called[i] = chunk;
2423 },
2424 ];
2425 })
2426 .reduce(function (set, x) {
2427 set[`callback-${x[0]}`] = x[1];
2428 return set;
2429 }, {});
2430 callbacks._called = [];
2431 const finishCalled = Promise.withResolvers();
2432 const tw = new TestWriter({
2433 highWaterMark: 100,
2434 });
2435 tw.on('finish', function () {
2436 queueMicrotask(function () {
2437 // Got chunks in the right order
2438 deepStrictEqual(tw.buffer, chunks);
2439 // Called all callbacks
2440 deepStrictEqual(callbacks._called, chunks);
2441 finishCalled.resolve();
2442 });
2443 });
2444 chunks.forEach(function (chunk, i) {
2445 tw.write(chunk, callbacks[`callback-${i}`]);
2446 });
2447 tw.end();
2448 await finishCalled.promise;
2449 }
2450 {
2451 // Verify end() callback
2452 const tw = new TestWriter();
2453 const endCalled = Promise.withResolvers();
2454 tw.end(endCalled.resolve);
2455 await endCalled.promise;
2456 }
2457 const helloWorldBuffer = Buffer.from('hello world');
2458 {
2459 // Verify end() callback with chunk
2460 const tw = new TestWriter();
2461 const endCalled = Promise.withResolvers();
2462 tw.end(helloWorldBuffer, endCalled.resolve);
2463 await endCalled.promise;
2464 }
2465 {
2466 // Verify end() callback with chunk and encoding
2467 const tw = new TestWriter();
2468 const endCalled = Promise.withResolvers();
2469 tw.end('hello world', 'ascii', endCalled.resolve);
2470 await endCalled.promise;
2471 }
2472 {
2473 // Verify end() callback after write() call
2474 const tw = new TestWriter();
2475 const endCalled = Promise.withResolvers();
2476 tw.write(helloWorldBuffer);
2477 tw.end(endCalled.resolve);
2478 await endCalled.promise;
2479 }
2480 {
2481 // Verify end() callback after write() callback
2482 const tw = new TestWriter();
2483 const endCalled = Promise.withResolvers();
2484 let writeCalledback = false;
2485 tw.write(helloWorldBuffer, function () {
2486 writeCalledback = true;
2487 });
2488 tw.end(function () {
2489 strictEqual(writeCalledback, true);
2490 endCalled.resolve();
2491 });
2492 await endCalled.promise;
2493 }
2494 {
2495 // Verify encoding is ignored for buffers
2496 const tw = new Writable();
2497 const hex = '018b5e9a8f6236ffe30e31baf80d2cf6eb';
2498 const writeCalled = Promise.withResolvers();
2499 tw._write = function (chunk) {
2500 strictEqual(chunk.toString('hex'), hex);
2501 writeCalled.resolve();
2502 };
2503 const buf = Buffer.from(hex, 'hex');
2504 tw.write(buf, 'latin1');
2505 await writeCalled.promise;
2506 }
2507 {
2508 // Verify writables cannot be piped
2509 const w = new Writable({
2510 autoDestroy: false,
2511 });
2512 const gotError = Promise.withResolvers();
2513 w._write = gotError.reject;
2514 w.on('error', gotError.resolve);
2515 w.pipe(new Writable({ write() {} }));
2516 await gotError.promise;
2517 }
2518 {
2519 // Verify that duplex streams can be piped
2520 const d = new Duplex();
2521 const readCalled = Promise.withResolvers();
2522 d._read = readCalled.resolve;
2523 d._write = () => {
2524 throw new Error('should not be called');
2525 };
2526 let gotError = false;
2527 d.on('error', function () {
2528 gotError = true;
2529 });
2530 d.pipe(new Writable({ write() {} }));
2531 strictEqual(gotError, false);
2532 }
2533 {
2534 // Verify that end(chunk) twice is an error
2535 const w = new Writable();
2536 const writeCalled = Promise.withResolvers();
2537 const gotError = Promise.withResolvers();
2538 w._write = (msg) => {
2539 strictEqual(msg.toString(), 'this is the end');
2540 writeCalled.resolve();
2541 };
2542 w.on('error', function (er) {
2543 strictEqual(er.message, 'write after end');
2544 gotError.resolve();
2545 });
2546 w.end('this is the end');
2547 w.end('and so is this');
2548 await Promise.all([writeCalled.promise, gotError.promise]);
2549 }
2550 {
2551 // Verify stream doesn't end while writing
2552 const w = new Writable();
2553 const wrote = Promise.withResolvers();
2554 const finishCalled = Promise.withResolvers();
2555 w._write = function (chunk, e, cb) {
2556 strictEqual(this.writing, undefined);
2557 wrote.resolve();
2558 this.writing = true;
2559 queueMicrotask(() => {
2560 this.writing = false;
2561 cb();
2562 }, 1);
2563 };
2564 w.on('finish', function () {
2565 strictEqual(this.writing, false);
2566 finishCalled.resolve();
2567 });
2568 w.write(Buffer.alloc(0));
2569 w.end();
2570 await Promise.all([wrote.promise, finishCalled.promise]);
2571 }
2572 {
2573 // Verify finish does not come before write() callback
2574 const w = new Writable();
2575 const finishCalled = Promise.withResolvers();
2576 let writeCb = false;
2577 w._write = function (chunk, e, cb) {
2578 setTimeout(function () {
2579 writeCb = true;
2580 cb();
2581 }, 10);
2582 };
2583 w.on('finish', function () {
2584 strictEqual(writeCb, true);
2585 finishCalled.resolve();
2586 });
2587 w.write(Buffer.alloc(0));
2588 w.end();
2589 await finishCalled.promise;
2590 }
2591 {
2592 // Verify finish does not come before synchronous _write() callback
2593 const w = new Writable();
2594 const finishCalled = Promise.withResolvers();
2595 let writeCb = false;
2596 w._write = function (chunk, e, cb) {
2597 cb();
2598 };
2599 w.on('finish', function () {
2600 strictEqual(writeCb, true);
2601 finishCalled.resolve();
2602 });
2603 w.write(Buffer.alloc(0), function () {
2604 writeCb = true;
2605 });
2606 w.end();
2607 await finishCalled.promise;
2608 }
2609 {
2610 // Verify finish is emitted if the last chunk is empty
2611 const w = new Writable();
2612 w._write = function (chunk, e, cb) {
2613 queueMicrotask(cb);
2614 };
2615 const finishCalled = Promise.withResolvers();
2616 w.on('finish', finishCalled.resolve);
2617 w.write(Buffer.allocUnsafe(1));
2618 w.end(Buffer.alloc(0));
2619 await finishCalled.promise;
2620 }
2621 {
2622 // Verify that finish is emitted after shutdown
2623 const w = new Writable();
2624 let shutdown = false;
2625 const finalCalled = Promise.withResolvers();
2626 const finishCalled = Promise.withResolvers();
2627 w._final = function (cb) {
2628 strictEqual(this, w);
2629 setTimeout(function () {
2630 finalCalled.resolve();
2631 shutdown = true;
2632 cb();
2633 }, 100);
2634 };
2635 w._write = function (chunk, e, cb) {
2636 queueMicrotask(cb);
2637 };
2638 w.on('finish', function () {
2639 strictEqual(shutdown, true);
2640 finishCalled.resolve();
2641 });
2642 w.write(Buffer.allocUnsafe(1));
2643 w.end(Buffer.allocUnsafe(0));
2644 await Promise.all([finalCalled.promise, finishCalled.promise]);
2645 }
2646 {
2647 // Verify that error is only emitted once when failing in _finish.
2648 const w = new Writable();
2649 const finalCalled = Promise.withResolvers();
2650 const gotError = Promise.withResolvers();
2651 w._final = function (cb) {
2652 cb(new Error('test'));
2653 finalCalled.resolve();
2654 };
2655 w.on('error', (err) => {
2656 gotError.resolve();
2657 strictEqual(w._writableState.errorEmitted, true);
2658 strictEqual(err.message, 'test');
2659 w.on('error', () => {
2660 throw new Error('should not be called again');
2661 });
2662 w.destroy(new Error());
2663 });
2664 w.end();
2665 await Promise.all([finalCalled.promise, gotError.promise]);
2666 }
2667 {
2668 // Verify that error is only emitted once when failing in write.
2669 const w = new Writable();
2670 throws(
2671 () => {
2672 w.write(null);
2673 },
2674 {
2675 code: 'ERR_STREAM_NULL_VALUES',
2676 }
2677 );
2678 }
2679 {
2680 // Verify that error is only emitted once when failing in write after end.
2681 const w = new Writable();
2682 const gotError = Promise.withResolvers();
2683 w.on('error', (err) => {
2684 strictEqual(w._writableState.errorEmitted, true);
2685 strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
2686 gotError.resolve();
2687 });
2688 w.end();
2689 w.write('hello');
2690 w.destroy(new Error());
2691 await gotError.promise;
2692 }
2693 {
2694 // Verify that finish is not emitted after error
2695 const w = new Writable();
2696 const finalCalled = Promise.withResolvers();
2697 const gotError = Promise.withResolvers();
2698 w._final = function (cb) {
2699 cb(new Error());
2700 finalCalled.resolve();
2701 };
2702 w._write = function (chunk, e, cb) {
2703 queueMicrotask(cb);
2704 };
2705 w.on('error', gotError.resolve);
2706 w.on('prefinish', gotError.reject);
2707 w.on('finish', gotError.reject);
2708 w.write(Buffer.allocUnsafe(1));
2709 w.end(Buffer.allocUnsafe(0));
2710 await Promise.all([finalCalled.promise, gotError.promise]);
2711 }
2712 },
2713};
2714 
2715export const unpipeLeak = {
2716 async test(ctrl, env, ctx) {
2717 const chunk = Buffer.from('hallo');
2718 class TestWriter extends Writable {
2719 _write(buffer, encoding, callback) {
2720 callback(null);
2721 }
2722 }
2723 const dest = new TestWriter();
2724 
2725 // Set this high so that we'd trigger a nextTick warning
2726 // and/or RangeError if we do maybeReadMore wrong.
2727 class TestReader extends Readable {
2728 constructor() {
2729 super({
2730 highWaterMark: 0x10000,
2731 });
2732 }
2733 _read(size) {
2734 this.push(chunk);
2735 }
2736 }
2737 const src = new TestReader();
2738 for (let i = 0; i < 10; i++) {
2739 src.pipe(dest);
2740 src.unpipe(dest);
2741 }
2742 
2743 strictEqual(src.listeners('end').length, 0);
2744 strictEqual(src.listeners('readable').length, 0);
2745 strictEqual(dest.listeners('unpipe').length, 0);
2746 strictEqual(dest.listeners('drain').length, 0);
2747 strictEqual(dest.listeners('error').length, 0);
2748 strictEqual(dest.listeners('close').length, 0);
2749 strictEqual(dest.listeners('finish').length, 0);
2750 },
2751};
2752 
2753export const unpipeDrain = {
2754 async test(ctrl, env, ctx) {
2755 class TestWriter extends Writable {
2756 _write(buffer, encoding, callback) {}
2757 }
2758 
2759 const dest = new TestWriter();
2760 class TestReader extends Readable {
2761 done = Promise.withResolvers();
2762 constructor() {
2763 super();
2764 this.reads = 0;
2765 }
2766 _read(size) {
2767 this.reads += 1;
2768 this.push(Buffer.alloc(size));
2769 if (this.reads == 2) this.done.resolve();
2770 }
2771 }
2772 const src1 = new TestReader();
2773 const src2 = new TestReader();
2774 src1.pipe(dest);
2775 src1.once('readable', () => {
2776 queueMicrotask(() => {
2777 src2.pipe(dest);
2778 src2.once('readable', () => {
2779 queueMicrotask(() => {
2780 src1.unpipe(dest);
2781 });
2782 });
2783 });
2784 });
2785 await Promise.all([src1.done.promise, src2.done.promise]);
2786 },
2787};
2788 
2789export const transformTest = {
2790 async test(ctrl, env, ctx) {
2791 {
2792 // Verify writable side consumption
2793 const tx = new Transform({
2794 highWaterMark: 10,
2795 });
2796 let transformed = 0;
2797 tx._transform = function (chunk, encoding, cb) {
2798 transformed += chunk.length;
2799 tx.push(chunk);
2800 cb();
2801 };
2802 for (let i = 1; i <= 10; i++) {
2803 tx.write(Buffer.allocUnsafe(i));
2804 }
2805 tx.end();
2806 strictEqual(tx.readableLength, 10);
2807 strictEqual(transformed, 10);
2808 deepStrictEqual(
2809 tx.writableBuffer.map(function (c) {
2810 return c.chunk.length;
2811 }),
2812 [5, 6, 7, 8, 9, 10]
2813 );
2814 }
2815 {
2816 // Verify passthrough behavior
2817 const pt = new PassThrough();
2818 pt.write(Buffer.from('foog'));
2819 pt.write(Buffer.from('bark'));
2820 pt.write(Buffer.from('bazy'));
2821 pt.write(Buffer.from('kuel'));
2822 pt.end();
2823 strictEqual(pt.read(5).toString(), 'foogb');
2824 strictEqual(pt.read(5).toString(), 'arkba');
2825 strictEqual(pt.read(5).toString(), 'zykue');
2826 strictEqual(pt.read(5).toString(), 'l');
2827 }
2828 {
2829 // Verify object passthrough behavior
2830 const pt = new PassThrough({
2831 objectMode: true,
2832 });
2833 pt.write(1);
2834 pt.write(true);
2835 pt.write(false);
2836 pt.write(0);
2837 pt.write('foo');
2838 pt.write('');
2839 pt.write({
2840 a: 'b',
2841 });
2842 pt.end();
2843 strictEqual(pt.read(), 1);
2844 strictEqual(pt.read(), true);
2845 strictEqual(pt.read(), false);
2846 strictEqual(pt.read(), 0);
2847 strictEqual(pt.read(), 'foo');
2848 strictEqual(pt.read(), '');
2849 deepStrictEqual(pt.read(), {
2850 a: 'b',
2851 });
2852 }
2853 {
2854 // Verify passthrough constructor behavior
2855 const pt = PassThrough();
2856 ok(pt instanceof PassThrough);
2857 }
2858 {
2859 // Verify transform constructor behavior
2860 const pt = Transform();
2861 ok(pt instanceof Transform);
2862 }
2863 {
2864 // Perform a simple transform
2865 const pt = new Transform();
2866 pt._transform = function (c, e, cb) {
2867 const ret = Buffer.alloc(c.length, 'x');
2868 pt.push(ret);
2869 cb();
2870 };
2871 pt.write(Buffer.from('foog'));
2872 pt.write(Buffer.from('bark'));
2873 pt.write(Buffer.from('bazy'));
2874 pt.write(Buffer.from('kuel'));
2875 pt.end();
2876 strictEqual(pt.read(5).toString(), 'xxxxx');
2877 strictEqual(pt.read(5).toString(), 'xxxxx');
2878 strictEqual(pt.read(5).toString(), 'xxxxx');
2879 strictEqual(pt.read(5).toString(), 'x');
2880 }
2881 {
2882 // Verify simple object transform
2883 const pt = new Transform({
2884 objectMode: true,
2885 });
2886 pt._transform = function (c, e, cb) {
2887 pt.push(JSON.stringify(c));
2888 cb();
2889 };
2890 pt.write(1);
2891 pt.write(true);
2892 pt.write(false);
2893 pt.write(0);
2894 pt.write('foo');
2895 pt.write('');
2896 pt.write({
2897 a: 'b',
2898 });
2899 pt.end();
2900 strictEqual(pt.read(), '1');
2901 strictEqual(pt.read(), 'true');
2902 strictEqual(pt.read(), 'false');
2903 strictEqual(pt.read(), '0');
2904 strictEqual(pt.read(), '"foo"');
2905 strictEqual(pt.read(), '""');
2906 strictEqual(pt.read(), '{"a":"b"}');
2907 }
2908 {
2909 // Verify async passthrough
2910 const pt = new Transform();
2911 pt._transform = function (chunk, encoding, cb) {
2912 setTimeout(function () {
2913 pt.push(chunk);
2914 cb();
2915 }, 10);
2916 };
2917 pt.write(Buffer.from('foog'));
2918 pt.write(Buffer.from('bark'));
2919 pt.write(Buffer.from('bazy'));
2920 pt.write(Buffer.from('kuel'));
2921 pt.end();
2922 const finishCalled = Promise.withResolvers();
2923 pt.on('finish', function () {
2924 strictEqual(pt.read(5).toString(), 'foogb');
2925 strictEqual(pt.read(5).toString(), 'arkba');
2926 strictEqual(pt.read(5).toString(), 'zykue');
2927 strictEqual(pt.read(5).toString(), 'l');
2928 finishCalled.resolve();
2929 });
2930 await finishCalled.promise;
2931 }
2932 {
2933 // Verify asymmetric transform (expand)
2934 const pt = new Transform();
2935 
2936 // Emit each chunk 2 times.
2937 pt._transform = function (chunk, encoding, cb) {
2938 setTimeout(function () {
2939 pt.push(chunk);
2940 setTimeout(function () {
2941 pt.push(chunk);
2942 cb();
2943 }, 10);
2944 }, 10);
2945 };
2946 pt.write(Buffer.from('foog'));
2947 pt.write(Buffer.from('bark'));
2948 pt.write(Buffer.from('bazy'));
2949 pt.write(Buffer.from('kuel'));
2950 pt.end();
2951 const finishCalled = Promise.withResolvers();
2952 pt.on('finish', function () {
2953 strictEqual(pt.read(5).toString(), 'foogf');
2954 strictEqual(pt.read(5).toString(), 'oogba');
2955 strictEqual(pt.read(5).toString(), 'rkbar');
2956 strictEqual(pt.read(5).toString(), 'kbazy');
2957 strictEqual(pt.read(5).toString(), 'bazyk');
2958 strictEqual(pt.read(5).toString(), 'uelku');
2959 strictEqual(pt.read(5).toString(), 'el');
2960 finishCalled.resolve();
2961 });
2962 await finishCalled.promise;
2963 }
2964 {
2965 // Verify asymmetric transform (compress)
2966 const pt = new Transform();
2967 
2968 // Each output is the first char of 3 consecutive chunks,
2969 // or whatever's left.
2970 pt.state = '';
2971 pt._transform = function (chunk, encoding, cb) {
2972 if (!chunk) chunk = '';
2973 const s = chunk.toString();
2974 setTimeout(() => {
2975 this.state += s.charAt(0);
2976 if (this.state.length === 3) {
2977 pt.push(Buffer.from(this.state));
2978 this.state = '';
2979 }
2980 cb();
2981 }, 10);
2982 };
2983 pt._flush = function (cb) {
2984 // Just output whatever we have.
2985 pt.push(Buffer.from(this.state));
2986 this.state = '';
2987 cb();
2988 };
2989 pt.write(Buffer.from('aaaa'));
2990 pt.write(Buffer.from('bbbb'));
2991 pt.write(Buffer.from('cccc'));
2992 pt.write(Buffer.from('dddd'));
2993 pt.write(Buffer.from('eeee'));
2994 pt.write(Buffer.from('aaaa'));
2995 pt.write(Buffer.from('bbbb'));
2996 pt.write(Buffer.from('cccc'));
2997 pt.write(Buffer.from('dddd'));
2998 pt.write(Buffer.from('eeee'));
2999 pt.write(Buffer.from('aaaa'));
3000 pt.write(Buffer.from('bbbb'));
3001 pt.write(Buffer.from('cccc'));
3002 pt.write(Buffer.from('dddd'));
3003 pt.end();
3004 
3005 const finishCalled = Promise.withResolvers();
3006 // 'abcdeabcdeabcd'
3007 pt.on('finish', function () {
3008 strictEqual(pt.read(5).toString(), 'abcde');
3009 strictEqual(pt.read(5).toString(), 'abcde');
3010 strictEqual(pt.read(5).toString(), 'abcd');
3011 finishCalled.resolve();
3012 });
3013 await finishCalled.promise;
3014 }
3015 
3016 // This tests for a stall when data is written to a full stream
3017 // that has empty transforms.
3018 {
3019 // Verify complex transform behavior
3020 let count = 0;
3021 let saved = null;
3022 const pt = new Transform({
3023 highWaterMark: 3,
3024 });
3025 pt._transform = function (c, e, cb) {
3026 if (count++ === 1) saved = c;
3027 else {
3028 if (saved) {
3029 pt.push(saved);
3030 saved = null;
3031 }
3032 pt.push(c);
3033 }
3034 cb();
3035 };
3036 const finishCalled = Promise.withResolvers();
3037 pt.on('finish', finishCalled.resolve);
3038 pt.once('readable', function () {
3039 queueMicrotask(function () {
3040 pt.write(Buffer.from('d'));
3041 pt.write(Buffer.from('ef'), function () {
3042 pt.end();
3043 });
3044 strictEqual(pt.read().toString(), 'abcdef');
3045 strictEqual(pt.read(), null);
3046 });
3047 });
3048 pt.write(Buffer.from('abc'));
3049 await finishCalled.promise;
3050 }
3051 {
3052 // Verify passthrough event emission
3053 const pt = new PassThrough();
3054 let emits = 0;
3055 pt.on('readable', function () {
3056 emits++;
3057 });
3058 pt.write(Buffer.from('foog'));
3059 pt.write(Buffer.from('bark'));
3060 strictEqual(emits, 0);
3061 strictEqual(pt.read(5).toString(), 'foogb');
3062 strictEqual(String(pt.read(5)), 'null');
3063 strictEqual(emits, 0);
3064 pt.write(Buffer.from('bazy'));
3065 pt.write(Buffer.from('kuel'));
3066 strictEqual(emits, 0);
3067 strictEqual(pt.read(5).toString(), 'arkba');
3068 strictEqual(pt.read(5).toString(), 'zykue');
3069 strictEqual(pt.read(5), null);
3070 pt.end();
3071 strictEqual(emits, 1);
3072 strictEqual(pt.read(5).toString(), 'l');
3073 strictEqual(pt.read(5), null);
3074 strictEqual(emits, 1);
3075 }
3076 {
3077 // Verify passthrough event emission reordering
3078 const pt = new PassThrough();
3079 let emits = 0;
3080 pt.on('readable', function () {
3081 emits++;
3082 });
3083 pt.write(Buffer.from('foog'));
3084 pt.write(Buffer.from('bark'));
3085 strictEqual(emits, 0);
3086 strictEqual(pt.read(5).toString(), 'foogb');
3087 strictEqual(pt.read(5), null);
3088 const readable1 = Promise.withResolvers();
3089 const readable2 = Promise.withResolvers();
3090 const readable3 = Promise.withResolvers();
3091 pt.once('readable', function () {
3092 strictEqual(pt.read(5).toString(), 'arkba');
3093 strictEqual(pt.read(5), null);
3094 pt.once('readable', function () {
3095 strictEqual(pt.read(5).toString(), 'zykue');
3096 strictEqual(pt.read(5), null);
3097 pt.once('readable', function () {
3098 strictEqual(pt.read(5).toString(), 'l');
3099 strictEqual(pt.read(5), null);
3100 strictEqual(emits, 3);
3101 readable3.resolve();
3102 });
3103 pt.end();
3104 readable2.resolve();
3105 });
3106 pt.write(Buffer.from('kuel'));
3107 readable1.resolve();
3108 });
3109 pt.write(Buffer.from('bazy'));
3110 await Promise.all([
3111 readable1.promise,
3112 readable2.promise,
3113 readable3.promise,
3114 ]);
3115 }
3116 {
3117 // Verify passthrough facade
3118 const pt = new PassThrough();
3119 const datas = [];
3120 pt.on('data', function (chunk) {
3121 datas.push(chunk.toString());
3122 });
3123 const endCalled = Promise.withResolvers();
3124 pt.on('end', function () {
3125 deepStrictEqual(datas, ['foog', 'bark', 'bazy', 'kuel']);
3126 endCalled.resolve();
3127 });
3128 pt.write(Buffer.from('foog'));
3129 setTimeout(function () {
3130 pt.write(Buffer.from('bark'));
3131 setTimeout(function () {
3132 pt.write(Buffer.from('bazy'));
3133 setTimeout(function () {
3134 pt.write(Buffer.from('kuel'));
3135 setTimeout(function () {
3136 pt.end();
3137 }, 10);
3138 }, 10);
3139 }, 10);
3140 }, 10);
3141 
3142 await endCalled.promise;
3143 }
3144 {
3145 // Verify object transform (JSON parse)
3146 const jp = new Transform({
3147 objectMode: true,
3148 });
3149 jp._transform = function (data, encoding, cb) {
3150 try {
3151 jp.push(JSON.parse(data));
3152 cb();
3153 } catch (er) {
3154 cb(er);
3155 }
3156 };
3157 
3158 // Anything except null/undefined is fine.
3159 // those are "magic" in the stream API, because they signal EOF.
3160 const objects = [
3161 {
3162 foo: 'bar',
3163 },
3164 100,
3165 'string',
3166 {
3167 nested: {
3168 things: [
3169 {
3170 foo: 'bar',
3171 },
3172 100,
3173 'string',
3174 ],
3175 },
3176 },
3177 ];
3178 const ended = Promise.withResolvers();
3179 jp.on('end', ended.resolve);
3180 objects.forEach(function (obj) {
3181 jp.write(JSON.stringify(obj));
3182 const res = jp.read();
3183 deepStrictEqual(res, obj);
3184 });
3185 jp.end();
3186 // Read one more time to get the 'end' event
3187 jp.read();
3188 await ended.promise;
3189 }
3190 {
3191 // Verify object transform (JSON stringify)
3192 const js = new Transform({
3193 objectMode: true,
3194 });
3195 js._transform = function (data, encoding, cb) {
3196 try {
3197 js.push(JSON.stringify(data));
3198 cb();
3199 } catch (er) {
3200 cb(er);
3201 }
3202 };
3203 
3204 // Anything except null/undefined is fine.
3205 // those are "magic" in the stream API, because they signal EOF.
3206 const objects = [
3207 {
3208 foo: 'bar',
3209 },
3210 100,
3211 'string',
3212 {
3213 nested: {
3214 things: [
3215 {
3216 foo: 'bar',
3217 },
3218 100,
3219 'string',
3220 ],
3221 },
3222 },
3223 ];
3224 const ended = Promise.withResolvers();
3225 js.on('end', ended.resolve);
3226 objects.forEach(function (obj) {
3227 js.write(obj);
3228 const res = js.read();
3229 strictEqual(res, JSON.stringify(obj));
3230 });
3231 js.end();
3232 // Read one more time to get the 'end' event
3233 js.read();
3234 await ended.promise;
3235 }
3236 },
3237};
3238 
3239export const set_encoding = {
3240 async test(ctrl, env, ctx) {
3241 class TestReader extends Readable {
3242 constructor(n, opts) {
3243 super(opts);
3244 this.pos = 0;
3245 this.len = n || 100;
3246 }
3247 _read(n) {
3248 setTimeout(() => {
3249 if (this.pos >= this.len) {
3250 // Double push(null) to test eos handling
3251 this.push(null);
3252 return this.push(null);
3253 }
3254 n = Math.min(n, this.len - this.pos);
3255 if (n <= 0) {
3256 // Double push(null) to test eos handling
3257 this.push(null);
3258 return this.push(null);
3259 }
3260 this.pos += n;
3261 const ret = Buffer.alloc(n, 'a');
3262 return this.push(ret);
3263 }, 1);
3264 }
3265 }
3266 {
3267 // Verify utf8 encoding
3268 const tr = new TestReader(100);
3269 tr.setEncoding('utf8');
3270 const out = [];
3271 const expect = [
3272 'aaaaaaaaaa',
3273 'aaaaaaaaaa',
3274 'aaaaaaaaaa',
3275 'aaaaaaaaaa',
3276 'aaaaaaaaaa',
3277 'aaaaaaaaaa',
3278 'aaaaaaaaaa',
3279 'aaaaaaaaaa',
3280 'aaaaaaaaaa',
3281 'aaaaaaaaaa',
3282 ];
3283 tr.on('readable', function flow() {
3284 let chunk;
3285 while (null !== (chunk = tr.read(10))) out.push(chunk);
3286 });
3287 const ended = Promise.withResolvers();
3288 tr.on('end', function () {
3289 deepStrictEqual(out, expect);
3290 ended.resolve();
3291 });
3292 await ended.promise;
3293 }
3294 {
3295 // Verify hex encoding
3296 const tr = new TestReader(100);
3297 tr.setEncoding('hex');
3298 const out = [];
3299 const expect = [
3300 '6161616161',
3301 '6161616161',
3302 '6161616161',
3303 '6161616161',
3304 '6161616161',
3305 '6161616161',
3306 '6161616161',
3307 '6161616161',
3308 '6161616161',
3309 '6161616161',
3310 '6161616161',
3311 '6161616161',
3312 '6161616161',
3313 '6161616161',
3314 '6161616161',
3315 '6161616161',
3316 '6161616161',
3317 '6161616161',
3318 '6161616161',
3319 '6161616161',
3320 ];
3321 tr.on('readable', function flow() {
3322 let chunk;
3323 while (null !== (chunk = tr.read(10))) out.push(chunk);
3324 });
3325 const ended = Promise.withResolvers();
3326 tr.on('end', function () {
3327 deepStrictEqual(out, expect);
3328 ended.resolve();
3329 });
3330 await ended.promise;
3331 }
3332 {
3333 // Verify hex encoding with read(13)
3334 const tr = new TestReader(100);
3335 tr.setEncoding('hex');
3336 const out = [];
3337 const expect = [
3338 '6161616161616',
3339 '1616161616161',
3340 '6161616161616',
3341 '1616161616161',
3342 '6161616161616',
3343 '1616161616161',
3344 '6161616161616',
3345 '1616161616161',
3346 '6161616161616',
3347 '1616161616161',
3348 '6161616161616',
3349 '1616161616161',
3350 '6161616161616',
3351 '1616161616161',
3352 '6161616161616',
3353 '16161',
3354 ];
3355 tr.on('readable', function flow() {
3356 let chunk;
3357 while (null !== (chunk = tr.read(13))) out.push(chunk);
3358 });
3359 const ended = Promise.withResolvers();
3360 tr.on('end', function () {
3361 deepStrictEqual(out, expect);
3362 ended.resolve();
3363 });
3364 await ended.promise;
3365 }
3366 {
3367 // Verify base64 encoding
3368 const tr = new TestReader(100);
3369 tr.setEncoding('base64');
3370 const out = [];
3371 const expect = [
3372 'YWFhYWFhYW',
3373 'FhYWFhYWFh',
3374 'YWFhYWFhYW',
3375 'FhYWFhYWFh',
3376 'YWFhYWFhYW',
3377 'FhYWFhYWFh',
3378 'YWFhYWFhYW',
3379 'FhYWFhYWFh',
3380 'YWFhYWFhYW',
3381 'FhYWFhYWFh',
3382 'YWFhYWFhYW',
3383 'FhYWFhYWFh',
3384 'YWFhYWFhYW',
3385 'FhYQ==',
3386 ];
3387 tr.on('readable', function flow() {
3388 let chunk;
3389 while (null !== (chunk = tr.read(10))) out.push(chunk);
3390 });
3391 const ended = Promise.withResolvers();
3392 tr.on('end', function () {
3393 deepStrictEqual(out, expect);
3394 ended.resolve();
3395 });
3396 await ended.promise;
3397 }
3398 {
3399 // Verify utf8 encoding
3400 const tr = new TestReader(100, {
3401 encoding: 'utf8',
3402 });
3403 const out = [];
3404 const expect = [
3405 'aaaaaaaaaa',
3406 'aaaaaaaaaa',
3407 'aaaaaaaaaa',
3408 'aaaaaaaaaa',
3409 'aaaaaaaaaa',
3410 'aaaaaaaaaa',
3411 'aaaaaaaaaa',
3412 'aaaaaaaaaa',
3413 'aaaaaaaaaa',
3414 'aaaaaaaaaa',
3415 ];
3416 tr.on('readable', function flow() {
3417 let chunk;
3418 while (null !== (chunk = tr.read(10))) out.push(chunk);
3419 });
3420 const ended = Promise.withResolvers();
3421 tr.on('end', function () {
3422 deepStrictEqual(out, expect);
3423 ended.resolve();
3424 });
3425 await ended.promise;
3426 }
3427 {
3428 // Verify hex encoding
3429 const tr = new TestReader(100, {
3430 encoding: 'hex',
3431 });
3432 const out = [];
3433 const expect = [
3434 '6161616161',
3435 '6161616161',
3436 '6161616161',
3437 '6161616161',
3438 '6161616161',
3439 '6161616161',
3440 '6161616161',
3441 '6161616161',
3442 '6161616161',
3443 '6161616161',
3444 '6161616161',
3445 '6161616161',
3446 '6161616161',
3447 '6161616161',
3448 '6161616161',
3449 '6161616161',
3450 '6161616161',
3451 '6161616161',
3452 '6161616161',
3453 '6161616161',
3454 ];
3455 tr.on('readable', function flow() {
3456 let chunk;
3457 while (null !== (chunk = tr.read(10))) out.push(chunk);
3458 });
3459 const ended = Promise.withResolvers();
3460 tr.on('end', function () {
3461 deepStrictEqual(out, expect);
3462 ended.resolve();
3463 });
3464 await ended.promise;
3465 }
3466 {
3467 // Verify hex encoding with read(13)
3468 const tr = new TestReader(100, {
3469 encoding: 'hex',
3470 });
3471 const out = [];
3472 const expect = [
3473 '6161616161616',
3474 '1616161616161',
3475 '6161616161616',
3476 '1616161616161',
3477 '6161616161616',
3478 '1616161616161',
3479 '6161616161616',
3480 '1616161616161',
3481 '6161616161616',
3482 '1616161616161',
3483 '6161616161616',
3484 '1616161616161',
3485 '6161616161616',
3486 '1616161616161',
3487 '6161616161616',
3488 '16161',
3489 ];
3490 tr.on('readable', function flow() {
3491 let chunk;
3492 while (null !== (chunk = tr.read(13))) out.push(chunk);
3493 });
3494 const ended = Promise.withResolvers();
3495 tr.on('end', function () {
3496 deepStrictEqual(out, expect);
3497 ended.resolve();
3498 });
3499 await ended.promise;
3500 }
3501 {
3502 // Verify base64 encoding
3503 const tr = new TestReader(100, {
3504 encoding: 'base64',
3505 });
3506 const out = [];
3507 const expect = [
3508 'YWFhYWFhYW',
3509 'FhYWFhYWFh',
3510 'YWFhYWFhYW',
3511 'FhYWFhYWFh',
3512 'YWFhYWFhYW',
3513 'FhYWFhYWFh',
3514 'YWFhYWFhYW',
3515 'FhYWFhYWFh',
3516 'YWFhYWFhYW',
3517 'FhYWFhYWFh',
3518 'YWFhYWFhYW',
3519 'FhYWFhYWFh',
3520 'YWFhYWFhYW',
3521 'FhYQ==',
3522 ];
3523 tr.on('readable', function flow() {
3524 let chunk;
3525 while (null !== (chunk = tr.read(10))) out.push(chunk);
3526 });
3527 const ended = Promise.withResolvers();
3528 tr.on('end', function () {
3529 deepStrictEqual(out, expect);
3530 ended.resolve();
3531 });
3532 await ended.promise;
3533 }
3534 {
3535 // Verify chaining behavior
3536 const tr = new TestReader(100);
3537 deepStrictEqual(tr.setEncoding('utf8'), tr);
3538 }
3539 },
3540};
3541 
3542export const readable_wrap = {
3543 async test(ctrl, env, ctx) {
3544 async function runTest(highWaterMark, objectMode, produce) {
3545 const rEnded = Promise.withResolvers();
3546 const old = new EventEmitter();
3547 const r = new Readable({
3548 highWaterMark,
3549 objectMode,
3550 });
3551 strictEqual(r, r.wrap(old));
3552 
3553 r.on('end', rEnded.resolve);
3554 old.pause = function () {
3555 old.emit('pause');
3556 flowing = false;
3557 };
3558 old.resume = function () {
3559 old.emit('resume');
3560 flow();
3561 };
3562 
3563 // Make sure pause is only emitted once.
3564 let pausing = false;
3565 r.on('pause', () => {
3566 strictEqual(pausing, false);
3567 pausing = true;
3568 queueMicrotask(() => {
3569 pausing = false;
3570 });
3571 });
3572 let flowing;
3573 let chunks = 10;
3574 let oldEnded = false;
3575 const expected = [];
3576 function flow() {
3577 flowing = true;
3578 while (flowing && chunks-- > 0) {
3579 const item = produce();
3580 expected.push(item);
3581 old.emit('data', item);
3582 }
3583 if (chunks <= 0) {
3584 oldEnded = true;
3585 old.emit('end');
3586 }
3587 }
3588 const w = new Writable({
3589 highWaterMark: highWaterMark * 2,
3590 objectMode,
3591 });
3592 const written = [];
3593 w._write = function (chunk, encoding, cb) {
3594 written.push(chunk);
3595 setTimeout(cb, 1);
3596 };
3597 const finishCalled = Promise.withResolvers();
3598 w.on('finish', function () {
3599 performAsserts();
3600 finishCalled.resolve();
3601 });
3602 r.pipe(w);
3603 flow();
3604 function performAsserts() {
3605 ok(oldEnded);
3606 deepStrictEqual(written, expected);
3607 }
3608 await Promise.all([rEnded.promise, finishCalled.promise]);
3609 }
3610 await runTest(100, false, function () {
3611 return Buffer.allocUnsafe(100);
3612 });
3613 await runTest(10, false, function () {
3614 return Buffer.from('xxxxxxxxxx');
3615 });
3616 await runTest(1, true, function () {
3617 return {
3618 foo: 'bar',
3619 };
3620 });
3621 const objectChunks = [
3622 5,
3623 'a',
3624 false,
3625 0,
3626 '',
3627 'xyz',
3628 {
3629 x: 4,
3630 },
3631 7,
3632 [],
3633 555,
3634 ];
3635 await runTest(1, true, function () {
3636 return objectChunks.shift();
3637 });
3638 },
3639};
3640 
3641export const readable_wrap_error = {
3642 async test(ctrl, env, ctx) {
3643 class LegacyStream extends EventEmitter {
3644 pause() {}
3645 resume() {}
3646 }
3647 {
3648 const err = new Error();
3649 const oldStream = new LegacyStream();
3650 const errored = Promise.withResolvers();
3651 const r = new Readable({
3652 autoDestroy: true,
3653 })
3654 .wrap(oldStream)
3655 .on('error', () => {
3656 strictEqual(r._readableState.errorEmitted, true);
3657 strictEqual(r._readableState.errored, err);
3658 strictEqual(r.destroyed, true);
3659 errored.resolve();
3660 });
3661 oldStream.emit('error', err);
3662 await errored.promise;
3663 }
3664 {
3665 const err = new Error();
3666 const oldStream = new LegacyStream();
3667 const errored = Promise.withResolvers();
3668 const r = new Readable({
3669 autoDestroy: false,
3670 })
3671 .wrap(oldStream)
3672 .on('error', () => {
3673 strictEqual(r._readableState.errorEmitted, true);
3674 strictEqual(r._readableState.errored, err);
3675 strictEqual(r.destroyed, false);
3676 errored.resolve();
3677 });
3678 oldStream.emit('error', err);
3679 await errored.promise;
3680 }
3681 },
3682};
3683 
3684export const readable_wrap_empty = {
3685 async test(ctrl, env, ctx) {
3686 const oldStream = new EventEmitter();
3687 oldStream.pause = () => {};
3688 oldStream.resume = () => {};
3689 const newStream = new Readable().wrap(oldStream);
3690 const ended = Promise.withResolvers();
3691 newStream.on('readable', () => {}).on('end', ended.resolve);
3692 oldStream.emit('end');
3693 await ended.promise;
3694 },
3695};
3696 
3697export const readable_wrap_destroy = {
3698 async test(ctrl, env, ctx) {
3699 const oldStream = new EventEmitter();
3700 oldStream.pause = () => {};
3701 oldStream.resume = () => {};
3702 {
3703 const destroyCalled = Promise.withResolvers();
3704 new Readable({
3705 autoDestroy: false,
3706 destroy: destroyCalled.resolve,
3707 }).wrap(oldStream);
3708 oldStream.emit('destroy');
3709 await destroyCalled.promise;
3710 }
3711 {
3712 const destroyCalled = Promise.withResolvers();
3713 new Readable({
3714 autoDestroy: false,
3715 destroy: destroyCalled.resolve,
3716 }).wrap(oldStream);
3717 oldStream.emit('close');
3718 await destroyCalled.promise;
3719 }
3720 },
3721};
3722 
3723export const readable_non_empty_end = {
3724 async test(_ctrl, _env, _ctx) {
3725 let len = 0;
3726 const chunks = Array.from({ length: 10 }, (_el, i) => {
3727 len += i + 1;
3728 return Buffer.allocUnsafe(i + 1);
3729 });
3730 const test = new Readable();
3731 let n = 0;
3732 test._read = function (size) {
3733 const chunk = chunks[n++];
3734 setTimeout(function () {
3735 test.push(chunk === undefined ? null : chunk);
3736 }, 1);
3737 };
3738 test.on('end', thrower);
3739 function thrower() {
3740 throw new Error('this should not happen!');
3741 }
3742 let bytesread = 0;
3743 const ended = Promise.withResolvers();
3744 test.on('readable', function () {
3745 const b = len - bytesread - 1;
3746 const res = test.read(b);
3747 if (res) {
3748 bytesread += res.length;
3749 setTimeout(next, 1);
3750 }
3751 test.read(0);
3752 });
3753 test.read(0);
3754 function next() {
3755 // Now let's make 'end' happen
3756 test.removeListener('end', thrower);
3757 test.on('end', ended.resolve);
3758 
3759 // One to get the last byte
3760 let r = test.read();
3761 ok(r);
3762 strictEqual(r.length, 1);
3763 r = test.read();
3764 strictEqual(r, null);
3765 }
3766 await ended.promise;
3767 },
3768};
3769 
3770export const readable_legacy_drain = {
3771 async test(ctrl, env, ctx) {
3772 const r = new Readable();
3773 const N = 256;
3774 let reads = 0;
3775 r._read = function (n) {
3776 return r.push(++reads === N ? null : Buffer.allocUnsafe(1));
3777 };
3778 const ended1 = Promise.withResolvers();
3779 r.on('end', ended1.resolve);
3780 const w = new Stream();
3781 w.writable = true;
3782 let buffered = 0;
3783 w.write = function (c) {
3784 buffered += c.length;
3785 queueMicrotask(drain);
3786 return false;
3787 };
3788 function drain() {
3789 ok(buffered <= 3);
3790 buffered = 0;
3791 w.emit('drain');
3792 }
3793 const ended2 = Promise.withResolvers();
3794 w.end = ended2.resolve;
3795 r.pipe(w);
3796 await Promise.all([ended1.promise, ended2.promise]);
3797 },
3798};
3799 
3800export const read_sync_stack = {
3801 async test(ctrl, env, ctx) {
3802 // This tests synchronous read callbacks and verifies that even if they nest
3803 // heavily the process handles it without an error
3804 
3805 const r = new Readable();
3806 const N = 256 * 1024;
3807 let reads = 0;
3808 r._read = function (n) {
3809 const chunk = reads++ === N ? null : Buffer.allocUnsafe(1);
3810 r.push(chunk);
3811 };
3812 r.on('readable', function onReadable() {
3813 r.read(N * 2);
3814 });
3815 const ended = Promise.withResolvers();
3816 r.on('end', ended.resolve);
3817 r.read(0);
3818 await ended.promise;
3819 },
3820};
3821 
3822export const stream2_push = {
3823 async test(ctrl, env, ctx) {
3824 const stream = new Readable({
3825 highWaterMark: 16,
3826 encoding: 'utf8',
3827 });
3828 const source = new EventEmitter();
3829 stream._read = function () {
3830 readStart();
3831 };
3832 const ended = Promise.withResolvers();
3833 stream.on('end', ended.resolve);
3834 source.on('data', function (chunk) {
3835 const ret = stream.push(chunk);
3836 if (!ret) readStop();
3837 });
3838 source.on('end', function () {
3839 stream.push(null);
3840 });
3841 let reading = false;
3842 function readStart() {
3843 reading = true;
3844 }
3845 function readStop() {
3846 reading = false;
3847 queueMicrotask(function () {
3848 const r = stream.read();
3849 if (r !== null) writer.write(r);
3850 });
3851 }
3852 const writer = new Writable({
3853 decodeStrings: false,
3854 });
3855 const written = [];
3856 const expectWritten = [
3857 'asdfgasdfgasdfgasdfg',
3858 'asdfgasdfgasdfgasdfg',
3859 'asdfgasdfgasdfgasdfg',
3860 'asdfgasdfgasdfgasdfg',
3861 'asdfgasdfgasdfgasdfg',
3862 'asdfgasdfgasdfgasdfg',
3863 ];
3864 writer._write = function (chunk, encoding, cb) {
3865 written.push(chunk);
3866 queueMicrotask(cb);
3867 };
3868 writer.on('finish', finish);
3869 
3870 // Now emit some chunks.
3871 
3872 const chunk = 'asdfg';
3873 let set = 0;
3874 readStart();
3875 data();
3876 function data() {
3877 ok(reading);
3878 source.emit('data', chunk);
3879 ok(reading);
3880 source.emit('data', chunk);
3881 ok(reading);
3882 source.emit('data', chunk);
3883 ok(reading);
3884 source.emit('data', chunk);
3885 ok(!reading);
3886 if (set++ < 5) setTimeout(data, 10);
3887 else end();
3888 }
3889 function finish() {
3890 deepStrictEqual(written, expectWritten);
3891 }
3892 function end() {
3893 source.emit('end');
3894 ok(!reading);
3895 writer.end(stream.read());
3896 }
3897 await ended.promise;
3898 },
3899};
3900 
3901export const stream2_pipe_error_once_listener = {
3902 async test(ctrl, env, ctx) {
3903 class Read extends Readable {
3904 _read(size) {
3905 this.push('x');
3906 this.push(null);
3907 }
3908 }
3909 class Write extends Writable {
3910 _write(buffer, encoding, cb) {
3911 this.emit('error', new Error('boom'));
3912 }
3913 }
3914 const read = new Read();
3915 const write = new Write();
3916 const errored = Promise.withResolvers();
3917 write.once('error', errored.resolve);
3918 read.pipe(write);
3919 
3920 await errored.promise;
3921 },
3922};
3923 
3924export const stream2_pipe_error_handling = {
3925 async test(ctrl, env, ctx) {
3926 {
3927 let count = 1000;
3928 const source = new Readable();
3929 source._read = function (n) {
3930 n = Math.min(count, n);
3931 count -= n;
3932 source.push(Buffer.allocUnsafe(n));
3933 };
3934 let unpipedDest;
3935 source.unpipe = function (dest) {
3936 unpipedDest = dest;
3937 Readable.prototype.unpipe.call(this, dest);
3938 };
3939 const dest = new Writable();
3940 dest._write = function (chunk, encoding, cb) {
3941 cb();
3942 };
3943 source.pipe(dest);
3944 let gotErr = null;
3945 dest.on('error', function (err) {
3946 gotErr = err;
3947 });
3948 let unpipedSource;
3949 dest.on('unpipe', function (src) {
3950 unpipedSource = src;
3951 });
3952 const err = new Error('This stream turned into bacon.');
3953 dest.emit('error', err);
3954 strictEqual(gotErr, err);
3955 strictEqual(unpipedSource, source);
3956 strictEqual(unpipedDest, dest);
3957 }
3958 {
3959 let count = 1000;
3960 const source = new Readable();
3961 source._read = function (n) {
3962 n = Math.min(count, n);
3963 count -= n;
3964 source.push(Buffer.allocUnsafe(n));
3965 };
3966 let unpipedDest;
3967 source.unpipe = function (dest) {
3968 unpipedDest = dest;
3969 Readable.prototype.unpipe.call(this, dest);
3970 };
3971 const dest = new Writable({
3972 autoDestroy: false,
3973 });
3974 dest._write = function (chunk, encoding, cb) {
3975 cb();
3976 };
3977 source.pipe(dest);
3978 let unpipedSource;
3979 dest.on('unpipe', function (src) {
3980 unpipedSource = src;
3981 });
3982 const err = new Error('This stream turned into bacon.');
3983 let gotErr = null;
3984 try {
3985 dest.emit('error', err);
3986 } catch (e) {
3987 gotErr = e;
3988 }
3989 strictEqual(gotErr, err);
3990 strictEqual(unpipedSource, source);
3991 strictEqual(unpipedDest, dest);
3992 }
3993 },
3994};
3995 
3996export const stream2_objects = {
3997 async test(ctrl, env, ctx) {
3998 function toArray(callback) {
3999 const stream = new Writable({
4000 objectMode: true,
4001 });
4002 const list = [];
4003 stream.write = function (chunk) {
4004 list.push(chunk);
4005 };
4006 stream.end = function () {
4007 callback(list);
4008 this.ended.resolve();
4009 };
4010 stream.ended = Promise.withResolvers();
4011 return stream;
4012 }
4013 function fromArray(list) {
4014 const r = new Readable({
4015 objectMode: true,
4016 });
4017 r._read = () => {
4018 throw new Error('should not have been called');
4019 };
4020 list.forEach(function (chunk) {
4021 r.push(chunk);
4022 });
4023 r.push(null);
4024 return r;
4025 }
4026 {
4027 // Verify that objects can be read from the stream
4028 const r = fromArray([
4029 {
4030 one: '1',
4031 },
4032 {
4033 two: '2',
4034 },
4035 ]);
4036 const v1 = r.read();
4037 const v2 = r.read();
4038 const v3 = r.read();
4039 deepStrictEqual(v1, {
4040 one: '1',
4041 });
4042 deepStrictEqual(v2, {
4043 two: '2',
4044 });
4045 strictEqual(v3, null);
4046 }
4047 {
4048 // Verify that objects can be piped into the stream
4049 const r = fromArray([
4050 {
4051 one: '1',
4052 },
4053 {
4054 two: '2',
4055 },
4056 ]);
4057 const w = toArray(function (list) {
4058 deepStrictEqual(list, [
4059 {
4060 one: '1',
4061 },
4062 {
4063 two: '2',
4064 },
4065 ]);
4066 });
4067 r.pipe(w);
4068 await w.ended.promise;
4069 }
4070 {
4071 // Verify that read(n) is ignored
4072 const r = fromArray([
4073 {
4074 one: '1',
4075 },
4076 {
4077 two: '2',
4078 },
4079 ]);
4080 const value = r.read(2);
4081 deepStrictEqual(value, {
4082 one: '1',
4083 });
4084 }
4085 {
4086 // Verify that objects can be synchronously read
4087 const r = new Readable({
4088 objectMode: true,
4089 });
4090 const list = [
4091 {
4092 one: '1',
4093 },
4094 {
4095 two: '2',
4096 },
4097 ];
4098 r._read = function (n) {
4099 const item = list.shift();
4100 r.push(item || null);
4101 };
4102 const dest = toArray(function (list) {
4103 deepStrictEqual(list, [
4104 {
4105 one: '1',
4106 },
4107 {
4108 two: '2',
4109 },
4110 ]);
4111 });
4112 r.pipe(dest);
4113 await dest.ended.promise;
4114 }
4115 {
4116 // Verify that objects can be asynchronously read
4117 const r = new Readable({
4118 objectMode: true,
4119 });
4120 const list = [
4121 {
4122 one: '1',
4123 },
4124 {
4125 two: '2',
4126 },
4127 ];
4128 r._read = function (n) {
4129 const item = list.shift();
4130 queueMicrotask(function () {
4131 r.push(item || null);
4132 });
4133 };
4134 const dest = toArray(function (list) {
4135 deepStrictEqual(list, [
4136 {
4137 one: '1',
4138 },
4139 {
4140 two: '2',
4141 },
4142 ]);
4143 });
4144 r.pipe(dest);
4145 await dest.ended.promise;
4146 }
4147 {
4148 // Verify that strings can be read as objects
4149 const r = new Readable({
4150 objectMode: true,
4151 });
4152 r._read = () => {
4153 throw new Error('should not have been called');
4154 };
4155 const list = ['one', 'two', 'three'];
4156 list.forEach(function (str) {
4157 r.push(str);
4158 });
4159 r.push(null);
4160 const dest = toArray(function (array) {
4161 deepStrictEqual(array, list);
4162 });
4163 r.pipe(dest);
4164 await dest.ended.promise;
4165 }
4166 {
4167 // Verify read(0) behavior for object streams
4168 const r = new Readable({
4169 objectMode: true,
4170 });
4171 r.push('foobar');
4172 r.push(null);
4173 const dest = toArray(function (array) {
4174 deepStrictEqual(array, ['foobar']);
4175 });
4176 r.pipe(dest);
4177 await dest.ended.promise;
4178 }
4179 {
4180 // Verify the behavior of pushing falsey values
4181 const r = new Readable({
4182 objectMode: true,
4183 });
4184 r.push(false);
4185 r.push(0);
4186 r.push('');
4187 r.push(null);
4188 const dest = toArray(function (array) {
4189 deepStrictEqual(array, [false, 0, '']);
4190 });
4191 r.pipe(dest);
4192 await dest.ended.promise;
4193 }
4194 {
4195 // Verify high watermark _read() behavior
4196 const r = new Readable({
4197 highWaterMark: 6,
4198 objectMode: true,
4199 });
4200 let calls = 0;
4201 const list = ['1', '2', '3', '4', '5', '6', '7', '8'];
4202 r._read = function (n) {
4203 calls++;
4204 };
4205 list.forEach(function (c) {
4206 r.push(c);
4207 });
4208 const v = r.read();
4209 strictEqual(calls, 0);
4210 strictEqual(v, '1');
4211 const v2 = r.read();
4212 strictEqual(v2, '2');
4213 const v3 = r.read();
4214 strictEqual(v3, '3');
4215 strictEqual(calls, 1);
4216 }
4217 {
4218 // Verify high watermark push behavior
4219 const r = new Readable({
4220 highWaterMark: 6,
4221 objectMode: true,
4222 });
4223 r._read = () => {
4224 throw new Error('should not have been called');
4225 };
4226 for (let i = 0; i < 6; i++) {
4227 const bool = r.push(i);
4228 strictEqual(bool, i !== 5);
4229 }
4230 }
4231 {
4232 // Verify that objects can be written to stream
4233 const w = new Writable({
4234 objectMode: true,
4235 });
4236 w._write = function (chunk, encoding, cb) {
4237 deepStrictEqual(chunk, {
4238 foo: 'bar',
4239 });
4240 cb();
4241 };
4242 const finishCalled = Promise.withResolvers();
4243 w.on('finish', finishCalled.resolve);
4244 w.write({
4245 foo: 'bar',
4246 });
4247 w.end();
4248 await finishCalled.promise;
4249 }
4250 {
4251 // Verify that multiple objects can be written to stream
4252 const w = new Writable({
4253 objectMode: true,
4254 });
4255 const list = [];
4256 w._write = function (chunk, encoding, cb) {
4257 list.push(chunk);
4258 cb();
4259 };
4260 const finishCalled = Promise.withResolvers();
4261 w.on('finish', function () {
4262 deepStrictEqual(list, [0, 1, 2, 3, 4]);
4263 finishCalled.resolve();
4264 });
4265 w.write(0);
4266 w.write(1);
4267 w.write(2);
4268 w.write(3);
4269 w.write(4);
4270 w.end();
4271 await finishCalled.promise;
4272 }
4273 {
4274 // Verify that strings can be written as objects
4275 const w = new Writable({
4276 objectMode: true,
4277 });
4278 const list = [];
4279 w._write = function (chunk, encoding, cb) {
4280 list.push(chunk);
4281 queueMicrotask(cb);
4282 };
4283 const finishCalled = Promise.withResolvers();
4284 w.on('finish', function () {
4285 deepStrictEqual(list, ['0', '1', '2', '3', '4']);
4286 finishCalled.resolve();
4287 });
4288 w.write('0');
4289 w.write('1');
4290 w.write('2');
4291 w.write('3');
4292 w.write('4');
4293 w.end();
4294 await finishCalled.promise;
4295 }
4296 {
4297 // Verify that stream buffers finish until callback is called
4298 const w = new Writable({
4299 objectMode: true,
4300 });
4301 let called = false;
4302 w._write = function (chunk, encoding, cb) {
4303 strictEqual(chunk, 'foo');
4304 queueMicrotask(function () {
4305 called = true;
4306 cb();
4307 });
4308 };
4309 const finishCalled = Promise.withResolvers();
4310 w.on('finish', function () {
4311 strictEqual(called, true);
4312 finishCalled.resolve();
4313 });
4314 w.write('foo');
4315 w.end();
4316 await finishCalled.promise;
4317 }
4318 },
4319};
4320 
4321export const stream2_large_read_stall = {
4322 async test(ctrl, env, ctx) {
4323 // If everything aligns so that you do a read(n) of exactly the
4324 // remaining buffer, then make sure that 'end' still emits.
4325 
4326 const READSIZE = 100;
4327 const PUSHSIZE = 20;
4328 const PUSHCOUNT = 1000;
4329 const HWM = 50;
4330 const r = new Readable({
4331 highWaterMark: HWM,
4332 });
4333 const _rs = r._readableState;
4334 r._read = push;
4335 r.on('readable', function () {
4336 let ret;
4337 do {
4338 ret = r.read(READSIZE);
4339 } while (ret && ret.length === READSIZE);
4340 });
4341 const ended = Promise.withResolvers();
4342 r.on('end', function () {
4343 strictEqual(pushes, PUSHCOUNT + 1);
4344 ended.resolve();
4345 });
4346 let pushes = 0;
4347 function push() {
4348 if (pushes > PUSHCOUNT) return;
4349 if (pushes++ === PUSHCOUNT) {
4350 return r.push(null);
4351 }
4352 if (r.push(Buffer.allocUnsafe(PUSHSIZE))) setTimeout(push, 1);
4353 }
4354 await ended.promise;
4355 },
4356};
4357 
4358export const stream2_decode_partial = {
4359 async test(ctrl, env, ctx) {
4360 let buf = '';
4361 const euro = Buffer.from([0xe2, 0x82, 0xac]);
4362 const cent = Buffer.from([0xc2, 0xa2]);
4363 const source = Buffer.concat([euro, cent]);
4364 const readable = Readable({
4365 encoding: 'utf8',
4366 });
4367 readable.push(source.slice(0, 2));
4368 readable.push(source.slice(2, 4));
4369 readable.push(source.slice(4, 6));
4370 readable.push(null);
4371 readable.on('data', function (data) {
4372 buf += data;
4373 });
4374 const closed = Promise.withResolvers();
4375 readable.on('close', closed.resolve);
4376 await closed.promise;
4377 
4378 strictEqual(buf, 'โ‚ฌยข');
4379 },
4380};
4381 
4382export const stream2_compatibility = {
4383 async test(ctrl, env, ctx) {
4384 let ondataCalled = 0;
4385 class TestReader extends Readable {
4386 constructor() {
4387 super();
4388 this._buffer = Buffer.alloc(100, 'x');
4389 this.on('data', () => {
4390 ondataCalled++;
4391 });
4392 }
4393 _read(n) {
4394 this.push(this._buffer);
4395 this._buffer = Buffer.alloc(0);
4396 }
4397 }
4398 const reader = new TestReader();
4399 queueMicrotask(function () {
4400 strictEqual(ondataCalled, 1);
4401 reader.push(null);
4402 });
4403 class TestWriter extends Writable {
4404 constructor() {
4405 super();
4406 this.write('foo');
4407 this.end();
4408 }
4409 _write(chunk, enc, cb) {
4410 cb();
4411 }
4412 }
4413 const writer = new TestWriter();
4414 
4415 const readerClose = Promise.withResolvers();
4416 const writerClose = Promise.withResolvers();
4417 reader.on('close', readerClose.resolve);
4418 writer.on('close', writerClose.resolve);
4419 
4420 await Promise.all([readerClose.promise, writerClose.promise]);
4421 
4422 strictEqual(reader.readable, false);
4423 strictEqual(writer.writable, false);
4424 },
4425};
4426 
4427export const stream2_basic = {
4428 async test(ctrl, env, ctx) {
4429 class TestReader extends Readable {
4430 constructor(n) {
4431 super();
4432 this._buffer = Buffer.alloc(n || 100, 'x');
4433 this._pos = 0;
4434 this._bufs = 10;
4435 }
4436 _read(n) {
4437 const max = this._buffer.length - this._pos;
4438 n = Math.max(n, 0);
4439 const toRead = Math.min(n, max);
4440 if (toRead === 0) {
4441 // Simulate the read buffer filling up with some more bytes some time
4442 // in the future.
4443 setTimeout(() => {
4444 this._pos = 0;
4445 this._bufs -= 1;
4446 if (this._bufs <= 0) {
4447 // read them all!
4448 if (!this.ended) this.push(null);
4449 } else {
4450 // now we have more.
4451 // kinda cheating by calling _read, but whatever,
4452 // it's just fake anyway.
4453 this._read(n);
4454 }
4455 }, 10);
4456 return;
4457 }
4458 const ret = this._buffer.slice(this._pos, this._pos + toRead);
4459 this._pos += toRead;
4460 this.push(ret);
4461 }
4462 }
4463 
4464 class TestWriter extends EventEmitter {
4465 constructor() {
4466 super();
4467 this.received = [];
4468 this.flush = false;
4469 }
4470 write(c) {
4471 this.received.push(c.toString());
4472 this.emit('write', c);
4473 return true;
4474 }
4475 end(c) {
4476 if (c) this.write(c);
4477 this.emit('end', this.received);
4478 }
4479 }
4480 
4481 {
4482 // Test basic functionality
4483 const r = new TestReader(20);
4484 const reads = [];
4485 const expect = [
4486 'x',
4487 'xx',
4488 'xxx',
4489 'xxxx',
4490 'xxxxx',
4491 'xxxxxxxxx',
4492 'xxxxxxxxxx',
4493 'xxxxxxxxxxxx',
4494 'xxxxxxxxxxxxx',
4495 'xxxxxxxxxxxxxxx',
4496 'xxxxxxxxxxxxxxxxx',
4497 'xxxxxxxxxxxxxxxxxxx',
4498 'xxxxxxxxxxxxxxxxxxxxx',
4499 'xxxxxxxxxxxxxxxxxxxxxxx',
4500 'xxxxxxxxxxxxxxxxxxxxxxxxx',
4501 'xxxxxxxxxxxxxxxxxxxxx',
4502 ];
4503 r.on('end', function () {
4504 deepStrictEqual(reads, expect);
4505 });
4506 let readSize = 1;
4507 function flow() {
4508 let res;
4509 while (null !== (res = r.read(readSize++))) {
4510 reads.push(res.toString());
4511 }
4512 r.once('readable', flow);
4513 }
4514 flow();
4515 
4516 await promises.finished(r);
4517 }
4518 {
4519 // Verify pipe
4520 const r = new TestReader(5);
4521 const expect = [
4522 'xxxxx',
4523 'xxxxx',
4524 'xxxxx',
4525 'xxxxx',
4526 'xxxxx',
4527 'xxxxx',
4528 'xxxxx',
4529 'xxxxx',
4530 'xxxxx',
4531 'xxxxx',
4532 ];
4533 const w = new TestWriter();
4534 w.on('end', function (received) {
4535 deepStrictEqual(received, expect);
4536 });
4537 r.pipe(w);
4538 await promises.finished(r);
4539 }
4540 await Promise.all(
4541 [1, 2, 3, 4, 5, 6, 7, 8, 9].map(async function (SPLIT) {
4542 // Verify unpipe
4543 const r = new TestReader(5);
4544 
4545 // Unpipe after 3 writes, then write to another stream instead.
4546 let expect = [
4547 'xxxxx',
4548 'xxxxx',
4549 'xxxxx',
4550 'xxxxx',
4551 'xxxxx',
4552 'xxxxx',
4553 'xxxxx',
4554 'xxxxx',
4555 'xxxxx',
4556 'xxxxx',
4557 ];
4558 expect = [expect.slice(0, SPLIT), expect.slice(SPLIT)];
4559 const w = [new TestWriter(), new TestWriter()];
4560 let writes = SPLIT;
4561 w[0].on('write', function () {
4562 if (--writes === 0) {
4563 r.unpipe();
4564 deepStrictEqual(r._readableState.pipes, []);
4565 w[0].end();
4566 r.pipe(w[1]);
4567 deepStrictEqual(r._readableState.pipes, [w[1]]);
4568 }
4569 });
4570 let ended = 0;
4571 w[0].on('end', function (results) {
4572 ended++;
4573 strictEqual(ended, 1);
4574 deepStrictEqual(results, expect[0]);
4575 });
4576 w[1].on('end', function (results) {
4577 ended++;
4578 strictEqual(ended, 2);
4579 deepStrictEqual(results, expect[1]);
4580 });
4581 r.pipe(w[0]);
4582 await promises.finished(r);
4583 })
4584 );
4585 {
4586 // Verify both writers get the same data when piping to destinations
4587 const r = new TestReader(5);
4588 const w = [new TestWriter(), new TestWriter()];
4589 const expect = [
4590 'xxxxx',
4591 'xxxxx',
4592 'xxxxx',
4593 'xxxxx',
4594 'xxxxx',
4595 'xxxxx',
4596 'xxxxx',
4597 'xxxxx',
4598 'xxxxx',
4599 'xxxxx',
4600 ];
4601 w[0].on('end', function (received) {
4602 deepStrictEqual(received, expect);
4603 });
4604 w[1].on('end', function (received) {
4605 deepStrictEqual(received, expect);
4606 });
4607 r.pipe(w[0]);
4608 r.pipe(w[1]);
4609 await promises.finished(r);
4610 }
4611 await Promise.all(
4612 [1, 2, 3, 4, 5, 6, 7, 8, 9].map(async function (SPLIT) {
4613 // Verify multi-unpipe
4614 const r = new TestReader(5);
4615 
4616 // Unpipe after 3 writes, then write to another stream instead.
4617 let expect = [
4618 'xxxxx',
4619 'xxxxx',
4620 'xxxxx',
4621 'xxxxx',
4622 'xxxxx',
4623 'xxxxx',
4624 'xxxxx',
4625 'xxxxx',
4626 'xxxxx',
4627 'xxxxx',
4628 ];
4629 expect = [expect.slice(0, SPLIT), expect.slice(SPLIT)];
4630 const w = [new TestWriter(), new TestWriter(), new TestWriter()];
4631 let writes = SPLIT;
4632 w[0].on('write', function () {
4633 if (--writes === 0) {
4634 r.unpipe();
4635 w[0].end();
4636 r.pipe(w[1]);
4637 }
4638 });
4639 let ended = 0;
4640 w[0].on('end', function (results) {
4641 ended++;
4642 strictEqual(ended, 1);
4643 deepStrictEqual(results, expect[0]);
4644 });
4645 w[1].on('end', function (results) {
4646 ended++;
4647 strictEqual(ended, 2);
4648 deepStrictEqual(results, expect[1]);
4649 });
4650 r.pipe(w[0]);
4651 r.pipe(w[2]);
4652 await promises.finished(r);
4653 })
4654 );
4655 {
4656 // Verify that back pressure is respected
4657 const r = new Readable({
4658 objectMode: true,
4659 });
4660 r._read = () => {
4661 throw new Error('should not have been called');
4662 };
4663 let counter = 0;
4664 r.push(['one']);
4665 r.push(['two']);
4666 r.push(['three']);
4667 r.push(['four']);
4668 r.push(null);
4669 const w1 = new Readable();
4670 w1.write = function (chunk) {
4671 strictEqual(chunk[0], 'one');
4672 w1.emit('close');
4673 queueMicrotask(function () {
4674 r.pipe(w2);
4675 r.pipe(w3);
4676 });
4677 };
4678 w1.end = () => {
4679 throw new Error('should not have been called');
4680 };
4681 r.pipe(w1);
4682 const expected = ['two', 'two', 'three', 'three', 'four', 'four'];
4683 const w2 = new Readable();
4684 w2.write = function (chunk) {
4685 strictEqual(chunk[0], expected.shift());
4686 strictEqual(counter, 0);
4687 counter++;
4688 if (chunk[0] === 'four') {
4689 return true;
4690 }
4691 setTimeout(function () {
4692 counter--;
4693 w2.emit('drain');
4694 }, 10);
4695 return false;
4696 };
4697 const ended2 = Promise.withResolvers();
4698 w2.end = ended2.resolve;
4699 const w3 = new Readable();
4700 w3.write = function (chunk) {
4701 strictEqual(chunk[0], expected.shift());
4702 strictEqual(counter, 1);
4703 counter++;
4704 if (chunk[0] === 'four') {
4705 return true;
4706 }
4707 setTimeout(function () {
4708 counter--;
4709 w3.emit('drain');
4710 }, 50);
4711 return false;
4712 };
4713 const ended3 = Promise.withResolvers();
4714 w3.end = function () {
4715 strictEqual(counter, 2);
4716 strictEqual(expected.length, 0);
4717 ended3.resolve();
4718 };
4719 await Promise.all([ended2.promise, ended3.promise]);
4720 }
4721 {
4722 // Verify read(0) behavior for ended streams
4723 const r = new Readable();
4724 let written = false;
4725 let ended = false;
4726 r._read = () => {
4727 throw new Error('should not have been called');
4728 };
4729 r.push(Buffer.from('foo'));
4730 r.push(null);
4731 const v = r.read(0);
4732 strictEqual(v, null);
4733 const w = new Readable();
4734 const writeCalled = Promise.withResolvers();
4735 w.write = function (buffer) {
4736 written = true;
4737 strictEqual(ended, false);
4738 strictEqual(buffer.toString(), 'foo');
4739 writeCalled.resolve();
4740 };
4741 const endCalled = Promise.withResolvers();
4742 w.end = function () {
4743 ended = true;
4744 strictEqual(written, true);
4745 endCalled.resolve();
4746 };
4747 r.pipe(w);
4748 await Promise.all([endCalled.promise, writeCalled.promise]);
4749 }
4750 {
4751 // Verify synchronous _read ending
4752 const r = new Readable();
4753 let called = false;
4754 r._read = function (n) {
4755 r.push(null);
4756 };
4757 r.once('end', function () {
4758 // Verify that this is called before the next tick
4759 called = true;
4760 });
4761 r.read();
4762 queueMicrotask(function () {
4763 strictEqual(called, true);
4764 });
4765 }
4766 {
4767 // Verify that adding readable listeners trigger data flow
4768 const r = new Readable({
4769 highWaterMark: 5,
4770 });
4771 let onReadable = false;
4772 let readCalled = 0;
4773 r._read = function (n) {
4774 if (readCalled++ === 2) r.push(null);
4775 else r.push(Buffer.from('asdf'));
4776 };
4777 r.on('readable', function () {
4778 onReadable = true;
4779 r.read();
4780 });
4781 const endCalled = Promise.withResolvers();
4782 r.on('end', function () {
4783 strictEqual(readCalled, 3);
4784 ok(onReadable);
4785 endCalled.resolve();
4786 });
4787 await endCalled.promise;
4788 }
4789 {
4790 // Verify that streams are chainable
4791 const r = new Readable();
4792 const readCalled = Promise.withResolvers();
4793 r._read = readCalled.resolve;
4794 const r2 = r.setEncoding('utf8').pause().resume().pause();
4795 strictEqual(r, r2);
4796 await readCalled.promise;
4797 }
4798 {
4799 // Verify readableEncoding property
4800 ok(Reflect.has(Readable.prototype, 'readableEncoding'));
4801 const r = new Readable({
4802 encoding: 'utf8',
4803 });
4804 strictEqual(r.readableEncoding, 'utf8');
4805 }
4806 {
4807 // Verify readableObjectMode property
4808 ok(Reflect.has(Readable.prototype, 'readableObjectMode'));
4809 const r = new Readable({
4810 objectMode: true,
4811 });
4812 strictEqual(r.readableObjectMode, true);
4813 }
4814 {
4815 // Verify writableObjectMode property
4816 ok(Reflect.has(Writable.prototype, 'writableObjectMode'));
4817 const w = new Writable({
4818 objectMode: true,
4819 });
4820 strictEqual(w.writableObjectMode, true);
4821 }
4822 },
4823};
4824 
4825export const stream2_base64_single_char_read_end = {
4826 async test(ctrl, env, ctx) {
4827 const src = new Readable({
4828 encoding: 'base64',
4829 });
4830 const dst = new Writable();
4831 let hasRead = false;
4832 const accum = [];
4833 src._read = function (n) {
4834 if (!hasRead) {
4835 hasRead = true;
4836 queueMicrotask(function () {
4837 src.push(Buffer.from('1'));
4838 src.push(null);
4839 });
4840 }
4841 };
4842 dst._write = function (chunk, enc, cb) {
4843 accum.push(chunk);
4844 cb();
4845 };
4846 src.on('end', function () {
4847 strictEqual(String(Buffer.concat(accum)), 'MQ==');
4848 clearTimeout(timeout);
4849 });
4850 src.pipe(dst);
4851 const timeout = setTimeout(function () {
4852 fail('timed out waiting for _write');
4853 }, 100);
4854 },
4855};
4856 
4857export const writev = {
4858 async test(ctrl, env, ctx) {
4859 const queue = [];
4860 for (let decode = 0; decode < 2; decode++) {
4861 for (let uncork = 0; uncork < 2; uncork++) {
4862 for (let multi = 0; multi < 2; multi++) {
4863 queue.push([!!decode, !!uncork, !!multi]);
4864 }
4865 }
4866 }
4867 run();
4868 function run() {
4869 const t = queue.pop();
4870 if (t) test(t[0], t[1], t[2], run);
4871 }
4872 function test(decode, uncork, multi, next) {
4873 let counter = 0;
4874 let expectCount = 0;
4875 function cnt(msg) {
4876 expectCount++;
4877 const expect = expectCount;
4878 return function (er) {
4879 ifError(er);
4880 counter++;
4881 strictEqual(counter, expect);
4882 };
4883 }
4884 const w = new Writable({
4885 decodeStrings: decode,
4886 });
4887 w._write = () => {
4888 throw new Error('Should not call _write');
4889 };
4890 const expectChunks = decode
4891 ? [
4892 {
4893 encoding: 'buffer',
4894 chunk: [104, 101, 108, 108, 111, 44, 32],
4895 },
4896 {
4897 encoding: 'buffer',
4898 chunk: [119, 111, 114, 108, 100],
4899 },
4900 {
4901 encoding: 'buffer',
4902 chunk: [33],
4903 },
4904 {
4905 encoding: 'buffer',
4906 chunk: [10, 97, 110, 100, 32, 116, 104, 101, 110, 46, 46, 46],
4907 },
4908 {
4909 encoding: 'buffer',
4910 chunk: [
4911 250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173,
4912 ],
4913 },
4914 ]
4915 : [
4916 {
4917 encoding: 'ascii',
4918 chunk: 'hello, ',
4919 },
4920 {
4921 encoding: 'utf8',
4922 chunk: 'world',
4923 },
4924 {
4925 encoding: 'buffer',
4926 chunk: [33],
4927 },
4928 {
4929 encoding: 'latin1',
4930 chunk: '\nand then...',
4931 },
4932 {
4933 encoding: 'hex',
4934 chunk: 'facebea7deadbeefdecafbad',
4935 },
4936 ];
4937 let actualChunks;
4938 w._writev = function (chunks, cb) {
4939 actualChunks = chunks.map(function (chunk) {
4940 return {
4941 encoding: chunk.encoding,
4942 chunk: Buffer.isBuffer(chunk.chunk)
4943 ? Array.prototype.slice.call(chunk.chunk)
4944 : chunk.chunk,
4945 };
4946 });
4947 cb();
4948 };
4949 w.cork();
4950 w.write('hello, ', 'ascii', cnt('hello'));
4951 w.write('world', 'utf8', cnt('world'));
4952 if (multi) w.cork();
4953 w.write(Buffer.from('!'), 'buffer', cnt('!'));
4954 w.write('\nand then...', 'latin1', cnt('and then'));
4955 if (multi) w.uncork();
4956 w.write('facebea7deadbeefdecafbad', 'hex', cnt('hex'));
4957 if (uncork) w.uncork();
4958 w.end(cnt('end'));
4959 w.on('finish', function () {
4960 // Make sure finish comes after all the write cb
4961 cnt('finish')();
4962 deepStrictEqual(actualChunks, expectChunks);
4963 next();
4964 });
4965 }
4966 {
4967 const writeCalled = Promise.withResolvers();
4968 const writeFinished = Promise.withResolvers();
4969 const w = new Writable({
4970 writev: function (chunks, cb) {
4971 cb();
4972 writeCalled.resolve();
4973 },
4974 });
4975 w.write('asd', writeFinished.resolve);
4976 await Promise.all([writeCalled.promise, writeFinished.promise]);
4977 }
4978 },
4979};
4980 
4981export const writeFinal = {
4982 async test(ctrl, env, ctx) {
4983 const finalCalled = Promise.withResolvers();
4984 const finishCalled = Promise.withResolvers();
4985 let shutdown = false;
4986 const w = new Writable({
4987 final: function (cb) {
4988 strictEqual(this, w);
4989 setTimeout(function () {
4990 shutdown = true;
4991 cb();
4992 finalCalled.resolve();
4993 }, 100);
4994 },
4995 write: function (chunk, e, cb) {
4996 queueMicrotask(cb);
4997 },
4998 });
4999 w.on('finish', function () {
5000 ok(shutdown);
5001 finishCalled.resolve();
5002 });
5003 w.write(Buffer.allocUnsafe(1));
5004 w.end(Buffer.allocUnsafe(0));
5005 await Promise.all([finalCalled.promise, finishCalled.promise]);
5006 },
5007};
5008 
5009export const writeDrain = {
5010 async test(ctrl, env, ctx) {
5011 const w = new Writable({
5012 write(data, enc, cb) {
5013 queueMicrotask(cb);
5014 },
5015 highWaterMark: 1,
5016 });
5017 w.on('drain', () => {
5018 throw new Error('should not be called');
5019 });
5020 w.write('asd');
5021 w.end();
5022 },
5023};
5024 
5025export const writeDestroy = {
5026 async test(ctrl, env, ctx) {
5027 for (const withPendingData of [false, true]) {
5028 for (const useEnd of [false, true]) {
5029 const callbacks = [];
5030 const w = new Writable({
5031 write(data, enc, cb) {
5032 callbacks.push(cb);
5033 },
5034 // Effectively disable the HWM to observe 'drain' events more easily.
5035 highWaterMark: 1,
5036 });
5037 let chunksWritten = 0;
5038 let drains = 0;
5039 w.on('drain', () => drains++);
5040 function onWrite(err) {
5041 if (err) {
5042 strictEqual(w.destroyed, true);
5043 strictEqual(err.code, 'ERR_STREAM_DESTROYED');
5044 } else {
5045 chunksWritten++;
5046 }
5047 }
5048 w.write('abc', onWrite);
5049 strictEqual(chunksWritten, 0);
5050 strictEqual(drains, 0);
5051 callbacks.shift()();
5052 strictEqual(chunksWritten, 1);
5053 strictEqual(drains, 1);
5054 if (withPendingData) {
5055 // Test 2 cases: There either is or is not data still in the write queue.
5056 // (The second write will never actually get executed either way.)
5057 w.write('def', onWrite);
5058 }
5059 if (useEnd) {
5060 // Again, test 2 cases: Either we indicate that we want to end the
5061 // writable or not.
5062 w.end('ghi', onWrite);
5063 } else {
5064 w.write('ghi', onWrite);
5065 }
5066 strictEqual(chunksWritten, 1);
5067 w.destroy();
5068 strictEqual(chunksWritten, 1);
5069 callbacks.shift()();
5070 strictEqual(chunksWritten, useEnd && !withPendingData ? 1 : 2);
5071 strictEqual(callbacks.length, 0);
5072 strictEqual(drains, 1);
5073 }
5074 }
5075 },
5076};
5077 
5078export const writableState_uncorked_bufferedRequestCount = {
5079 async test(ctrl, env, ctx) {
5080 const writable = new Writable();
5081 const writevCalled = Promise.withResolvers();
5082 const writeCalled = Promise.withResolvers();
5083 writable._writev = (chunks, cb) => {
5084 strictEqual(chunks.length, 2);
5085 cb();
5086 writevCalled.resolve();
5087 };
5088 writable._write = (chunk, encoding, cb) => {
5089 cb();
5090 writeCalled.resolve();
5091 };
5092 
5093 // first cork
5094 writable.cork();
5095 strictEqual(writable._writableState.corked, 1);
5096 strictEqual(writable._writableState.bufferedRequestCount, 0);
5097 
5098 // cork again
5099 writable.cork();
5100 strictEqual(writable._writableState.corked, 2);
5101 
5102 // The first chunk is buffered
5103 writable.write('first chunk');
5104 strictEqual(writable._writableState.bufferedRequestCount, 1);
5105 
5106 // First uncork does nothing
5107 writable.uncork();
5108 strictEqual(writable._writableState.corked, 1);
5109 strictEqual(writable._writableState.bufferedRequestCount, 1);
5110 queueMicrotask(uncork);
5111 
5112 // The second chunk is buffered, because we uncork at the end of tick
5113 writable.write('second chunk');
5114 strictEqual(writable._writableState.corked, 1);
5115 strictEqual(writable._writableState.bufferedRequestCount, 2);
5116 const uncorkCalled = Promise.withResolvers();
5117 function uncork() {
5118 // Second uncork flushes the buffer
5119 writable.uncork();
5120 strictEqual(writable._writableState.corked, 0);
5121 strictEqual(writable._writableState.bufferedRequestCount, 0);
5122 
5123 // Verify that end() uncorks correctly
5124 writable.cork();
5125 writable.write('third chunk');
5126 writable.end();
5127 
5128 // End causes an uncork() as well
5129 strictEqual(writable._writableState.corked, 0);
5130 strictEqual(writable._writableState.bufferedRequestCount, 0);
5131 uncorkCalled.resolve();
5132 }
5133 
5134 await Promise.all([
5135 writevCalled.promise,
5136 writeCalled.promise,
5137 uncorkCalled.promise,
5138 ]);
5139 },
5140};
5141 
5142export const writeableState_ending = {
5143 async test(ctrl, env, ctx) {
5144 const writable = new Writable();
5145 function testStates(ending, finished, ended) {
5146 strictEqual(writable._writableState.ending, ending);
5147 strictEqual(writable._writableState.finished, finished);
5148 strictEqual(writable._writableState.ended, ended);
5149 }
5150 writable._write = (chunk, encoding, cb) => {
5151 // Ending, finished, ended start in false.
5152 testStates(false, false, false);
5153 cb();
5154 };
5155 writable.on('finish', () => {
5156 // Ending, finished, ended = true.
5157 testStates(true, true, true);
5158 });
5159 const result = writable.end('testing function end()', () => {
5160 // Ending, finished, ended = true.
5161 testStates(true, true, true);
5162 });
5163 
5164 // End returns the writable instance
5165 strictEqual(result, writable);
5166 
5167 // Ending, ended = true.
5168 // finished = false.
5169 testStates(true, false, true);
5170 },
5171};
5172 
5173export const writable_write_writev_finish = {
5174 async test(ctrl, env, ctx) {
5175 {
5176 const writable = new Writable();
5177 const errored = Promise.withResolvers();
5178 writable._write = (chunks, encoding, cb) => {
5179 cb(new Error('write test error'));
5180 };
5181 writable.on('finish', errored.reject);
5182 writable.on('prefinish', errored.reject);
5183 writable.on('error', (er) => {
5184 strictEqual(er.message, 'write test error');
5185 errored.resolve();
5186 });
5187 writable.end('test');
5188 await errored.promise;
5189 }
5190 {
5191 const writable = new Writable();
5192 const errored = Promise.withResolvers();
5193 writable._write = (chunks, encoding, cb) => {
5194 queueMicrotask(() => cb(new Error('write test error')));
5195 };
5196 writable.on('finish', errored.reject);
5197 writable.on('prefinish', errored.reject);
5198 writable.on('error', (er) => {
5199 strictEqual(er.message, 'write test error');
5200 errored.resolve();
5201 });
5202 writable.end('test');
5203 await errored.promise;
5204 }
5205 {
5206 const writable = new Writable();
5207 const errored = Promise.withResolvers();
5208 writable._write = (chunks, encoding, cb) => {
5209 cb(new Error('write test error'));
5210 };
5211 writable._writev = (chunks, cb) => {
5212 cb(new Error('writev test error'));
5213 };
5214 writable.on('finish', errored.reject);
5215 writable.on('prefinish', errored.reject);
5216 writable.on('error', (er) => {
5217 strictEqual(er.message, 'writev test error');
5218 errored.resolve();
5219 });
5220 writable.cork();
5221 writable.write('test');
5222 queueMicrotask(function () {
5223 writable.end('test');
5224 });
5225 await errored.promise;
5226 }
5227 {
5228 const writable = new Writable();
5229 const errored = Promise.withResolvers();
5230 writable._write = (chunks, encoding, cb) => {
5231 queueMicrotask(() => cb(new Error('write test error')));
5232 };
5233 writable._writev = (chunks, cb) => {
5234 queueMicrotask(() => cb(new Error('writev test error')));
5235 };
5236 writable.on('finish', errored.reject);
5237 writable.on('prefinish', errored.reject);
5238 writable.on('error', (er) => {
5239 strictEqual(er.message, 'writev test error');
5240 errored.resolve();
5241 });
5242 writable.cork();
5243 writable.write('test');
5244 queueMicrotask(function () {
5245 writable.end('test');
5246 });
5247 await errored.promise;
5248 }
5249 
5250 // Regression test for
5251 // https://github.com/nodejs/node/issues/13812
5252 
5253 {
5254 const rs = new Readable();
5255 rs.push('ok');
5256 rs.push(null);
5257 rs._read = () => {};
5258 const ws = new Writable();
5259 const errored = Promise.withResolvers();
5260 ws.on('finish', errored.reject);
5261 ws.on('error', errored.resolve);
5262 ws._write = (chunk, encoding, done) => {
5263 queueMicrotask(() => done(new Error()));
5264 };
5265 rs.pipe(ws);
5266 await errored.promise;
5267 }
5268 {
5269 const rs = new Readable();
5270 rs.push('ok');
5271 rs.push(null);
5272 rs._read = () => {};
5273 const ws = new Writable();
5274 const errored = Promise.withResolvers();
5275 ws.on('finish', errored.reject);
5276 ws.on('error', errored.resolve);
5277 ws._write = (chunk, encoding, done) => {
5278 done(new Error());
5279 };
5280 rs.pipe(ws);
5281 await errored.promise;
5282 }
5283 {
5284 const w = new Writable();
5285 w._write = (chunk, encoding, cb) => {
5286 queueMicrotask(cb);
5287 };
5288 const errored = Promise.withResolvers();
5289 w.on('error', errored.resolve);
5290 w.on('finish', errored.reject);
5291 w.on('prefinish', () => {
5292 w.write("shouldn't write in prefinish listener");
5293 });
5294 w.end();
5295 await errored.promise;
5296 }
5297 {
5298 const w = new Writable();
5299 w._write = (chunk, encoding, cb) => {
5300 queueMicrotask(cb);
5301 };
5302 const errored = Promise.withResolvers();
5303 w.on('error', errored.resolve);
5304 w.on('finish', () => {
5305 w.write("shouldn't write in finish listener");
5306 });
5307 w.end();
5308 await errored.promise;
5309 }
5310 },
5311};
5312 
5313export const writable_write_error = {
5314 async test(ctrl, env, ctx) {
5315 async function expectError(w, args, code, sync) {
5316 if (sync) {
5317 if (code) {
5318 throws(() => w.write(...args), {
5319 code,
5320 });
5321 } else {
5322 w.write(...args);
5323 }
5324 } else {
5325 let ticked = false;
5326 const writeCalled = Promise.withResolvers();
5327 const errorCalled = Promise.withResolvers();
5328 w.write(...args, (err) => {
5329 strictEqual(ticked, true);
5330 strictEqual(err.code, code);
5331 writeCalled.resolve();
5332 });
5333 ticked = true;
5334 w.on('error', (err) => {
5335 strictEqual(err.code, code);
5336 errorCalled.resolve();
5337 });
5338 await Promise.all([writeCalled.promise, errorCalled.promise]);
5339 }
5340 }
5341 async function test(autoDestroy) {
5342 {
5343 const w = new Writable({
5344 autoDestroy,
5345 _write() {},
5346 });
5347 w.end();
5348 await expectError(w, ['asd'], 'ERR_STREAM_WRITE_AFTER_END');
5349 }
5350 {
5351 const w = new Writable({
5352 autoDestroy,
5353 _write() {},
5354 });
5355 w.destroy();
5356 }
5357 {
5358 const w = new Writable({
5359 autoDestroy,
5360 _write() {},
5361 });
5362 await expectError(w, [null], 'ERR_STREAM_NULL_VALUES', true);
5363 }
5364 {
5365 const w = new Writable({
5366 autoDestroy,
5367 _write() {},
5368 });
5369 await expectError(w, [{}], 'ERR_INVALID_ARG_TYPE', true);
5370 }
5371 {
5372 const w = new Writable({
5373 decodeStrings: false,
5374 autoDestroy,
5375 _write() {},
5376 });
5377 await expectError(
5378 w,
5379 ['asd', 'noencoding'],
5380 'ERR_UNKNOWN_ENCODING',
5381 true
5382 );
5383 }
5384 }
5385 await test(false);
5386 await test(true);
5387 },
5388};
5389 
5390export const writable_write_cb_twice = {
5391 async test(ctrl, env, ctx) {
5392 {
5393 // Sync + Sync
5394 const writeCalled = Promise.withResolvers();
5395 const errored = Promise.withResolvers();
5396 const writable = new Writable({
5397 write: (buf, enc, cb) => {
5398 cb();
5399 cb();
5400 writeCalled.resolve();
5401 },
5402 });
5403 writable.write('hi');
5404 writable.on('error', function (err) {
5405 strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK');
5406 errored.resolve();
5407 });
5408 await Promise.all([writeCalled.promise, errored.promise]);
5409 }
5410 {
5411 // Sync + Async
5412 const writeCalled = Promise.withResolvers();
5413 const errored = Promise.withResolvers();
5414 const writable = new Writable({
5415 write: (buf, enc, cb) => {
5416 cb();
5417 queueMicrotask(() => {
5418 cb();
5419 writeCalled.resolve();
5420 });
5421 },
5422 });
5423 writable.write('hi');
5424 writable.on('error', function (err) {
5425 strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK');
5426 errored.resolve();
5427 });
5428 await Promise.all([writeCalled.promise, errored.promise]);
5429 }
5430 {
5431 // Async + Async
5432 const writeCalled = Promise.withResolvers();
5433 const errored = Promise.withResolvers();
5434 const writable = new Writable({
5435 write: (buf, enc, cb) => {
5436 queueMicrotask(cb);
5437 queueMicrotask(() => {
5438 cb();
5439 writeCalled.resolve();
5440 });
5441 },
5442 });
5443 writable.write('hi');
5444 writable.on('error', function (err) {
5445 strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK');
5446 errored.resolve();
5447 });
5448 await Promise.all([writeCalled.promise, errored.promise]);
5449 }
5450 },
5451};
5452 
5453export const writable_write_cb_error = {
5454 async test(ctrl, env, ctx) {
5455 {
5456 let callbackCalled = false;
5457 // Sync Error
5458 const writeCalled = Promise.withResolvers();
5459 const errored = Promise.withResolvers();
5460 const writeFinished = Promise.withResolvers();
5461 const writable = new Writable({
5462 write: (buf, enc, cb) => {
5463 cb(new Error());
5464 writeCalled.resolve();
5465 },
5466 });
5467 writable.on('error', () => {
5468 strictEqual(callbackCalled, true);
5469 errored.resolve();
5470 });
5471 writable.write('hi', () => {
5472 callbackCalled = true;
5473 writeFinished.resolve();
5474 });
5475 await Promise.all([
5476 writeCalled.promise,
5477 errored.promise,
5478 writeFinished.promise,
5479 ]);
5480 }
5481 {
5482 let callbackCalled = false;
5483 // Async Error
5484 const writeCalled = Promise.withResolvers();
5485 const errored = Promise.withResolvers();
5486 const writeFinished = Promise.withResolvers();
5487 const writable = new Writable({
5488 write: (buf, enc, cb) => {
5489 queueMicrotask(() => cb(new Error()));
5490 writeCalled.resolve();
5491 },
5492 });
5493 writable.on('error', () => {
5494 strictEqual(callbackCalled, true);
5495 errored.resolve();
5496 });
5497 writable.write('hi', () => {
5498 callbackCalled = true;
5499 writeFinished.resolve();
5500 });
5501 await Promise.all([
5502 writeCalled.promise,
5503 errored.promise,
5504 writeFinished.promise,
5505 ]);
5506 }
5507 {
5508 // Sync Error
5509 const errored = Promise.withResolvers();
5510 const writeCalled = Promise.withResolvers();
5511 const writable = new Writable({
5512 write: (buf, enc, cb) => {
5513 cb(new Error());
5514 writeCalled.resolve();
5515 },
5516 });
5517 writable.on('error', errored.resolve);
5518 let cnt = 0;
5519 // Ensure we don't live lock on sync error
5520 while (writable.write('a')) cnt++;
5521 strictEqual(cnt, 0);
5522 await Promise.all([writeCalled.promise, errored.promise]);
5523 }
5524 },
5525};
5526 
5527export const writable_writable = {
5528 async test(ctrl, env, ctx) {
5529 {
5530 const w = new Writable({
5531 write() {},
5532 });
5533 strictEqual(w.writable, true);
5534 w.destroy();
5535 strictEqual(w.writable, false);
5536 }
5537 {
5538 const writeCalled = Promise.withResolvers();
5539 const errored = Promise.withResolvers();
5540 const w = new Writable({
5541 write: (chunk, encoding, callback) => {
5542 callback(new Error());
5543 writeCalled.resolve();
5544 },
5545 });
5546 strictEqual(w.writable, true);
5547 w.write('asd');
5548 strictEqual(w.writable, false);
5549 w.on('error', errored.resolve);
5550 await Promise.all([writeCalled.promise, errored.promise]);
5551 }
5552 {
5553 const writeCalled = Promise.withResolvers();
5554 const errored = Promise.withResolvers();
5555 const w = new Writable({
5556 write: (chunk, encoding, callback) => {
5557 queueMicrotask(() => {
5558 callback(new Error());
5559 strictEqual(w.writable, false);
5560 writeCalled.resolve();
5561 });
5562 },
5563 });
5564 w.write('asd');
5565 w.on('error', errored.resolve);
5566 await Promise.all([writeCalled.promise, errored.promise]);
5567 }
5568 {
5569 const closed = Promise.withResolvers();
5570 const w = new Writable({
5571 write: closed.reject,
5572 });
5573 w.on('close', closed.resolve);
5574 strictEqual(w.writable, true);
5575 w.end();
5576 strictEqual(w.writable, false);
5577 await closed.promise;
5578 }
5579 },
5580};
5581 
5582export const writable_properties = {
5583 test(ctrl, env, ctx) {
5584 {
5585 const w = new Writable();
5586 strictEqual(w.writableCorked, 0);
5587 w.uncork();
5588 strictEqual(w.writableCorked, 0);
5589 w.cork();
5590 strictEqual(w.writableCorked, 1);
5591 w.cork();
5592 strictEqual(w.writableCorked, 2);
5593 w.uncork();
5594 strictEqual(w.writableCorked, 1);
5595 w.uncork();
5596 strictEqual(w.writableCorked, 0);
5597 w.uncork();
5598 strictEqual(w.writableCorked, 0);
5599 }
5600 },
5601};
5602 
5603export const writable_null = {
5604 async test(ctrl, env, ctx) {
5605 class MyWritable extends Writable {
5606 constructor(options) {
5607 super({
5608 autoDestroy: false,
5609 ...options,
5610 });
5611 }
5612 _write(chunk, encoding, callback) {
5613 notStrictEqual(chunk, null);
5614 callback();
5615 }
5616 }
5617 {
5618 const m = new MyWritable({
5619 objectMode: true,
5620 });
5621 m.on('error', () => {
5622 throw new Error('should not be called');
5623 });
5624 throws(
5625 () => {
5626 m.write(null);
5627 },
5628 {
5629 code: 'ERR_STREAM_NULL_VALUES',
5630 }
5631 );
5632 }
5633 {
5634 const m = new MyWritable();
5635 m.on('error', () => {
5636 throw new Error('should not be called');
5637 });
5638 throws(
5639 () => {
5640 m.write(false);
5641 },
5642 {
5643 code: 'ERR_INVALID_ARG_TYPE',
5644 }
5645 );
5646 }
5647 {
5648 // Should not throw.
5649 const m = new MyWritable({
5650 objectMode: true,
5651 });
5652 m.write(false, ifError);
5653 }
5654 {
5655 // Should not throw.
5656 const m = new MyWritable({
5657 objectMode: true,
5658 }).on('error', (e) => {
5659 ifError(e || new Error('should not get here'));
5660 });
5661 m.write(false, ifError);
5662 }
5663 },
5664};
5665 
5666export const writable_needdrain_state = {
5667 async test(ctrl, env, ctx) {
5668 const transform = new Transform({
5669 transform: _transform,
5670 highWaterMark: 1,
5671 });
5672 const transformCalled = Promise.withResolvers();
5673 const writeFinished = Promise.withResolvers();
5674 function _transform(chunk, encoding, cb) {
5675 queueMicrotask(() => {
5676 strictEqual(transform._writableState.needDrain, true);
5677 cb();
5678 transformCalled.resolve();
5679 });
5680 }
5681 strictEqual(transform._writableState.needDrain, false);
5682 transform.write('asdasd', () => {
5683 strictEqual(transform._writableState.needDrain, false);
5684 writeFinished.resolve();
5685 });
5686 strictEqual(transform._writableState.needDrain, true);
5687 await Promise.all([transformCalled.promise, writeFinished.promise]);
5688 },
5689};
5690 
5691export const writable_invalid_chunk = {
5692 test(ctrl, env, ctx) {
5693 function testWriteType(val, objectMode, code) {
5694 const writable = new Writable({
5695 objectMode,
5696 write: () => {},
5697 });
5698 writable.on('error', () => {
5699 throw new Error('should not have been called');
5700 });
5701 if (code) {
5702 throws(
5703 () => {
5704 writable.write(val);
5705 },
5706 {
5707 code,
5708 }
5709 );
5710 } else {
5711 writable.write(val);
5712 }
5713 }
5714 testWriteType([], false, 'ERR_INVALID_ARG_TYPE');
5715 testWriteType({}, false, 'ERR_INVALID_ARG_TYPE');
5716 testWriteType(0, false, 'ERR_INVALID_ARG_TYPE');
5717 testWriteType(true, false, 'ERR_INVALID_ARG_TYPE');
5718 testWriteType(0.0, false, 'ERR_INVALID_ARG_TYPE');
5719 testWriteType(undefined, false, 'ERR_INVALID_ARG_TYPE');
5720 testWriteType(null, false, 'ERR_STREAM_NULL_VALUES');
5721 testWriteType([], true);
5722 testWriteType({}, true);
5723 testWriteType(0, true);
5724 testWriteType(true, true);
5725 testWriteType(0.0, true);
5726 testWriteType(undefined, true);
5727 testWriteType(null, true, 'ERR_STREAM_NULL_VALUES');
5728 },
5729};
5730 
5731export const writable_finished = {
5732 async test(ctrl, env, ctx) {
5733 // basic
5734 {
5735 // Find it on Writable.prototype
5736 ok(Reflect.has(Writable.prototype, 'writableFinished'));
5737 }
5738 
5739 // event
5740 {
5741 const writable = new Writable();
5742 writable._write = (chunk, encoding, cb) => {
5743 // The state finished should start in false.
5744 strictEqual(writable.writableFinished, false);
5745 cb();
5746 };
5747 const finishCalled = Promise.withResolvers();
5748 const endCalled = Promise.withResolvers();
5749 writable.on('finish', () => {
5750 strictEqual(writable.writableFinished, true);
5751 finishCalled.resolve();
5752 });
5753 writable.end('testing finished state', () => {
5754 strictEqual(writable.writableFinished, true);
5755 endCalled.resolve();
5756 });
5757 await Promise.all([finishCalled.promise, endCalled.promise]);
5758 }
5759 {
5760 // Emit finish asynchronously.
5761 
5762 const w = new Writable({
5763 write(chunk, encoding, cb) {
5764 cb();
5765 },
5766 });
5767 w.end();
5768 const finishCalled = Promise.withResolvers();
5769 w.on('finish', finishCalled.resolve);
5770 await finishCalled.promise;
5771 }
5772 {
5773 // Emit prefinish synchronously.
5774 
5775 const w = new Writable({
5776 write(chunk, encoding, cb) {
5777 cb();
5778 },
5779 });
5780 let sync = true;
5781 w.on('prefinish', () => {
5782 strictEqual(sync, true);
5783 });
5784 w.end();
5785 sync = false;
5786 }
5787 {
5788 // Emit prefinish synchronously w/ final.
5789 
5790 const w = new Writable({
5791 write(chunk, encoding, cb) {
5792 cb();
5793 },
5794 final(cb) {
5795 cb();
5796 },
5797 });
5798 let sync = true;
5799 w.on('prefinish', () => {
5800 strictEqual(sync, true);
5801 });
5802 w.end();
5803 sync = false;
5804 }
5805 {
5806 // Call _final synchronously.
5807 
5808 let sync = true;
5809 const w = new Writable({
5810 write(chunk, encoding, cb) {
5811 cb();
5812 },
5813 final: (cb) => {
5814 strictEqual(sync, true);
5815 cb();
5816 },
5817 });
5818 w.end();
5819 sync = false;
5820 }
5821 },
5822};
5823 
5824export const writable_finished_state = {
5825 async test(ctrl, env, ctx) {
5826 const writable = new Writable();
5827 writable._write = (chunk, encoding, cb) => {
5828 // The state finished should start in false.
5829 strictEqual(writable._writableState.finished, false);
5830 cb();
5831 };
5832 const finishCalled = Promise.withResolvers();
5833 const endCalled = Promise.withResolvers();
5834 writable.on('finish', () => {
5835 strictEqual(writable._writableState.finished, true);
5836 finishCalled.resolve();
5837 });
5838 writable.end('testing finished state', () => {
5839 strictEqual(writable._writableState.finished, true);
5840 endCalled.resolve();
5841 });
5842 await Promise.all([finishCalled.promise, endCalled.promise]);
5843 },
5844};
5845 
5846export const writable_finish_destroyed = {
5847 async test(ctrl, env, ctx) {
5848 {
5849 const writeCalled = Promise.withResolvers();
5850 const closed = Promise.withResolvers();
5851 const w = new Writable({
5852 write: (chunk, encoding, cb) => {
5853 w.on('close', () => {
5854 cb();
5855 writeCalled.resolve();
5856 });
5857 },
5858 });
5859 w.on('close', closed.resolve);
5860 w.on('finish', closed.reject);
5861 w.end('asd');
5862 w.destroy();
5863 await Promise.all([writeCalled.promise, closed.promise]);
5864 }
5865 {
5866 const writeCalled = Promise.withResolvers();
5867 const closed = Promise.withResolvers();
5868 const w = new Writable({
5869 write: (chunk, encoding, cb) => {
5870 w.on('close', () => {
5871 cb();
5872 w.end();
5873 writeCalled.resolve();
5874 });
5875 },
5876 });
5877 w.on('finish', closed.reject);
5878 w.on('close', closed.resolve);
5879 w.write('asd');
5880 w.destroy();
5881 await Promise.all([writeCalled.promise, closed.promise]);
5882 }
5883 {
5884 const w = new Writable({
5885 write() {},
5886 });
5887 const closed = Promise.withResolvers();
5888 w.on('finish', closed.reject);
5889 w.on('close', closed.resolve);
5890 w.end();
5891 w.destroy();
5892 await closed.promise;
5893 }
5894 },
5895};
5896 
5897export const writable_final_throw = {
5898 async test(ctrl, env, ctx) {
5899 class Foo extends Duplex {
5900 _final(callback) {
5901 throw new Error('fhqwhgads');
5902 }
5903 _read() {}
5904 }
5905 const writeCalled = Promise.withResolvers();
5906 const endFinished = Promise.withResolvers();
5907 const errored = Promise.withResolvers();
5908 const foo = new Foo();
5909 foo._write = (chunk, encoding, cb) => {
5910 cb();
5911 writeCalled.resolve();
5912 };
5913 foo.end('test', function (err) {
5914 strictEqual(err.message, 'fhqwhgads');
5915 endFinished.resolve();
5916 });
5917 foo.on('error', errored.resolve);
5918 await Promise.all([
5919 writeCalled.promise,
5920 endFinished.promise,
5921 errored.promise,
5922 ]);
5923 },
5924};
5925 
5926export const writable_final_destroy = {
5927 async test(ctrl, env, ctx) {
5928 const w = new Writable({
5929 write(chunk, encoding, callback) {
5930 callback(null);
5931 },
5932 final(callback) {
5933 queueMicrotask(callback);
5934 },
5935 });
5936 const closed = Promise.withResolvers();
5937 w.end();
5938 w.destroy();
5939 w.on('prefinish', closed.reject);
5940 w.on('finish', closed.reject);
5941 w.on('close', closed.resolve);
5942 await closed.promise;
5943 },
5944};
5945 
5946export const writable_final_async = {
5947 async test(ctrl, env, ctx) {
5948 {
5949 class Foo extends Duplex {
5950 async _final(callback) {
5951 await scheduler.wait(10);
5952 callback();
5953 }
5954 _read() {}
5955 }
5956 const foo = new Foo();
5957 const writeCalled = Promise.withResolvers();
5958 const endCalled = Promise.withResolvers();
5959 foo._write = (chunk, encoding, cb) => {
5960 cb();
5961 writeCalled.resolve();
5962 };
5963 foo.end('test', endCalled.resolve);
5964 foo.on('error', endCalled.reject);
5965 await Promise.all([endCalled.promise, writeCalled.promise]);
5966 }
5967 },
5968};
5969 
5970export const writable_ended_state = {
5971 async test(ctrl, env, ctx) {
5972 const writable = new Writable();
5973 const writeCalled = Promise.withResolvers();
5974 const endCalled = Promise.withResolvers();
5975 writable._write = (chunk, encoding, cb) => {
5976 strictEqual(writable._writableState.ended, false);
5977 strictEqual(writable._writableState.writable, undefined);
5978 strictEqual(writable.writableEnded, false);
5979 cb();
5980 writeCalled.resolve();
5981 };
5982 strictEqual(writable._writableState.ended, false);
5983 strictEqual(writable._writableState.writable, undefined);
5984 strictEqual(writable.writable, true);
5985 strictEqual(writable.writableEnded, false);
5986 writable.end('testing ended state', () => {
5987 strictEqual(writable._writableState.ended, true);
5988 strictEqual(writable._writableState.writable, undefined);
5989 strictEqual(writable.writable, false);
5990 strictEqual(writable.writableEnded, true);
5991 endCalled.resolve();
5992 });
5993 strictEqual(writable._writableState.ended, true);
5994 strictEqual(writable._writableState.writable, undefined);
5995 strictEqual(writable.writable, false);
5996 strictEqual(writable.writableEnded, true);
5997 await Promise.all([writeCalled.promise, endCalled.promise]);
5998 },
5999};
6000 
6001export const writable_end_multiple = {
6002 async test(ctrl, env, ctx) {
6003 const writable = new Writable();
6004 writable._write = (chunk, encoding, cb) => {
6005 setTimeout(() => cb(), 10);
6006 };
6007 const endCalled1 = Promise.withResolvers();
6008 const endCalled2 = Promise.withResolvers();
6009 const finishCalled = Promise.withResolvers();
6010 writable.end('testing ended state', endCalled1.resolve);
6011 writable.end(endCalled2.resolve);
6012 writable.on('finish', () => {
6013 let ticked = false;
6014 writable.end((err) => {
6015 strictEqual(ticked, true);
6016 strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED');
6017 finishCalled.resolve();
6018 });
6019 ticked = true;
6020 });
6021 await Promise.all([
6022 endCalled1.promise,
6023 endCalled2.promise,
6024 finishCalled.promise,
6025 ]);
6026 },
6027};
6028 
6029export const writable_end_cb_error = {
6030 async test(ctrl, env, ctx) {
6031 {
6032 // Invoke end callback on failure.
6033 const writable = new Writable();
6034 const _err = new Error('kaboom');
6035 writable._write = (chunk, encoding, cb) => {
6036 queueMicrotask(() => cb(_err));
6037 };
6038 const errored = Promise.withResolvers();
6039 const endCalled1 = Promise.withResolvers();
6040 const endCalled2 = Promise.withResolvers();
6041 writable.on('error', (err) => {
6042 strictEqual(err, _err);
6043 errored.resolve();
6044 });
6045 writable.write('asd');
6046 writable.end((err) => {
6047 strictEqual(err, _err);
6048 endCalled1.resolve();
6049 });
6050 writable.end((err) => {
6051 strictEqual(err, _err);
6052 endCalled2.resolve();
6053 });
6054 await Promise.all([
6055 errored.promise,
6056 endCalled1.promise,
6057 endCalled2.promise,
6058 ]);
6059 }
6060 {
6061 // Don't invoke end callback twice
6062 const writable = new Writable();
6063 writable._write = (chunk, encoding, cb) => {
6064 queueMicrotask(cb);
6065 };
6066 let called = false;
6067 const endCalled = Promise.withResolvers();
6068 const errored = Promise.withResolvers();
6069 const finishCalled = Promise.withResolvers();
6070 writable.end('asd', (err) => {
6071 called = true;
6072 strictEqual(err, null);
6073 endCalled.resolve();
6074 });
6075 writable.on('error', (err) => {
6076 strictEqual(err.message, 'kaboom');
6077 errored.resolve();
6078 });
6079 writable.on('finish', () => {
6080 strictEqual(called, true);
6081 writable.emit('error', new Error('kaboom'));
6082 finishCalled.resolve();
6083 });
6084 await Promise.all([
6085 endCalled.promise,
6086 errored.promise,
6087 finishCalled.promise,
6088 ]);
6089 }
6090 {
6091 const w = new Writable({
6092 write(chunk, encoding, callback) {
6093 queueMicrotask(callback);
6094 },
6095 finish(callback) {
6096 queueMicrotask(callback);
6097 },
6098 });
6099 const endCalled1 = Promise.withResolvers();
6100 const endCalled2 = Promise.withResolvers();
6101 const endCalled3 = Promise.withResolvers();
6102 const errored = Promise.withResolvers();
6103 w.end('testing ended state', (err) => {
6104 strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
6105 endCalled1.resolve();
6106 });
6107 strictEqual(w.destroyed, false);
6108 strictEqual(w.writableEnded, true);
6109 w.end((err) => {
6110 strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
6111 endCalled2.resolve();
6112 });
6113 strictEqual(w.destroyed, false);
6114 strictEqual(w.writableEnded, true);
6115 w.end('end', (err) => {
6116 strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
6117 endCalled3.resolve();
6118 });
6119 strictEqual(w.destroyed, true);
6120 w.on('error', (err) => {
6121 strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
6122 errored.resolve();
6123 });
6124 w.on('finish', errored.reject);
6125 await Promise.all([
6126 endCalled1.promise,
6127 endCalled2.promise,
6128 endCalled3.promise,
6129 errored.promise,
6130 ]);
6131 }
6132 },
6133};
6134 
6135export const writable_destroy = {
6136 async test(ctrl, env, ctx) {
6137 {
6138 const write = new Writable({
6139 write(chunk, enc, cb) {
6140 cb();
6141 },
6142 });
6143 const closed = Promise.withResolvers();
6144 write.on('finish', closed.reject);
6145 write.on('close', closed.resolve);
6146 write.destroy();
6147 strictEqual(write.destroyed, true);
6148 await closed.promise;
6149 }
6150 {
6151 const write = new Writable({
6152 write(chunk, enc, cb) {
6153 this.destroy(new Error('asd'));
6154 cb();
6155 },
6156 });
6157 const errored = Promise.withResolvers();
6158 write.on('error', errored.resolve);
6159 write.on('finish', errored.reject);
6160 write.end('asd');
6161 strictEqual(write.destroyed, true);
6162 await errored.promise;
6163 }
6164 {
6165 const write = new Writable({
6166 write(chunk, enc, cb) {
6167 cb();
6168 },
6169 });
6170 const expected = new Error('kaboom');
6171 const errored = Promise.withResolvers();
6172 const closed = Promise.withResolvers();
6173 write.on('finish', closed.reject);
6174 write.on('close', closed.resolve);
6175 write.on('error', (err) => {
6176 strictEqual(err, expected);
6177 errored.resolve();
6178 });
6179 write.destroy(expected);
6180 strictEqual(write.destroyed, true);
6181 await Promise.all([errored.promise, closed.promise]);
6182 }
6183 {
6184 const write = new Writable({
6185 write(chunk, enc, cb) {
6186 cb();
6187 },
6188 });
6189 write._destroy = function (err, cb) {
6190 strictEqual(err, expected);
6191 cb(err);
6192 };
6193 const errored = Promise.withResolvers();
6194 const closed = Promise.withResolvers();
6195 const expected = new Error('kaboom');
6196 write.on('finish', closed.reject);
6197 write.on('close', closed.resolve);
6198 write.on('error', (err) => {
6199 strictEqual(err, expected);
6200 errored.resolve();
6201 });
6202 write.destroy(expected);
6203 strictEqual(write.destroyed, true);
6204 await Promise.all([closed.promise, errored.promise]);
6205 }
6206 {
6207 const closed = Promise.withResolvers();
6208 const destroyCalled = Promise.withResolvers();
6209 const write = new Writable({
6210 write(chunk, enc, cb) {
6211 cb();
6212 },
6213 destroy: function (err, cb) {
6214 strictEqual(err, expected);
6215 cb();
6216 destroyCalled.resolve();
6217 },
6218 });
6219 const expected = new Error('kaboom');
6220 write.on('finish', closed.reject);
6221 write.on('close', closed.resolve);
6222 
6223 // Error is swallowed by the custom _destroy
6224 write.on('error', closed.reject);
6225 write.destroy(expected);
6226 strictEqual(write.destroyed, true);
6227 await Promise.all([destroyCalled.promise, closed.promise]);
6228 }
6229 {
6230 const write = new Writable({
6231 write(chunk, enc, cb) {
6232 cb();
6233 },
6234 });
6235 const destroyCalled = Promise.withResolvers();
6236 write._destroy = function (err, cb) {
6237 strictEqual(err, null);
6238 cb();
6239 destroyCalled.resolve();
6240 };
6241 write.destroy();
6242 strictEqual(write.destroyed, true);
6243 await destroyCalled.promise;
6244 }
6245 {
6246 const write = new Writable({
6247 write(chunk, enc, cb) {
6248 cb();
6249 },
6250 });
6251 const destroyCalled = Promise.withResolvers();
6252 const closed = Promise.withResolvers();
6253 write._destroy = function (err, cb) {
6254 strictEqual(err, null);
6255 queueMicrotask(() => {
6256 this.end();
6257 cb();
6258 destroyCalled.resolve();
6259 });
6260 };
6261 write.on('finish', closed.reject);
6262 write.on('close', closed.resolve);
6263 write.destroy();
6264 strictEqual(write.destroyed, true);
6265 await Promise.all([destroyCalled.promise, closed.promise]);
6266 }
6267 {
6268 const write = new Writable({
6269 write(chunk, enc, cb) {
6270 cb();
6271 },
6272 });
6273 const expected = new Error('kaboom');
6274 const destroyCalled = Promise.withResolvers();
6275 const closed = Promise.withResolvers();
6276 const errored = Promise.withResolvers();
6277 write._destroy = function (err, cb) {
6278 strictEqual(err, null);
6279 cb(expected);
6280 destroyCalled.resolve();
6281 };
6282 write.on('close', closed.resolve);
6283 write.on('finish', closed.reject);
6284 write.on('error', (err) => {
6285 strictEqual(err, expected);
6286 errored.resolve();
6287 });
6288 write.destroy();
6289 strictEqual(write.destroyed, true);
6290 await Promise.all([
6291 destroyCalled.promise,
6292 closed.promise,
6293 errored.promise,
6294 ]);
6295 }
6296 {
6297 // double error case
6298 const write = new Writable({
6299 write(chunk, enc, cb) {
6300 cb();
6301 },
6302 });
6303 let ticked = false;
6304 const writeFinished = Promise.withResolvers();
6305 const errored = Promise.withResolvers();
6306 write.on('close', () => {
6307 strictEqual(ticked, true);
6308 writeFinished.resolve();
6309 });
6310 write.on('error', (err) => {
6311 strictEqual(ticked, true);
6312 strictEqual(err.message, 'kaboom 1');
6313 strictEqual(write._writableState.errorEmitted, true);
6314 errored.resolve();
6315 });
6316 const expected = new Error('kaboom 1');
6317 write.destroy(expected);
6318 write.destroy(new Error('kaboom 2'));
6319 strictEqual(write._writableState.errored, expected);
6320 strictEqual(write._writableState.errorEmitted, false);
6321 strictEqual(write.destroyed, true);
6322 ticked = true;
6323 await Promise.all([writeFinished.promise, errored.promise]);
6324 }
6325 {
6326 const writable = new Writable({
6327 destroy: function (err, cb) {
6328 queueMicrotask(() => cb(new Error('kaboom 1')));
6329 },
6330 write(chunk, enc, cb) {
6331 cb();
6332 },
6333 });
6334 let ticked = false;
6335 const closed = Promise.withResolvers();
6336 const errored = Promise.withResolvers();
6337 writable.on('close', () => {
6338 writable.on('error', () => {
6339 throw new Error('should not have been called');
6340 });
6341 writable.destroy(new Error('hello'));
6342 strictEqual(ticked, true);
6343 strictEqual(writable._writableState.errorEmitted, true);
6344 closed.resolve();
6345 });
6346 writable.on('error', (err) => {
6347 strictEqual(ticked, true);
6348 strictEqual(err.message, 'kaboom 1');
6349 strictEqual(writable._writableState.errorEmitted, true);
6350 errored.resolve();
6351 });
6352 writable.destroy();
6353 strictEqual(writable.destroyed, true);
6354 strictEqual(writable._writableState.errored, null);
6355 strictEqual(writable._writableState.errorEmitted, false);
6356 
6357 // Test case where `writable.destroy()` is called again with an error before
6358 // the `_destroy()` callback is called.
6359 writable.destroy(new Error('kaboom 2'));
6360 strictEqual(writable._writableState.errorEmitted, false);
6361 strictEqual(writable._writableState.errored, null);
6362 ticked = true;
6363 
6364 await Promise.all([closed.promise, errored.promise]);
6365 }
6366 {
6367 const write = new Writable({
6368 write(chunk, enc, cb) {
6369 cb();
6370 },
6371 });
6372 write.destroyed = true;
6373 strictEqual(write.destroyed, true);
6374 
6375 // The internal destroy() mechanism should not be triggered
6376 write.on('close', () => {
6377 throw new Error('should not have been called');
6378 });
6379 write.destroy();
6380 }
6381 {
6382 function MyWritable() {
6383 strictEqual(this.destroyed, false);
6384 this.destroyed = false;
6385 Writable.call(this);
6386 }
6387 Object.setPrototypeOf(MyWritable.prototype, Writable.prototype);
6388 Object.setPrototypeOf(MyWritable, Writable);
6389 new MyWritable();
6390 }
6391 {
6392 // Destroy and destroy callback
6393 const write = new Writable({
6394 write(chunk, enc, cb) {
6395 cb();
6396 },
6397 });
6398 write.destroy();
6399 const expected = new Error('kaboom');
6400 const destroyed = Promise.withResolvers();
6401 write.destroy(expected, (err) => {
6402 strictEqual(err, undefined);
6403 destroyed.resolve();
6404 });
6405 await destroyed.promise;
6406 }
6407 {
6408 // Checks that `._undestroy()` restores the state so that `final` will be
6409 // called again.
6410 const writeCalled = Promise.withResolvers();
6411 const finalCalled = Promise.withResolvers();
6412 const closed = Promise.withResolvers();
6413 let finalCounter = 0;
6414 const write = new Writable({
6415 write: writeCalled.resolve(),
6416 final: (cb) => {
6417 cb();
6418 if (++finalCounter === 2) finalCalled.resolve();
6419 },
6420 autoDestroy: true,
6421 });
6422 write.end();
6423 write.once('close', () => {
6424 write._undestroy();
6425 write.end();
6426 closed.resolve();
6427 });
6428 await Promise.all([
6429 writeCalled.promise,
6430 finalCalled.promise,
6431 closed.promise,
6432 ]);
6433 }
6434 {
6435 const write = new Writable();
6436 write.destroy();
6437 const writeFinished = Promise.withResolvers();
6438 write.on('error', writeFinished.reject);
6439 write.write('asd', function (err) {
6440 strictEqual(err.code, 'ERR_STREAM_DESTROYED');
6441 writeFinished.resolve();
6442 });
6443 await writeFinished.promise;
6444 }
6445 {
6446 const write = new Writable({
6447 write(chunk, enc, cb) {
6448 cb();
6449 },
6450 });
6451 const writeFinished1 = Promise.withResolvers();
6452 const writeFinished2 = Promise.withResolvers();
6453 const writeFinished3 = Promise.withResolvers();
6454 write.on('error', writeFinished1.reject);
6455 write.cork();
6456 write.write('asd', writeFinished1.resolve);
6457 write.uncork();
6458 write.cork();
6459 write.write('asd', function (err) {
6460 strictEqual(err.code, 'ERR_STREAM_DESTROYED');
6461 writeFinished2.resolve();
6462 });
6463 write.destroy();
6464 write.write('asd', function (err) {
6465 strictEqual(err.code, 'ERR_STREAM_DESTROYED');
6466 writeFinished3.resolve();
6467 });
6468 write.uncork();
6469 await Promise.all([
6470 writeFinished1.promise,
6471 writeFinished2.promise,
6472 writeFinished3.promise,
6473 ]);
6474 }
6475 {
6476 // Call end(cb) after error & destroy
6477 
6478 const write = new Writable({
6479 write(chunk, enc, cb) {
6480 cb(new Error('asd'));
6481 },
6482 });
6483 const errored = Promise.withResolvers();
6484 write.on('error', () => {
6485 write.destroy();
6486 let ticked = false;
6487 write.end((err) => {
6488 strictEqual(ticked, true);
6489 strictEqual(err.code, 'ERR_STREAM_DESTROYED');
6490 errored.resolve();
6491 });
6492 ticked = true;
6493 });
6494 write.write('asd');
6495 await errored.promise;
6496 }
6497 {
6498 // Call end(cb) after finish & destroy
6499 
6500 const write = new Writable({
6501 write(chunk, enc, cb) {
6502 cb();
6503 },
6504 });
6505 const finishCalled = Promise.withResolvers();
6506 write.on('finish', () => {
6507 write.destroy();
6508 let ticked = false;
6509 write.end((err) => {
6510 strictEqual(ticked, true);
6511 strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED');
6512 finishCalled.resolve();
6513 });
6514 ticked = true;
6515 });
6516 write.end();
6517 await finishCalled.promise;
6518 }
6519 {
6520 // Call end(cb) after error & destroy and don't trigger
6521 // unhandled exception.
6522 
6523 const write = new Writable({
6524 write(chunk, enc, cb) {
6525 queueMicrotask(cb);
6526 },
6527 });
6528 const _err = new Error('asd');
6529 const errored = Promise.withResolvers();
6530 const ended = Promise.withResolvers();
6531 write.once('error', (err) => {
6532 strictEqual(err.message, 'asd');
6533 errored.resolve();
6534 });
6535 write.end('asd', (err) => {
6536 strictEqual(err, _err);
6537 ended.resolve();
6538 });
6539 write.destroy(_err);
6540 await Promise.all([errored.promise, ended.promise]);
6541 }
6542 {
6543 // Call buffered write callback with error
6544 
6545 const _err = new Error('asd');
6546 const write = new Writable({
6547 write(chunk, enc, cb) {
6548 queueMicrotask(() => cb(_err));
6549 },
6550 autoDestroy: false,
6551 });
6552 write.cork();
6553 const writeFinished1 = Promise.withResolvers();
6554 const writeFinished2 = Promise.withResolvers();
6555 const errored = Promise.withResolvers();
6556 write.write('asd', (err) => {
6557 strictEqual(err, _err);
6558 writeFinished1.resolve();
6559 });
6560 write.write('asd', (err) => {
6561 strictEqual(err, _err);
6562 writeFinished2.resolve();
6563 });
6564 write.on('error', (err) => {
6565 strictEqual(err, _err);
6566 errored.resolve();
6567 });
6568 write.uncork();
6569 await Promise.all([
6570 writeFinished1.promise,
6571 writeFinished2.promise,
6572 errored.promise,
6573 ]);
6574 }
6575 {
6576 // Ensure callback order.
6577 
6578 let state = 0;
6579 const write = new Writable({
6580 write(chunk, enc, cb) {
6581 // `queueMicrotask()` is used on purpose to ensure the callback is called
6582 // after `queueMicrotask()` callbacks.
6583 queueMicrotask(cb);
6584 },
6585 });
6586 const writeFinished1 = Promise.withResolvers();
6587 const writeFinished2 = Promise.withResolvers();
6588 write.write('asd', () => {
6589 strictEqual(state++, 0);
6590 writeFinished1.resolve();
6591 });
6592 write.write('asd', (err) => {
6593 strictEqual(err.code, 'ERR_STREAM_DESTROYED');
6594 strictEqual(state++, 1);
6595 writeFinished2.resolve();
6596 });
6597 write.destroy();
6598 await Promise.all([writeFinished1.promise, writeFinished2.promise]);
6599 }
6600 {
6601 const write = new Writable({
6602 autoDestroy: false,
6603 write(chunk, enc, cb) {
6604 cb();
6605 cb();
6606 },
6607 });
6608 const errored = Promise.withResolvers();
6609 write.on('error', () => {
6610 ok(write._writableState.errored);
6611 errored.resolve();
6612 });
6613 write.write('asd');
6614 await errored.promise;
6615 }
6616 {
6617 const ac = new AbortController();
6618 const write = addAbortSignal(
6619 ac.signal,
6620 new Writable({
6621 write(chunk, enc, cb) {
6622 cb();
6623 },
6624 })
6625 );
6626 const errored = Promise.withResolvers();
6627 write.on('error', (e) => {
6628 strictEqual(e.name, 'AbortError');
6629 strictEqual(write.destroyed, true);
6630 errored.resolve();
6631 });
6632 write.write('asd');
6633 ac.abort();
6634 await errored.promise;
6635 }
6636 {
6637 const ac = new AbortController();
6638 const write = new Writable({
6639 signal: ac.signal,
6640 write(chunk, enc, cb) {
6641 cb();
6642 },
6643 });
6644 const errored = Promise.withResolvers();
6645 write.on('error', (e) => {
6646 strictEqual(e.name, 'AbortError');
6647 strictEqual(write.destroyed, true);
6648 errored.resolve();
6649 });
6650 write.write('asd');
6651 ac.abort();
6652 await errored.promise;
6653 }
6654 {
6655 const signal = AbortSignal.abort();
6656 const write = new Writable({
6657 signal,
6658 write(chunk, enc, cb) {
6659 cb();
6660 },
6661 });
6662 const errored = Promise.withResolvers();
6663 write.on('error', (e) => {
6664 strictEqual(e.name, 'AbortError');
6665 strictEqual(write.destroyed, true);
6666 errored.resolve();
6667 });
6668 await errored.promise;
6669 }
6670 {
6671 // Destroy twice
6672 const write = new Writable({
6673 write(chunk, enc, cb) {
6674 cb();
6675 },
6676 });
6677 const ended = Promise.withResolvers();
6678 write.end(ended.resolve);
6679 write.destroy();
6680 write.destroy();
6681 await ended.promise;
6682 }
6683 {
6684 // https://github.com/nodejs/node/issues/39356
6685 const s = new Writable({
6686 final() {},
6687 });
6688 const _err = new Error('oh no');
6689 // Remove `callback` and it works
6690 const ended = Promise.withResolvers();
6691 const errored = Promise.withResolvers();
6692 s.end((err) => {
6693 strictEqual(err, _err);
6694 ended.resolve();
6695 });
6696 s.on('error', (err) => {
6697 strictEqual(err, _err);
6698 errored.resolve();
6699 });
6700 s.destroy(_err);
6701 await Promise.all([errored.promise, ended.promise]);
6702 }
6703 },
6704};
6705 
6706export const writable_decoded_encoding = {
6707 async test(ctrl, env, ctx) {
6708 class MyWritable extends Writable {
6709 constructor(fn, options) {
6710 super(options);
6711 this.fn = fn;
6712 }
6713 _write(chunk, encoding, callback) {
6714 this.fn(Buffer.isBuffer(chunk), typeof chunk, encoding);
6715 callback();
6716 }
6717 }
6718 {
6719 const m = new MyWritable(
6720 function (isBuffer, type, enc) {
6721 ok(isBuffer);
6722 strictEqual(type, 'object');
6723 strictEqual(enc, 'buffer');
6724 },
6725 {
6726 decodeStrings: true,
6727 }
6728 );
6729 m.write('some-text', 'utf8');
6730 m.end();
6731 await promises.finished(m);
6732 }
6733 {
6734 const m = new MyWritable(
6735 function (isBuffer, type, enc) {
6736 ok(!isBuffer);
6737 strictEqual(type, 'string');
6738 strictEqual(enc, 'utf8');
6739 },
6740 {
6741 decodeStrings: false,
6742 }
6743 );
6744 m.write('some-text', 'utf8');
6745 m.end();
6746 await promises.finished(m);
6747 }
6748 },
6749};
6750 
6751export const writable_constructor_set_methods = {
6752 async test(ctrl, env, ctx) {
6753 const bufferBlerg = Buffer.from('blerg');
6754 const w = new Writable();
6755 throws(
6756 () => {
6757 w.end(bufferBlerg);
6758 },
6759 {
6760 name: 'Error',
6761 code: 'ERR_METHOD_NOT_IMPLEMENTED',
6762 message: 'The _write() method is not implemented',
6763 }
6764 );
6765 const writeCalled = Promise.withResolvers();
6766 const writevCalled = Promise.withResolvers();
6767 const _write = (chunk, _, next) => {
6768 next();
6769 writeCalled.resolve();
6770 };
6771 const _writev = (chunks, next) => {
6772 strictEqual(chunks.length, 2);
6773 next();
6774 writevCalled.resolve();
6775 };
6776 const w2 = new Writable({
6777 write: _write,
6778 writev: _writev,
6779 });
6780 strictEqual(w2._write, _write);
6781 strictEqual(w2._writev, _writev);
6782 w2.write(bufferBlerg);
6783 w2.cork();
6784 w2.write(bufferBlerg);
6785 w2.write(bufferBlerg);
6786 w2.end();
6787 await Promise.all([writeCalled.promise, writevCalled.promise]);
6788 },
6789};
6790 
6791export const writable_clear_buffer = {
6792 async test(ctrl, env, ctx) {
6793 class StreamWritable extends Writable {
6794 constructor() {
6795 super({
6796 objectMode: true,
6797 });
6798 }
6799 
6800 // Refs: https://github.com/nodejs/node/issues/6758
6801 // We need a timer like on the original issue thread.
6802 // Otherwise the code will never reach our test case.
6803 _write(chunk, encoding, cb) {
6804 queueMicrotask(cb);
6805 }
6806 }
6807 const testStream = new StreamWritable();
6808 testStream.cork();
6809 const writePromises = [];
6810 for (let i = 1; i <= 5; i++) {
6811 const p = Promise.withResolvers();
6812 writePromises.push(p.promise);
6813 testStream.write(i, () => {
6814 strictEqual(
6815 testStream._writableState.bufferedRequestCount,
6816 testStream._writableState.getBuffer().length
6817 );
6818 p.resolve();
6819 });
6820 }
6821 testStream.end();
6822 await Promise.all(writePromises);
6823 },
6824};
6825 
6826export const writable_change_deafult_encoding = {
6827 async test(ctrl, env, ctx) {
6828 class MyWritable extends Writable {
6829 constructor(fn, options) {
6830 super(options);
6831 this.fn = fn;
6832 }
6833 _write(chunk, encoding, callback) {
6834 this.fn(Buffer.isBuffer(chunk), typeof chunk, encoding);
6835 callback();
6836 }
6837 }
6838 
6839 await (async function defaultCondingIsUtf8() {
6840 const m = new MyWritable(
6841 function (isBuffer, type, enc) {
6842 strictEqual(enc, 'utf8');
6843 },
6844 {
6845 decodeStrings: false,
6846 }
6847 );
6848 m.write('foo');
6849 m.end();
6850 await promises.finished(m);
6851 })();
6852 
6853 await (async function changeDefaultEncodingToAscii() {
6854 const m = new MyWritable(
6855 function (isBuffer, type, enc) {
6856 strictEqual(enc, 'ascii');
6857 },
6858 {
6859 decodeStrings: false,
6860 }
6861 );
6862 m.setDefaultEncoding('ascii');
6863 m.write('bar');
6864 m.end();
6865 await promises.finished(m);
6866 })();
6867 
6868 // Change default encoding to invalid value.
6869 throws(
6870 () => {
6871 const m = new MyWritable((isBuffer, type, enc) => {}, {
6872 decodeStrings: false,
6873 });
6874 m.setDefaultEncoding({});
6875 m.write('bar');
6876 m.end();
6877 },
6878 {
6879 code: 'ERR_UNKNOWN_ENCODING',
6880 }
6881 );
6882 await (async function checkVariableCaseEncoding() {
6883 const m = new MyWritable(
6884 function (isBuffer, type, enc) {
6885 strictEqual(enc, 'ascii');
6886 },
6887 {
6888 decodeStrings: false,
6889 }
6890 );
6891 m.setDefaultEncoding('AsCii');
6892 m.write('bar');
6893 m.end();
6894 await promises.finished(m);
6895 })();
6896 },
6897};
6898 
6899export const writable_aborted = {
6900 async test(ctrl, env, ctx) {
6901 {
6902 const writable = new Writable({
6903 write() {},
6904 });
6905 strictEqual(writable.writableAborted, false);
6906 writable.destroy();
6907 strictEqual(writable.writableAborted, true);
6908 }
6909 {
6910 const writable = new Writable({
6911 write() {},
6912 });
6913 strictEqual(writable.writableAborted, false);
6914 writable.end();
6915 writable.destroy();
6916 strictEqual(writable.writableAborted, true);
6917 }
6918 },
6919};
6920 
6921export const unshift_read_race = {
6922 async test(ctrl, env, ctx) {
6923 const hwm = 10;
6924 const r = Readable({
6925 highWaterMark: hwm,
6926 autoDestroy: false,
6927 });
6928 const chunks = 10;
6929 const data = Buffer.allocUnsafe(chunks * hwm + Math.ceil(hwm / 2));
6930 for (let i = 0; i < data.length; i++) {
6931 const c = 'asdf'.charCodeAt(i % 4);
6932 data[i] = c;
6933 }
6934 let pos = 0;
6935 let pushedNull = false;
6936 r._read = function (n) {
6937 ok(!pushedNull, '_read after null push');
6938 
6939 // Every third chunk is fast
6940 push(!(chunks % 3));
6941 function push(fast) {
6942 ok(!pushedNull, 'push() after null push');
6943 const c = pos >= data.length ? null : data.slice(pos, pos + n);
6944 pushedNull = c === null;
6945 if (fast) {
6946 pos += n;
6947 r.push(c);
6948 if (c === null) pushError();
6949 } else {
6950 setTimeout(function () {
6951 pos += n;
6952 r.push(c);
6953 if (c === null) pushError();
6954 }, 1);
6955 }
6956 }
6957 };
6958 function pushError() {
6959 r.unshift(Buffer.allocUnsafe(1));
6960 w.end();
6961 throws(
6962 () => {
6963 r.push(Buffer.allocUnsafe(1));
6964 },
6965 {
6966 code: 'ERR_STREAM_PUSH_AFTER_EOF',
6967 name: 'Error',
6968 message: 'stream.push() after EOF',
6969 }
6970 );
6971 }
6972 const w = Writable();
6973 const written = [];
6974 const finishCalled = Promise.withResolvers();
6975 w._write = function (chunk, encoding, cb) {
6976 written.push(chunk.toString());
6977 cb();
6978 };
6979 r.on('end', finishCalled.reject);
6980 r.on('readable', function () {
6981 let chunk;
6982 while (null !== (chunk = r.read(10))) {
6983 w.write(chunk);
6984 if (chunk.length > 4) r.unshift(Buffer.from('1234'));
6985 }
6986 });
6987 w.on('finish', function () {
6988 // Each chunk should start with 1234, and then be asfdasdfasdf...
6989 // The first got pulled out before the first unshift('1234'), so it's
6990 // lacking that piece.
6991 strictEqual(written[0], 'asdfasdfas');
6992 let asdf = 'd';
6993 for (let i = 1; i < written.length; i++) {
6994 strictEqual(written[i].slice(0, 4), '1234');
6995 for (let j = 4; j < written[i].length; j++) {
6996 const c = written[i].charAt(j);
6997 strictEqual(c, asdf);
6998 switch (asdf) {
6999 case 'a':
7000 asdf = 's';
7001 break;
7002 case 's':
7003 asdf = 'd';
7004 break;
7005 case 'd':
7006 asdf = 'f';
7007 break;
7008 case 'f':
7009 asdf = 'a';
7010 break;
7011 }
7012 }
7013 }
7014 finishCalled.resolve();
7015 });
7016 await finishCalled.promise;
7017 strictEqual(written.length, 18);
7018 },
7019};
7020 
7021export const unshift_empty_chunk = {
7022 async test(ctrl, env, ctx) {
7023 const r = new Readable();
7024 let nChunks = 10;
7025 const chunk = Buffer.alloc(10, 'x');
7026 r._read = function (n) {
7027 queueMicrotask(() => {
7028 r.push(--nChunks === 0 ? null : chunk);
7029 });
7030 };
7031 let readAll = false;
7032 const seen = [];
7033 r.on('readable', () => {
7034 let chunk;
7035 while ((chunk = r.read()) !== null) {
7036 seen.push(chunk.toString());
7037 // Simulate only reading a certain amount of the data,
7038 // and then putting the rest of the chunk back into the
7039 // stream, like a parser might do. We just fill it with
7040 // 'y' so that it's easy to see which bits were touched,
7041 // and which were not.
7042 const putBack = Buffer.alloc(readAll ? 0 : 5, 'y');
7043 readAll = !readAll;
7044 r.unshift(putBack);
7045 }
7046 });
7047 const expect = [
7048 'xxxxxxxxxx',
7049 'yyyyy',
7050 'xxxxxxxxxx',
7051 'yyyyy',
7052 'xxxxxxxxxx',
7053 'yyyyy',
7054 'xxxxxxxxxx',
7055 'yyyyy',
7056 'xxxxxxxxxx',
7057 'yyyyy',
7058 'xxxxxxxxxx',
7059 'yyyyy',
7060 'xxxxxxxxxx',
7061 'yyyyy',
7062 'xxxxxxxxxx',
7063 'yyyyy',
7064 'xxxxxxxxxx',
7065 'yyyyy',
7066 ];
7067 r.on('end', () => {
7068 deepStrictEqual(seen, expect);
7069 });
7070 await promises.finished(r);
7071 },
7072};
7073 
7074export const unpipe_event = {
7075 async test(ctrl, env, ctx) {
7076 class NullWriteable extends Writable {
7077 _write(chunk, encoding, callback) {
7078 return callback();
7079 }
7080 }
7081 class QuickEndReadable extends Readable {
7082 _read() {
7083 this.push(null);
7084 }
7085 }
7086 class NeverEndReadable extends Readable {
7087 _read() {}
7088 }
7089 {
7090 const pipeCalled = Promise.withResolvers();
7091 const unpipeCalled = Promise.withResolvers();
7092 const dest = new NullWriteable();
7093 const src = new QuickEndReadable();
7094 dest.on('pipe', pipeCalled.resolve);
7095 dest.on('unpipe', unpipeCalled.resolve);
7096 src.pipe(dest);
7097 await Promise.all([pipeCalled.promise, unpipeCalled.promise]);
7098 strictEqual(src._readableState.pipes.length, 0);
7099 }
7100 {
7101 const pipeCalled = Promise.withResolvers();
7102 const dest = new NullWriteable();
7103 const src = new NeverEndReadable();
7104 dest.on('pipe', pipeCalled.resolve);
7105 dest.on('unpipe', pipeCalled.reject);
7106 src.pipe(dest);
7107 await pipeCalled.promise;
7108 strictEqual(src._readableState.pipes.length, 1);
7109 }
7110 {
7111 const pipeCalled = Promise.withResolvers();
7112 const unpipeCalled = Promise.withResolvers();
7113 const dest = new NullWriteable();
7114 const src = new NeverEndReadable();
7115 dest.on('pipe', pipeCalled.resolve);
7116 dest.on('unpipe', unpipeCalled.resolve);
7117 src.pipe(dest);
7118 src.unpipe(dest);
7119 await Promise.all([pipeCalled.promise, unpipeCalled.promise]);
7120 strictEqual(src._readableState.pipes.length, 0);
7121 }
7122 {
7123 const pipeCalled = Promise.withResolvers();
7124 const unpipeCalled = Promise.withResolvers();
7125 const dest = new NullWriteable();
7126 const src = new QuickEndReadable();
7127 dest.on('pipe', pipeCalled.resolve);
7128 dest.on('unpipe', unpipeCalled.resolve);
7129 src.pipe(dest, {
7130 end: false,
7131 });
7132 await Promise.all([pipeCalled.promise, unpipeCalled.promise]);
7133 strictEqual(src._readableState.pipes.length, 0);
7134 }
7135 {
7136 const pipeCalled = Promise.withResolvers();
7137 const dest = new NullWriteable();
7138 const src = new NeverEndReadable();
7139 dest.on('pipe', pipeCalled.resolve);
7140 dest.on('unpipe', pipeCalled.reject);
7141 src.pipe(dest, {
7142 end: false,
7143 });
7144 await pipeCalled.promise;
7145 strictEqual(src._readableState.pipes.length, 1);
7146 }
7147 {
7148 const pipeCalled = Promise.withResolvers();
7149 const unpipeCalled = Promise.withResolvers();
7150 const dest = new NullWriteable();
7151 const src = new NeverEndReadable();
7152 dest.on('pipe', pipeCalled.resolve);
7153 dest.on('unpipe', unpipeCalled.resolve);
7154 src.pipe(dest, {
7155 end: false,
7156 });
7157 src.unpipe(dest);
7158 await Promise.all([pipeCalled.promise, unpipeCalled.promise]);
7159 strictEqual(src._readableState.pipes.length, 0);
7160 }
7161 },
7162};
7163 
7164export const uint8array = {
7165 async test(ctrl, env, ctx) {
7166 const ABC = new Uint8Array([0x41, 0x42, 0x43]);
7167 const DEF = new Uint8Array([0x44, 0x45, 0x46]);
7168 const GHI = new Uint8Array([0x47, 0x48, 0x49]);
7169 {
7170 // Simple Writable test.
7171 
7172 let n = 0;
7173 const writeCalled = Promise.withResolvers();
7174 let writeCount = 0;
7175 const writable = new Writable({
7176 write: (chunk, encoding, cb) => {
7177 ok(chunk instanceof Buffer);
7178 if (n++ === 0) {
7179 strictEqual(String(chunk), 'ABC');
7180 } else {
7181 strictEqual(String(chunk), 'DEF');
7182 }
7183 cb();
7184 if (++writeCount === 2) writeCalled.resolve();
7185 },
7186 });
7187 writable.write(ABC);
7188 writable.end(DEF);
7189 await writeCalled.promise;
7190 }
7191 {
7192 // Writable test, pass in Uint8Array in object mode.
7193 const writeCalled = Promise.withResolvers();
7194 const writable = new Writable({
7195 objectMode: true,
7196 write: (chunk, encoding, cb) => {
7197 ok(!(chunk instanceof Buffer));
7198 ok(chunk instanceof Uint8Array);
7199 strictEqual(chunk, ABC);
7200 strictEqual(encoding, undefined);
7201 cb();
7202 writeCalled.resolve();
7203 },
7204 });
7205 writable.end(ABC);
7206 await writeCalled.promise;
7207 }
7208 {
7209 // Writable test, multiple writes carried out via writev.
7210 let callback;
7211 const writeCalled = Promise.withResolvers();
7212 const writevCalled = Promise.withResolvers();
7213 const writable = new Writable({
7214 write: (chunk, encoding, cb) => {
7215 ok(chunk instanceof Buffer);
7216 strictEqual(encoding, 'buffer');
7217 strictEqual(String(chunk), 'ABC');
7218 callback = cb;
7219 writeCalled.resolve();
7220 },
7221 writev: (chunks, cb) => {
7222 strictEqual(chunks.length, 2);
7223 strictEqual(chunks[0].encoding, 'buffer');
7224 strictEqual(chunks[1].encoding, 'buffer');
7225 strictEqual(chunks[0].chunk + chunks[1].chunk, 'DEFGHI');
7226 writevCalled.resolve();
7227 },
7228 });
7229 writable.write(ABC);
7230 writable.write(DEF);
7231 writable.end(GHI);
7232 callback();
7233 await Promise.all([writeCalled.promise, writevCalled.promise]);
7234 }
7235 {
7236 // Simple Readable test.
7237 const readable = new Readable({
7238 read() {},
7239 });
7240 readable.push(DEF);
7241 readable.unshift(ABC);
7242 const buf = readable.read();
7243 ok(buf instanceof Buffer);
7244 deepStrictEqual([...buf], [...ABC, ...DEF]);
7245 }
7246 {
7247 // Readable test, setEncoding.
7248 const readable = new Readable({
7249 read() {},
7250 });
7251 readable.setEncoding('utf8');
7252 readable.push(DEF);
7253 readable.unshift(ABC);
7254 const out = readable.read();
7255 strictEqual(out, 'ABCDEF');
7256 }
7257 },
7258};
7259 
7260export const transform_split_objectmode = {
7261 async test(ctrl, env, ctx) {
7262 const parser = new Transform({
7263 readableObjectMode: true,
7264 });
7265 ok(parser._readableState.objectMode);
7266 ok(!parser._writableState.objectMode);
7267 strictEqual(parser.readableHighWaterMark, 16);
7268 strictEqual(parser.writableHighWaterMark, 64 * 1024);
7269 strictEqual(
7270 parser.readableHighWaterMark,
7271 parser._readableState.highWaterMark
7272 );
7273 strictEqual(
7274 parser.writableHighWaterMark,
7275 parser._writableState.highWaterMark
7276 );
7277 parser._transform = function (chunk, enc, callback) {
7278 callback(null, {
7279 val: chunk[0],
7280 });
7281 };
7282 let parsed;
7283 parser.on('data', function (obj) {
7284 parsed = obj;
7285 });
7286 parser.end(Buffer.from([42]));
7287 
7288 const serializer = new Transform({
7289 writableObjectMode: true,
7290 });
7291 ok(!serializer._readableState.objectMode);
7292 ok(serializer._writableState.objectMode);
7293 strictEqual(serializer.readableHighWaterMark, 64 * 1024);
7294 strictEqual(serializer.writableHighWaterMark, 16);
7295 strictEqual(
7296 parser.readableHighWaterMark,
7297 parser._readableState.highWaterMark
7298 );
7299 strictEqual(
7300 parser.writableHighWaterMark,
7301 parser._writableState.highWaterMark
7302 );
7303 serializer._transform = function (obj, _, callback) {
7304 callback(null, Buffer.from([obj.val]));
7305 };
7306 let serialized;
7307 serializer.on('data', function (chunk) {
7308 serialized = chunk;
7309 });
7310 serializer.write({
7311 val: 42,
7312 });
7313 
7314 strictEqual(parsed.val, 42);
7315 strictEqual(serialized[0], 42);
7316 },
7317};
7318 
7319export const transform_split_highwatermark = {
7320 async test(ctrl, env, ctx) {
7321 const DEFAULT = 64 * 1024;
7322 function testTransform(expectedReadableHwm, expectedWritableHwm, options) {
7323 const t = new Transform(options);
7324 strictEqual(t._readableState.highWaterMark, expectedReadableHwm);
7325 strictEqual(t._writableState.highWaterMark, expectedWritableHwm);
7326 }
7327 
7328 // Test overriding defaultHwm
7329 testTransform(666, DEFAULT, {
7330 readableHighWaterMark: 666,
7331 });
7332 testTransform(DEFAULT, 777, {
7333 writableHighWaterMark: 777,
7334 });
7335 testTransform(666, 777, {
7336 readableHighWaterMark: 666,
7337 writableHighWaterMark: 777,
7338 });
7339 
7340 // Test highWaterMark overriding
7341 testTransform(555, 555, {
7342 highWaterMark: 555,
7343 readableHighWaterMark: 666,
7344 });
7345 testTransform(555, 555, {
7346 highWaterMark: 555,
7347 writableHighWaterMark: 777,
7348 });
7349 testTransform(555, 555, {
7350 highWaterMark: 555,
7351 readableHighWaterMark: 666,
7352 writableHighWaterMark: 777,
7353 });
7354 
7355 // Test undefined, null
7356 [undefined, null].forEach((v) => {
7357 testTransform(DEFAULT, DEFAULT, {
7358 readableHighWaterMark: v,
7359 });
7360 testTransform(DEFAULT, DEFAULT, {
7361 writableHighWaterMark: v,
7362 });
7363 testTransform(666, DEFAULT, {
7364 highWaterMark: v,
7365 readableHighWaterMark: 666,
7366 });
7367 testTransform(DEFAULT, 777, {
7368 highWaterMark: v,
7369 writableHighWaterMark: 777,
7370 });
7371 });
7372 
7373 // test NaN
7374 {
7375 throws(
7376 () => {
7377 new Transform({
7378 readableHighWaterMark: NaN,
7379 });
7380 },
7381 {
7382 name: 'TypeError',
7383 code: 'ERR_INVALID_ARG_VALUE',
7384 }
7385 );
7386 throws(
7387 () => {
7388 new Transform({
7389 writableHighWaterMark: NaN,
7390 });
7391 },
7392 {
7393 name: 'TypeError',
7394 code: 'ERR_INVALID_ARG_VALUE',
7395 }
7396 );
7397 }
7398 
7399 // Test non Duplex streams ignore the options
7400 {
7401 const r = new Readable({
7402 readableHighWaterMark: 666,
7403 });
7404 strictEqual(r._readableState.highWaterMark, DEFAULT);
7405 const w = new Writable({
7406 writableHighWaterMark: 777,
7407 });
7408 strictEqual(w._writableState.highWaterMark, DEFAULT);
7409 }
7410 },
7411};
7412 
7413export const transform_objectmode_falsey_value = {
7414 async test(ctrl, env, ctx) {
7415 const src = new PassThrough({
7416 objectMode: true,
7417 });
7418 const tx = new PassThrough({
7419 objectMode: true,
7420 });
7421 const dest = new PassThrough({
7422 objectMode: true,
7423 });
7424 const expect = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7425 const results = [];
7426 const dataCalled = Promise.withResolvers();
7427 const intervalFinished = Promise.withResolvers();
7428 let dataCount = 0;
7429 let intCount = 0;
7430 dest.on('data', function (x) {
7431 results.push(x);
7432 if (++dataCount === expect.length) dataCalled.resolve();
7433 });
7434 src.pipe(tx).pipe(dest);
7435 let i = -1;
7436 const int = setInterval(function () {
7437 if (results.length === expect.length) {
7438 src.end();
7439 clearInterval(int);
7440 deepStrictEqual(results, expect);
7441 } else {
7442 src.write(i++);
7443 }
7444 if (++intCount === expect.length + 1) intervalFinished.resolve();
7445 }, 1);
7446 await Promise.all([dataCalled.promise, intervalFinished.promise]);
7447 },
7448};
7449 
7450export const transform_hwm0 = {
7451 async test(ctrl, env, ctx) {
7452 const t = new Transform({
7453 objectMode: true,
7454 highWaterMark: 0,
7455 transform(chunk, enc, callback) {
7456 queueMicrotask(() => callback(null, chunk, enc));
7457 },
7458 });
7459 strictEqual(t.write(1), false);
7460 const drainCalled = Promise.withResolvers();
7461 const readableCalled = Promise.withResolvers();
7462 t.on('drain', () => {
7463 strictEqual(t.write(2), false);
7464 t.end();
7465 drainCalled.resolve();
7466 });
7467 t.once('readable', () => {
7468 strictEqual(t.read(), 1);
7469 queueMicrotask(() => {
7470 strictEqual(t.read(), null);
7471 t.once('readable', () => {
7472 strictEqual(t.read(), 2);
7473 readableCalled.resolve();
7474 });
7475 });
7476 });
7477 await Promise.all([drainCalled.promise, readableCalled.promise]);
7478 },
7479};
7480 
7481export const transform_flush_data = {
7482 async test(ctrl, env, ctx) {
7483 const expected = 'asdf';
7484 function _transform(d, e, n) {
7485 n();
7486 }
7487 function _flush(n) {
7488 n(null, expected);
7489 }
7490 const t = new Transform({
7491 transform: _transform,
7492 flush: _flush,
7493 });
7494 t.end(Buffer.from('blerg'));
7495 t.on('data', (data) => {
7496 strictEqual(data.toString(), expected);
7497 });
7498 await promises.finished(t);
7499 },
7500};
7501 
7502export const transform_final = {
7503 async test(ctrl, env, ctx) {
7504 let state = 0;
7505 const transformCalled = Promise.withResolvers();
7506 const finalCalled = Promise.withResolvers();
7507 const flushCalled = Promise.withResolvers();
7508 const finishCalled = Promise.withResolvers();
7509 const endCalled = Promise.withResolvers();
7510 const dataCalled = Promise.withResolvers();
7511 const endFinished = Promise.withResolvers();
7512 let dataCount = 0;
7513 let transformCount = 0;
7514 const t = new Transform({
7515 objectMode: true,
7516 transform: function (chunk, _, next) {
7517 // transformCallback part 1
7518 strictEqual(++state, chunk);
7519 this.push(state);
7520 // transformCallback part 2
7521 strictEqual(++state, chunk + 2);
7522 queueMicrotask(next);
7523 if (++transformCount === 3) transformCalled.resolve();
7524 },
7525 final: function (done) {
7526 state++;
7527 // finalCallback part 1
7528 strictEqual(state, 10);
7529 setTimeout(function () {
7530 state++;
7531 // finalCallback part 2
7532 strictEqual(state, 11);
7533 done();
7534 finalCalled.resolve();
7535 }, 100);
7536 },
7537 flush: function (done) {
7538 state++;
7539 // flushCallback part 1
7540 strictEqual(state, 12);
7541 queueMicrotask(function () {
7542 state++;
7543 // flushCallback part 2
7544 strictEqual(state, 13);
7545 done();
7546 flushCalled.resolve();
7547 });
7548 },
7549 });
7550 t.on('finish', function () {
7551 state++;
7552 // finishListener
7553 strictEqual(state, 15);
7554 finishCalled.resolve();
7555 });
7556 t.on('end', function () {
7557 state++;
7558 // end event
7559 strictEqual(state, 16);
7560 endCalled.resolve();
7561 });
7562 t.on('data', function (d) {
7563 // dataListener
7564 strictEqual(++state, d + 1);
7565 if (++dataCount) dataCalled.resolve();
7566 });
7567 t.write(1);
7568 t.write(4);
7569 t.end(7, function () {
7570 state++;
7571 // endMethodCallback
7572 strictEqual(state, 14);
7573 endFinished.resolve();
7574 });
7575 await Promise.all([
7576 transformCalled.promise,
7577 finalCalled.promise,
7578 flushCalled.promise,
7579 finishCalled.promise,
7580 endCalled.promise,
7581 dataCalled.promise,
7582 endFinished.promise,
7583 ]);
7584 },
7585};
7586 
7587export const transform_final_sync = {
7588 async test(ctrl, env, ctx) {
7589 let state = 0;
7590 const transformCalled = Promise.withResolvers();
7591 const finalCalled = Promise.withResolvers();
7592 const flushCalled = Promise.withResolvers();
7593 const finishCalled = Promise.withResolvers();
7594 const endCalled = Promise.withResolvers();
7595 const dataCalled = Promise.withResolvers();
7596 const endFinished = Promise.withResolvers();
7597 let transformCount = 0;
7598 let dataCount = 0;
7599 const t = new Transform({
7600 objectMode: true,
7601 transform: function (chunk, _, next) {
7602 // transformCallback part 1
7603 strictEqual(++state, chunk);
7604 this.push(state);
7605 // transformCallback part 2
7606 strictEqual(++state, chunk + 2);
7607 queueMicrotask(next);
7608 if (++transformCount === 3) transformCalled.resolve();
7609 },
7610 final: function (done) {
7611 state++;
7612 // finalCallback part 1
7613 strictEqual(state, 10);
7614 state++;
7615 // finalCallback part 2
7616 strictEqual(state, 11);
7617 done();
7618 finalCalled.resolve();
7619 },
7620 flush: function (done) {
7621 state++;
7622 // fluchCallback part 1
7623 strictEqual(state, 12);
7624 queueMicrotask(function () {
7625 state++;
7626 // fluchCallback part 2
7627 strictEqual(state, 13);
7628 done();
7629 flushCalled.resolve();
7630 });
7631 },
7632 });
7633 t.on('finish', function () {
7634 state++;
7635 // finishListener
7636 strictEqual(state, 15);
7637 finishCalled.resolve();
7638 });
7639 t.on('end', function () {
7640 state++;
7641 // endEvent
7642 strictEqual(state, 16);
7643 endCalled.resolve();
7644 });
7645 t.on('data', function (d) {
7646 // dataListener
7647 strictEqual(++state, d + 1);
7648 if (++dataCount === 3) dataCalled.resolve();
7649 });
7650 t.write(1);
7651 t.write(4);
7652 t.end(7, function () {
7653 state++;
7654 // endMethodCallback
7655 strictEqual(state, 14);
7656 endFinished.resolve();
7657 });
7658 await Promise.all([
7659 transformCalled.promise,
7660 finalCalled.promise,
7661 flushCalled.promise,
7662 finishCalled.promise,
7663 endCalled.promise,
7664 dataCalled.promise,
7665 endFinished.promise,
7666 ]);
7667 },
7668};
7669 
7670export const transform_destroy = {
7671 async test(ctrl, env, ctx) {
7672 {
7673 const transform = new Transform({
7674 transform(chunk, enc, cb) {},
7675 });
7676 transform.resume();
7677 const closed = Promise.withResolvers();
7678 transform.on('end', closed.reject);
7679 transform.on('close', closed.resolve);
7680 transform.on('finish', closed.reject);
7681 transform.destroy();
7682 await closed.promise;
7683 }
7684 {
7685 const transform = new Transform({
7686 transform(chunk, enc, cb) {},
7687 });
7688 transform.resume();
7689 const expected = new Error('kaboom');
7690 const errored = Promise.withResolvers();
7691 const closed = Promise.withResolvers();
7692 transform.on('end', closed.reject);
7693 transform.on('finish', closed.reject);
7694 transform.on('close', closed.resolve);
7695 transform.on('error', (err) => {
7696 strictEqual(err, expected);
7697 errored.resolve();
7698 });
7699 transform.destroy(expected);
7700 await Promise.all([closed.promise, errored.promise]);
7701 }
7702 {
7703 const transform = new Transform({
7704 transform(chunk, enc, cb) {},
7705 });
7706 transform._destroy = function (err, cb) {
7707 strictEqual(err, expected);
7708 cb(err);
7709 };
7710 const expected = new Error('kaboom');
7711 const closed = Promise.withResolvers();
7712 const errored = Promise.withResolvers();
7713 transform.on('finish', closed.reject);
7714 transform.on('close', closed.resolve);
7715 transform.on('error', (err) => {
7716 strictEqual(err, expected);
7717 errored.resolve();
7718 });
7719 transform.destroy(expected);
7720 await Promise.all([closed.promise, errored.promise]);
7721 }
7722 {
7723 const expected = new Error('kaboom');
7724 const destroyCalled = Promise.withResolvers();
7725 const closed = Promise.withResolvers();
7726 const transform = new Transform({
7727 transform(chunk, enc, cb) {},
7728 destroy: function (err, cb) {
7729 strictEqual(err, expected);
7730 cb();
7731 destroyCalled.resolve();
7732 },
7733 });
7734 transform.resume();
7735 transform.on('end', closed.reject);
7736 transform.on('close', closed.resolve);
7737 transform.on('finish', closed.reject);
7738 
7739 // Error is swallowed by the custom _destroy
7740 transform.on('error', closed.reject);
7741 transform.destroy(expected);
7742 await Promise.all([destroyCalled.promise, closed.promise]);
7743 }
7744 {
7745 const transform = new Transform({
7746 transform(chunk, enc, cb) {},
7747 });
7748 const destroyCalled = Promise.withResolvers();
7749 transform._destroy = function (err, cb) {
7750 strictEqual(err, null);
7751 cb();
7752 destroyCalled.resolve();
7753 };
7754 transform.destroy();
7755 await destroyCalled.promise;
7756 }
7757 {
7758 const transform = new Transform({
7759 transform(chunk, enc, cb) {},
7760 });
7761 transform.resume();
7762 const destroyCalled = Promise.withResolvers();
7763 const closed = Promise.withResolvers();
7764 const endCalled = Promise.withResolvers();
7765 transform._destroy = function (err, cb) {
7766 strictEqual(err, null);
7767 queueMicrotask(() => {
7768 this.push(null);
7769 this.end();
7770 cb();
7771 destroyCalled.resolve();
7772 });
7773 };
7774 transform.on('finish', closed.reject);
7775 transform.on('end', closed.reject);
7776 transform.on('close', closed.resolve);
7777 transform.destroy();
7778 transform.removeListener('end', closed.reject);
7779 transform.removeListener('finish', closed.reject);
7780 transform.on('end', endCalled.resolve);
7781 transform.on('finish', closed.reject);
7782 await Promise.all([
7783 destroyCalled.promise,
7784 closed.promise,
7785 endCalled.promise,
7786 ]);
7787 }
7788 {
7789 const transform = new Transform({
7790 transform(chunk, enc, cb) {},
7791 });
7792 const expected = new Error('kaboom');
7793 const destroyCalled = Promise.withResolvers();
7794 const closed = Promise.withResolvers();
7795 const errored = Promise.withResolvers();
7796 transform._destroy = function (err, cb) {
7797 strictEqual(err, null);
7798 cb(expected);
7799 destroyCalled.resolve();
7800 };
7801 transform.on('close', closed.resolve);
7802 transform.on('finish', closed.reject);
7803 transform.on('end', closed.reject);
7804 transform.on('error', (err) => {
7805 strictEqual(err, expected);
7806 errored.resolve();
7807 });
7808 transform.destroy();
7809 await Promise.all([
7810 destroyCalled.promise,
7811 closed.promise,
7812 errored.promise,
7813 ]);
7814 }
7815 },
7816};
7817 
7818export const transform_constructor_set_methods = {
7819 async test(ctrl, env, ctx) {
7820 const t = new Transform();
7821 throws(
7822 () => {
7823 t.end(Buffer.from('blerg'));
7824 },
7825 {
7826 name: 'Error',
7827 code: 'ERR_METHOD_NOT_IMPLEMENTED',
7828 message: 'The _transform() method is not implemented',
7829 }
7830 );
7831 const transformCalled = Promise.withResolvers();
7832 const finalCalled = Promise.withResolvers();
7833 const flushCalled = Promise.withResolvers();
7834 const _transform = (chunk, _, next) => {
7835 next();
7836 transformCalled.resolve();
7837 };
7838 const _final = (next) => {
7839 next();
7840 finalCalled.resolve();
7841 };
7842 const _flush = (next) => {
7843 next();
7844 flushCalled.resolve();
7845 };
7846 const t2 = new Transform({
7847 transform: _transform,
7848 flush: _flush,
7849 final: _final,
7850 });
7851 strictEqual(t2._transform, _transform);
7852 strictEqual(t2._flush, _flush);
7853 strictEqual(t2._final, _final);
7854 t2.end(Buffer.from('blerg'));
7855 t2.resume();
7856 await Promise.all([
7857 transformCalled.promise,
7858 finalCalled.promise,
7859 flushCalled.promise,
7860 ]);
7861 },
7862};
7863 
7864export const transform_callback_twice = {
7865 async test(ctrl, env, ctx) {
7866 const stream = new Transform({
7867 transform(chunk, enc, cb) {
7868 cb();
7869 cb();
7870 },
7871 });
7872 const errored = Promise.withResolvers();
7873 stream.on('error', function (err) {
7874 strictEqual(err.code, 'ERR_MULTIPLE_CALLBACK');
7875 errored.resolve();
7876 });
7877 stream.write('foo');
7878 await errored.promise;
7879 },
7880};
7881 
7882export const toarray = {
7883 async test(ctrl, env, ctx) {
7884 {
7885 // Works on a synchronous stream
7886 await (async () => {
7887 const tests = [
7888 [],
7889 [1],
7890 [1, 2, 3],
7891 Array.from({ length: 100 }, (_, i) => i),
7892 ];
7893 for (const test of tests) {
7894 const stream = Readable.from(test);
7895 const result = await stream.toArray();
7896 deepStrictEqual(result, test);
7897 }
7898 })();
7899 }
7900 {
7901 // Works on a non-object-mode stream
7902 await (async () => {
7903 const firstBuffer = Buffer.from([1, 2, 3]);
7904 const secondBuffer = Buffer.from([4, 5, 6]);
7905 const stream = Readable.from([firstBuffer, secondBuffer], {
7906 objectMode: false,
7907 });
7908 const result = await stream.toArray();
7909 strictEqual(Array.isArray(result), true);
7910 deepStrictEqual(result, [firstBuffer, secondBuffer]);
7911 })();
7912 }
7913 {
7914 // Works on an asynchronous stream
7915 await (async () => {
7916 const tests = [
7917 [],
7918 [1],
7919 [1, 2, 3],
7920 Array.from({ length: 100 }, (_, i) => i),
7921 ];
7922 for (const test of tests) {
7923 const stream = Readable.from(test).map((x) => Promise.resolve(x));
7924 const result = await stream.toArray();
7925 deepStrictEqual(result, test);
7926 }
7927 })();
7928 }
7929 {
7930 // Support for AbortSignal
7931 const ac = new AbortController();
7932 let stream;
7933 queueMicrotask(() => ac.abort());
7934 await rejects(
7935 async () => {
7936 stream = Readable.from([1, 2, 3]).map(async (x) => {
7937 if (x === 3) {
7938 await new Promise(() => {}); // Explicitly do not pass signal here
7939 }
7940 
7941 return Promise.resolve(x);
7942 });
7943 await stream.toArray({
7944 signal: ac.signal,
7945 });
7946 },
7947 {
7948 name: 'AbortError',
7949 }
7950 );
7951 
7952 // Only stops toArray, does not destroy the stream
7953 ok(stream.destroyed, false);
7954 }
7955 {
7956 // Test result is a Promise
7957 const result = Readable.from([1, 2, 3, 4, 5]).toArray();
7958 strictEqual(result instanceof Promise, true);
7959 }
7960 {
7961 // Error cases
7962 await rejects(async () => {
7963 await Readable.from([1]).toArray(1);
7964 }, /ERR_INVALID_ARG_TYPE/);
7965 await rejects(async () => {
7966 await Readable.from([1]).toArray({
7967 signal: true,
7968 });
7969 }, /ERR_INVALID_ARG_TYPE/);
7970 }
7971 },
7972};
7973 
7974export const some_find_every = {
7975 async test(ctrl, env, ctx) {
7976 function oneTo5() {
7977 return Readable.from([1, 2, 3, 4, 5]);
7978 }
7979 
7980 function oneTo5Async() {
7981 return oneTo5().map(async (x) => {
7982 await Promise.resolve();
7983 return x;
7984 });
7985 }
7986 {
7987 // Some, find, and every work with a synchronous stream and predicate
7988 strictEqual(await oneTo5().some((x) => x > 3), true);
7989 strictEqual(await oneTo5().every((x) => x > 3), false);
7990 strictEqual(await oneTo5().find((x) => x > 3), 4);
7991 strictEqual(await oneTo5().some((x) => x > 6), false);
7992 strictEqual(await oneTo5().every((x) => x < 6), true);
7993 strictEqual(await oneTo5().find((x) => x > 6), undefined);
7994 strictEqual(await Readable.from([]).some(() => true), false);
7995 strictEqual(await Readable.from([]).every(() => true), true);
7996 strictEqual(await Readable.from([]).find(() => true), undefined);
7997 }
7998 
7999 {
8000 // Some, find, and every work with an asynchronous stream and synchronous predicate
8001 strictEqual(await oneTo5Async().some((x) => x > 3), true);
8002 strictEqual(await oneTo5Async().every((x) => x > 3), false);
8003 strictEqual(await oneTo5Async().find((x) => x > 3), 4);
8004 strictEqual(await oneTo5Async().some((x) => x > 6), false);
8005 strictEqual(await oneTo5Async().every((x) => x < 6), true);
8006 strictEqual(await oneTo5Async().find((x) => x > 6), undefined);
8007 }
8008 
8009 {
8010 // Some, find, and every work on synchronous streams with an asynchronous predicate
8011 strictEqual(await oneTo5().some(async (x) => x > 3), true);
8012 strictEqual(await oneTo5().every(async (x) => x > 3), false);
8013 strictEqual(await oneTo5().find(async (x) => x > 3), 4);
8014 strictEqual(await oneTo5().some(async (x) => x > 6), false);
8015 strictEqual(await oneTo5().every(async (x) => x < 6), true);
8016 strictEqual(await oneTo5().find(async (x) => x > 6), undefined);
8017 }
8018 
8019 {
8020 // Some, find, and every work on asynchronous streams with an asynchronous predicate
8021 strictEqual(await oneTo5Async().some(async (x) => x > 3), true);
8022 strictEqual(await oneTo5Async().every(async (x) => x > 3), false);
8023 strictEqual(await oneTo5Async().find(async (x) => x > 3), 4);
8024 strictEqual(await oneTo5Async().some(async (x) => x > 6), false);
8025 strictEqual(await oneTo5Async().every(async (x) => x < 6), true);
8026 strictEqual(await oneTo5Async().find(async (x) => x > 6), undefined);
8027 }
8028 
8029 {
8030 async function checkDestroyed(stream) {
8031 await scheduler.wait(1);
8032 strictEqual(stream.destroyed, true);
8033 }
8034 
8035 {
8036 // Some, find, and every short circuit
8037 const someStream = oneTo5();
8038 await someStream.some((x) => x > 2);
8039 await checkDestroyed(someStream);
8040 
8041 const everyStream = oneTo5();
8042 await everyStream.every((x) => x < 3);
8043 await checkDestroyed(everyStream);
8044 
8045 const findStream = oneTo5();
8046 await findStream.find((x) => x > 1);
8047 await checkDestroyed(findStream);
8048 
8049 // When short circuit isn't possible the whole stream is iterated
8050 await oneTo5().some(() => false);
8051 await oneTo5().every(() => true);
8052 await oneTo5().find(() => false);
8053 }
8054 
8055 {
8056 // Some, find, and every short circuit async stream/predicate
8057 const someStream = oneTo5Async();
8058 await someStream.some(async (x) => x > 2);
8059 await checkDestroyed(someStream);
8060 
8061 const everyStream = oneTo5Async();
8062 await everyStream.every(async (x) => x < 3);
8063 await checkDestroyed(everyStream);
8064 
8065 const findStream = oneTo5Async();
8066 await findStream.find(async (x) => x > 1);
8067 await checkDestroyed(findStream);
8068 
8069 // When short circuit isn't possible the whole stream is iterated
8070 await oneTo5Async().some(async () => false);
8071 await oneTo5Async().every(async () => true);
8072 await oneTo5Async().find(async () => false);
8073 }
8074 }
8075 
8076 {
8077 // Concurrency doesn't affect which value is found.
8078 const found = await Readable.from([1, 2]).find(
8079 async (val) => {
8080 if (val === 1) {
8081 await scheduler.wait(100);
8082 }
8083 return true;
8084 },
8085 { concurrency: 2 }
8086 );
8087 strictEqual(found, 1);
8088 }
8089 
8090 {
8091 // Support for AbortSignal
8092 for (const op of ['some', 'every', 'find']) {
8093 {
8094 const ac = new AbortController();
8095 queueMicrotask(() => ac.abort());
8096 await rejects(
8097 Readable.from([1, 2, 3])[op](() => new Promise(() => {}), {
8098 signal: ac.signal,
8099 }),
8100 {
8101 name: 'AbortError',
8102 },
8103 `${op} should abort correctly with sync abort`
8104 );
8105 }
8106 {
8107 // Support for pre-aborted AbortSignal
8108 await rejects(
8109 Readable.from([1, 2, 3])[op](() => new Promise(() => {}), {
8110 signal: AbortSignal.abort(),
8111 }),
8112 {
8113 name: 'AbortError',
8114 },
8115 `${op} should abort with pre-aborted abort controller`
8116 );
8117 }
8118 }
8119 }
8120 {
8121 // Error cases
8122 for (const op of ['some', 'every', 'find']) {
8123 await rejects(
8124 async () => {
8125 await Readable.from([1])[op](1);
8126 },
8127 /ERR_INVALID_ARG_TYPE/,
8128 `${op} should throw for invalid function`
8129 );
8130 await rejects(
8131 async () => {
8132 await Readable.from([1])[op]((x) => x, {
8133 concurrency: 'Foo',
8134 });
8135 },
8136 /RangeError/,
8137 `${op} should throw for invalid concurrency`
8138 );
8139 await rejects(
8140 async () => {
8141 await Readable.from([1])[op]((x) => x, 1);
8142 },
8143 /ERR_INVALID_ARG_TYPE/,
8144 `${op} should throw for invalid concurrency`
8145 );
8146 await rejects(
8147 async () => {
8148 await Readable.from([1])[op]((x) => x, {
8149 signal: true,
8150 });
8151 },
8152 /ERR_INVALID_ARG_TYPE/,
8153 `${op} should throw for invalid signal`
8154 );
8155 }
8156 }
8157 {
8158 for (const op of ['some', 'every', 'find']) {
8159 const stream = oneTo5();
8160 Object.defineProperty(stream, 'map', {
8161 value: () => {
8162 throw new Error('should not be called');
8163 },
8164 });
8165 // Check that map isn't getting called.
8166 stream[op](() => {});
8167 }
8168 }
8169 },
8170};
8171 
8172export const reduce = {
8173 async test(ctrl, env, ctx) {
8174 function sum(p, c) {
8175 return p + c;
8176 }
8177 {
8178 // Does the same thing as `(await stream.toArray()).reduce(...)`
8179 await (async () => {
8180 const tests = [
8181 [[], sum, 0],
8182 [[1], sum, 0],
8183 [[1, 2, 3, 4, 5], sum, 0],
8184 [[...Array(100).keys()], sum, 0],
8185 [['a', 'b', 'c'], sum, ''],
8186 [[1, 2], sum],
8187 [[1, 2, 3], (x, y) => y],
8188 ];
8189 for (const [values, fn, initial] of tests) {
8190 const streamReduce = await Readable.from(values).reduce(fn, initial);
8191 const arrayReduce = values.reduce(fn, initial);
8192 deepStrictEqual(streamReduce, arrayReduce);
8193 }
8194 // Does the same thing as `(await stream.toArray()).reduce(...)` with an
8195 // asynchronous reducer
8196 for (const [values, fn, initial] of tests) {
8197 const streamReduce = await Readable.from(values)
8198 .map(async (x) => x)
8199 .reduce(fn, initial);
8200 const arrayReduce = values.reduce(fn, initial);
8201 deepStrictEqual(streamReduce, arrayReduce);
8202 }
8203 })();
8204 }
8205 {
8206 // Works with an async reducer, with or without initial value
8207 await (async () => {
8208 const six = await Readable.from([1, 2, 3]).reduce(
8209 async (p, c) => p + c,
8210 0
8211 );
8212 strictEqual(six, 6);
8213 })();
8214 await (async () => {
8215 const six = await Readable.from([1, 2, 3]).reduce(
8216 async (p, c) => p + c
8217 );
8218 strictEqual(six, 6);
8219 })();
8220 }
8221 {
8222 // Works lazily
8223 await rejects(
8224 Readable.from([1, 2, 3, 4, 5, 6])
8225 .map((x) => {
8226 return x;
8227 }) // Two consumed and one buffered by `map` due to default concurrency
8228 .reduce(async (p, c) => {
8229 if (p === 1) {
8230 throw new Error('boom');
8231 }
8232 return c;
8233 }, 0),
8234 /boom/
8235 );
8236 }
8237 {
8238 // Support for AbortSignal
8239 const ac = new AbortController();
8240 queueMicrotask(() => ac.abort());
8241 await rejects(
8242 async () => {
8243 await Readable.from([1, 2, 3]).reduce(
8244 async (p, c) => {
8245 if (c === 3) {
8246 await new Promise(() => {}); // Explicitly do not pass signal here
8247 }
8248 
8249 return Promise.resolve();
8250 },
8251 0,
8252 {
8253 signal: ac.signal,
8254 }
8255 );
8256 },
8257 {
8258 name: 'AbortError',
8259 }
8260 );
8261 }
8262 {
8263 // Support for AbortSignal - pre aborted
8264 const stream = Readable.from([1, 2, 3]);
8265 await rejects(
8266 async () => {
8267 await stream.reduce(
8268 async (p, c) => {
8269 if (c === 3) {
8270 await new Promise(() => {}); // Explicitly do not pass signal here
8271 }
8272 
8273 return Promise.resolve();
8274 },
8275 0,
8276 {
8277 signal: AbortSignal.abort(),
8278 }
8279 );
8280 },
8281 {
8282 name: 'AbortError',
8283 }
8284 );
8285 
8286 strictEqual(stream.destroyed, true);
8287 }
8288 {
8289 // Support for AbortSignal - deep
8290 const stream = Readable.from([1, 2, 3]);
8291 await rejects(
8292 async () => {
8293 await stream.reduce(
8294 async (p, c, { signal }) => {
8295 signal.addEventListener('abort', () => {}, {
8296 once: true,
8297 });
8298 if (c === 3) {
8299 await new Promise(() => {}); // Explicitly do not pass signal here
8300 }
8301 
8302 return Promise.resolve();
8303 },
8304 0,
8305 {
8306 signal: AbortSignal.abort(),
8307 }
8308 );
8309 },
8310 {
8311 name: 'AbortError',
8312 }
8313 );
8314 strictEqual(stream.destroyed, true);
8315 }
8316 {
8317 // Error cases
8318 await rejects(() => Readable.from([]).reduce(1), /TypeError/);
8319 await rejects(() => Readable.from([]).reduce('5'), /TypeError/);
8320 await rejects(
8321 () => Readable.from([]).reduce((x, y) => x + y, 0, 1),
8322 /ERR_INVALID_ARG_TYPE/
8323 );
8324 await rejects(
8325 () =>
8326 Readable.from([]).reduce((x, y) => x + y, 0, {
8327 signal: true,
8328 }),
8329 /ERR_INVALID_ARG_TYPE/
8330 );
8331 }
8332 {
8333 // Test result is a Promise
8334 const result = Readable.from([1, 2, 3, 4, 5]).reduce(sum, 0);
8335 ok(result instanceof Promise);
8336 }
8337 },
8338};
8339 
8340export const readablelistening_state = {
8341 async test(ctrl, env, ctx) {
8342 const r = new Readable({
8343 read: () => {},
8344 });
8345 
8346 // readableListening state should start in `false`.
8347 strictEqual(r._readableState.readableListening, false);
8348 const readableCalled = Promise.withResolvers();
8349 const dataCalled = Promise.withResolvers();
8350 r.on('readable', () => {
8351 // Inside the readable event this state should be true.
8352 strictEqual(r._readableState.readableListening, true);
8353 readableCalled.resolve();
8354 });
8355 r.push(Buffer.from('Testing readableListening state'));
8356 const r2 = new Readable({
8357 read: () => {},
8358 });
8359 
8360 // readableListening state should start in `false`.
8361 strictEqual(r2._readableState.readableListening, false);
8362 r2.on('data', (chunk) => {
8363 // readableListening should be false because we don't have
8364 // a `readable` listener
8365 strictEqual(r2._readableState.readableListening, false);
8366 dataCalled.resolve();
8367 });
8368 r2.push(Buffer.from('Testing readableListening state'));
8369 await Promise.all([readableCalled.promise, dataCalled.promise]);
8370 },
8371};
8372 
8373export const readable_with_unimplemented_read = {
8374 async test(ctrl, env, ctx) {
8375 const readable = new Readable();
8376 readable.read();
8377 const errored = Promise.withResolvers();
8378 const closed = Promise.withResolvers();
8379 readable.on('error', function (err) {
8380 strictEqual(err.code, 'ERR_METHOD_NOT_IMPLEMENTED');
8381 errored.resolve();
8382 });
8383 readable.on('close', closed.resolve);
8384 await Promise.all([errored.promise, closed.promise]);
8385 },
8386};
8387 
8388export const readable_unshift = {
8389 async test(ctrl, env, ctx) {
8390 {
8391 // Check that strings are saved as Buffer
8392 const readable = new Readable({
8393 read() {},
8394 });
8395 const string = 'abc';
8396 const dataCalled = Promise.withResolvers();
8397 readable.on('data', (chunk) => {
8398 ok(Buffer.isBuffer(chunk));
8399 strictEqual(chunk.toString('utf8'), string);
8400 dataCalled.resolve();
8401 });
8402 readable.unshift(string);
8403 await dataCalled.promise;
8404 }
8405 {
8406 // Check that data goes at the beginning
8407 const readable = new Readable({
8408 read() {},
8409 });
8410 const unshift = 'front';
8411 const push = 'back';
8412 const expected = [unshift, push];
8413 const dataCalled = Promise.withResolvers();
8414 let dataCount = 0;
8415 readable.on('data', (chunk) => {
8416 strictEqual(chunk.toString('utf8'), expected.shift());
8417 if (++dataCount === 2) dataCalled.resolve();
8418 });
8419 readable.push(push);
8420 readable.unshift(unshift);
8421 await dataCalled.promise;
8422 }
8423 {
8424 // Check that buffer is saved with correct encoding
8425 const readable = new Readable({
8426 read() {},
8427 });
8428 const encoding = 'base64';
8429 const string = Buffer.from('abc').toString(encoding);
8430 const dataCalled = Promise.withResolvers();
8431 readable.on('data', (chunk) => {
8432 strictEqual(chunk.toString(encoding), string);
8433 dataCalled.resolve();
8434 });
8435 readable.unshift(string, encoding);
8436 await dataCalled.promise;
8437 }
8438 {
8439 const streamEncoding = 'base64';
8440 const dataCalled = Promise.withResolvers();
8441 function checkEncoding(readable) {
8442 // chunk encodings
8443 const encodings = ['utf8', 'binary', 'hex', 'base64'];
8444 const expected = [];
8445 let dataCount = 0;
8446 readable.on('data', (chunk) => {
8447 const { encoding, string } = expected.pop();
8448 strictEqual(chunk.toString(encoding), string);
8449 if (++dataCount === encodings.length) dataCalled.resolve();
8450 });
8451 for (const encoding of encodings) {
8452 const string = 'abc';
8453 
8454 // If encoding is the same as the state.encoding the string is
8455 // saved as is
8456 const expect =
8457 encoding !== streamEncoding
8458 ? Buffer.from(string, encoding).toString(streamEncoding)
8459 : string;
8460 expected.push({
8461 encoding,
8462 string: expect,
8463 });
8464 readable.unshift(string, encoding);
8465 }
8466 }
8467 const r1 = new Readable({
8468 read() {},
8469 });
8470 r1.setEncoding(streamEncoding);
8471 checkEncoding(r1);
8472 const r2 = new Readable({
8473 read() {},
8474 encoding: streamEncoding,
8475 });
8476 checkEncoding(r2);
8477 await dataCalled.promise;
8478 }
8479 {
8480 // Both .push & .unshift should have the same behavior
8481 // When setting an encoding, each chunk should be emitted with that encoding
8482 const encoding = 'base64';
8483 const dataCalled = Promise.withResolvers();
8484 function checkEncoding(readable) {
8485 const string = 'abc';
8486 let dataCount = 0;
8487 readable.on('data', (chunk) => {
8488 strictEqual(chunk, Buffer.from(string).toString(encoding));
8489 if (++dataCount === 2) dataCalled.resolve();
8490 });
8491 readable.push(string);
8492 readable.unshift(string);
8493 }
8494 const r1 = new Readable({
8495 read() {},
8496 });
8497 r1.setEncoding(encoding);
8498 checkEncoding(r1);
8499 const r2 = new Readable({
8500 read() {},
8501 encoding,
8502 });
8503 checkEncoding(r2);
8504 await dataCalled.promise;
8505 }
8506 {
8507 // Check that ObjectMode works
8508 const readable = new Readable({
8509 objectMode: true,
8510 read() {},
8511 });
8512 const chunks = ['a', 1, {}, []];
8513 const dataCalled = Promise.withResolvers();
8514 let dataCount = 0;
8515 readable.on('data', (chunk) => {
8516 strictEqual(chunk, chunks.pop());
8517 if (++dataCount === chunks.length) dataCalled.resolve();
8518 });
8519 for (const chunk of chunks) {
8520 readable.unshift(chunk);
8521 }
8522 await dataCalled.promise;
8523 }
8524 {
8525 // Should not throw: https://github.com/nodejs/node/issues/27192
8526 const highWaterMark = 50;
8527 class ArrayReader extends Readable {
8528 constructor(opt) {
8529 super({
8530 highWaterMark,
8531 });
8532 // The error happened only when pushing above hwm
8533 this.buffer = Array.from({ length: highWaterMark * 2 }, () => '0');
8534 }
8535 _read(size) {
8536 while (this.buffer.length) {
8537 const chunk = this.buffer.shift();
8538 if (!this.buffer.length) {
8539 this.push(chunk);
8540 this.push(null);
8541 return true;
8542 }
8543 if (!this.push(chunk)) return;
8544 }
8545 }
8546 }
8547 const readCalled = Promise.withResolvers();
8548 function onRead() {
8549 while (null !== stream.read()) {
8550 // Remove the 'readable' listener before unshifting
8551 stream.removeListener('readable', onRead);
8552 stream.unshift('a');
8553 break;
8554 }
8555 readCalled.resolve();
8556 }
8557 const stream = new ArrayReader();
8558 stream.once('readable', onRead);
8559 await readCalled.promise;
8560 }
8561 },
8562};
8563 
8564export const readable_setencoding_null = {
8565 async test(ctrl, env, ctx) {
8566 const readable = new Readable({
8567 encoding: 'hex',
8568 });
8569 strictEqual(readable._readableState.encoding, 'hex');
8570 readable.setEncoding(null);
8571 strictEqual(readable._readableState.encoding, 'utf8');
8572 },
8573};
8574 
8575export const readable_setencoding_existing_buffers = {
8576 async test(ctrl, env, ctx) {
8577 {
8578 // Call .setEncoding() while there are bytes already in the buffer.
8579 const r = new Readable({
8580 read() {},
8581 });
8582 r.push(Buffer.from('a'));
8583 r.push(Buffer.from('b'));
8584 r.setEncoding('utf8');
8585 const chunks = [];
8586 r.on('data', (chunk) => chunks.push(chunk));
8587 queueMicrotask(() => {
8588 deepStrictEqual(chunks, ['ab']);
8589 });
8590 }
8591 {
8592 // Call .setEncoding() while the buffer contains a complete,
8593 // but chunked character.
8594 const r = new Readable({
8595 read() {},
8596 });
8597 r.push(Buffer.from([0xf0]));
8598 r.push(Buffer.from([0x9f]));
8599 r.push(Buffer.from([0x8e]));
8600 r.push(Buffer.from([0x89]));
8601 r.setEncoding('utf8');
8602 const chunks = [];
8603 r.on('data', (chunk) => chunks.push(chunk));
8604 queueMicrotask(() => {
8605 deepStrictEqual(chunks, ['๐ŸŽ‰']);
8606 });
8607 }
8608 {
8609 // Call .setEncoding() while the buffer contains an incomplete character,
8610 // and finish the character later.
8611 const r = new Readable({
8612 read() {},
8613 });
8614 r.push(Buffer.from([0xf0]));
8615 r.push(Buffer.from([0x9f]));
8616 r.setEncoding('utf8');
8617 r.push(Buffer.from([0x8e]));
8618 r.push(Buffer.from([0x89]));
8619 const chunks = [];
8620 r.on('data', (chunk) => chunks.push(chunk));
8621 queueMicrotask(() => {
8622 deepStrictEqual(chunks, ['๐ŸŽ‰']);
8623 });
8624 }
8625 },
8626};
8627 
8628export const readable_resumescheduled = {
8629 async test(ctrl, env, ctx) {
8630 {
8631 // pipe() test case
8632 const r = new Readable({
8633 read() {},
8634 });
8635 const w = new Writable();
8636 
8637 // resumeScheduled should start = `false`.
8638 strictEqual(r._readableState.resumeScheduled, false);
8639 
8640 // Calling pipe() should change the state value = true.
8641 r.pipe(w);
8642 strictEqual(r._readableState.resumeScheduled, true);
8643 queueMicrotask(() => {
8644 strictEqual(r._readableState.resumeScheduled, false);
8645 });
8646 }
8647 {
8648 // 'data' listener test case
8649 const r = new Readable({
8650 read() {},
8651 });
8652 
8653 // resumeScheduled should start = `false`.
8654 strictEqual(r._readableState.resumeScheduled, false);
8655 r.push(Buffer.from([1, 2, 3]));
8656 
8657 // Adding 'data' listener should change the state value
8658 r.on('data', () => {
8659 strictEqual(r._readableState.resumeScheduled, false);
8660 });
8661 strictEqual(r._readableState.resumeScheduled, true);
8662 queueMicrotask(() => {
8663 strictEqual(r._readableState.resumeScheduled, false);
8664 });
8665 }
8666 {
8667 // resume() test case
8668 const r = new Readable({
8669 read() {},
8670 });
8671 
8672 // resumeScheduled should start = `false`.
8673 strictEqual(r._readableState.resumeScheduled, false);
8674 
8675 // Calling resume() should change the state value.
8676 r.resume();
8677 strictEqual(r._readableState.resumeScheduled, true);
8678 r.on('resume', () => {
8679 // The state value should be `false` again
8680 strictEqual(r._readableState.resumeScheduled, false);
8681 });
8682 queueMicrotask(() => {
8683 strictEqual(r._readableState.resumeScheduled, false);
8684 });
8685 }
8686 },
8687};
8688 
8689export const readable_resume_hwm = {
8690 async test(ctrl, env, ctx) {
8691 const readable = new Readable({
8692 read: () => {
8693 throw new Error('should not be called');
8694 },
8695 highWaterMark: 100,
8696 });
8697 
8698 // Fill up the internal buffer so that we definitely exceed the HWM:
8699 for (let i = 0; i < 10; i++) readable.push('a'.repeat(200));
8700 
8701 // Call resume, and pause after one chunk.
8702 // The .pause() is just so that we donโ€™t empty the buffer fully, which would
8703 // be a valid reason to call ._read().
8704 readable.resume();
8705 const dataCalled = Promise.withResolvers();
8706 readable.once('data', () => {
8707 readable.pause();
8708 dataCalled.resolve();
8709 });
8710 await dataCalled.promise;
8711 },
8712};
8713 
8714export const readable_reading_readingmore = {
8715 async test(ctrl, env, ctx) {
8716 {
8717 const readable = new Readable({
8718 read(size) {},
8719 });
8720 const state = readable._readableState;
8721 
8722 // Starting off with false initially.
8723 strictEqual(state.reading, false);
8724 strictEqual(state.readingMore, false);
8725 let dataCount = 0;
8726 let readableCount = 0;
8727 const dataCalled = Promise.withResolvers();
8728 const readableCalled = Promise.withResolvers();
8729 const ended = Promise.withResolvers();
8730 readable.on('data', (data) => {
8731 // While in a flowing state with a 'readable' listener
8732 // we should not be reading more
8733 if (readable.readableFlowing) strictEqual(state.readingMore, true);
8734 
8735 // Reading as long as we've not ended
8736 strictEqual(state.reading, !state.ended);
8737 if (++dataCount === 2) dataCalled.resolve();
8738 });
8739 function onStreamEnd() {
8740 // End of stream; state.reading is false
8741 // And so should be readingMore.
8742 strictEqual(state.readingMore, false);
8743 strictEqual(state.reading, false);
8744 ended.resolve();
8745 }
8746 const expectedReadingMore = [true, true, false];
8747 readable.on('readable', () => {
8748 // There is only one readingMore scheduled from on('data'),
8749 // after which everything is governed by the .read() call
8750 strictEqual(state.readingMore, expectedReadingMore.shift());
8751 
8752 // If the stream has ended, we shouldn't be reading
8753 strictEqual(state.ended, !state.reading);
8754 
8755 // Consume all the data
8756 while (readable.read() !== null);
8757 if (expectedReadingMore.length === 0)
8758 // Reached end of stream
8759 queueMicrotask(onStreamEnd);
8760 if (++readableCount === 3) readableCalled.resolve();
8761 });
8762 readable.on('end', onStreamEnd);
8763 readable.push('pushed');
8764 readable.read(6);
8765 
8766 // reading
8767 strictEqual(state.reading, true);
8768 strictEqual(state.readingMore, true);
8769 
8770 // add chunk to front
8771 readable.unshift('unshifted');
8772 
8773 // end
8774 readable.push(null);
8775 await Promise.all([
8776 dataCalled.promise,
8777 readableCalled.promise,
8778 ended.promise,
8779 ]);
8780 }
8781 {
8782 const readable = new Readable({
8783 read(size) {},
8784 });
8785 const state = readable._readableState;
8786 
8787 // Starting off with false initially.
8788 strictEqual(state.reading, false);
8789 strictEqual(state.readingMore, false);
8790 let dataCount = 0;
8791 const dataCalled = Promise.withResolvers();
8792 const ended = Promise.withResolvers();
8793 readable.on('data', (data) => {
8794 // While in a flowing state without a 'readable' listener
8795 // we should be reading more
8796 if (readable.readableFlowing) strictEqual(state.readingMore, true);
8797 
8798 // Reading as long as we've not ended
8799 strictEqual(state.reading, !state.ended);
8800 if (++dataCount === 2) dataCalled.resolve();
8801 });
8802 function onStreamEnd() {
8803 // End of stream; state.reading is false
8804 // And so should be readingMore.
8805 strictEqual(state.readingMore, false);
8806 strictEqual(state.reading, false);
8807 ended.resolve();
8808 }
8809 readable.on('end', onStreamEnd);
8810 readable.push('pushed');
8811 
8812 // Stop emitting 'data' events
8813 strictEqual(state.flowing, true);
8814 readable.pause();
8815 
8816 // paused
8817 strictEqual(state.reading, false);
8818 strictEqual(state.flowing, false);
8819 readable.resume();
8820 strictEqual(state.reading, false);
8821 strictEqual(state.flowing, true);
8822 
8823 // add chunk to front
8824 readable.unshift('unshifted');
8825 
8826 // end
8827 readable.push(null);
8828 await Promise.all([dataCalled.promise, ended.promise]);
8829 }
8830 {
8831 const readable = new Readable({
8832 read(size) {},
8833 });
8834 const state = readable._readableState;
8835 
8836 let dataCount = 0;
8837 const dataCalled = Promise.withResolvers();
8838 const ended = Promise.withResolvers();
8839 
8840 // Starting off with false initially.
8841 strictEqual(state.reading, false);
8842 strictEqual(state.readingMore, false);
8843 readable.on('readable', fail);
8844 readable.on('data', (data) => {
8845 // Reading as long as we've not ended
8846 strictEqual(state.reading, !state.ended);
8847 if (++dataCount === 2) dataCalled.resolve();
8848 });
8849 readable.removeListener('readable', fail);
8850 function onStreamEnd() {
8851 // End of stream; state.reading is false
8852 // And so should be readingMore.
8853 strictEqual(state.readingMore, false);
8854 strictEqual(state.reading, false);
8855 ended.resolve();
8856 }
8857 readable.on('end', onStreamEnd);
8858 readable.push('pushed');
8859 
8860 // We are still not flowing, we will be resuming in the next tick
8861 strictEqual(state.flowing, false);
8862 
8863 // Wait for nextTick, so the readableListener flag resets
8864 queueMicrotask(function () {
8865 readable.resume();
8866 
8867 // Stop emitting 'data' events
8868 strictEqual(state.flowing, true);
8869 readable.pause();
8870 
8871 // paused
8872 strictEqual(state.flowing, false);
8873 readable.resume();
8874 strictEqual(state.flowing, true);
8875 
8876 // add chunk to front
8877 readable.unshift('unshifted');
8878 
8879 // end
8880 readable.push(null);
8881 });
8882 
8883 await Promise.all([dataCalled.promise, ended.promise]);
8884 }
8885 },
8886};
8887 
8888export const readable_readable = {
8889 async test(ctrl, env, ctx) {
8890 {
8891 const r = new Readable({
8892 read() {},
8893 });
8894 strictEqual(r.readable, true);
8895 r.destroy();
8896 strictEqual(r.readable, false);
8897 }
8898 {
8899 const r = new Readable({
8900 read() {},
8901 });
8902 strictEqual(r.readable, true);
8903 r.on('end', fail);
8904 r.resume();
8905 r.push(null);
8906 strictEqual(r.readable, true);
8907 r.off('end', fail);
8908 const ended = Promise.withResolvers();
8909 r.on('end', () => {
8910 strictEqual(r.readable, false);
8911 ended.resolve();
8912 });
8913 }
8914 {
8915 const readCalled = Promise.withResolvers();
8916 const errored = Promise.withResolvers();
8917 const r = new Readable({
8918 read: () => {
8919 queueMicrotask(() => {
8920 r.destroy(new Error());
8921 strictEqual(r.readable, false);
8922 readCalled.resolve();
8923 });
8924 },
8925 });
8926 r.resume();
8927 r.on('error', () => {
8928 strictEqual(r.readable, false);
8929 errored.resolve();
8930 });
8931 await Promise.all([readCalled.promise, errored.promise]);
8932 }
8933 },
8934};
8935 
8936export const readable_readable_then_resume = {
8937 async test(ctrl, env, ctx) {
8938 await check(
8939 new Readable({
8940 objectMode: true,
8941 highWaterMark: 1,
8942 read() {
8943 if (!this.first) {
8944 this.push('hello');
8945 this.first = true;
8946 return;
8947 }
8948 this.push(null);
8949 },
8950 })
8951 );
8952 async function check(s) {
8953 const ended = Promise.withResolvers();
8954 s.on('readable', ended.reject);
8955 s.on('end', ended.resolve);
8956 strictEqual(s.removeListener, s.off);
8957 s.removeListener('readable', ended.reject);
8958 s.resume();
8959 await ended.promise;
8960 }
8961 },
8962};
8963 
8964export const readable_pause_and_resume = {
8965 async test(ctrl, env, ctx) {
8966 let ticks = 18;
8967 let expectedData = 19;
8968 const rs = new Readable({
8969 objectMode: true,
8970 read: () => {
8971 if (ticks-- > 0) return queueMicrotask(() => rs.push({}));
8972 rs.push({});
8973 rs.push(null);
8974 },
8975 });
8976 const ended = Promise.withResolvers();
8977 const ondataCalled = Promise.withResolvers();
8978 rs.on('end', ended.resolve);
8979 await readAndPause();
8980 async function readAndPause() {
8981 // Does a on(data) -> pause -> wait -> resume -> on(data) ... loop.
8982 // Expects on(data) to never fire if the stream is paused.
8983 const ondata = (data) => {
8984 rs.pause();
8985 expectedData--;
8986 if (expectedData <= 0) return;
8987 queueMicrotask(function () {
8988 rs.removeListener('data', ondata);
8989 readAndPause();
8990 rs.resume();
8991 ondataCalled.resolve();
8992 });
8993 }; // Only call ondata once
8994 
8995 rs.on('data', ondata);
8996 await Promise.all([ended.promise, ondataCalled.promise]);
8997 }
8998 {
8999 const readable = new Readable({
9000 read() {},
9001 });
9002 function read() {}
9003 readable.setEncoding('utf8');
9004 readable.on('readable', read);
9005 readable.removeListener('readable', read);
9006 readable.pause();
9007 queueMicrotask(function () {
9008 ok(readable.isPaused());
9009 });
9010 }
9011 {
9012 const source3 = new PassThrough();
9013 const target3 = new PassThrough();
9014 const chunk = Buffer.allocUnsafe(1000);
9015 while (target3.write(chunk));
9016 source3.pipe(target3);
9017 const drainCalled = Promise.withResolvers();
9018 target3.on('drain', () => {
9019 ok(!source3.isPaused());
9020 drainCalled.resolve();
9021 });
9022 target3.on('data', () => {});
9023 await drainCalled.promise;
9024 }
9025 },
9026};
9027 
9028export const readable_object_multi_push_async = {
9029 async test(ctrl, env, ctx) {
9030 const MAX = 42;
9031 const BATCH = 10;
9032 {
9033 const readCalled = Promise.withResolvers();
9034 const ended = Promise.withResolvers();
9035 let readCount = 0;
9036 const readable = new Readable({
9037 objectMode: true,
9038 read: function () {
9039 fetchData((err, data) => {
9040 if (err) {
9041 this.destroy(err);
9042 return;
9043 }
9044 if (data.length === 0) {
9045 this.push(null);
9046 return;
9047 }
9048 data.forEach((d) => this.push(d));
9049 });
9050 if (++readCount === Math.floor(MAX / BATCH) + 2) readCalled.resolve();
9051 },
9052 });
9053 let i = 0;
9054 function fetchData(cb) {
9055 if (i > MAX) {
9056 setTimeout(cb, 10, null, []);
9057 } else {
9058 const array = [];
9059 const max = i + BATCH;
9060 for (; i < max; i++) {
9061 array.push(i);
9062 }
9063 setTimeout(cb, 10, null, array);
9064 }
9065 }
9066 readable.on('readable', () => {
9067 let _data;
9068 while ((_data = readable.read()) !== null) {
9069 // intentionally empty
9070 }
9071 });
9072 readable.on('end', () => {
9073 strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH);
9074 ended.resolve();
9075 });
9076 await Promise.all([readCalled.promise, ended.promise]);
9077 }
9078 {
9079 const readCalled = Promise.withResolvers();
9080 const ended = Promise.withResolvers();
9081 let readCount = 0;
9082 const readable = new Readable({
9083 objectMode: true,
9084 read: function () {
9085 fetchData((err, data) => {
9086 if (err) {
9087 this.destroy(err);
9088 return;
9089 }
9090 if (data.length === 0) {
9091 this.push(null);
9092 return;
9093 }
9094 data.forEach((d) => this.push(d));
9095 });
9096 if (++readCount === Math.floor(MAX / BATCH) + 2) readCalled.resolve();
9097 },
9098 });
9099 let i = 0;
9100 function fetchData(cb) {
9101 if (i > MAX) {
9102 setTimeout(cb, 10, null, []);
9103 } else {
9104 const array = [];
9105 const max = i + BATCH;
9106 for (; i < max; i++) {
9107 array.push(i);
9108 }
9109 setTimeout(cb, 10, null, array);
9110 }
9111 }
9112 readable.on('data', (data) => {});
9113 readable.on('end', () => {
9114 strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH);
9115 ended.resolve();
9116 });
9117 await Promise.all([readCalled.promise, ended.promise]);
9118 }
9119 {
9120 const readCalled = Promise.withResolvers();
9121 const ended = Promise.withResolvers();
9122 let readCount = 0;
9123 const readable = new Readable({
9124 objectMode: true,
9125 read: function () {
9126 fetchData((err, data) => {
9127 if (err) {
9128 this.destroy(err);
9129 return;
9130 }
9131 data.forEach((d) => this.push(d));
9132 if (data[BATCH - 1] >= MAX) {
9133 this.push(null);
9134 }
9135 });
9136 if (++readCount === Math.floor(MAX / BATCH) + 1) readCalled.resolve();
9137 },
9138 });
9139 let i = 0;
9140 function fetchData(cb) {
9141 const array = [];
9142 const max = i + BATCH;
9143 for (; i < max; i++) {
9144 array.push(i);
9145 }
9146 setTimeout(cb, 10, null, array);
9147 }
9148 readable.on('data', (data) => {});
9149 readable.on('end', () => {
9150 strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH);
9151 ended.resolve();
9152 });
9153 await Promise.all([readCalled.promise, ended.promise]);
9154 }
9155 {
9156 const ended = Promise.withResolvers();
9157 const readable = new Readable({
9158 objectMode: true,
9159 read() {},
9160 });
9161 readable.on('data', ended.reject);
9162 readable.push(null);
9163 let nextTickPassed = false;
9164 queueMicrotask(() => {
9165 nextTickPassed = true;
9166 });
9167 readable.on('end', () => {
9168 strictEqual(nextTickPassed, true);
9169 ended.resolve();
9170 });
9171 await ended.promise;
9172 }
9173 {
9174 const ended = Promise.withResolvers();
9175 const readCalled = Promise.withResolvers();
9176 const readable = new Readable({
9177 objectMode: true,
9178 read: readCalled.resolve,
9179 });
9180 readable.on('data', (data) => {});
9181 readable.on('end', ended.resolve);
9182 queueMicrotask(() => {
9183 readable.push('aaa');
9184 readable.push(null);
9185 });
9186 await Promise.all([readCalled.promise, ended.promise]);
9187 }
9188 },
9189};
9190 
9191export const readable_no_unneeded_readable = {
9192 async test(ctrl, env, ctx) {
9193 async function test(r) {
9194 const wrapper = new Readable({
9195 read: () => {
9196 let data = r.read();
9197 if (data) {
9198 wrapper.push(data);
9199 return;
9200 }
9201 r.once('readable', function () {
9202 data = r.read();
9203 if (data) {
9204 wrapper.push(data);
9205 }
9206 // else: the end event should fire
9207 });
9208 },
9209 });
9210 
9211 r.once('end', function () {
9212 wrapper.push(null);
9213 });
9214 const ended = Promise.withResolvers();
9215 wrapper.resume();
9216 wrapper.once('end', ended.resolve);
9217 await ended.promise;
9218 }
9219 {
9220 const source = new Readable({
9221 read: () => {},
9222 });
9223 source.push('foo');
9224 source.push('bar');
9225 source.push(null);
9226 const pt = source.pipe(new PassThrough());
9227 await test(pt);
9228 }
9229 {
9230 // This is the underlying cause of the above test case.
9231 const pushChunks = ['foo', 'bar'];
9232 const r = new Readable({
9233 read: () => {
9234 const chunk = pushChunks.shift();
9235 if (chunk) {
9236 // synchronous call
9237 r.push(chunk);
9238 } else {
9239 // asynchronous call
9240 queueMicrotask(() => r.push(null));
9241 }
9242 },
9243 });
9244 await test(r);
9245 }
9246 },
9247};
9248 
9249export const readable_next_no_null = {
9250 async test(ctrl, env, ctx) {
9251 async function* generate() {
9252 yield null;
9253 }
9254 const stream = Readable.from(generate());
9255 const errored = Promise.withResolvers();
9256 stream.on('error', function (err) {
9257 strictEqual(err.code, 'ERR_STREAM_NULL_VALUES');
9258 errored.resolve();
9259 });
9260 stream.on('data', errored.reject);
9261 stream.on('end', errored.reject);
9262 await errored.promise;
9263 },
9264};
9265 
9266export const readable_needreadable = {
9267 async test(ctrl, env, ctx) {
9268 const readable = new Readable({
9269 read: () => {},
9270 });
9271 
9272 // Initialized to false.
9273 strictEqual(readable._readableState.needReadable, false);
9274 const readableCalled1 = Promise.withResolvers();
9275 const ended = Promise.withResolvers();
9276 readable.on('readable', () => {
9277 // When the readable event fires, needReadable is reset.
9278 strictEqual(readable._readableState.needReadable, false, '1');
9279 readable.read();
9280 readableCalled1.resolve();
9281 });
9282 
9283 // If a readable listener is attached, then a readable event is needed.
9284 strictEqual(readable._readableState.needReadable, true);
9285 readable.push('foo');
9286 readable.push(null);
9287 readable.on('end', () => {
9288 // No need to emit readable anymore when the stream ends.
9289 strictEqual(readable._readableState.needReadable, false, '2');
9290 ended.resolve();
9291 });
9292 await Promise.all([readableCalled1.promise, ended.promise]);
9293 
9294 const readableCalled2 = Promise.withResolvers();
9295 const _ended2 = Promise.withResolvers();
9296 const dataCalled = Promise.withResolvers();
9297 let _readableCount = 0;
9298 let dataCount = 0;
9299 const asyncReadable = new Readable({
9300 read: () => {},
9301 });
9302 
9303 asyncReadable.on('readable', () => {
9304 if (asyncReadable.read() !== null) {
9305 // After each read(), the buffer is empty.
9306 // If the stream doesn't end now,
9307 // then we need to notify the reader on future changes.
9308 readableCalled2.resolve();
9309 }
9310 });
9311 queueMicrotask(() => {
9312 asyncReadable.push('foooo');
9313 });
9314 queueMicrotask(() => {
9315 asyncReadable.push('bar');
9316 });
9317 queueMicrotask(() => {
9318 asyncReadable.push(null);
9319 strictEqual(asyncReadable._readableState.needReadable, false);
9320 });
9321 const flowing = new Readable({
9322 read: () => {},
9323 });
9324 
9325 // Notice this must be above the on('data') call.
9326 flowing.push('foooo');
9327 flowing.push('bar');
9328 flowing.push('quo');
9329 queueMicrotask(() => {
9330 flowing.push(null);
9331 });
9332 
9333 // When the buffer already has enough data, and the stream is
9334 // in flowing mode, there is no need for the readable event.
9335 flowing.on('data', function (data) {
9336 strictEqual(flowing._readableState.needReadable, false);
9337 if (++dataCount === 3) dataCalled.resolve();
9338 });
9339 await Promise.all([
9340 readableCalled2.promise,
9341 dataCalled.promise,
9342 ended.promise,
9343 ]);
9344 
9345 // const slowProducer = new Readable({
9346 // read: () => {}
9347 // });
9348 // const readableCalled3 = Promise.withResolvers();;
9349 // readableCount = 0;
9350 // slowProducer.on(
9351 // 'readable',
9352 // () => {
9353 // const chunk = slowProducer.read(8);
9354 // const state = slowProducer._readableState;
9355 // if (chunk === null) {
9356 // // The buffer doesn't have enough data, and the stream is not need,
9357 // // we need to notify the reader when data arrives.
9358 // strictEqual(state.needReadable, true);
9359 // } else {
9360 // strictEqual(state.needReadable, false);
9361 // }
9362 // if (++readableCount === 4) readableCalled3.resolve();
9363 // }
9364 // );
9365 // queueMicrotask(
9366 // () => {
9367 // slowProducer.push('foo')
9368 // queueMicrotask(
9369 // () => {
9370 // slowProducer.push('foo')
9371 // queueMicrotask(
9372 // () => {
9373 // slowProducer.push('foo')
9374 // queueMicrotask(
9375 // () => {
9376 // slowProducer.push(null)
9377 // }
9378 // );
9379 // }
9380 // );
9381 // }
9382 // );
9383 // }
9384 // );
9385 },
9386};
9387 
9388export const readable_invalid_chunk = {
9389 async test(ctrl, env, ctx) {
9390 async function testPushArg(val) {
9391 const readable = new Readable({
9392 read: () => {},
9393 });
9394 const errored = Promise.withResolvers();
9395 readable.on('error', function (err) {
9396 strictEqual(err.code, 'ERR_INVALID_ARG_TYPE');
9397 errored.resolve();
9398 });
9399 readable.push(val);
9400 await errored.promise;
9401 }
9402 await Promise.all([testPushArg([]), testPushArg({}), testPushArg(0)]);
9403 async function testUnshiftArg(val) {
9404 const readable = new Readable({
9405 read: () => {},
9406 });
9407 const errored = Promise.withResolvers();
9408 readable.on('error', function (err) {
9409 strictEqual(err.code, 'ERR_INVALID_ARG_TYPE');
9410 errored.resolve();
9411 });
9412 readable.unshift(val);
9413 await errored.promise;
9414 }
9415 await Promise.all([
9416 testUnshiftArg([]),
9417 testUnshiftArg({}),
9418 testUnshiftArg(0),
9419 ]);
9420 },
9421};
9422 
9423export const readable_hwm_0 = {
9424 async test(ctrl, env, ctx) {
9425 const readableCalled = Promise.withResolvers();
9426 const readCalled = Promise.withResolvers();
9427 const ended = Promise.withResolvers();
9428 const r = new Readable({
9429 // Must be called only once upon setting 'readable' listener
9430 read: readCalled.resolve,
9431 highWaterMark: 0,
9432 });
9433 let pushedNull = false;
9434 // This will trigger read(0) but must only be called after push(null)
9435 // because the we haven't pushed any data
9436 r.on('readable', () => {
9437 strictEqual(r.read(), null);
9438 strictEqual(pushedNull, true);
9439 readableCalled.resolve();
9440 });
9441 r.on('end', ended.resolve);
9442 queueMicrotask(() => {
9443 strictEqual(r.read(), null);
9444 pushedNull = true;
9445 r.push(null);
9446 });
9447 await Promise.all([
9448 readableCalled.promise,
9449 readCalled.promise,
9450 ended.promise,
9451 ]);
9452 },
9453};
9454 
9455export const readable_hwm_0_async = {
9456 async test(ctrl, env, ctx) {
9457 let count = 5;
9458 const readCalled = Promise.withResolvers();
9459 const ended = Promise.withResolvers();
9460 const dataCalled = Promise.withResolvers();
9461 let readCount = 0;
9462 let dataCount = 0;
9463 const r = new Readable({
9464 // Called 6 times: First 5 return data, last one signals end of stream.
9465 read: () => {
9466 queueMicrotask(() => {
9467 if (count--) r.push('a');
9468 else r.push(null);
9469 });
9470 if (++readCount === 6) readCalled.resolve();
9471 },
9472 highWaterMark: 0,
9473 });
9474 r.on('end', ended.resolve);
9475 r.on('data', () => {
9476 if (++dataCount === 5) dataCalled.resolve();
9477 });
9478 await Promise.all([readCalled.promise, ended.promise, dataCalled.promise]);
9479 },
9480};
9481 
9482export const readable_event = {
9483 async test(ctrl, env, ctx) {
9484 {
9485 // First test, not reading when the readable is added.
9486 // make sure that on('readable', ...) triggers a readable event.
9487 const r = new Readable({
9488 highWaterMark: 3,
9489 });
9490 const readableCalled = Promise.withResolvers();
9491 r._read = readableCalled.reject;
9492 
9493 // This triggers a 'readable' event, which is lost.
9494 r.push(Buffer.from('blerg'));
9495 setTimeout(function () {
9496 // We're testing what we think we are
9497 ok(!r._readableState.reading);
9498 r.on('readable', readableCalled.resolve);
9499 }, 1);
9500 await readableCalled.promise;
9501 }
9502 {
9503 // Second test, make sure that readable is re-emitted if there's
9504 // already a length, while it IS reading.
9505 
9506 const r = new Readable({
9507 highWaterMark: 3,
9508 });
9509 const readCalled = Promise.withResolvers();
9510 const readableCalled = Promise.withResolvers();
9511 r._read = readCalled.resolve;
9512 
9513 // This triggers a 'readable' event, which is lost.
9514 r.push(Buffer.from('bl'));
9515 setTimeout(function () {
9516 // Assert we're testing what we think we are
9517 ok(r._readableState.reading);
9518 r.on('readable', readableCalled.resolve);
9519 }, 1);
9520 await Promise.all([readCalled.promise, readableCalled.promise]);
9521 }
9522 {
9523 // Third test, not reading when the stream has not passed
9524 // the highWaterMark but *has* reached EOF.
9525 const r = new Readable({
9526 highWaterMark: 30,
9527 });
9528 
9529 // This triggers a 'readable' event, which is lost.
9530 r.push(Buffer.from('blerg'));
9531 r.push(null);
9532 const readableCalled = Promise.withResolvers();
9533 r._read = readableCalled.reject;
9534 setTimeout(function () {
9535 // Assert we're testing what we think we are
9536 ok(!r._readableState.reading);
9537 r.on('readable', readableCalled.resolve);
9538 }, 1);
9539 await readableCalled.promise;
9540 }
9541 {
9542 // Pushing an empty string in non-objectMode should
9543 // trigger next `read()`.
9544 const underlyingData = ['', 'x', 'y', '', 'z'];
9545 const expected = underlyingData.filter((data) => data);
9546 const result = [];
9547 const r = new Readable({
9548 encoding: 'utf8',
9549 });
9550 r._read = function () {
9551 queueMicrotask(() => {
9552 if (!underlyingData.length) {
9553 this.push(null);
9554 } else {
9555 this.push(underlyingData.shift());
9556 }
9557 });
9558 };
9559 r.on('readable', () => {
9560 const data = r.read();
9561 if (data !== null) result.push(data);
9562 });
9563 const ended = Promise.withResolvers();
9564 r.on('end', () => {
9565 deepStrictEqual(result, expected);
9566 ended.resolve();
9567 });
9568 await ended.promise;
9569 }
9570 {
9571 // #20923
9572 const r = new Readable();
9573 r._read = function () {
9574 // Actually doing thing here
9575 };
9576 r.on('data', function () {});
9577 r.removeAllListeners();
9578 strictEqual(r.eventNames().length, 0);
9579 }
9580 },
9581};
9582 
9583export const readable_error_end = {
9584 async test(ctrl, env, ctx) {
9585 const r = new Readable({
9586 read() {},
9587 });
9588 const data = Promise.withResolvers();
9589 const errored = Promise.withResolvers();
9590 r.on('end', errored.reject);
9591 r.on('data', data.resolve);
9592 r.on('error', errored.resolve);
9593 r.push('asd');
9594 r.push(null);
9595 r.destroy(new Error('kaboom'));
9596 await Promise.all([data.promise, errored.promise]);
9597 },
9598};
9599 
9600export const readable_ended = {
9601 async test(ctrl, env, ctx) {
9602 {
9603 // Find it on Readable.prototype
9604 ok(Reflect.has(Readable.prototype, 'readableEnded'));
9605 }
9606 
9607 // event
9608 {
9609 const readable = new Readable();
9610 readable._read = () => {
9611 // The state ended should start in false.
9612 strictEqual(readable.readableEnded, false);
9613 readable.push('asd');
9614 strictEqual(readable.readableEnded, false);
9615 readable.push(null);
9616 strictEqual(readable.readableEnded, false);
9617 };
9618 const ended = Promise.withResolvers();
9619 const dataCalled = Promise.withResolvers();
9620 readable.on('end', () => {
9621 strictEqual(readable.readableEnded, true);
9622 ended.resolve();
9623 });
9624 readable.on('data', () => {
9625 strictEqual(readable.readableEnded, false);
9626 dataCalled.resolve();
9627 });
9628 await Promise.all([ended.promise, dataCalled.promise]);
9629 }
9630 
9631 // Verifies no `error` triggered on multiple .push(null) invocations
9632 {
9633 const readable = new Readable();
9634 readable.on('readable', () => {
9635 readable.read();
9636 });
9637 const ended = Promise.withResolvers();
9638 readable.on('error', ended.reject);
9639 readable.on('end', ended.resolve);
9640 readable.push('a');
9641 readable.push(null);
9642 readable.push(null);
9643 await ended.promise;
9644 }
9645 },
9646};
9647 
9648export const readable_end_destroyed = {
9649 async test(ctrl, env, ctx) {
9650 const r = new Readable();
9651 const closed = Promise.withResolvers();
9652 r.on('end', fail);
9653 r.resume();
9654 r.destroy();
9655 r.on('close', () => {
9656 r.push(null);
9657 closed.resolve();
9658 });
9659 await closed.promise;
9660 },
9661};
9662 
9663export const readable_short_stream = {
9664 async test(ctrl, env, ctx) {
9665 {
9666 const readCalled = Promise.withResolvers();
9667 const transformCalled = Promise.withResolvers();
9668 const flushCalled = Promise.withResolvers();
9669 const readableCalled = Promise.withResolvers();
9670 let readableCount = 0;
9671 const r = new Readable({
9672 read: function () {
9673 this.push('content');
9674 this.push(null);
9675 readCalled.resolve();
9676 },
9677 });
9678 const t = new Transform({
9679 transform: function (chunk, encoding, callback) {
9680 transformCalled.resolve();
9681 this.push(chunk);
9682 return callback();
9683 },
9684 flush: function (callback) {
9685 flushCalled.resolve();
9686 return callback();
9687 },
9688 });
9689 r.pipe(t);
9690 t.on('readable', function () {
9691 while (true) {
9692 const chunk = t.read();
9693 if (!chunk) break;
9694 strictEqual(chunk.toString(), 'content');
9695 }
9696 if (++readableCount === 2) readableCalled.resolve();
9697 });
9698 await Promise.all([
9699 readCalled.promise,
9700 transformCalled.promise,
9701 flushCalled.promise,
9702 readableCalled.promise,
9703 ]);
9704 }
9705 {
9706 const transformCalled = Promise.withResolvers();
9707 const flushCalled = Promise.withResolvers();
9708 const readableCalled = Promise.withResolvers();
9709 const t = new Transform({
9710 transform: function (chunk, encoding, callback) {
9711 transformCalled.resolve();
9712 this.push(chunk);
9713 return callback();
9714 },
9715 flush: function (callback) {
9716 flushCalled.resolve();
9717 return callback();
9718 },
9719 });
9720 t.end('content');
9721 t.on('readable', function () {
9722 while (true) {
9723 const chunk = t.read();
9724 if (!chunk) break;
9725 strictEqual(chunk.toString(), 'content');
9726 }
9727 readableCalled.resolve();
9728 });
9729 await Promise.all([
9730 transformCalled.promise,
9731 flushCalled.promise,
9732 readableCalled.promise,
9733 ]);
9734 }
9735 {
9736 const transformCalled = Promise.withResolvers();
9737 const flushCalled = Promise.withResolvers();
9738 const readableCalled = Promise.withResolvers();
9739 const t = new Transform({
9740 transform: function (chunk, encoding, callback) {
9741 transformCalled.resolve();
9742 this.push(chunk);
9743 return callback();
9744 },
9745 flush: function (callback) {
9746 flushCalled.resolve();
9747 return callback();
9748 },
9749 });
9750 t.write('content');
9751 t.end();
9752 t.on('readable', function () {
9753 while (true) {
9754 const chunk = t.read();
9755 if (!chunk) break;
9756 strictEqual(chunk.toString(), 'content');
9757 readableCalled.resolve();
9758 }
9759 });
9760 await Promise.all([
9761 transformCalled.promise,
9762 flushCalled.promise,
9763 readableCalled.promise,
9764 ]);
9765 }
9766 {
9767 const t = new Readable({
9768 read() {},
9769 });
9770 const readableCalled = Promise.withResolvers();
9771 t.on('readable', function () {
9772 while (true) {
9773 const chunk = t.read();
9774 if (!chunk) break;
9775 strictEqual(chunk.toString(), 'content');
9776 }
9777 readableCalled.resolve();
9778 });
9779 t.push('content');
9780 t.push(null);
9781 await readableCalled.promise;
9782 }
9783 {
9784 const t = new Readable({
9785 read() {},
9786 });
9787 const readableCalled = Promise.withResolvers();
9788 let readableCount = 0;
9789 t.on('readable', function () {
9790 while (true) {
9791 const chunk = t.read();
9792 if (!chunk) break;
9793 strictEqual(chunk.toString(), 'content');
9794 }
9795 if (++readableCount === 2) readableCalled.resolve();
9796 });
9797 queueMicrotask(() => {
9798 t.push('content');
9799 t.push(null);
9800 });
9801 await readableCalled.promise;
9802 }
9803 {
9804 const transformCalled = Promise.withResolvers();
9805 const flushCalled = Promise.withResolvers();
9806 const readableCalled = Promise.withResolvers();
9807 let readableCount = 0;
9808 const t = new Transform({
9809 transform: function (chunk, encoding, callback) {
9810 transformCalled.resolve();
9811 this.push(chunk);
9812 return callback();
9813 },
9814 flush: function (callback) {
9815 flushCalled.resolve();
9816 return callback();
9817 },
9818 });
9819 t.on('readable', function () {
9820 while (true) {
9821 const chunk = t.read();
9822 if (!chunk) break;
9823 strictEqual(chunk.toString(), 'content');
9824 }
9825 if (++readableCount === 2) readableCalled.resolve();
9826 });
9827 t.write('content');
9828 t.end();
9829 await Promise.all([
9830 transformCalled.promise,
9831 flushCalled.promise,
9832 readableCalled.promise,
9833 ]);
9834 }
9835 },
9836};
9837 
9838export const readable_didread = {
9839 async test(ctrl, env, ctx) {
9840 function noop() {}
9841 async function check(readable, data, fn) {
9842 const closed = Promise.withResolvers();
9843 strictEqual(readable.readableDidRead, false);
9844 strictEqual(isDisturbed(readable), false);
9845 strictEqual(isErrored(readable), false);
9846 if (data === -1) {
9847 readable.on('error', () => {
9848 strictEqual(isErrored(readable), true);
9849 });
9850 readable.on('data', fail);
9851 readable.on('end', fail);
9852 } else {
9853 readable.on('error', fail);
9854 if (data === -2) {
9855 readable.on('end', fail);
9856 } else {
9857 readable.on('end', () => {});
9858 }
9859 if (data > 0) {
9860 readable.on('data', () => {});
9861 } else {
9862 readable.on('data', fail);
9863 }
9864 }
9865 readable.on('close', closed.resolve);
9866 fn();
9867 queueMicrotask(() => {
9868 strictEqual(readable.readableDidRead, data > 0);
9869 if (data > 0) {
9870 strictEqual(isDisturbed(readable), true);
9871 }
9872 });
9873 await closed.promise;
9874 }
9875 {
9876 const readable = new Readable({
9877 read() {
9878 this.push(null);
9879 },
9880 });
9881 await check(readable, 0, () => {
9882 readable.read();
9883 });
9884 }
9885 {
9886 const readable = new Readable({
9887 read() {
9888 this.push(null);
9889 },
9890 });
9891 await check(readable, 0, () => {
9892 readable.resume();
9893 });
9894 }
9895 {
9896 const readable = new Readable({
9897 read() {
9898 this.push(null);
9899 },
9900 });
9901 await check(readable, -2, () => {
9902 readable.destroy();
9903 });
9904 }
9905 {
9906 const readable = new Readable({
9907 read() {
9908 this.push(null);
9909 },
9910 });
9911 await check(readable, -1, () => {
9912 readable.destroy(new Error());
9913 });
9914 }
9915 {
9916 const readable = new Readable({
9917 read() {
9918 this.push('data');
9919 this.push(null);
9920 },
9921 });
9922 await check(readable, 1, () => {
9923 readable.on('data', noop);
9924 });
9925 }
9926 {
9927 const readable = new Readable({
9928 read() {
9929 this.push('data');
9930 this.push(null);
9931 },
9932 });
9933 await check(readable, 1, () => {
9934 readable.on('data', noop);
9935 readable.off('data', noop);
9936 });
9937 }
9938 },
9939};
9940 
9941export const readable_destroy = {
9942 async test(ctrl, env, ctx) {
9943 {
9944 const closed = Promise.withResolvers();
9945 const read = new Readable({
9946 read() {},
9947 });
9948 read.resume();
9949 read.on('close', closed.resolve);
9950 read.destroy();
9951 strictEqual(read.errored, null);
9952 strictEqual(read.destroyed, true);
9953 await closed.promise;
9954 }
9955 {
9956 const read = new Readable({
9957 read() {},
9958 });
9959 const closed = Promise.withResolvers();
9960 const errored = Promise.withResolvers();
9961 read.resume();
9962 const expected = new Error('kaboom');
9963 read.on('end', closed.reject);
9964 read.on('close', closed.resolve);
9965 read.on('error', (err) => {
9966 strictEqual(err, expected);
9967 errored.resolve();
9968 });
9969 read.destroy(expected);
9970 strictEqual(read.errored, expected);
9971 strictEqual(read.destroyed, true);
9972 await Promise.all([closed.promise, errored.promise]);
9973 }
9974 {
9975 const destroyCalled = Promise.withResolvers();
9976 const closed = Promise.withResolvers();
9977 const errored = Promise.withResolvers();
9978 const read = new Readable({
9979 read() {},
9980 });
9981 read._destroy = function (err, cb) {
9982 strictEqual(err, expected);
9983 cb(err);
9984 destroyCalled.resolve();
9985 };
9986 const expected = new Error('kaboom');
9987 read.on('end', closed.reject);
9988 read.on('close', closed.resolve);
9989 read.on('error', (err) => {
9990 strictEqual(err, expected);
9991 errored.resolve();
9992 });
9993 read.destroy(expected);
9994 strictEqual(read.destroyed, true);
9995 await Promise.all([
9996 destroyCalled.promise,
9997 closed.promise,
9998 errored.promise,
9999 ]);
10000 }
10001 {
10002 const destroyCalled = Promise.withResolvers();
10003 const closed = Promise.withResolvers();
10004 const read = new Readable({
10005 read() {},
10006 destroy: function (err, cb) {
10007 strictEqual(err, expected);
10008 cb();
10009 destroyCalled.resolve();
10010 },
10011 });
10012 const expected = new Error('kaboom');
10013 read.on('end', closed.reject);
10014 
10015 // Error is swallowed by the custom _destroy
10016 read.on('error', fail);
10017 read.on('close', closed.resolve);
10018 read.destroy(expected);
10019 strictEqual(read.destroyed, true);
10020 await Promise.all([destroyCalled.promise, closed.promise]);
10021 }
10022 {
10023 const read = new Readable({
10024 read() {},
10025 });
10026 const destroyCalled = Promise.withResolvers();
10027 read._destroy = function (err, cb) {
10028 strictEqual(err, null);
10029 cb();
10030 destroyCalled.resolve();
10031 };
10032 read.destroy();
10033 strictEqual(read.destroyed, true);
10034 await destroyCalled.promise;
10035 }
10036 {
10037 const read = new Readable({
10038 read() {},
10039 });
10040 read.resume();
10041 const closed = Promise.withResolvers();
10042 const destroyCalled = Promise.withResolvers();
10043 read._destroy = function (err, cb) {
10044 strictEqual(err, null);
10045 queueMicrotask(() => {
10046 this.push(null);
10047 cb();
10048 destroyCalled.resolve();
10049 });
10050 };
10051 read.on('end', fail);
10052 read.on('close', closed.resolve);
10053 read.destroy();
10054 read.removeListener('end', fail);
10055 read.on('end', closed.reject);
10056 strictEqual(read.destroyed, true);
10057 await Promise.all([closed.promise, destroyCalled.promise]);
10058 }
10059 {
10060 const read = new Readable({
10061 read() {},
10062 });
10063 const expected = new Error('kaboom');
10064 const destroyCalled = Promise.withResolvers();
10065 const closed = Promise.withResolvers();
10066 const errored = Promise.withResolvers();
10067 read._destroy = function (err, cb) {
10068 strictEqual(err, null);
10069 cb(expected);
10070 destroyCalled.resolve();
10071 };
10072 let ticked = false;
10073 read.on('end', closed.reject);
10074 read.on('close', closed.resolve);
10075 read.on('error', (err) => {
10076 strictEqual(ticked, true);
10077 strictEqual(read._readableState.errorEmitted, true);
10078 strictEqual(read._readableState.errored, expected);
10079 strictEqual(err, expected);
10080 errored.resolve();
10081 });
10082 read.destroy();
10083 strictEqual(read._readableState.errorEmitted, false);
10084 strictEqual(read._readableState.errored, expected);
10085 strictEqual(read.destroyed, true);
10086 ticked = true;
10087 await Promise.all([
10088 destroyCalled.promise,
10089 closed.promise,
10090 errored.promise,
10091 ]);
10092 }
10093 {
10094 function MyReadable() {
10095 strictEqual(this.destroyed, false);
10096 this.destroyed = false;
10097 Readable.call(this);
10098 }
10099 Object.setPrototypeOf(MyReadable.prototype, Readable.prototype);
10100 Object.setPrototypeOf(MyReadable, Readable);
10101 new MyReadable();
10102 }
10103 {
10104 // Destroy and destroy callback
10105 const read = new Readable({
10106 read() {},
10107 });
10108 read.resume();
10109 const expected = new Error('kaboom');
10110 let ticked = false;
10111 const closed = Promise.withResolvers();
10112 const destroyCalled = Promise.withResolvers();
10113 const errored = Promise.withResolvers();
10114 read.on('close', () => {
10115 strictEqual(read._readableState.errorEmitted, true);
10116 strictEqual(ticked, true);
10117 closed.resolve();
10118 });
10119 read.on('error', (err) => {
10120 strictEqual(err, expected);
10121 errored.resolve();
10122 });
10123 strictEqual(read._readableState.errored, null);
10124 strictEqual(read._readableState.errorEmitted, false);
10125 read.destroy(expected, function (err) {
10126 strictEqual(read._readableState.errored, expected);
10127 strictEqual(err, expected);
10128 destroyCalled.resolve();
10129 });
10130 strictEqual(read._readableState.errorEmitted, false);
10131 strictEqual(read._readableState.errored, expected);
10132 ticked = true;
10133 await Promise.all([
10134 closed.promise,
10135 destroyCalled.promise,
10136 errored.promise,
10137 ]);
10138 }
10139 {
10140 const destroyCalled = Promise.withResolvers();
10141 const closed = Promise.withResolvers();
10142 const errored = Promise.withResolvers();
10143 const readable = new Readable({
10144 destroy: function (err, cb) {
10145 queueMicrotask(() => cb(new Error('kaboom 1')));
10146 destroyCalled.resolve();
10147 },
10148 read() {},
10149 });
10150 let ticked = false;
10151 readable.on('close', () => {
10152 strictEqual(ticked, true);
10153 strictEqual(readable._readableState.errorEmitted, true);
10154 closed.resolve();
10155 });
10156 readable.on('error', (err) => {
10157 strictEqual(ticked, true);
10158 strictEqual(err.message, 'kaboom 1');
10159 strictEqual(readable._readableState.errorEmitted, true);
10160 errored.resolve();
10161 });
10162 readable.destroy();
10163 strictEqual(readable.destroyed, true);
10164 strictEqual(readable._readableState.errored, null);
10165 strictEqual(readable._readableState.errorEmitted, false);
10166 
10167 // Test case where `readable.destroy()` is called again with an error before
10168 // the `_destroy()` callback is called.
10169 readable.destroy(new Error('kaboom 2'));
10170 strictEqual(readable._readableState.errorEmitted, false);
10171 strictEqual(readable._readableState.errored, null);
10172 ticked = true;
10173 
10174 await Promise.all([
10175 destroyCalled.promise,
10176 closed.promise,
10177 errored.promise,
10178 ]);
10179 }
10180 {
10181 const read = new Readable({
10182 read() {},
10183 });
10184 const closed = Promise.withResolvers();
10185 read.destroy();
10186 read.push('hi');
10187 read.on('data', fail);
10188 read.on('close', closed.resolve);
10189 await closed.promise;
10190 }
10191 {
10192 const closed = Promise.withResolvers();
10193 const read = new Readable({
10194 read: closed.reject,
10195 });
10196 read.on('close', closed.resolve);
10197 read.destroy();
10198 strictEqual(read.destroyed, true);
10199 read.read();
10200 await closed.promise;
10201 }
10202 {
10203 const read = new Readable({
10204 autoDestroy: false,
10205 read() {
10206 this.push(null);
10207 this.push('asd');
10208 },
10209 });
10210 const errored = Promise.withResolvers();
10211 read.on('error', () => {
10212 ok(read._readableState.errored);
10213 errored.resolve();
10214 });
10215 read.resume();
10216 await errored.promise;
10217 }
10218 {
10219 const controller = new AbortController();
10220 const read = addAbortSignal(
10221 controller.signal,
10222 new Readable({
10223 read() {
10224 this.push('asd');
10225 },
10226 })
10227 );
10228 const closed = Promise.withResolvers();
10229 const errored = Promise.withResolvers();
10230 read.on('error', (e) => {
10231 strictEqual(e.name, 'AbortError');
10232 errored.resolve();
10233 });
10234 controller.abort();
10235 read.on('data', closed.reject);
10236 read.on('close', closed.resolve);
10237 await Promise.all([closed.promise, errored.promise]);
10238 }
10239 {
10240 const controller = new AbortController();
10241 const read = new Readable({
10242 signal: controller.signal,
10243 read() {
10244 this.push('asd');
10245 },
10246 });
10247 const closed = Promise.withResolvers();
10248 const errored = Promise.withResolvers();
10249 read.on('error', (e) => {
10250 strictEqual(e.name, 'AbortError');
10251 errored.resolve();
10252 });
10253 controller.abort();
10254 read.on('data', closed.reject);
10255 read.on('close', closed.resolve);
10256 await Promise.all([closed.promise, errored.promise]);
10257 }
10258 {
10259 const controller = new AbortController();
10260 const read = addAbortSignal(
10261 controller.signal,
10262 new Readable({
10263 objectMode: true,
10264 read() {
10265 return false;
10266 },
10267 })
10268 );
10269 read.push('asd');
10270 const errored = Promise.withResolvers();
10271 read.on('error', (e) => {
10272 strictEqual(e.name, 'AbortError');
10273 errored.resolve();
10274 });
10275 const rejected = rejects(
10276 (async () => {
10277 for await (const _chunk of read) {
10278 // intentionally empty
10279 }
10280 })(),
10281 /AbortError/
10282 );
10283 setTimeout(() => controller.abort(), 0);
10284 await Promise.all([errored.promise, rejected]);
10285 }
10286 {
10287 const read = new Readable({
10288 read() {},
10289 });
10290 const closed = Promise.withResolvers();
10291 const errored = Promise.withResolvers();
10292 read.on('data', closed.reject);
10293 read.on('error', (e) => {
10294 read.push('asd');
10295 read.read();
10296 errored.resolve();
10297 });
10298 read.on('close', (e) => {
10299 read.push('asd');
10300 read.read();
10301 closed.resolve();
10302 });
10303 read.destroy(new Error('asd'));
10304 await Promise.all([closed.promise, errored.promise]);
10305 }
10306 {
10307 const read = new Readable({
10308 read() {},
10309 });
10310 const closed = Promise.withResolvers();
10311 read.on('data', closed.reject);
10312 read.on('close', (e) => {
10313 read.push('asd');
10314 read.read();
10315 closed.resolve();
10316 });
10317 read.destroy();
10318 await closed.promise;
10319 }
10320 {
10321 const read = new Readable({
10322 read() {},
10323 });
10324 const closed = Promise.withResolvers();
10325 read.on('data', closed.reject);
10326 read.on('close', (e) => {
10327 read.push('asd');
10328 read.unshift('asd');
10329 closed.resolve();
10330 });
10331 read.destroy();
10332 await closed.promise;
10333 }
10334 {
10335 const read = new Readable({
10336 read() {},
10337 });
10338 const closed = Promise.withResolvers();
10339 read.on('data', closed.reject);
10340 read.on('close', closed.resolve);
10341 read.destroy();
10342 read.unshift('asd');
10343 await closed.promise;
10344 }
10345 {
10346 const read = new Readable({
10347 read() {},
10348 });
10349 read.resume();
10350 const closed = Promise.withResolvers();
10351 read.on('data', closed.reject);
10352 read.on('close', (e) => {
10353 read.push('asd');
10354 closed.resolve();
10355 });
10356 read.destroy();
10357 await closed.promise;
10358 }
10359 {
10360 const read = new Readable({
10361 read() {},
10362 });
10363 const closed = Promise.withResolvers();
10364 read.on('data', closed.reject);
10365 read.on('close', closed.resolve);
10366 read.destroy();
10367 read.push('asd');
10368 await closed.promise;
10369 }
10370 },
10371};
10372 
10373export const readable_data = {
10374 async test(ctrl, env, ctx) {
10375 const readable = new Readable({
10376 read() {},
10377 });
10378 function read() {}
10379 readable.setEncoding('utf8');
10380 readable.on('readable', read);
10381 readable.removeListener('readable', read);
10382 const dataCalled = Promise.withResolvers();
10383 queueMicrotask(function () {
10384 readable.on('data', dataCalled.resolve);
10385 readable.push('hello');
10386 });
10387 await dataCalled.promise;
10388 },
10389};
10390 
10391export const readable_constructor_set_methods = {
10392 async test(ctrl, env, ctx) {
10393 const readCalled = Promise.withResolvers();
10394 const _read = function _read(n) {
10395 this.push(null);
10396 readCalled.resolve();
10397 };
10398 const r = new Readable({
10399 read: _read,
10400 });
10401 r.resume();
10402 await readCalled.promise;
10403 },
10404};
10405 
10406export const readable_add_chunk_during_data = {
10407 async test(ctrl, env, ctx) {
10408 const dataCalled = Promise.withResolvers();
10409 let dataCount = 0;
10410 for (const method of ['push', 'unshift']) {
10411 const r = new Readable({
10412 read() {},
10413 });
10414 r.once('data', (chunk) => {
10415 strictEqual(r.readableLength, 0);
10416 r[method](chunk);
10417 strictEqual(r.readableLength, chunk.length);
10418 r.on('data', (chunk) => {
10419 strictEqual(chunk.toString(), 'Hello, world');
10420 if (++dataCount === 2) dataCalled.resolve();
10421 });
10422 });
10423 r.push('Hello, world');
10424 }
10425 },
10426};
10427 
10428export const readable_aborted = {
10429 async test(ctrl, env, ctx) {
10430 {
10431 const readable = new Readable({
10432 read() {},
10433 });
10434 strictEqual(readable.readableAborted, false);
10435 readable.destroy();
10436 strictEqual(readable.readableAborted, true);
10437 }
10438 {
10439 const readable = new Readable({
10440 read() {},
10441 });
10442 strictEqual(readable.readableAborted, false);
10443 readable.push(null);
10444 readable.destroy();
10445 strictEqual(readable.readableAborted, true);
10446 }
10447 {
10448 const readable = new Readable({
10449 read() {},
10450 });
10451 strictEqual(readable.readableAborted, false);
10452 readable.push('asd');
10453 readable.destroy();
10454 strictEqual(readable.readableAborted, true);
10455 }
10456 {
10457 const readable = new Readable({
10458 read() {},
10459 });
10460 strictEqual(readable.readableAborted, false);
10461 readable.push('asd');
10462 readable.push(null);
10463 strictEqual(readable.readableAborted, false);
10464 const ended = Promise.withResolvers();
10465 readable.on('end', () => {
10466 strictEqual(readable.readableAborted, false);
10467 readable.destroy();
10468 strictEqual(readable.readableAborted, false);
10469 queueMicrotask(() => {
10470 strictEqual(readable.readableAborted, false);
10471 ended.resolve();
10472 });
10473 });
10474 readable.resume();
10475 await ended.promise;
10476 }
10477 {
10478 const duplex = new Duplex({
10479 readable: false,
10480 write() {},
10481 });
10482 duplex.destroy();
10483 strictEqual(duplex.readableAborted, false);
10484 }
10485 },
10486};
10487 
10488export const push_strings = {
10489 async test(ctrl, env, ctx) {
10490 class MyStream extends Readable {
10491 constructor(options) {
10492 super(options);
10493 this._chunks = 3;
10494 }
10495 _read(n) {
10496 switch (this._chunks--) {
10497 case 0:
10498 return this.push(null);
10499 case 1:
10500 return setTimeout(() => {
10501 this.push('last chunk');
10502 }, 100);
10503 case 2:
10504 return this.push('second to last chunk');
10505 case 3:
10506 return queueMicrotask(() => {
10507 this.push('first chunk');
10508 });
10509 default:
10510 throw new Error('?');
10511 }
10512 }
10513 }
10514 const ms = new MyStream();
10515 const results = [];
10516 ms.on('readable', function () {
10517 let chunk;
10518 while (null !== (chunk = ms.read())) results.push(String(chunk));
10519 });
10520 const expect = ['first chunksecond to last chunk', 'last chunk'];
10521 await promises.finished(ms);
10522 strictEqual(ms._chunks, -1);
10523 deepStrictEqual(results, expect);
10524 },
10525};
10526 
10527export const filter = {
10528 async test(ctrl, env, ctx) {
10529 {
10530 // Filter works on synchronous streams with a synchronous predicate
10531 const stream = Readable.from([1, 2, 3, 4, 5]).filter((x) => x < 3);
10532 const result = [1, 2];
10533 
10534 for await (const item of stream) {
10535 strictEqual(item, result.shift());
10536 }
10537 }
10538 {
10539 // Filter works on synchronous streams with an asynchronous predicate
10540 const stream = Readable.from([1, 2, 3, 4, 5]).filter(async (x) => {
10541 await Promise.resolve();
10542 return x > 3;
10543 });
10544 const result = [4, 5];
10545 for await (const item of stream) {
10546 strictEqual(item, result.shift());
10547 }
10548 }
10549 {
10550 // Map works on asynchronous streams with a asynchronous mapper
10551 const stream = Readable.from([1, 2, 3, 4, 5])
10552 .map(async (x) => {
10553 await Promise.resolve();
10554 return x + x;
10555 })
10556 .filter((x) => x > 5);
10557 const result = [6, 8, 10];
10558 for await (const item of stream) {
10559 strictEqual(item, result.shift());
10560 }
10561 }
10562 {
10563 // Filter works on an infinite stream
10564 const stream = Readable.from(
10565 (async function* () {
10566 while (true) yield 1;
10567 })()
10568 ).filter(async (x) => x < 3);
10569 let i = 1;
10570 for await (const item of stream) {
10571 strictEqual(item, 1);
10572 if (++i === 5) break;
10573 }
10574 }
10575 {
10576 // Filter works on constructor created streams
10577 let i = 0;
10578 const stream = new Readable({
10579 read() {
10580 if (i === 10) {
10581 this.push(null);
10582 return;
10583 }
10584 this.push(Uint8Array.from([i]));
10585 i++;
10586 },
10587 highWaterMark: 0,
10588 }).filter(async ([x]) => x !== 5);
10589 const result = (await stream.toArray()).map((x) => x[0]);
10590 const expected = [...Array(10).keys()].filter((x) => x !== 5);
10591 deepStrictEqual(result, expected);
10592 }
10593 {
10594 // Throwing an error during `filter` (sync)
10595 const stream = Readable.from([1, 2, 3, 4, 5]).filter((x) => {
10596 if (x === 3) {
10597 throw new Error('boom');
10598 }
10599 return true;
10600 });
10601 await rejects(stream.map((x) => x + x).toArray(), /boom/);
10602 }
10603 {
10604 // Throwing an error during `filter` (async)
10605 const stream = Readable.from([1, 2, 3, 4, 5]).filter(async (x) => {
10606 if (x === 3) {
10607 throw new Error('boom');
10608 }
10609 return true;
10610 });
10611 await rejects(stream.filter(() => true).toArray(), /boom/);
10612 }
10613 {
10614 function once(ee, event) {
10615 const deferred = Promise.withResolvers();
10616 ee.once(event, deferred.resolve);
10617 return deferred.promise;
10618 }
10619 // Concurrency + AbortSignal
10620 const ac = new AbortController();
10621 let _calls = 0;
10622 const stream = Readable.from([1, 2, 3, 4]).filter(
10623 async (_, { signal }) => {
10624 _calls++;
10625 await once(signal, 'abort');
10626 },
10627 {
10628 signal: ac.signal,
10629 concurrency: 2,
10630 }
10631 );
10632 queueMicrotask(() => ac.abort());
10633 // pump
10634 await rejects(
10635 async () => {
10636 for await (const _item of stream) {
10637 // nope
10638 }
10639 },
10640 {
10641 name: 'AbortError',
10642 }
10643 );
10644 }
10645 {
10646 // Concurrency result order
10647 const stream = Readable.from([1, 2]).filter(
10648 async (item, { signal }) => {
10649 await scheduler.wait(10 - item);
10650 return true;
10651 },
10652 {
10653 concurrency: 2,
10654 }
10655 );
10656 const expected = [1, 2];
10657 for await (const item of stream) {
10658 strictEqual(item, expected.shift());
10659 }
10660 }
10661 {
10662 // Error cases
10663 throws(() => Readable.from([1]).filter(1), /ERR_INVALID_ARG_TYPE/);
10664 throws(
10665 () =>
10666 Readable.from([1]).filter((x) => x, {
10667 concurrency: 'Foo',
10668 }),
10669 { code: 'ERR_OUT_OF_RANGE' }
10670 );
10671 throws(() => Readable.from([1]).filter((x) => x, 1), {
10672 code: 'ERR_INVALID_ARG_TYPE',
10673 });
10674 }
10675 {
10676 // Test result is a Readable
10677 const stream = Readable.from([1, 2, 3, 4, 5]).filter((x) => true);
10678 strictEqual(stream.readable, true);
10679 }
10680 },
10681};
10682 
10683export const pipeWithoutListenerCount = {
10684 async test(ctrl, env, ctx) {
10685 const r = new Stream();
10686 r.listenerCount = undefined;
10687 const w = new Stream();
10688 w.listenerCount = undefined;
10689 w.on('pipe', function () {
10690 r.emit('error', new Error('Readable Error'));
10691 w.emit('error', new Error('Writable Error'));
10692 });
10693 const rErrored = Promise.withResolvers();
10694 const wErrored = Promise.withResolvers();
10695 r.on('error', rErrored.resolve);
10696 w.on('error', wErrored.resolve);
10697 r.pipe(w);
10698 await Promise.all([rErrored.promise, wErrored.promise]);
10699 },
10700};
10701 
10702export const pipeUnpipeStreams = {
10703 async test(ctrl, env, ctx) {
10704 const source = Readable({
10705 read: () => {},
10706 });
10707 const dest1 = Writable({
10708 write: () => {},
10709 });
10710 const dest2 = Writable({
10711 write: () => {},
10712 });
10713 source.pipe(dest1);
10714 source.pipe(dest2);
10715 
10716 const unpipe1 = Promise.withResolvers();
10717 const unpipe2 = Promise.withResolvers();
10718 
10719 dest1.on('unpipe', unpipe1.resolve);
10720 dest2.on('unpipe', unpipe2.resolve);
10721 strictEqual(source._readableState.pipes[0], dest1);
10722 strictEqual(source._readableState.pipes[1], dest2);
10723 strictEqual(source._readableState.pipes.length, 2);
10724 
10725 // Should be able to unpipe them in the reverse order that they were piped.
10726 
10727 source.unpipe(dest2);
10728 deepStrictEqual(source._readableState.pipes, [dest1]);
10729 notStrictEqual(source._readableState.pipes, dest2);
10730 dest2.on('unpipe', fail);
10731 source.unpipe(dest2);
10732 source.unpipe(dest1);
10733 strictEqual(source._readableState.pipes.length, 0);
10734 {
10735 // Test `cleanup()` if we unpipe all streams.
10736 const source = Readable({
10737 read: () => {},
10738 });
10739 const dest1 = Writable({
10740 write: () => {},
10741 });
10742 const dest2 = Writable({
10743 write: () => {},
10744 });
10745 let destCount = 0;
10746 const srcCheckEventNames = ['end', 'data'];
10747 const destCheckEventNames = [
10748 'close',
10749 'finish',
10750 'drain',
10751 'error',
10752 'unpipe',
10753 ];
10754 const checkSrcCleanup = () => {
10755 strictEqual(source._readableState.pipes.length, 0);
10756 strictEqual(source._readableState.flowing, false);
10757 srcCheckEventNames.forEach((eventName) => {
10758 strictEqual(
10759 source.listenerCount(eventName),
10760 0,
10761 `source's '${eventName}' event listeners not removed`
10762 );
10763 });
10764 };
10765 async function checkDestCleanup(dest) {
10766 const done = Promise.withResolvers();
10767 const currentDestId = ++destCount;
10768 source.pipe(dest);
10769 const unpipeChecker = () => {
10770 destCheckEventNames.forEach((eventName) => {
10771 strictEqual(
10772 dest.listenerCount(eventName),
10773 0,
10774 `destination{${currentDestId}}'s '${eventName}' event ` +
10775 'listeners not removed'
10776 );
10777 });
10778 if (--destCount === 0) checkSrcCleanup();
10779 done.resolve();
10780 };
10781 dest.once('unpipe', unpipeChecker);
10782 await done.promise;
10783 }
10784 const p1 = checkDestCleanup(dest1);
10785 const p2 = checkDestCleanup(dest2);
10786 source.unpipe();
10787 await Promise.all([p1, p2, unpipe1.promise, unpipe2.promise]);
10788 }
10789 {
10790 const src = Readable({
10791 read: () => {},
10792 });
10793 const dst = Writable({
10794 write: () => {},
10795 });
10796 src.pipe(dst);
10797 const resumeCalled = Promise.withResolvers();
10798 src.on('resume', () => {
10799 src.on('pause', resumeCalled.resolve);
10800 src.unpipe(dst);
10801 });
10802 await resumeCalled.promise;
10803 }
10804 },
10805};
10806 
10807export const pipeSameDestinationTwice = {
10808 async test(ctrl, env, ctx) {
10809 // Regression test for https://github.com/nodejs/node/issues/12718.
10810 // Tests that piping a source stream twice to the same destination stream
10811 // works, and that a subsequent unpipe() call only removes the pipe *once*.
10812 {
10813 const passThrough = new PassThrough();
10814 const writeCalled = Promise.withResolvers();
10815 const dest = new Writable({
10816 write: (chunk, encoding, cb) => {
10817 strictEqual(`${chunk}`, 'foobar');
10818 cb();
10819 writeCalled.resolve();
10820 },
10821 });
10822 passThrough.pipe(dest);
10823 passThrough.pipe(dest);
10824 strictEqual(passThrough._events.data.length, 2);
10825 strictEqual(passThrough._readableState.pipes.length, 2);
10826 strictEqual(passThrough._readableState.pipes[0], dest);
10827 strictEqual(passThrough._readableState.pipes[1], dest);
10828 passThrough.unpipe(dest);
10829 strictEqual(passThrough._events.data.length, 1);
10830 strictEqual(passThrough._readableState.pipes.length, 1);
10831 deepStrictEqual(passThrough._readableState.pipes, [dest]);
10832 passThrough.write('foobar');
10833 passThrough.pipe(dest);
10834 await writeCalled.promise;
10835 }
10836 {
10837 const passThrough = new PassThrough();
10838 const writeCalled = Promise.withResolvers();
10839 let writeCount = 0;
10840 const dest = new Writable({
10841 write: (chunk, encoding, cb) => {
10842 strictEqual(`${chunk}`, 'foobar');
10843 cb();
10844 if (++writeCount == 2) writeCalled.resolve();
10845 },
10846 });
10847 passThrough.pipe(dest);
10848 passThrough.pipe(dest);
10849 strictEqual(passThrough._events.data.length, 2);
10850 strictEqual(passThrough._readableState.pipes.length, 2);
10851 strictEqual(passThrough._readableState.pipes[0], dest);
10852 strictEqual(passThrough._readableState.pipes[1], dest);
10853 passThrough.write('foobar');
10854 await writeCalled.promise;
10855 }
10856 {
10857 const passThrough = new PassThrough();
10858 const dest = new Writable({
10859 write: fail,
10860 });
10861 passThrough.pipe(dest);
10862 passThrough.pipe(dest);
10863 strictEqual(passThrough._events.data.length, 2);
10864 strictEqual(passThrough._readableState.pipes.length, 2);
10865 strictEqual(passThrough._readableState.pipes[0], dest);
10866 strictEqual(passThrough._readableState.pipes[1], dest);
10867 passThrough.unpipe(dest);
10868 passThrough.unpipe(dest);
10869 strictEqual(passThrough._events.data, undefined);
10870 strictEqual(passThrough._readableState.pipes.length, 0);
10871 passThrough.write('foobar');
10872 }
10873 },
10874};
10875 
10876export const pipeNeedDrain = {
10877 async test(ctrl, env, ctx) {
10878 // Pipe should pause temporarily if writable needs drain.
10879 const w = new Writable({
10880 write(buf, encoding, callback) {
10881 queueMicrotask(callback);
10882 },
10883 highWaterMark: 1,
10884 });
10885 while (w.write('asd'));
10886 strictEqual(w.writableNeedDrain, true);
10887 const r = new Readable({
10888 read() {
10889 this.push('asd');
10890 this.push(null);
10891 },
10892 });
10893 const pauseCalled = Promise.withResolvers();
10894 const endCalled = Promise.withResolvers();
10895 let pauseCount = 0;
10896 r.on('pause', () => {
10897 if (++pauseCount === 2) pauseCalled.resolve();
10898 });
10899 r.on('end', endCalled.resolve);
10900 r.pipe(w);
10901 await Promise.all([pauseCalled.promise, endCalled.promise]);
10902 },
10903};
10904 
10905export const pipeMultiplePipes = {
10906 async test(ctrl, env, ctx) {
10907 const readable = new Readable({
10908 read: () => {},
10909 });
10910 const writables = [];
10911 const promises = [];
10912 for (let i = 0; i < 5; i++) {
10913 const writeCalled = Promise.withResolvers();
10914 promises.push(writeCalled.promise);
10915 const target = new Writable({
10916 write: (chunk, encoding, callback) => {
10917 target.output.push(chunk);
10918 callback();
10919 writeCalled.resolve();
10920 },
10921 });
10922 const pipeCalled = Promise.withResolvers();
10923 promises.push(pipeCalled.promise);
10924 target.output = [];
10925 target.on('pipe', pipeCalled.resolve);
10926 readable.pipe(target);
10927 writables.push(target);
10928 }
10929 const input = Buffer.from([1, 2, 3, 4, 5]);
10930 readable.push(input);
10931 
10932 await Promise.all(promises);
10933 
10934 // The pipe() calls will postpone emission of the 'resume' event using nextTick,
10935 // so no data will be available to the writable streams until then.
10936 
10937 for (const target of writables) {
10938 deepStrictEqual(target.output, [input]);
10939 readable.unpipe(target);
10940 }
10941 readable.push('something else'); // This does not get through.
10942 readable.push(null);
10943 readable.resume(); // Make sure the 'end' event gets emitted.
10944 
10945 const ended = Promise.withResolvers();
10946 readable.on('end', () => {
10947 for (const target of writables) {
10948 deepStrictEqual(target.output, [input]);
10949 }
10950 ended.resolve();
10951 });
10952 await ended.promise;
10953 },
10954};
10955 
10956export const pipeManualResume = {
10957 async test(ctrl, env, ctx) {
10958 async function test(throwCodeInbetween) {
10959 // Check that a pipe does not stall if .read() is called unexpectedly
10960 // (i.e. the stream is not resumed by the pipe).
10961 
10962 const n = 1000;
10963 let counter = n;
10964 const rClosed = Promise.withResolvers();
10965 const wClosed = Promise.withResolvers();
10966 const rs = Readable({
10967 objectMode: true,
10968 read: () => {
10969 if (--counter >= 0) rs.push({ counter });
10970 else rs.push(null);
10971 },
10972 });
10973 const ws = Writable({
10974 objectMode: true,
10975 write: (data, enc, cb) => {
10976 queueMicrotask(cb);
10977 },
10978 });
10979 rs.on('close', rClosed.resolve);
10980 ws.on('close', wClosed.resolve);
10981 queueMicrotask(() => throwCodeInbetween(rs, ws));
10982 rs.pipe(ws);
10983 await Promise.all([rClosed.promise, wClosed.promise]);
10984 }
10985 
10986 await Promise.all([
10987 test((rs) => rs.read()),
10988 test((rs) => rs.resume()),
10989 test(() => 0),
10990 ]);
10991 },
10992};
10993 
10994export const pipeFlow = {
10995 async test(ctrl, env, ctx) {
10996 {
10997 let ticks = 17;
10998 const rs = new Readable({
10999 objectMode: true,
11000 read: () => {
11001 if (ticks-- > 0) return queueMicrotask(() => rs.push({}));
11002 rs.push({});
11003 rs.push(null);
11004 },
11005 });
11006 const ws = new Writable({
11007 highWaterMark: 0,
11008 objectMode: true,
11009 write: (data, end, cb) => queueMicrotask(cb),
11010 });
11011 const ended = Promise.withResolvers();
11012 const finished = Promise.withResolvers();
11013 rs.on('end', ended.resolve);
11014 ws.on('finish', finished.resolve);
11015 rs.pipe(ws);
11016 await Promise.all([ended.promise, finished.promise]);
11017 }
11018 {
11019 let missing = 8;
11020 const rs = new Readable({
11021 objectMode: true,
11022 read: () => {
11023 if (missing--) rs.push({});
11024 else rs.push(null);
11025 },
11026 });
11027 const pt = rs
11028 .pipe(
11029 new PassThrough({
11030 objectMode: true,
11031 highWaterMark: 2,
11032 })
11033 )
11034 .pipe(
11035 new PassThrough({
11036 objectMode: true,
11037 highWaterMark: 2,
11038 })
11039 );
11040 pt.on('end', () => {
11041 wrapper.push(null);
11042 });
11043 const wrapper = new Readable({
11044 objectMode: true,
11045 read: () => {
11046 queueMicrotask(() => {
11047 let data = pt.read();
11048 if (data === null) {
11049 pt.once('readable', () => {
11050 data = pt.read();
11051 if (data !== null) wrapper.push(data);
11052 });
11053 } else {
11054 wrapper.push(data);
11055 }
11056 });
11057 },
11058 });
11059 wrapper.resume();
11060 const ended = Promise.withResolvers();
11061 wrapper.on('end', ended.resolve);
11062 await ended.promise;
11063 }
11064 {
11065 // Only register drain if there is backpressure.
11066 const rs = new Readable({
11067 read() {},
11068 });
11069 const pt = rs.pipe(
11070 new PassThrough({
11071 objectMode: true,
11072 highWaterMark: 2,
11073 })
11074 );
11075 strictEqual(pt.listenerCount('drain'), 0);
11076 pt.on('finish', () => {
11077 strictEqual(pt.listenerCount('drain'), 0);
11078 });
11079 rs.push('asd');
11080 strictEqual(pt.listenerCount('drain'), 0);
11081 const done = Promise.withResolvers();
11082 queueMicrotask(() => {
11083 rs.push('asd');
11084 strictEqual(pt.listenerCount('drain'), 0);
11085 rs.push(null);
11086 strictEqual(pt.listenerCount('drain'), 0);
11087 done.resolve();
11088 });
11089 await done.promise;
11090 }
11091 },
11092};
11093 
11094export const pipeErrorHandling = {
11095 async test(ctrl, env, ctx) {
11096 {
11097 const source = new Stream();
11098 const dest = new Stream();
11099 source.pipe(dest);
11100 let gotErr = null;
11101 source.on('error', function (err) {
11102 gotErr = err;
11103 });
11104 const err = new Error('This stream turned into bacon.');
11105 source.emit('error', err);
11106 strictEqual(gotErr, err);
11107 }
11108 {
11109 const source = new Stream();
11110 const dest = new Stream();
11111 source.pipe(dest);
11112 const err = new Error('This stream turned into bacon.');
11113 let gotErr = null;
11114 try {
11115 source.emit('error', err);
11116 } catch (e) {
11117 gotErr = e;
11118 }
11119 strictEqual(gotErr, err);
11120 }
11121 {
11122 const r = new Readable({
11123 autoDestroy: false,
11124 });
11125 const w = new Writable({
11126 autoDestroy: false,
11127 });
11128 let removed = false;
11129 r._read = function () {
11130 setTimeout(function () {
11131 ok(removed);
11132 throws(function () {
11133 w.emit('error', new Error('fail'));
11134 }, /^Error: fail$/);
11135 }, 1);
11136 };
11137 w.on('error', myOnError);
11138 r.pipe(w);
11139 w.removeListener('error', myOnError);
11140 removed = true;
11141 function myOnError() {
11142 throw new Error('this should not happen');
11143 }
11144 }
11145 {
11146 const r = new Readable();
11147 const w = new Writable();
11148 let removed = false;
11149 r._read = function () {
11150 setTimeout(function () {
11151 ok(removed);
11152 w.emit('error', new Error('fail'));
11153 }, 1);
11154 };
11155 const errored = Promise.withResolvers();
11156 w.on('error', errored.resolve);
11157 w._write = () => {};
11158 r.pipe(w);
11159 // Removing some OTHER random listener should not do anything
11160 w.removeListener('error', () => {});
11161 removed = true;
11162 await errored.promise;
11163 }
11164 {
11165 const _err = new Error('this should be handled');
11166 const destination = new PassThrough();
11167 const errored = Promise.withResolvers();
11168 destination.once('error', (err) => {
11169 strictEqual(err, _err);
11170 errored.resolve();
11171 });
11172 const stream = new Stream();
11173 stream.pipe(destination);
11174 destination.destroy(_err);
11175 await errored.promise;
11176 }
11177 },
11178};
11179 
11180export const pipeCleanup = {
11181 async test(ctrl, env, ctx) {
11182 function Writable() {
11183 this.writable = true;
11184 this.endCalls = 0;
11185 Stream.call(this);
11186 }
11187 Object.setPrototypeOf(Writable.prototype, Stream.prototype);
11188 Object.setPrototypeOf(Writable, Stream);
11189 Writable.prototype.end = function () {
11190 this.endCalls++;
11191 };
11192 Writable.prototype.destroy = function () {
11193 this.endCalls++;
11194 };
11195 function Readable() {
11196 this.readable = true;
11197 Stream.call(this);
11198 }
11199 Object.setPrototypeOf(Readable.prototype, Stream.prototype);
11200 Object.setPrototypeOf(Readable, Stream);
11201 function Duplex() {
11202 this.readable = true;
11203 Writable.call(this);
11204 }
11205 Object.setPrototypeOf(Duplex.prototype, Writable.prototype);
11206 Object.setPrototypeOf(Duplex, Writable);
11207 let i = 0;
11208 const limit = 100;
11209 let w = new Writable();
11210 let r;
11211 for (i = 0; i < limit; i++) {
11212 r = new Readable();
11213 r.pipe(w);
11214 r.emit('end');
11215 }
11216 strictEqual(r.listeners('end').length, 0);
11217 strictEqual(w.endCalls, limit);
11218 w.endCalls = 0;
11219 for (i = 0; i < limit; i++) {
11220 r = new Readable();
11221 r.pipe(w);
11222 r.emit('close');
11223 }
11224 strictEqual(r.listeners('close').length, 0);
11225 strictEqual(w.endCalls, limit);
11226 w.endCalls = 0;
11227 r = new Readable();
11228 for (i = 0; i < limit; i++) {
11229 w = new Writable();
11230 r.pipe(w);
11231 w.emit('close');
11232 }
11233 strictEqual(w.listeners('close').length, 0);
11234 r = new Readable();
11235 w = new Writable();
11236 const d = new Duplex();
11237 r.pipe(d); // pipeline A
11238 d.pipe(w); // pipeline B
11239 strictEqual(r.listeners('end').length, 2); // A.onend, A.cleanup
11240 strictEqual(r.listeners('close').length, 2); // A.onclose, A.cleanup
11241 strictEqual(d.listeners('end').length, 2); // B.onend, B.cleanup
11242 // A.cleanup, B.onclose, B.cleanup
11243 strictEqual(d.listeners('close').length, 3);
11244 strictEqual(w.listeners('end').length, 0);
11245 strictEqual(w.listeners('close').length, 1); // B.cleanup
11246 
11247 r.emit('end');
11248 strictEqual(d.endCalls, 1);
11249 strictEqual(w.endCalls, 0);
11250 strictEqual(r.listeners('end').length, 0);
11251 strictEqual(r.listeners('close').length, 0);
11252 strictEqual(d.listeners('end').length, 2); // B.onend, B.cleanup
11253 strictEqual(d.listeners('close').length, 2); // B.onclose, B.cleanup
11254 strictEqual(w.listeners('end').length, 0);
11255 strictEqual(w.listeners('close').length, 1); // B.cleanup
11256 
11257 d.emit('end');
11258 strictEqual(d.endCalls, 1);
11259 strictEqual(w.endCalls, 1);
11260 strictEqual(r.listeners('end').length, 0);
11261 strictEqual(r.listeners('close').length, 0);
11262 strictEqual(d.listeners('end').length, 0);
11263 strictEqual(d.listeners('close').length, 0);
11264 strictEqual(w.listeners('end').length, 0);
11265 strictEqual(w.listeners('close').length, 0);
11266 },
11267};
11268 
11269export const pipeCleanupPause = {
11270 async test(ctrl, env, ctx) {
11271 const done = Promise.withResolvers();
11272 const reader = new Readable();
11273 const writer1 = new Writable();
11274 const writer2 = new Writable();
11275 
11276 // 560000 is chosen here because it is larger than the (default) highWaterMark
11277 // and will cause `.write()` to return false
11278 // See: https://github.com/nodejs/node/issues/2323
11279 const buffer = Buffer.allocUnsafe(560000);
11280 reader._read = () => {};
11281 writer1._write = function (chunk, encoding, cb) {
11282 this.emit('chunk-received');
11283 cb();
11284 };
11285 writer1.once('chunk-received', function () {
11286 reader.unpipe(writer1);
11287 reader.pipe(writer2);
11288 reader.push(buffer);
11289 queueMicrotask(function () {
11290 reader.push(buffer);
11291 queueMicrotask(function () {
11292 reader.push(buffer);
11293 done.resolve();
11294 });
11295 });
11296 });
11297 writer2._write = function (chunk, encoding, cb) {
11298 cb();
11299 };
11300 reader.pipe(writer1);
11301 reader.push(buffer);
11302 await done.promise;
11303 },
11304};
11305 
11306export const writableAdapter = {
11307 async test(ctrl, env, ctx) {
11308 const enc = new TextEncoder();
11309 const dec = new TextDecoder();
11310 // toWeb
11311 {
11312 const p = Promise.withResolvers();
11313 const w = new Writable({
11314 write(chunk, encoding, callback) {
11315 strictEqual(dec.decode(chunk), 'ok');
11316 p.resolve();
11317 },
11318 });
11319 const ws = Writable.toWeb(w);
11320 const writer = ws.getWriter();
11321 await Promise.all([writer.write(enc.encode('ok')), p.promise]);
11322 }
11323 
11324 // fromWeb
11325 {
11326 const p = Promise.withResolvers();
11327 const ws = new WritableStream({
11328 write(chunk) {
11329 strictEqual(dec.decode(chunk), 'ok');
11330 p.resolve();
11331 },
11332 });
11333 const w = Writable.fromWeb(ws);
11334 const p2 = Promise.withResolvers();
11335 w.write(enc.encode('ok'), p2.resolve);
11336 await Promise.all([p.promise, p2.promise]);
11337 }
11338 },
11339};
11340 
11341export const readableAdapter = {
11342 async test(ctrl, env, ctx) {
11343 const enc = new TextEncoder();
11344 const dec = new TextDecoder();
11345 // toWeb
11346 {
11347 const r = new Readable({
11348 read() {
11349 this.push(enc.encode('ok'));
11350 },
11351 });
11352 const rs = Readable.toWeb(r);
11353 const reader = rs.getReader();
11354 const value = await reader.read();
11355 strictEqual(dec.decode(value.value), 'ok');
11356 }
11357 
11358 {
11359 // Using a Node.js stream to feed into a Response...
11360 const r = new Readable({
11361 highWaterMark: 2,
11362 read() {},
11363 });
11364 setTimeout(() => r.push(enc.encode('ok')), 10);
11365 setTimeout(() => r.push(enc.encode(' there')), 20);
11366 setTimeout(() => r.push(null), 30);
11367 const rs = Readable.toWeb(r);
11368 const res = new Response(rs);
11369 const text = await res.text();
11370 strictEqual(text, 'ok there');
11371 }
11372 
11373 // fromWeb
11374 {
11375 const rs = new ReadableStream({
11376 pull(c) {
11377 c.enqueue(enc.encode('ok'));
11378 c.close();
11379 },
11380 });
11381 const r = Readable.fromWeb(rs);
11382 const p = Promise.withResolvers();
11383 r.on('data', (chunk) => {
11384 strictEqual(dec.decode(chunk), 'ok');
11385 p.resolve();
11386 });
11387 await p.promise;
11388 }
11389 },
11390};
11391 
11392export const errorHandling = {
11393 async test() {
11394 const rs = new ReadableStream({
11395 start(c) {
11396 throw new Error('boom');
11397 },
11398 });
11399 const ns = Readable.fromWeb(rs);
11400 try {
11401 for await (const _chunk of ns) {
11402 // intentionally empty
11403 }
11404 throw new Error('should have thrown');
11405 } catch (err) {
11406 // The error should have propagated correctly through the adapter
11407 strictEqual(err.message, 'boom');
11408 }
11409 },
11410};
11411 
11412export const errorHandling2 = {
11413 async test() {
11414 const rs = new ReadableStream({
11415 async pull(c) {
11416 await scheduler.wait(100);
11417 throw new Error('boom');
11418 },
11419 });
11420 const ns = Readable.fromWeb(rs);
11421 try {
11422 for await (const _chunk of ns) {
11423 // intentionally empty
11424 }
11425 throw new Error('should have thrown');
11426 } catch (err) {
11427 // The error should have propagated correctly through the adapter
11428 strictEqual(err.message, 'boom');
11429 }
11430 },
11431};
11432 
11433// Tests are taken from
11434// https://github.com/nodejs/node/blob/98513884684bccf944d7834f4820b061af41fb36/test/parallel/test-stream-duplexpair.js
11435export const testDuplexPair = {
11436 async test() {
11437 {
11438 const pair = duplexPair();
11439 
11440 ok(pair[0] instanceof Duplex);
11441 ok(pair[1] instanceof Duplex);
11442 notStrictEqual(pair[0], pair[1]);
11443 }
11444 
11445 {
11446 const { promise, resolve } = Promise.withResolvers();
11447 const [clientSide, serverSide] = duplexPair();
11448 ok(clientSide instanceof Duplex);
11449 ok(serverSide instanceof Duplex);
11450 serverSide.on('data', (d) => strictEqual(`${d}`, 'foo'));
11451 serverSide.on('end', resolve);
11452 clientSide.end('foo');
11453 await promise;
11454 }
11455 
11456 {
11457 const { promise, resolve } = Promise.withResolvers();
11458 const [serverSide, clientSide] = duplexPair();
11459 serverSide.cork();
11460 serverSide.write('abc');
11461 serverSide.write('12');
11462 serverSide.end('\n');
11463 serverSide.uncork();
11464 let characters = '';
11465 clientSide.on('readable', function () {
11466 for (let segment; (segment = this.read()) !== null; )
11467 characters += segment;
11468 });
11469 clientSide.on('end', function () {
11470 strictEqual(characters, 'abc12\n');
11471 resolve();
11472 });
11473 await promise;
11474 }
11475 
11476 // Test the case where the the _write never calls [kCallback]
11477 // because a zero-size push doesn't trigger a _read
11478 {
11479 const { promise, resolve } = Promise.withResolvers();
11480 const [serverSide, clientSide] = duplexPair();
11481 serverSide.write('');
11482 serverSide.write('12');
11483 serverSide.write('');
11484 serverSide.write('');
11485 serverSide.end('\n');
11486 let characters = '';
11487 clientSide.on('readable', function () {
11488 for (let segment; (segment = this.read()) !== null; )
11489 characters += segment;
11490 });
11491 clientSide.on('end', function () {
11492 strictEqual(characters, '12\n');
11493 resolve();
11494 });
11495 await promise;
11496 }
11497 },
11498};