1'use strict';
2
3const common = require('../common');
4const { Readable, addAbortSignal } = require('stream');
5const assert = require('assert');
6
7{
8  const read = new Readable({
9    read() {}
10  });
11  read.resume();
12
13  read.on('close', common.mustCall());
14
15  read.destroy();
16  assert.strictEqual(read.errored, null);
17  assert.strictEqual(read.destroyed, true);
18}
19
20{
21  const read = new Readable({
22    read() {}
23  });
24  read.resume();
25
26  const expected = new Error('kaboom');
27
28  read.on('end', common.mustNotCall('no end event'));
29  read.on('close', common.mustCall());
30  read.on('error', common.mustCall((err) => {
31    assert.strictEqual(err, expected);
32  }));
33
34  read.destroy(expected);
35  assert.strictEqual(read.errored, expected);
36  assert.strictEqual(read.destroyed, true);
37}
38
39{
40  const read = new Readable({
41    read() {}
42  });
43
44  read._destroy = common.mustCall(function(err, cb) {
45    assert.strictEqual(err, expected);
46    cb(err);
47  });
48
49  const expected = new Error('kaboom');
50
51  read.on('end', common.mustNotCall('no end event'));
52  read.on('close', common.mustCall());
53  read.on('error', common.mustCall((err) => {
54    assert.strictEqual(err, expected);
55  }));
56
57  read.destroy(expected);
58  assert.strictEqual(read.destroyed, true);
59}
60
61{
62  const read = new Readable({
63    read() {},
64    destroy: common.mustCall(function(err, cb) {
65      assert.strictEqual(err, expected);
66      cb();
67    })
68  });
69
70  const expected = new Error('kaboom');
71
72  read.on('end', common.mustNotCall('no end event'));
73
74  // Error is swallowed by the custom _destroy
75  read.on('error', common.mustNotCall('no error event'));
76  read.on('close', common.mustCall());
77
78  read.destroy(expected);
79  assert.strictEqual(read.destroyed, true);
80}
81
82{
83  const read = new Readable({
84    read() {}
85  });
86
87  read._destroy = common.mustCall(function(err, cb) {
88    assert.strictEqual(err, null);
89    cb();
90  });
91
92  read.destroy();
93  assert.strictEqual(read.destroyed, true);
94}
95
96{
97  const read = new Readable({
98    read() {}
99  });
100  read.resume();
101
102  read._destroy = common.mustCall(function(err, cb) {
103    assert.strictEqual(err, null);
104    process.nextTick(() => {
105      this.push(null);
106      cb();
107    });
108  });
109
110  const fail = common.mustNotCall('no end event');
111
112  read.on('end', fail);
113  read.on('close', common.mustCall());
114
115  read.destroy();
116
117  read.removeListener('end', fail);
118  read.on('end', common.mustNotCall());
119  assert.strictEqual(read.destroyed, true);
120}
121
122{
123  const read = new Readable({
124    read() {}
125  });
126
127  const expected = new Error('kaboom');
128
129  read._destroy = common.mustCall(function(err, cb) {
130    assert.strictEqual(err, null);
131    cb(expected);
132  });
133
134  let ticked = false;
135  read.on('end', common.mustNotCall('no end event'));
136  read.on('error', common.mustCall((err) => {
137    assert.strictEqual(ticked, true);
138    assert.strictEqual(read._readableState.errorEmitted, true);
139    assert.strictEqual(read._readableState.errored, expected);
140    assert.strictEqual(err, expected);
141  }));
142
143  read.destroy();
144  assert.strictEqual(read._readableState.errorEmitted, false);
145  assert.strictEqual(read._readableState.errored, expected);
146  assert.strictEqual(read.destroyed, true);
147  ticked = true;
148}
149
150{
151  const read = new Readable({
152    read() {}
153  });
154  read.resume();
155
156  read.destroyed = true;
157  assert.strictEqual(read.destroyed, true);
158
159  // The internal destroy() mechanism should not be triggered
160  read.on('end', common.mustNotCall());
161  read.destroy();
162}
163
164{
165  function MyReadable() {
166    assert.strictEqual(this.destroyed, false);
167    this.destroyed = false;
168    Readable.call(this);
169  }
170
171  Object.setPrototypeOf(MyReadable.prototype, Readable.prototype);
172  Object.setPrototypeOf(MyReadable, Readable);
173
174  new MyReadable();
175}
176
177{
178  // Destroy and destroy callback
179  const read = new Readable({
180    read() {}
181  });
182  read.resume();
183
184  const expected = new Error('kaboom');
185
186  let ticked = false;
187  read.on('close', common.mustCall(() => {
188    assert.strictEqual(read._readableState.errorEmitted, true);
189    assert.strictEqual(ticked, true);
190  }));
191  read.on('error', common.mustCall((err) => {
192    assert.strictEqual(err, expected);
193  }));
194
195  assert.strictEqual(read._readableState.errored, null);
196  assert.strictEqual(read._readableState.errorEmitted, false);
197
198  read.destroy(expected, common.mustCall(function(err) {
199    assert.strictEqual(read._readableState.errored, expected);
200    assert.strictEqual(err, expected);
201  }));
202  assert.strictEqual(read._readableState.errorEmitted, false);
203  assert.strictEqual(read._readableState.errored, expected);
204  ticked = true;
205}
206
207{
208  const readable = new Readable({
209    destroy: common.mustCall(function(err, cb) {
210      process.nextTick(cb, new Error('kaboom 1'));
211    }),
212    read() {}
213  });
214
215  let ticked = false;
216  readable.on('close', common.mustCall(() => {
217    assert.strictEqual(ticked, true);
218    assert.strictEqual(readable._readableState.errorEmitted, true);
219  }));
220  readable.on('error', common.mustCall((err) => {
221    assert.strictEqual(ticked, true);
222    assert.strictEqual(err.message, 'kaboom 1');
223    assert.strictEqual(readable._readableState.errorEmitted, true);
224  }));
225
226  readable.destroy();
227  assert.strictEqual(readable.destroyed, true);
228  assert.strictEqual(readable._readableState.errored, null);
229  assert.strictEqual(readable._readableState.errorEmitted, false);
230
231  // Test case where `readable.destroy()` is called again with an error before
232  // the `_destroy()` callback is called.
233  readable.destroy(new Error('kaboom 2'));
234  assert.strictEqual(readable._readableState.errorEmitted, false);
235  assert.strictEqual(readable._readableState.errored, null);
236
237  ticked = true;
238}
239
240{
241  const read = new Readable({
242    read() {}
243  });
244
245  read.destroy();
246  read.push('hi');
247  read.on('data', common.mustNotCall());
248}
249
250{
251  const read = new Readable({
252    read: common.mustNotCall()
253  });
254  read.destroy();
255  assert.strictEqual(read.destroyed, true);
256  read.read();
257}
258
259{
260  const read = new Readable({
261    autoDestroy: false,
262    read() {
263      this.push(null);
264      this.push('asd');
265    }
266  });
267
268  read.on('error', common.mustCall(() => {
269    assert(read._readableState.errored);
270  }));
271  read.resume();
272}
273
274{
275  const controller = new AbortController();
276  const read = addAbortSignal(controller.signal, new Readable({
277    read() {
278      this.push('asd');
279    },
280  }));
281
282  read.on('error', common.mustCall((e) => {
283    assert.strictEqual(e.name, 'AbortError');
284  }));
285  controller.abort();
286  read.on('data', common.mustNotCall());
287}
288
289{
290  const controller = new AbortController();
291  const read = new Readable({
292    signal: controller.signal,
293    read() {
294      this.push('asd');
295    },
296  });
297
298  read.on('error', common.mustCall((e) => {
299    assert.strictEqual(e.name, 'AbortError');
300  }));
301  controller.abort();
302  read.on('data', common.mustNotCall());
303}
304
305{
306  const controller = new AbortController();
307  const read = addAbortSignal(controller.signal, new Readable({
308    objectMode: true,
309    read() {
310      return false;
311    }
312  }));
313  read.push('asd');
314
315  read.on('error', common.mustCall((e) => {
316    assert.strictEqual(e.name, 'AbortError');
317  }));
318  assert.rejects((async () => {
319    // eslint-disable-next-line no-unused-vars, no-empty
320    for await (const chunk of read) { }
321  })(), /AbortError/);
322  setTimeout(() => controller.abort(), 0);
323}
324
325{
326  const read = new Readable({
327    read() {
328    },
329  });
330
331  read.on('data', common.mustNotCall());
332  read.on('error', common.mustCall((e) => {
333    read.push('asd');
334    read.read();
335  }));
336  read.on('close', common.mustCall((e) => {
337    read.push('asd');
338    read.read();
339  }));
340  read.destroy(new Error('asd'));
341}
342
343{
344  const read = new Readable({
345    read() {
346    },
347  });
348
349  read.on('data', common.mustNotCall());
350  read.on('close', common.mustCall((e) => {
351    read.push('asd');
352    read.read();
353  }));
354  read.destroy();
355}
356
357{
358  const read = new Readable({
359    read() {
360    },
361  });
362
363  read.on('data', common.mustNotCall());
364  read.on('close', common.mustCall((e) => {
365    read.push('asd');
366    read.unshift('asd');
367  }));
368  read.destroy();
369}
370
371{
372  const read = new Readable({
373    read() {
374    },
375  });
376
377  read.on('data', common.mustNotCall());
378  read.destroy();
379  read.unshift('asd');
380}
381
382{
383  const read = new Readable({
384    read() {
385    },
386  });
387
388  read.resume();
389  read.on('data', common.mustNotCall());
390  read.on('close', common.mustCall((e) => {
391    read.push('asd');
392  }));
393  read.destroy();
394}
395
396{
397  const read = new Readable({
398    read() {
399    },
400  });
401
402  read.on('data', common.mustNotCall());
403  read.destroy();
404  read.push('asd');
405}
406