• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23
24const common = require('../common');
25const Readable = require('_stream_readable');
26const Writable = require('_stream_writable');
27const assert = require('assert');
28
29function toArray(callback) {
30  const stream = new Writable({ objectMode: true });
31  const list = [];
32  stream.write = function(chunk) {
33    list.push(chunk);
34  };
35
36  stream.end = common.mustCall(function() {
37    callback(list);
38  });
39
40  return stream;
41}
42
43function fromArray(list) {
44  const r = new Readable({ objectMode: true });
45  r._read = common.mustNotCall();
46  list.forEach(function(chunk) {
47    r.push(chunk);
48  });
49  r.push(null);
50
51  return r;
52}
53
54{
55  // Verify that objects can be read from the stream
56  const r = fromArray([{ one: '1' }, { two: '2' }]);
57
58  const v1 = r.read();
59  const v2 = r.read();
60  const v3 = r.read();
61
62  assert.deepStrictEqual(v1, { one: '1' });
63  assert.deepStrictEqual(v2, { two: '2' });
64  assert.deepStrictEqual(v3, null);
65}
66
67{
68  // Verify that objects can be piped into the stream
69  const r = fromArray([{ one: '1' }, { two: '2' }]);
70
71  r.pipe(toArray(common.mustCall(function(list) {
72    assert.deepStrictEqual(list, [
73      { one: '1' },
74      { two: '2' },
75    ]);
76  })));
77}
78
79{
80  // Verify that read(n) is ignored
81  const r = fromArray([{ one: '1' }, { two: '2' }]);
82  const value = r.read(2);
83
84  assert.deepStrictEqual(value, { one: '1' });
85}
86
87{
88  // Verify that objects can be synchronously read
89  const r = new Readable({ objectMode: true });
90  const list = [{ one: '1' }, { two: '2' }];
91  r._read = function(n) {
92    const item = list.shift();
93    r.push(item || null);
94  };
95
96  r.pipe(toArray(common.mustCall(function(list) {
97    assert.deepStrictEqual(list, [
98      { one: '1' },
99      { two: '2' },
100    ]);
101  })));
102}
103
104{
105  // Verify that objects can be asynchronously read
106  const r = new Readable({ objectMode: true });
107  const list = [{ one: '1' }, { two: '2' }];
108  r._read = function(n) {
109    const item = list.shift();
110    process.nextTick(function() {
111      r.push(item || null);
112    });
113  };
114
115  r.pipe(toArray(common.mustCall(function(list) {
116    assert.deepStrictEqual(list, [
117      { one: '1' },
118      { two: '2' },
119    ]);
120  })));
121}
122
123{
124  // Verify that strings can be read as objects
125  const r = new Readable({
126    objectMode: true
127  });
128  r._read = common.mustNotCall();
129  const list = ['one', 'two', 'three'];
130  list.forEach(function(str) {
131    r.push(str);
132  });
133  r.push(null);
134
135  r.pipe(toArray(common.mustCall(function(array) {
136    assert.deepStrictEqual(array, list);
137  })));
138}
139
140{
141  // Verify read(0) behavior for object streams
142  const r = new Readable({
143    objectMode: true
144  });
145  r._read = common.mustNotCall();
146
147  r.push('foobar');
148  r.push(null);
149
150  r.pipe(toArray(common.mustCall(function(array) {
151    assert.deepStrictEqual(array, ['foobar']);
152  })));
153}
154
155{
156  // Verify the behavior of pushing falsey values
157  const r = new Readable({
158    objectMode: true
159  });
160  r._read = common.mustNotCall();
161
162  r.push(false);
163  r.push(0);
164  r.push('');
165  r.push(null);
166
167  r.pipe(toArray(common.mustCall(function(array) {
168    assert.deepStrictEqual(array, [false, 0, '']);
169  })));
170}
171
172{
173  // Verify high watermark _read() behavior
174  const r = new Readable({
175    highWaterMark: 6,
176    objectMode: true
177  });
178  let calls = 0;
179  const list = ['1', '2', '3', '4', '5', '6', '7', '8'];
180
181  r._read = function(n) {
182    calls++;
183  };
184
185  list.forEach(function(c) {
186    r.push(c);
187  });
188
189  const v = r.read();
190
191  assert.strictEqual(calls, 0);
192  assert.strictEqual(v, '1');
193
194  const v2 = r.read();
195  assert.strictEqual(v2, '2');
196
197  const v3 = r.read();
198  assert.strictEqual(v3, '3');
199
200  assert.strictEqual(calls, 1);
201}
202
203{
204  // Verify high watermark push behavior
205  const r = new Readable({
206    highWaterMark: 6,
207    objectMode: true
208  });
209  r._read = common.mustNotCall();
210  for (let i = 0; i < 6; i++) {
211    const bool = r.push(i);
212    assert.strictEqual(bool, i !== 5);
213  }
214}
215
216{
217  // Verify that objects can be written to stream
218  const w = new Writable({ objectMode: true });
219
220  w._write = function(chunk, encoding, cb) {
221    assert.deepStrictEqual(chunk, { foo: 'bar' });
222    cb();
223  };
224
225  w.on('finish', common.mustCall());
226  w.write({ foo: 'bar' });
227  w.end();
228}
229
230{
231  // Verify that multiple objects can be written to stream
232  const w = new Writable({ objectMode: true });
233  const list = [];
234
235  w._write = function(chunk, encoding, cb) {
236    list.push(chunk);
237    cb();
238  };
239
240  w.on('finish', common.mustCall(function() {
241    assert.deepStrictEqual(list, [0, 1, 2, 3, 4]);
242  }));
243
244  w.write(0);
245  w.write(1);
246  w.write(2);
247  w.write(3);
248  w.write(4);
249  w.end();
250}
251
252{
253  // Verify that strings can be written as objects
254  const w = new Writable({
255    objectMode: true
256  });
257  const list = [];
258
259  w._write = function(chunk, encoding, cb) {
260    list.push(chunk);
261    process.nextTick(cb);
262  };
263
264  w.on('finish', common.mustCall(function() {
265    assert.deepStrictEqual(list, ['0', '1', '2', '3', '4']);
266  }));
267
268  w.write('0');
269  w.write('1');
270  w.write('2');
271  w.write('3');
272  w.write('4');
273  w.end();
274}
275
276{
277  // Verify that stream buffers finish until callback is called
278  const w = new Writable({
279    objectMode: true
280  });
281  let called = false;
282
283  w._write = function(chunk, encoding, cb) {
284    assert.strictEqual(chunk, 'foo');
285
286    process.nextTick(function() {
287      called = true;
288      cb();
289    });
290  };
291
292  w.on('finish', common.mustCall(function() {
293    assert.strictEqual(called, true);
294  }));
295
296  w.write('foo');
297  w.end();
298}
299