mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
54cc7212df
When node began using the OneByte API (f150d56
) it also switched to
officially supporting ISO-8859-1. Though at the time no new encoding
string was introduced.
Introduce the new encoding string 'latin1' to be more explicit. The
previous 'binary' and documented as an alias to 'latin1'. While many
tests have switched to use 'latin1', there are still plenty that do both
'binary' and 'latin1' checks side-by-side to ensure there is no
regression.
PR-URL: https://github.com/nodejs/node/pull/7111
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
388 lines
7.8 KiB
JavaScript
388 lines
7.8 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',
|
|
'latin1',
|
|
'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 = Buffer.from(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 = Buffer.from(chunk, encoding);
|
|
return TestWriter.prototype._write.call(this, chunk, encoding, cb);
|
|
};
|
|
|
|
var encodings =
|
|
[ 'hex',
|
|
'utf8',
|
|
'utf-8',
|
|
'ascii',
|
|
'latin1',
|
|
'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 = Buffer.from(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(Buffer.from('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(Buffer.from('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(Buffer.from('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 = Buffer.from(hex, 'hex');
|
|
tw.write(buf, 'latin1');
|
|
});
|
|
|
|
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.alloc(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.alloc(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.alloc(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.allocUnsafe(1));
|
|
w.end(Buffer.alloc(0));
|
|
});
|