• 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 tmpdir = require('../common/tmpdir');
25
26const child_process = require('child_process');
27const assert = require('assert');
28const fs = require('fs');
29const fixtures = require('../common/fixtures');
30
31const fn = fixtures.path('elipses.txt');
32const rangeFile = fixtures.path('x.txt');
33
34function test1(options) {
35  let paused = false;
36  let bytesRead = 0;
37
38  const file = fs.createReadStream(fn, options);
39  const fileSize = fs.statSync(fn).size;
40
41  assert.strictEqual(file.bytesRead, 0);
42
43  file.on('open', common.mustCall(function(fd) {
44    file.length = 0;
45    assert.strictEqual(typeof fd, 'number');
46    assert.strictEqual(file.bytesRead, 0);
47    assert.ok(file.readable);
48
49    // GH-535
50    file.pause();
51    file.resume();
52    file.pause();
53    file.resume();
54  }));
55
56  file.on('data', function(data) {
57    assert.ok(data instanceof Buffer);
58    assert.ok(data.byteOffset % 8 === 0);
59    assert.ok(!paused);
60    file.length += data.length;
61
62    bytesRead += data.length;
63    assert.strictEqual(file.bytesRead, bytesRead);
64
65    paused = true;
66    file.pause();
67
68    setTimeout(function() {
69      paused = false;
70      file.resume();
71    }, 10);
72  });
73
74
75  file.on('end', common.mustCall(function(chunk) {
76    assert.strictEqual(bytesRead, fileSize);
77    assert.strictEqual(file.bytesRead, fileSize);
78  }));
79
80
81  file.on('close', common.mustCall(function() {
82    assert.strictEqual(bytesRead, fileSize);
83    assert.strictEqual(file.bytesRead, fileSize);
84  }));
85
86  process.on('exit', function() {
87    assert.strictEqual(file.length, 30000);
88  });
89}
90
91test1({});
92test1({
93  fs: {
94    open: common.mustCall(fs.open),
95    read: common.mustCallAtLeast(fs.read, 1),
96    close: common.mustCall(fs.close),
97  }
98});
99
100{
101  const file = fs.createReadStream(fn, common.mustNotMutateObjectDeep({ encoding: 'utf8' }));
102  file.length = 0;
103  file.on('data', function(data) {
104    assert.strictEqual(typeof data, 'string');
105    file.length += data.length;
106
107    for (let i = 0; i < data.length; i++) {
108      // http://www.fileformat.info/info/unicode/char/2026/index.htm
109      assert.strictEqual(data[i], '\u2026');
110    }
111  });
112
113  file.on('close', common.mustCall());
114
115  process.on('exit', function() {
116    assert.strictEqual(file.length, 10000);
117  });
118}
119
120{
121  const file =
122    fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ bufferSize: 1, start: 1, end: 2 }));
123  let contentRead = '';
124  file.on('data', function(data) {
125    contentRead += data.toString('utf-8');
126  });
127  file.on('end', common.mustCall(function(data) {
128    assert.strictEqual(contentRead, 'yz');
129  }));
130}
131
132{
133  const file = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ bufferSize: 1, start: 1 }));
134  file.data = '';
135  file.on('data', function(data) {
136    file.data += data.toString('utf-8');
137  });
138  file.on('end', common.mustCall(function() {
139    assert.strictEqual(file.data, 'yz\n');
140  }));
141}
142
143{
144  // Ref: https://github.com/nodejs/node-v0.x-archive/issues/2320
145  const file = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ bufferSize: 1.23, start: 1 }));
146  file.data = '';
147  file.on('data', function(data) {
148    file.data += data.toString('utf-8');
149  });
150  file.on('end', common.mustCall(function() {
151    assert.strictEqual(file.data, 'yz\n');
152  }));
153}
154
155assert.throws(
156  () => {
157    fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ start: 10, end: 2 }));
158  },
159  {
160    code: 'ERR_OUT_OF_RANGE',
161    message: 'The value of "start" is out of range. It must be <= "end"' +
162             ' (here: 2). Received 10',
163    name: 'RangeError'
164  });
165
166{
167  const stream = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ start: 0, end: 0 }));
168  stream.data = '';
169
170  stream.on('data', function(chunk) {
171    stream.data += chunk;
172  });
173
174  stream.on('end', common.mustCall(function() {
175    assert.strictEqual(stream.data, 'x');
176  }));
177}
178
179{
180  // Verify that end works when start is not specified.
181  const stream = new fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ end: 1 }));
182  stream.data = '';
183
184  stream.on('data', function(chunk) {
185    stream.data += chunk;
186  });
187
188  stream.on('end', common.mustCall(function() {
189    assert.strictEqual(stream.data, 'xy');
190  }));
191}
192
193if (!common.isWindows) {
194  // Verify that end works when start is not specified, and we do not try to
195  // use positioned reads. This makes sure that this keeps working for
196  // non-seekable file descriptors.
197  tmpdir.refresh();
198  const filename = `${tmpdir.path}/foo.pipe`;
199  const mkfifoResult = child_process.spawnSync('mkfifo', [filename]);
200  if (!mkfifoResult.error) {
201    child_process.exec(`echo "xyz foobar" > '${filename}'`);
202    const stream = new fs.createReadStream(filename, common.mustNotMutateObjectDeep({ end: 1 }));
203    stream.data = '';
204
205    stream.on('data', function(chunk) {
206      stream.data += chunk;
207    });
208
209    stream.on('end', common.mustCall(function() {
210      assert.strictEqual(stream.data, 'xy');
211      fs.unlinkSync(filename);
212    }));
213  } else {
214    common.printSkipMessage('mkfifo not available');
215  }
216}
217
218{
219  // Pause and then resume immediately.
220  const pauseRes = fs.createReadStream(rangeFile);
221  pauseRes.pause();
222  pauseRes.resume();
223}
224
225{
226  let file = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ autoClose: false }));
227  let data = '';
228  file.on('data', function(chunk) { data += chunk; });
229  file.on('end', common.mustCall(function() {
230    assert.strictEqual(data, 'xyz\n');
231    process.nextTick(function() {
232      assert(!file.closed);
233      assert(!file.destroyed);
234      fileNext();
235    });
236  }));
237
238  function fileNext() {
239    // This will tell us if the fd is usable again or not.
240    file = fs.createReadStream(null, common.mustNotMutateObjectDeep({ fd: file.fd, start: 0 }));
241    file.data = '';
242    file.on('data', function(data) {
243      file.data += data;
244    });
245    file.on('end', common.mustCall(function(err) {
246      assert.strictEqual(file.data, 'xyz\n');
247    }));
248    process.on('exit', function() {
249      assert(file.closed);
250      assert(file.destroyed);
251    });
252  }
253}
254
255{
256  // Just to make sure autoClose won't close the stream because of error.
257  const file = fs.createReadStream(null, common.mustNotMutateObjectDeep({ fd: 13337, autoClose: false }));
258  file.on('data', common.mustNotCall());
259  file.on('error', common.mustCall());
260  process.on('exit', function() {
261    assert(!file.closed);
262    assert(!file.destroyed);
263    assert(file.fd);
264  });
265}
266
267{
268  // Make sure stream is destroyed when file does not exist.
269  const file = fs.createReadStream('/path/to/file/that/does/not/exist');
270  file.on('data', common.mustNotCall());
271  file.on('error', common.mustCall());
272
273  process.on('exit', function() {
274    assert(file.closed);
275    assert(file.destroyed);
276  });
277}
278