- concatenates a named file to outStream
const options = {
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
nodecat([filePath], options, (err) => {
assert.ifError(err);
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), fileContent);
assert.strictEqual(options.errStream.read(), null);
done();
});
});
- concatenates two named files to outStream
const options = {
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
nodecat([filePath, filePath], options, (err) => {
assert.ifError(err);
options.outStream.end(() => {
assert.deepEqual(
options.outStream.read(),
Buffer.concat([fileContent, fileContent])
);
assert.strictEqual(options.errStream.read(), null);
done();
});
});
- concatenates stdout to outStream
const testData = Buffer.from('Stuff');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
nodecat(['-'], options, (err) => {
assert.ifError(err);
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), testData);
assert.strictEqual(options.errStream.read(), null);
done();
});
});
inStream.end(testData);
- concatenates stdout once when named twice
const testData = Buffer.from('Stuff');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
nodecat(['-', '-'], options, (err) => {
assert.ifError(err);
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), testData);
assert.strictEqual(options.errStream.read(), null);
done();
});
});
inStream.end(testData);
- continues with next file after read error
const errTest = new Error('test read error');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
let callCount = 0;
nodecat(['-', filePath], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.strictEqual(err, errTest);
assert.strictEqual(err.fileName, '-');
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), fileContent);
assert.match(
options.errStream.read(),
/^nodecat: -: .*test read error.*\n$/
);
done();
});
});
inStream.emit('error', errTest);
- does not retry stream after read error
const testData = Buffer.from('Stuff');
const errTest = new Error('test read error');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
let callCount = 0;
nodecat(['-', filePath, '-'], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.strictEqual(err, errTest);
assert.strictEqual(err.fileName, '-');
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), fileContent);
assert.match(
options.errStream.read(),
/^nodecat: -: .*test read error.*\n$/
);
done();
});
});
inStream.emit('error', errTest);
inStream.end(testData);
- returns AggregateError for multiple read errors
const errTest1 = new Error('test read error 1');
const errTest2 = new Error('test read error 2');
const errTest3 = new Error('test read error 3');
const stream1 = new stream.PassThrough();
const stream2 = new stream.PassThrough();
const stream3 = new stream.PassThrough();
const options = {
fileStreams: {
'file1.txt': stream1,
'file2.txt': stream2,
'file3.txt': stream3
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
let callCount = 0;
nodecat(['file1.txt', 'file2.txt', 'file3.txt'], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.instanceOf(err, AggregateError);
assert.strictEqual(err.length, 3);
assert.strictEqual(err[0], errTest1);
assert.strictEqual(err[0].fileName, 'file1.txt');
assert.strictEqual(err[1], errTest2);
assert.strictEqual(err[1].fileName, 'file2.txt');
assert.strictEqual(err[2], errTest3);
assert.strictEqual(err[2].fileName, 'file3.txt');
// Confirm that AggregateError.toString has contained messages
const errMsgRE = new RegExp(
'.*test read error 1.*\\n'
+ '.*test read error 2.*\\n'
+ '.*test read error 3.*\\n.*'
);
assert.match(String(err), errMsgRE);
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), null);
const errText = String(options.errStream.read());
const errRE
= new RegExp('^nodecat: file1.txt: .*test read error 1.*\\n'
+ 'nodecat: file2.txt: .*test read error 2.*\\n'
+ 'nodecat: file3.txt: .*test read error 3.*\\n$');
assert.match(errText, errRE);
done();
});
});
stream1.emit('error', errTest1);
process.nextTick(() => {
stream2.emit('error', errTest2);
process.nextTick(() => {
stream3.emit('error', errTest3);
});
});
- returns AggregateError for read and write errors
const errTestRead = new Error('test read error');
const errTestWrite = new Error('test write error');
const stream1 = new stream.PassThrough();
const stream2 = new stream.PassThrough();
const options = {
fileStreams: {
'file1.txt': stream1,
'file2.txt': stream2
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
let callCount = 0;
nodecat(['file1.txt', 'file2.txt'], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.instanceOf(err, AggregateError);
assert.strictEqual(err.length, 2);
assert.strictEqual(err[0], errTestRead);
assert.strictEqual(err[0].fileName, 'file1.txt');
assert.strictEqual(err[1], errTestWrite);
assert.strictEqual(err[1].fileName, undefined);
options.outStream.end(() => {
assert.deepEqual(options.outStream.read(), null);
const errText = String(options.errStream.read());
const errRE
= new RegExp('^nodecat: file1.txt: .*test read error.*\\n'
+ 'nodecat: .*test write error.*\\n$');
assert.match(errText, errRE);
done();
});
});
stream1.emit('error', errTestRead);
options.outStream.emit('error', errTestWrite);
- stops writing after write error
const testData = Buffer.from('Stuff');
const errTest = new Error('test write error');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
options.fileStreams[filePath] = {
pipe: sinon.mock().never()
};
let callCount = 0;
nodecat(['-', filePath], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.strictEqual(err, errTest);
process.nextTick(() => {
assert.strictEqual(options.outStream.read(), null);
assert.match(
options.errStream.read(),
/^nodecat: .*test write error.*\n/
);
done();
});
});
options.outStream.emit('error', errTest);
inStream.end(testData);
- stops listening for read error after write error
const testData = Buffer.from('Stuff');
const errTestRead = new Error('test read error');
const errTestWrite = new Error('test write error');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
options.fileStreams[filePath] = {
pipe: sinon.mock().never()
};
// Assert would throw without this test listener.
inStream.on('error', function() {
assert.strictEqual(listenerCount(this, 'error'), 1);
});
let callCount = 0;
nodecat(['-', filePath], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.strictEqual(err, errTestWrite);
inStream.emit('error', errTestRead);
setImmediate(() => {
assert.strictEqual(options.outStream.read(), null);
assert.match(
options.errStream.read(),
/^nodecat: .*test write error.*\n/
);
done();
});
});
options.outStream.emit('error', errTestWrite);
inStream.emit('error', errTestRead);
inStream.end(testData);
- stops listening for write error after callback
const testData = Buffer.from('Stuff');
const errTestWrite = new Error('test write error');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
// Assert would throw without this test listener.
options.outStream.on('error', function() {
assert.strictEqual(listenerCount(this, 'error'), 1);
});
let callCount = 0;
nodecat(['-'], options, (err) => {
callCount += 1;
assert.strictEqual(callCount, 1);
assert.ifError(err);
options.outStream.emit('error', errTestWrite);
setImmediate(() => {
assert.deepEqual(options.outStream.read(), testData);
assert.strictEqual(options.errStream.read(), null);
done();
});
});
inStream.end(testData);
- throws TypeError for non-function callback
assert.throws(
() => { nodecat([], {}, true); },
TypeError,
/\bcallback\b/
);
- yields TypeError for non-Array-like fileNames
nodecat('file.txt', (err) => {
assert.instanceOf(err, TypeError);
assert.match(err.message, /\bfileNames\b/);
done();
});
- yields TypeError for non-object options
nodecat([], true, (err) => {
assert.instanceOf(err, TypeError);
assert.match(err.message, /\boptions\b/);
done();
});
- yields TypeError for non-object options.fileStreams
nodecat([], {fileStreams: true}, (err) => {
assert.instanceOf(err, TypeError);
assert.match(err.message, /\boptions.fileStreams\b/);
done();
});
- yields TypeError for non-Writable outStream
nodecat([], {outStream: new stream.Readable()}, (err) => {
assert.instanceOf(err, TypeError);
assert.match(err.message, /\boptions.outStream\b/);
done();
});
- yields TypeError for non-Writable errStream
nodecat([], {errStream: new stream.Readable()}, (err) => {
assert.instanceOf(err, TypeError);
assert.match(err.message, /\boptions.errStream\b/);
done();
});
- returns undefined when called with a function
const result = nodecat([], done);
assert.strictEqual(result, undefined);
- returns a Promise when called without a function
const result = nodecat([]);
assert(result instanceof global.Promise);
- returned Promise is resolved after writing
let ended = false;
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
setImmediate(() => {
ended = true;
inStream.end();
});
return nodecat(['-'], options).then(() => {
assert(ended);
});
- returned Promise is rejected with argument Error
const result = nodecat([], true);
return result.then(
sinon.mock().never(),
(err) => { assert.instanceOf(err, TypeError); }
);
- returned Promise is rejected with read Error
const errTest = new Error('test error');
const inStream = new stream.PassThrough();
const options = {
fileStreams: {
'-': inStream
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
setImmediate(() => {
inStream.emit('error', errTest);
});
return nodecat(['-'], options).then(
sinon.mock().never(),
(err) => { assert.strictEqual(err, errTest); }
);
- returned Promise is rejected with write Error
const errTest = new Error('test error');
const options = {
fileStreams: {
'-': new stream.PassThrough()
},
outStream: new stream.PassThrough(),
errStream: new stream.PassThrough()
};
setImmediate(() => {
options.outStream.emit('error', errTest);
});
return nodecat(['-'], options).then(
sinon.mock().never(),
(err) => { assert.strictEqual(err, errTest); }
);