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