node/test/parallel/test-stream2-writable.js
Rich Trott d795301025 test: remove unnecessary assignments
common.js needs to be loaded in all tests so that there is checking
for variable leaks and possibly other things. However, it does not
need to be assigned to a variable if nothing in common.js is referred
to elsewhere in the test.

The main tradeoff for this bit of code churn is that it gets the code
base most of the way to being able to enable the no-unused-vars rule in
eslint.

(The non-tooling benefit is that it lessens cognitive load when reading
tests as it is an immediate indication that none of the functions or
properties in common.js will be used by the test.)

PR-URL: https://github.com/nodejs/node/pull/4563
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
2016-01-19 11:52:30 -08:00

385 lines
7.7 KiB
JavaScript

'use strict';
require('../common');
var W = require('_stream_writable');
var D = require('_stream_duplex');
var assert = require('assert');
var util = require('util');
util.inherits(TestWriter, W);
function TestWriter() {
W.apply(this, arguments);
this.buffer = [];
this.written = 0;
}
TestWriter.prototype._write = function(chunk, encoding, cb) {
// simulate a small unpredictable latency
setTimeout(function() {
this.buffer.push(chunk.toString());
this.written += chunk.length;
cb();
}.bind(this), Math.floor(Math.random() * 10));
};
var chunks = new Array(50);
for (var i = 0; i < chunks.length; i++) {
chunks[i] = new Array(i + 1).join('x');
}
// tiny node-tap lookalike.
var tests = [];
var count = 0;
function test(name, fn) {
count++;
tests.push([name, fn]);
}
function run() {
var next = tests.shift();
if (!next)
return console.error('ok');
var name = next[0];
var fn = next[1];
console.log('# %s', name);
fn({
same: assert.deepEqual,
equal: assert.equal,
end: function() {
count--;
run();
}
});
}
// ensure all tests have run
process.on('exit', function() {
assert.equal(count, 0);
});
process.nextTick(run);
test('write fast', function(t) {
var tw = new TestWriter({
highWaterMark: 100
});
tw.on('finish', function() {
t.same(tw.buffer, chunks, 'got chunks in the right order');
t.end();
});
chunks.forEach(function(chunk) {
// screw backpressure. Just buffer it all up.
tw.write(chunk);
});
tw.end();
});
test('write slow', function(t) {
var tw = new TestWriter({
highWaterMark: 100
});
tw.on('finish', function() {
t.same(tw.buffer, chunks, 'got chunks in the right order');
t.end();
});
var i = 0;
(function W() {
tw.write(chunks[i++]);
if (i < chunks.length)
setTimeout(W, 10);
else
tw.end();
})();
});
test('write backpressure', function(t) {
var tw = new TestWriter({
highWaterMark: 50
});
var drains = 0;
tw.on('finish', function() {
t.same(tw.buffer, chunks, 'got chunks in the right order');
t.equal(drains, 17);
t.end();
});
tw.on('drain', function() {
drains++;
});
var i = 0;
(function W() {
do {
var ret = tw.write(chunks[i++]);
} while (ret !== false && i < chunks.length);
if (i < chunks.length) {
assert(tw._writableState.length >= 50);
tw.once('drain', W);
} else {
tw.end();
}
})();
});
test('write bufferize', function(t) {
var tw = new TestWriter({
highWaterMark: 100
});
var encodings =
[ 'hex',
'utf8',
'utf-8',
'ascii',
'binary',
'base64',
'ucs2',
'ucs-2',
'utf16le',
'utf-16le',
undefined ];
tw.on('finish', function() {
t.same(tw.buffer, chunks, 'got the expected chunks');
});
chunks.forEach(function(chunk, i) {
var enc = encodings[ i % encodings.length ];
chunk = new Buffer(chunk);
tw.write(chunk.toString(enc), enc);
});
t.end();
});
test('write no bufferize', function(t) {
var tw = new TestWriter({
highWaterMark: 100,
decodeStrings: false
});
tw._write = function(chunk, encoding, cb) {
assert(typeof chunk === 'string');
chunk = new Buffer(chunk, encoding);
return TestWriter.prototype._write.call(this, chunk, encoding, cb);
};
var encodings =
[ 'hex',
'utf8',
'utf-8',
'ascii',
'binary',
'base64',
'ucs2',
'ucs-2',
'utf16le',
'utf-16le',
undefined ];
tw.on('finish', function() {
t.same(tw.buffer, chunks, 'got the expected chunks');
});
chunks.forEach(function(chunk, i) {
var enc = encodings[ i % encodings.length ];
chunk = new Buffer(chunk);
tw.write(chunk.toString(enc), enc);
});
t.end();
});
test('write callbacks', function(t) {
var callbacks = chunks.map(function(chunk, i) {
return [i, function(er) {
callbacks._called[i] = chunk;
}];
}).reduce(function(set, x) {
set['callback-' + x[0]] = x[1];
return set;
}, {});
callbacks._called = [];
var tw = new TestWriter({
highWaterMark: 100
});
tw.on('finish', function() {
process.nextTick(function() {
t.same(tw.buffer, chunks, 'got chunks in the right order');
t.same(callbacks._called, chunks, 'called all callbacks');
t.end();
});
});
chunks.forEach(function(chunk, i) {
tw.write(chunk, callbacks['callback-' + i]);
});
tw.end();
});
test('end callback', function(t) {
var tw = new TestWriter();
tw.end(function() {
t.end();
});
});
test('end callback with chunk', function(t) {
var tw = new TestWriter();
tw.end(new Buffer('hello world'), function() {
t.end();
});
});
test('end callback with chunk and encoding', function(t) {
var tw = new TestWriter();
tw.end('hello world', 'ascii', function() {
t.end();
});
});
test('end callback after .write() call', function(t) {
var tw = new TestWriter();
tw.write(new Buffer('hello world'));
tw.end(function() {
t.end();
});
});
test('end callback called after write callback', function(t) {
var tw = new TestWriter();
var writeCalledback = false;
tw.write(new Buffer('hello world'), function() {
writeCalledback = true;
});
tw.end(function() {
t.equal(writeCalledback, true);
t.end();
});
});
test('encoding should be ignored for buffers', function(t) {
var tw = new W();
var hex = '018b5e9a8f6236ffe30e31baf80d2cf6eb';
tw._write = function(chunk, encoding, cb) {
t.equal(chunk.toString('hex'), hex);
t.end();
};
var buf = new Buffer(hex, 'hex');
tw.write(buf, 'binary');
});
test('writables are not pipable', function(t) {
var w = new W();
w._write = function() {};
var gotError = false;
w.on('error', function(er) {
gotError = true;
});
w.pipe(process.stdout);
assert(gotError);
t.end();
});
test('duplexes are pipable', function(t) {
var d = new D();
d._read = function() {};
d._write = function() {};
var gotError = false;
d.on('error', function(er) {
gotError = true;
});
d.pipe(process.stdout);
assert(!gotError);
t.end();
});
test('end(chunk) two times is an error', function(t) {
var w = new W();
w._write = function() {};
var gotError = false;
w.on('error', function(er) {
gotError = true;
t.equal(er.message, 'write after end');
});
w.end('this is the end');
w.end('and so is this');
process.nextTick(function() {
assert(gotError);
t.end();
});
});
test('dont end while writing', function(t) {
var w = new W();
var wrote = false;
w._write = function(chunk, e, cb) {
assert(!this.writing);
wrote = true;
this.writing = true;
setTimeout(function() {
this.writing = false;
cb();
});
};
w.on('finish', function() {
assert(wrote);
t.end();
});
w.write(Buffer(0));
w.end();
});
test('finish does not come before write cb', function(t) {
var w = new W();
var writeCb = false;
w._write = function(chunk, e, cb) {
setTimeout(function() {
writeCb = true;
cb();
}, 10);
};
w.on('finish', function() {
assert(writeCb);
t.end();
});
w.write(Buffer(0));
w.end();
});
test('finish does not come before sync _write cb', function(t) {
var w = new W();
var writeCb = false;
w._write = function(chunk, e, cb) {
cb();
};
w.on('finish', function() {
assert(writeCb);
t.end();
});
w.write(Buffer(0), function(er) {
writeCb = true;
});
w.end();
});
test('finish is emitted if last chunk is empty', function(t) {
var w = new W();
w._write = function(chunk, e, cb) {
process.nextTick(cb);
};
w.on('finish', function() {
t.end();
});
w.write(Buffer(1));
w.end(Buffer(0));
});