• 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';
23const common = require('../common');
24const assert = require('assert');
25
26// This test verifies that:
27// 1. unshift() does not cause colliding _read() calls.
28// 2. unshift() after the 'end' event is an error, but after the EOF
29//    signalling null, it is ok, and just creates a new readable chunk.
30// 3. push() after the EOF signaling null is an error.
31// 4. _read() is not called after pushing the EOF null chunk.
32
33const stream = require('stream');
34const hwm = 10;
35const r = stream.Readable({ highWaterMark: hwm, autoDestroy: false });
36const chunks = 10;
37
38const data = Buffer.allocUnsafe(chunks * hwm + Math.ceil(hwm / 2));
39for (let i = 0; i < data.length; i++) {
40  const c = 'asdf'.charCodeAt(i % 4);
41  data[i] = c;
42}
43
44let pos = 0;
45let pushedNull = false;
46r._read = function(n) {
47  assert(!pushedNull, '_read after null push');
48
49  // Every third chunk is fast
50  push(!(chunks % 3));
51
52  function push(fast) {
53    assert(!pushedNull, 'push() after null push');
54    const c = pos >= data.length ? null : data.slice(pos, pos + n);
55    pushedNull = c === null;
56    if (fast) {
57      pos += n;
58      r.push(c);
59      if (c === null) pushError();
60    } else {
61      setTimeout(function() {
62        pos += n;
63        r.push(c);
64        if (c === null) pushError();
65      }, 1);
66    }
67  }
68};
69
70function pushError() {
71  r.unshift(Buffer.allocUnsafe(1));
72  w.end();
73
74  assert.throws(() => {
75    r.push(Buffer.allocUnsafe(1));
76  }, {
77    code: 'ERR_STREAM_PUSH_AFTER_EOF',
78    name: 'Error',
79    message: 'stream.push() after EOF'
80  });
81}
82
83
84const w = stream.Writable();
85const written = [];
86w._write = function(chunk, encoding, cb) {
87  written.push(chunk.toString());
88  cb();
89};
90
91r.on('end', common.mustNotCall());
92
93r.on('readable', function() {
94  let chunk;
95  while (null !== (chunk = r.read(10))) {
96    w.write(chunk);
97    if (chunk.length > 4)
98      r.unshift(Buffer.from('1234'));
99  }
100});
101
102w.on('finish', common.mustCall(function() {
103  // Each chunk should start with 1234, and then be asfdasdfasdf...
104  // The first got pulled out before the first unshift('1234'), so it's
105  // lacking that piece.
106  assert.strictEqual(written[0], 'asdfasdfas');
107  let asdf = 'd';
108  console.error(`0: ${written[0]}`);
109  for (let i = 1; i < written.length; i++) {
110    console.error(`${i.toString(32)}: ${written[i]}`);
111    assert.strictEqual(written[i].slice(0, 4), '1234');
112    for (let j = 4; j < written[i].length; j++) {
113      const c = written[i].charAt(j);
114      assert.strictEqual(c, asdf);
115      switch (asdf) {
116        case 'a': asdf = 's'; break;
117        case 's': asdf = 'd'; break;
118        case 'd': asdf = 'f'; break;
119        case 'f': asdf = 'a'; break;
120      }
121    }
122  }
123}));
124
125process.on('exit', function() {
126  assert.strictEqual(written.length, 18);
127  console.log('ok');
128});
129