@@ -44,6 +44,11 @@
'lib/readline.js',
'lib/repl.js',
'lib/stream.js',
'lib/_stream_readable.js',
'lib/_stream_writable.js',
'lib/_stream_duplex.js',
'lib/_stream_transform.js',
'lib/_stream_passthrough.js',
'lib/string_decoder.js',
'lib/sys.js',
'lib/timers.js',
@@ -701,8 +701,8 @@

var nativeModule = new NativeModule(id);

nativeModule.compile();
nativeModule.cache();
nativeModule.compile();

return nativeModule.exports;
};
@@ -3728,9 +3728,9 @@ void EIO_PBKDF2After(pbkdf2_req* req, Local<Value> argv[2]) {
}


void EIO_PBKDF2After(uv_work_t* work_req) {
void EIO_PBKDF2After(uv_work_t* work_req, int status) {
assert(status == 0);
pbkdf2_req* req = container_of(work_req, pbkdf2_req, work_req);

HandleScope scope;
Local<Value> argv[2];
Persistent<Object> obj = req->obj;
@@ -3902,16 +3902,15 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
}


void RandomBytesAfter(uv_work_t* work_req) {
void RandomBytesAfter(uv_work_t* work_req, int status) {
assert(status == 0);
RandomBytesRequest* req = container_of(work_req,
RandomBytesRequest,
work_req_);

HandleScope scope;
Local<Value> argv[2];
RandomBytesCheck(req, argv);
MakeCallback(req->obj_, "ondone", ARRAY_SIZE(argv), argv);

delete req;
}

@@ -109,7 +109,19 @@ class ZCtx : public ObjectWrap {
assert(!ctx->write_in_progress_ && "write already in progress");
ctx->write_in_progress_ = true;

assert(!args[0]->IsUndefined() && "must provide flush value");

unsigned int flush = args[0]->Uint32Value();

if (flush != Z_NO_FLUSH &&
flush != Z_PARTIAL_FLUSH &&
flush != Z_SYNC_FLUSH &&
flush != Z_FULL_FLUSH &&
flush != Z_FINISH &&
flush != Z_BLOCK) {
assert(0 && "Invalid flush value");
}

Bytef *in;
Bytef *out;
size_t in_off, in_len, out_off, out_len;
@@ -213,7 +225,9 @@ class ZCtx : public ObjectWrap {
}

// v8 land!
static void After(uv_work_t* work_req) {
static void After(uv_work_t* work_req, int status) {
assert(status == 0);

HandleScope scope;
ZCtx *ctx = container_of(work_req, ZCtx, work_req_);

@@ -481,6 +495,7 @@ void InitZlib(Handle<Object> target) {
callback_sym = NODE_PSYMBOL("callback");
onerror_sym = NODE_PSYMBOL("onerror");

// valid flush values.
NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH);
@@ -0,0 +1 @@
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
@@ -230,15 +230,20 @@ var rfc4231 = [

for (var i = 0, l = rfc4231.length; i < l; i++) {
for (var hash in rfc4231[i]['hmac']) {
var str = crypto.createHmac(hash, rfc4231[i].key);
str.end(rfc4231[i].data);
var strRes = str.read().toString('hex');
var result = crypto.createHmac(hash, rfc4231[i]['key'])
.update(rfc4231[i]['data'])
.digest('hex');
if (rfc4231[i]['truncate']) {
result = result.substr(0, 32); // first 128 bits == 32 hex chars
strRes = strRes.substr(0, 32);
}
assert.equal(rfc4231[i]['hmac'][hash],
result,
'Test HMAC-' + hash + ': Test case ' + (i + 1) + ' rfc 4231');
assert.equal(strRes, result, 'Should get same result from stream');
}
}

@@ -373,6 +378,18 @@ var a2 = crypto.createHash('sha256').update('Test123').digest('base64');
var a3 = crypto.createHash('sha512').update('Test123').digest(); // binary
var a4 = crypto.createHash('sha1').update('Test123').digest('buffer');

// stream interface
var a5 = crypto.createHash('sha512');
a5.end('Test123');
a5 = a5.read();

var a6 = crypto.createHash('sha512');
a6.write('Te');
a6.write('st');
a6.write('123');
a6.end();
a6 = a6.read();

assert.equal(a0, '8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'Test SHA1');
assert.equal(a1, 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca' +
'\u00bd\u008c', 'Test MD5 as binary');
@@ -392,6 +409,10 @@ assert.deepEqual(a4,
new Buffer('8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'hex'),
'Test SHA1');

// stream interface should produce the same result.
assert.deepEqual(a5, a3, 'stream interface is consistent');
assert.deepEqual(a6, a3, 'stream interface is consistent');

// Test multiple updates to same hash
var h1 = crypto.createHash('sha1').update('Test123').digest('hex');
var h2 = crypto.createHash('sha1').update('Test').update('123').digest('hex');
@@ -419,6 +440,11 @@ assert.throws(function() {
var s1 = crypto.createSign('RSA-SHA1')
.update('Test123')
.sign(keyPem, 'base64');
var s1stream = crypto.createSign('RSA-SHA1');
s1stream.end('Test123');
s1stream = s1stream.sign(keyPem, 'base64');
assert.equal(s1, s1stream, 'Stream produces same output');

var verified = crypto.createVerify('RSA-SHA1')
.update('Test')
.update('123')
@@ -427,13 +453,25 @@ assert.strictEqual(verified, true, 'sign and verify (base 64)');

var s2 = crypto.createSign('RSA-SHA256')
.update('Test123')
.sign(keyPem); // binary
.sign(keyPem, 'binary');
var s2stream = crypto.createSign('RSA-SHA256');
s2stream.end('Test123');
s2stream = s2stream.sign(keyPem, 'binary');
assert.equal(s2, s2stream, 'Stream produces same output');

var verified = crypto.createVerify('RSA-SHA256')
.update('Test')
.update('123')
.verify(certPem, s2); // binary
.verify(certPem, s2, 'binary');
assert.strictEqual(verified, true, 'sign and verify (binary)');

var verStream = crypto.createVerify('RSA-SHA256');
verStream.write('Tes');
verStream.write('t12');
verStream.end('3');
verified = verStream.verify(certPem, s2, 'binary');
assert.strictEqual(verified, true, 'sign and verify (stream)');

var s3 = crypto.createSign('RSA-SHA1')
.update('Test123')
.sign(keyPem, 'buffer');
@@ -443,6 +481,13 @@ var verified = crypto.createVerify('RSA-SHA1')
.verify(certPem, s3);
assert.strictEqual(verified, true, 'sign and verify (buffer)');

var verStream = crypto.createVerify('RSA-SHA1');
verStream.write('Tes');
verStream.write('t12');
verStream.end('3');
verified = verStream.verify(certPem, s3);
assert.strictEqual(verified, true, 'sign and verify (stream)');


function testCipher1(key) {
// Test encryption and decryption
@@ -460,6 +505,20 @@ function testCipher1(key) {
txt += decipher.final('utf8');

assert.equal(txt, plaintext, 'encryption and decryption');

// streaming cipher interface
// NB: In real life, it's not guaranteed that you can get all of it
// in a single read() like this. But in this case, we know it's
// quite small, so there's no harm.
var cStream = crypto.createCipher('aes192', key);
cStream.end(plaintext);
ciph = cStream.read();

var dStream = crypto.createDecipher('aes192', key);
dStream.end(ciph);
txt = dStream.read().toString('utf8');

assert.equal(txt, plaintext, 'encryption and decryption with streams');
}


@@ -500,6 +559,20 @@ function testCipher3(key, iv) {
txt += decipher.final('utf8');

assert.equal(txt, plaintext, 'encryption and decryption with key and iv');

// streaming cipher interface
// NB: In real life, it's not guaranteed that you can get all of it
// in a single read() like this. But in this case, we know it's
// quite small, so there's no harm.
var cStream = crypto.createCipheriv('des-ede3-cbc', key, iv);
cStream.end(plaintext);
ciph = cStream.read();

var dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv);
dStream.end(ciph);
txt = dStream.read().toString('utf8');

assert.equal(txt, plaintext, 'streaming cipher iv');
}


@@ -21,16 +21,10 @@

var common = require('../common');
var assert = require('assert');
var zlib = require('zlib');
var events = require('events');

['Deflate', 'Inflate', 'Gzip', 'Gunzip', 'DeflateRaw', 'InflateRaw', 'Unzip']
.forEach(function (name) {
var a = false;
var zStream = new zlib[name]();
zStream.on('close', function () {
a = true;
});
zStream.destroy();
var e = new events.EventEmitter;

assert.equal(a, true, name+'#destroy() must emit \'close\'');
});
assert.equal(typeof e._events, 'undefined');
e.setMaxListeners(5);
assert.equal(typeof e._events, 'undefined');
@@ -22,46 +22,50 @@
var common = require('../common');
var assert = require('assert');

var path = require('path'),
fs = require('fs'),
fn = path.join(common.tmpDir, 'write.txt'),
file = fs.createWriteStream(fn),
var path = require('path');
var fs = require('fs');
var fn = path.join(common.tmpDir, 'write.txt');
var file = fs.createWriteStream(fn, {
lowWaterMark: 0,
highWaterMark: 10
});

EXPECTED = '012345678910',
var EXPECTED = '012345678910';

callbacks = {
var callbacks = {
open: -1,
drain: -2,
close: -1,
endCb: -1
close: -1
};

file
.on('open', function(fd) {
console.error('open!');
callbacks.open++;
assert.equal('number', typeof fd);
})
.on('error', function(err) {
throw err;
console.error('error!', err.stack);
})
.on('drain', function() {
console.error('drain!', callbacks.drain);
callbacks.drain++;
if (callbacks.drain == -1) {
assert.equal(EXPECTED, fs.readFileSync(fn));
assert.equal(EXPECTED, fs.readFileSync(fn, 'utf8'));
file.write(EXPECTED);
} else if (callbacks.drain == 0) {
assert.equal(EXPECTED + EXPECTED, fs.readFileSync(fn));
file.end(function(err) {
assert.ok(!err);
callbacks.endCb++;
});
assert.equal(EXPECTED + EXPECTED, fs.readFileSync(fn, 'utf8'));
file.end();
}
})
.on('close', function() {
console.error('close!');
assert.strictEqual(file.bytesWritten, EXPECTED.length * 2);

callbacks.close++;
assert.throws(function() {
console.error('write after end should not be allowed');
file.write('should not work anymore');
});

@@ -70,12 +74,13 @@ file

for (var i = 0; i < 11; i++) {
(function(i) {
assert.strictEqual(false, file.write(i));
file.write('' + i);
})(i);
}

process.on('exit', function() {
for (var k in callbacks) {
assert.equal(0, callbacks[k], k + ' count off by ' + callbacks[k]);
}
console.log('ok');
});
@@ -22,18 +22,18 @@
var common = require('../common');
var assert = require('assert');

var path = require('path'),
fs = require('fs'),
util = require('util');
var path = require('path');
var fs = require('fs');
var util = require('util');


var filepath = path.join(common.tmpDir, 'write.txt'),
file;
var filepath = path.join(common.tmpDir, 'write.txt');
var file;

var EXPECTED = '012345678910';

var cb_expected = 'write open drain write drain close error ',
cb_occurred = '';
var cb_expected = 'write open drain write drain close error ';
var cb_occurred = '';

var countDrains = 0;

@@ -47,6 +47,8 @@ process.on('exit', function() {
assert.strictEqual(cb_occurred, cb_expected,
'events missing or out of order: "' +
cb_occurred + '" !== "' + cb_expected + '"');
} else {
console.log('ok');
}
});

@@ -59,22 +61,30 @@ function removeTestFile() {

removeTestFile();

file = fs.createWriteStream(filepath);
// drain at 0, return false at 10.
file = fs.createWriteStream(filepath, {
lowWaterMark: 0,
highWaterMark: 11
});

file.on('open', function(fd) {
console.error('open');
cb_occurred += 'open ';
assert.equal(typeof fd, 'number');
});

file.on('drain', function() {
console.error('drain');
cb_occurred += 'drain ';
++countDrains;
if (countDrains === 1) {
assert.equal(fs.readFileSync(filepath), EXPECTED);
file.write(EXPECTED);
console.error('drain=1, write again');
assert.equal(fs.readFileSync(filepath, 'utf8'), EXPECTED);
console.error('ondrain write ret=%j', file.write(EXPECTED));
cb_occurred += 'write ';
} else if (countDrains == 2) {
assert.equal(fs.readFileSync(filepath), EXPECTED + EXPECTED);
console.error('second drain, end');
assert.equal(fs.readFileSync(filepath, 'utf8'), EXPECTED + EXPECTED);
file.end();
}
});
@@ -88,11 +98,15 @@ file.on('close', function() {

file.on('error', function(err) {
cb_occurred += 'error ';
assert.ok(err.message.indexOf('not writable') >= 0);
assert.ok(err.message.indexOf('write after end') >= 0);
});


for (var i = 0; i < 11; i++) {
assert.strictEqual(file.write(i), false);
var ret = file.write(i + '');
console.error('%d %j', i, ret);

// return false when i hits 10
assert(ret === (i != 10));
}
cb_occurred += 'write ';
@@ -32,12 +32,13 @@ fs.open(emptyFile, 'r', function (error, fd) {
var read = fs.createReadStream(emptyFile, { 'fd': fd });

read.once('data', function () {
throw new Error("data event should not emit");
throw new Error('data event should not emit');
});

var readEmit = false;
read.once('end', function () {
readEmit = true;
console.error('end event 1');
});

setTimeout(function () {
@@ -52,12 +53,13 @@ fs.open(emptyFile, 'r', function (error, fd) {
read.pause();

read.once('data', function () {
throw new Error("data event should not emit");
throw new Error('data event should not emit');
});

var readEmit = false;
read.once('end', function () {
readEmit = true;
console.error('end event 2');
});

setTimeout(function () {
@@ -0,0 +1,75 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var fs = require('fs');

function check(async, sync) {
var expected = /Path must be a string without null bytes./;
var argsSync = Array.prototype.slice.call(arguments, 2);
var argsAsync = argsSync.concat(function(er) {
assert(er && er.message.match(expected));
});

if (sync)
assert.throws(function() {
console.error(sync.name, argsSync);
sync.apply(null, argsSync);
}, expected);

if (async)
async.apply(null, argsAsync);
}

check(fs.appendFile, fs.appendFileSync, 'foo\u0000bar');
check(fs.chmod, fs.chmodSync, 'foo\u0000bar', '0644');
check(fs.chown, fs.chownSync, 'foo\u0000bar', 12, 34);
check(fs.link, fs.linkSync, 'foo\u0000bar', 'foobar');
check(fs.link, fs.linkSync, 'foobar', 'foo\u0000bar');
check(fs.lstat, fs.lstatSync, 'foo\u0000bar');
check(fs.mkdir, fs.mkdirSync, 'foo\u0000bar', '0755');
check(fs.open, fs.openSync, 'foo\u0000bar', 'r');
check(fs.readFile, fs.readFileSync, 'foo\u0000bar');
check(fs.readdir, fs.readdirSync, 'foo\u0000bar');
check(fs.readlink, fs.readlinkSync, 'foo\u0000bar');
check(fs.realpath, fs.realpathSync, 'foo\u0000bar');
check(fs.rename, fs.renameSync, 'foo\u0000bar', 'foobar');
check(fs.rename, fs.renameSync, 'foobar', 'foo\u0000bar');
check(fs.rmdir, fs.rmdirSync, 'foo\u0000bar');
check(fs.stat, fs.statSync, 'foo\u0000bar');
check(fs.symlink, fs.symlinkSync, 'foo\u0000bar', 'foobar');
check(fs.symlink, fs.symlinkSync, 'foobar', 'foo\u0000bar');
check(fs.truncate, fs.truncateSync, 'foo\u0000bar');
check(fs.unlink, fs.unlinkSync, 'foo\u0000bar');
check(null, fs.unwatchFile, 'foo\u0000bar', assert.fail);
check(fs.utimes, fs.utimesSync, 'foo\u0000bar', 0, 0);
check(null, fs.watch, 'foo\u0000bar', assert.fail);
check(null, fs.watchFile, 'foo\u0000bar', assert.fail);
check(fs.writeFile, fs.writeFileSync, 'foo\u0000bar');

// an 'error' for exists means that it doesn't exist.
// one of many reasons why this file is the absolute worst.
fs.exists('foo\u0000bar', function(exists) {
assert(!exists);
});
assert(!fs.existsSync('foo\u0000bar'));

@@ -60,12 +60,10 @@ file.on('data', function(data) {

paused = true;
file.pause();
assert.ok(file.paused);

setTimeout(function() {
paused = false;
file.resume();
assert.ok(!file.paused);
}, 10);
});

@@ -77,7 +75,6 @@ file.on('end', function(chunk) {

file.on('close', function() {
callbacks.close++;
assert.ok(!file.readable);

//assert.equal(fs.readFileSync(fn), fileContent);
});
@@ -104,6 +101,7 @@ process.on('exit', function() {
assert.equal(2, callbacks.close);
assert.equal(30000, file.length);
assert.equal(10000, file3.length);
console.error('ok');
});

var file4 = fs.createReadStream(rangeFile, {bufferSize: 1, start: 1, end: 2});
@@ -31,7 +31,8 @@ var writeEndOk = false;
var file = path.join(common.tmpDir, 'write-end-test.txt');
var stream = fs.createWriteStream(file);

stream.end('a\n', 'utf8', function() {
stream.end('a\n', 'utf8');
stream.on('close', function() {
var content = fs.readFileSync(file, 'utf8');
assert.equal(content, 'a\n');
writeEndOk = true;
@@ -73,7 +73,11 @@ server.listen(common.PORT, function() {
assert(!socket.onend);
assert.equal(socket.listeners('connect').length, 0);
assert.equal(socket.listeners('data').length, 0);
assert.equal(socket.listeners('end').length, 0);

// the stream.Duplex onend listener
// allow 0 here, so that i can run the same test on streams1 impl
assert(socket.listeners('end').length <= 1);

assert.equal(socket.listeners('free').length, 0);
assert.equal(socket.listeners('close').length, 0);
assert.equal(socket.listeners('error').length, 0);
@@ -0,0 +1,64 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common'),
assert = require('assert'),
http = require('http');

var testIndex = 0,
responses = 0;

var server = http.createServer(function(req, res) {
switch (testIndex++) {
case 0:
res.writeHead(200, { test: 'foo \r\ninvalid: bar' });
break;
case 1:
res.writeHead(200, { test: 'foo \ninvalid: bar' });
break;
case 2:
res.writeHead(200, { test: 'foo \rinvalid: bar' });
break;
case 3:
res.writeHead(200, { test: 'foo \n\n\ninvalid: bar' });
break;
case 4:
res.writeHead(200, { test: 'foo \r\n \r\n \r\ninvalid: bar' });
server.close();
break;
default:
assert(false);
}
res.end('Hi mars!');
});
server.listen(common.PORT);

for (var i = 0; i < 5; i++) {
var req = http.get({ port: common.PORT, path: '/' }, function(res) {
assert.strictEqual(res.headers.test, 'foo invalid: bar');
assert.strictEqual(res.headers.invalid, undefined);
responses++;
});
}

process.on('exit', function() {
assert.strictEqual(responses, 5);
});
@@ -48,8 +48,9 @@ function test1(){
putIn.write = function (data) {
gotWrite = true;
if (data.length) {

// inspect output matches repl output
assert.equal(data, util.inspect(require('fs'), null, null, false) + '\n');
assert.equal(data, util.inspect(require('fs'), null, 2, false) + '\n');
// globally added lib matches required lib
assert.equal(global.fs, require('fs'));
test2();
@@ -0,0 +1,320 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.


var common = require('../common.js');
var R = require('_stream_readable');
var assert = require('assert');

var util = require('util');
var EE = require('events').EventEmitter;

function TestReader(n) {
R.apply(this);
this._buffer = new Buffer(n || 100);
this._buffer.fill('x');
this._pos = 0;
this._bufs = 10;
}

util.inherits(TestReader, R);

TestReader.prototype.read = function(n) {
var max = this._buffer.length - this._pos;
n = n || max;
n = Math.max(n, 0);
var toRead = Math.min(n, max);
if (toRead === 0) {
// simulate the read buffer filling up with some more bytes some time
// in the future.
setTimeout(function() {
this._pos = 0;
this._bufs -= 1;
if (this._bufs <= 0) {
// read them all!
if (!this.ended) {
this.emit('end');
this.ended = true;
}
} else {
this.emit('readable');
}
}.bind(this), 10);
return null;
}

var ret = this._buffer.slice(this._pos, this._pos + toRead);
this._pos += toRead;
return ret;
};

/////

function TestWriter() {
EE.apply(this);
this.received = [];
this.flush = false;
}

util.inherits(TestWriter, EE);

TestWriter.prototype.write = function(c) {
this.received.push(c.toString());
this.emit('write', c);
return true;

// flip back and forth between immediate acceptance and not.
this.flush = !this.flush;
if (!this.flush) setTimeout(this.emit.bind(this, 'drain'), 10);
return this.flush;
};

TestWriter.prototype.end = function(c) {
if (c) this.write(c);
this.emit('end', this.received);
};

////////

// tiny node-tap lookalike.
var tests = [];
function test(name, fn) {
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: run
});
}

process.nextTick(run);


test('a most basic test', function(t) {
var r = new TestReader(20);

var reads = [];
var expect = [ 'x',
'xx',
'xxx',
'xxxx',
'xxxxx',
'xxxxx',
'xxxxxxxx',
'xxxxxxxxx',
'xxx',
'xxxxxxxxxxxx',
'xxxxxxxx',
'xxxxxxxxxxxxxxx',
'xxxxx',
'xxxxxxxxxxxxxxxxxx',
'xx',
'xxxxxxxxxxxxxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxx' ];

r.on('end', function() {
t.same(reads, expect);
t.end();
});

var readSize = 1;
function flow() {
var res;
while (null !== (res = r.read(readSize++))) {
reads.push(res.toString());
}
r.once('readable', flow);
}

flow();
});

test('pipe', function(t) {
var r = new TestReader(5);

var expect = [ 'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx' ]

var w = new TestWriter;
var flush = true;
w.on('end', function(received) {
t.same(received, expect);
t.end();
});

r.pipe(w);
});



[1,2,3,4,5,6,7,8,9].forEach(function(SPLIT) {
test('unpipe', function(t) {
var r = new TestReader(5);

// unpipe after 3 writes, then write to another stream instead.
var expect = [ 'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx' ];
expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ];

var w = [ new TestWriter(), new TestWriter() ];

var writes = SPLIT;
w[0].on('write', function() {
if (--writes === 0) {
r.unpipe();
t.equal(r._readableState.pipes, null);
w[0].end();
r.pipe(w[1]);
t.equal(r._readableState.pipes, w[1]);
}
});

var ended = 0;

var ended0 = false;
var ended1 = false;
w[0].on('end', function(results) {
t.equal(ended0, false);
ended0 = true;
ended++;
t.same(results, expect[0]);
});

w[1].on('end', function(results) {
t.equal(ended1, false);
ended1 = true;
ended++;
t.equal(ended, 2);
t.same(results, expect[1]);
t.end();
});

r.pipe(w[0]);
});
});


// both writers should get the same exact data.
test('multipipe', function(t) {
var r = new TestReader(5);
var w = [ new TestWriter, new TestWriter ];

var expect = [ 'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx' ];

var c = 2;
w[0].on('end', function(received) {
t.same(received, expect, 'first');
if (--c === 0) t.end();
});
w[1].on('end', function(received) {
t.same(received, expect, 'second');
if (--c === 0) t.end();
});

r.pipe(w[0]);
r.pipe(w[1]);
});


[1,2,3,4,5,6,7,8,9].forEach(function(SPLIT) {
test('multi-unpipe', function(t) {
var r = new TestReader(5);

// unpipe after 3 writes, then write to another stream instead.
var expect = [ 'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx',
'xxxxx' ];
expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ];

var w = [ new TestWriter(), new TestWriter(), new TestWriter() ];

var writes = SPLIT;
w[0].on('write', function() {
if (--writes === 0) {
r.unpipe();
w[0].end();
r.pipe(w[1]);
}
});

var ended = 0;

w[0].on('end', function(results) {
ended++;
t.same(results, expect[0]);
});

w[1].on('end', function(results) {
ended++;
t.equal(ended, 2);
t.same(results, expect[1]);
t.end();
});

r.pipe(w[0]);
r.pipe(w[2]);
});
});
@@ -0,0 +1,76 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.


var common = require('../common.js');
var R = require('_stream_readable');
var assert = require('assert');

var fs = require('fs');
var FSReadable = fs.ReadStream;

var path = require('path');
var file = path.resolve(common.fixturesDir, 'x1024.txt');

var size = fs.statSync(file).size;

// expect to see chunks no more than 10 bytes each.
var expectLengths = [];
for (var i = size; i > 0; i -= 10) {
expectLengths.push(Math.min(i, 10));
}

var util = require('util');
var Stream = require('stream');

util.inherits(TestWriter, Stream);

function TestWriter() {
Stream.apply(this);
this.buffer = [];
this.length = 0;
}

TestWriter.prototype.write = function(c) {
this.buffer.push(c.toString());
this.length += c.length;
return true;
};

TestWriter.prototype.end = function(c) {
if (c) this.buffer.push(c.toString());
this.emit('results', this.buffer);
}

var r = new FSReadable(file, { bufferSize: 10 });
var w = new TestWriter();

w.on('results', function(res) {
console.error(res, w.length);
assert.equal(w.length, size);
var l = 0;
assert.deepEqual(res.map(function (c) {
return c.length;
}), expectLengths);
console.log('ok');
});

r.pipe(w, { chunkSize: 10 });
@@ -0,0 +1,105 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var stream = require('stream');

(function testErrorListenerCatches() {
var count = 1000;

var source = new stream.Readable();
source._read = function(n, cb) {
n = Math.min(count, n);
count -= n;
cb(null, new Buffer(n));
};

var unpipedDest;
source.unpipe = function(dest) {
unpipedDest = dest;
stream.Readable.prototype.unpipe.call(this, dest);
};

var dest = new stream.Writable();
dest._write = function(chunk, cb) {
cb();
};

source.pipe(dest);

var gotErr = null;
dest.on('error', function(err) {
gotErr = err;
});

var unpipedSource;
dest.on('unpipe', function(src) {
unpipedSource = src;
});

var err = new Error('This stream turned into bacon.');
dest.emit('error', err);
assert.strictEqual(gotErr, err);
assert.strictEqual(unpipedSource, source);
assert.strictEqual(unpipedDest, dest);
})();

(function testErrorWithoutListenerThrows() {
var count = 1000;

var source = new stream.Readable();
source._read = function(n, cb) {
n = Math.min(count, n);
count -= n;
cb(null, new Buffer(n));
};

var unpipedDest;
source.unpipe = function(dest) {
unpipedDest = dest;
stream.Readable.prototype.unpipe.call(this, dest);
};

var dest = new stream.Writable();
dest._write = function(chunk, cb) {
cb();
};

source.pipe(dest);

var unpipedSource;
dest.on('unpipe', function(src) {
unpipedSource = src;
});

var err = new Error('This stream turned into bacon.');

var gotErr = null;
try {
dest.emit('error', err);
} catch (e) {
gotErr = e;
}
assert.strictEqual(gotErr, err);
assert.strictEqual(unpipedSource, source);
assert.strictEqual(unpipedDest, dest);
})();
@@ -0,0 +1,109 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var assert = require('assert');
var common = require('../common.js');
var fromList = require('_stream_readable')._fromList;

// tiny node-tap lookalike.
var tests = [];
function test(name, fn) {
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: run
});
}

process.nextTick(run);



test('buffers', function(t) {
// have a length
var len = 16;
var list = [ new Buffer('foog'),
new Buffer('bark'),
new Buffer('bazy'),
new Buffer('kuel') ];

// read more than the first element.
var ret = fromList(6, list, 16);
t.equal(ret.toString(), 'foogba');

// read exactly the first element.
ret = fromList(2, list, 10);
t.equal(ret.toString(), 'rk');

// read less than the first element.
ret = fromList(2, list, 8);
t.equal(ret.toString(), 'ba');

// read more than we have.
ret = fromList(100, list, 6);
t.equal(ret.toString(), 'zykuel');

// all consumed.
t.same(list, []);

t.end();
});

test('strings', function(t) {
// have a length
var len = 16;
var list = [ 'foog',
'bark',
'bazy',
'kuel' ];

// read more than the first element.
var ret = fromList(6, list, 16, true);
t.equal(ret, 'foogba');

// read exactly the first element.
ret = fromList(2, list, 10, true);
t.equal(ret, 'rk');

// read less than the first element.
ret = fromList(2, list, 8, true);
t.equal(ret, 'ba');

// read more than we have.
ret = fromList(100, list, 6, true);
t.equal(ret, 'zykuel');

// all consumed.
t.same(list, []);

t.end();
});
@@ -0,0 +1,299 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.


var common = require('../common.js');
var assert = require('assert');
var R = require('_stream_readable');
var util = require('util');

// tiny node-tap lookalike.
var tests = [];
function test(name, fn) {
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: run
});
}

process.nextTick(run);

/////

util.inherits(TestReader, R);

function TestReader(n, opts) {
R.call(this, util._extend({
bufferSize: 5
}, opts));

this.pos = 0;
this.len = n || 100;
}

TestReader.prototype._read = function(n, cb) {
setTimeout(function() {

if (this.pos >= this.len) {
return cb();
}

n = Math.min(n, this.len - this.pos);
if (n <= 0) {
return cb();
}

this.pos += n;
var ret = new Buffer(n);
ret.fill('a');

return cb(null, ret);
}.bind(this), 1);
};

test('setEncoding utf8', function(t) {
var tr = new TestReader(100);
tr.setEncoding('utf8');
var out = [];
var expect =
[ 'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa' ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(10)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});


test('setEncoding hex', function(t) {
var tr = new TestReader(100);
tr.setEncoding('hex');
var out = [];
var expect =
[ '6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161' ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(10)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});

test('setEncoding hex with read(13)', function(t) {
var tr = new TestReader(100);
tr.setEncoding('hex');
var out = [];
var expect =
[ "6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"16161" ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(13)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});

test('encoding: utf8', function(t) {
var tr = new TestReader(100, { encoding: 'utf8' });
var out = [];
var expect =
[ 'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa',
'aaaaaaaaaa' ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(10)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});


test('encoding: hex', function(t) {
var tr = new TestReader(100, { encoding: 'hex' });
var out = [];
var expect =
[ '6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161',
'6161616161' ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(10)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});

test('encoding: hex with read(13)', function(t) {
var tr = new TestReader(100, { encoding: 'hex' });
var out = [];
var expect =
[ "6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"1616161616161",
"6161616161616",
"16161" ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(13)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});
@@ -0,0 +1,314 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var assert = require('assert');
var common = require('../common.js');
var PassThrough = require('_stream_passthrough');
var Transform = require('_stream_transform');

// tiny node-tap lookalike.
var tests = [];
function test(name, fn) {
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: run
});
}

process.nextTick(run);

/////

test('passthrough', function(t) {
var pt = new PassThrough();

pt.write(new Buffer('foog'));
pt.write(new Buffer('bark'));
pt.write(new Buffer('bazy'));
pt.write(new Buffer('kuel'));
pt.end();

t.equal(pt.read(5).toString(), 'foogb');
t.equal(pt.read(5).toString(), 'arkba');
t.equal(pt.read(5).toString(), 'zykue');
t.equal(pt.read(5).toString(), 'l');
t.end();
});

test('simple transform', function(t) {
var pt = new Transform;
pt._transform = function(c, output, cb) {
var ret = new Buffer(c.length);
ret.fill('x');
output(ret);
cb();
};

pt.write(new Buffer('foog'));
pt.write(new Buffer('bark'));
pt.write(new Buffer('bazy'));
pt.write(new Buffer('kuel'));
pt.end();

t.equal(pt.read(5).toString(), 'xxxxx');
t.equal(pt.read(5).toString(), 'xxxxx');
t.equal(pt.read(5).toString(), 'xxxxx');
t.equal(pt.read(5).toString(), 'x');
t.end();
});

test('async passthrough', function(t) {
var pt = new Transform;
pt._transform = function(chunk, output, cb) {
setTimeout(function() {
output(chunk);
cb();
}, 10);
};

pt.write(new Buffer('foog'));
pt.write(new Buffer('bark'));
pt.write(new Buffer('bazy'));
pt.write(new Buffer('kuel'));
pt.end();

setTimeout(function() {
t.equal(pt.read(5).toString(), 'foogb');
t.equal(pt.read(5).toString(), 'arkba');
t.equal(pt.read(5).toString(), 'zykue');
t.equal(pt.read(5).toString(), 'l');
t.end();
}, 100);
});

test('assymetric transform (expand)', function(t) {
var pt = new Transform;

// emit each chunk 2 times.
pt._transform = function(chunk, output, cb) {
setTimeout(function() {
output(chunk);
setTimeout(function() {
output(chunk);
cb();
}, 10)
}, 10);
};

pt.write(new Buffer('foog'));
pt.write(new Buffer('bark'));
pt.write(new Buffer('bazy'));
pt.write(new Buffer('kuel'));
pt.end();

setTimeout(function() {
t.equal(pt.read(5).toString(), 'foogf');
t.equal(pt.read(5).toString(), 'oogba');
t.equal(pt.read(5).toString(), 'rkbar');
t.equal(pt.read(5).toString(), 'kbazy');
t.equal(pt.read(5).toString(), 'bazyk');
t.equal(pt.read(5).toString(), 'uelku');
t.equal(pt.read(5).toString(), 'el');
t.end();
}, 200);
});

test('assymetric transform (compress)', function(t) {
var pt = new Transform;

// each output is the first char of 3 consecutive chunks,
// or whatever's left.
pt.state = '';

pt._transform = function(chunk, output, cb) {
if (!chunk)
chunk = '';
var s = chunk.toString();
setTimeout(function() {
this.state += s.charAt(0);
if (this.state.length === 3) {
output(new Buffer(this.state));
this.state = '';
}
cb();
}.bind(this), 10);
};

pt._flush = function(output, cb) {
// just output whatever we have.
setTimeout(function() {
output(new Buffer(this.state));
this.state = '';
cb();
}.bind(this), 10);
};

pt._writableState.lowWaterMark = 3;

pt.write(new Buffer('aaaa'));
pt.write(new Buffer('bbbb'));
pt.write(new Buffer('cccc'));
pt.write(new Buffer('dddd'));
pt.write(new Buffer('eeee'));
pt.write(new Buffer('aaaa'));
pt.write(new Buffer('bbbb'));
pt.write(new Buffer('cccc'));
pt.write(new Buffer('dddd'));
pt.write(new Buffer('eeee'));
pt.write(new Buffer('aaaa'));
pt.write(new Buffer('bbbb'));
pt.write(new Buffer('cccc'));
pt.write(new Buffer('dddd'));
pt.end();

// 'abcdeabcdeabcd'
setTimeout(function() {
t.equal(pt.read(5).toString(), 'abcde');
t.equal(pt.read(5).toString(), 'abcde');
t.equal(pt.read(5).toString(), 'abcd');
t.end();
}, 200);
});


test('passthrough event emission', function(t) {
var pt = new PassThrough({
lowWaterMark: 0
});
var emits = 0;
pt.on('readable', function() {
var state = pt._readableState;
console.error('>>> emit readable %d', emits);
emits++;
});

var i = 0;

pt.write(new Buffer('foog'));
pt.write(new Buffer('bark'));

t.equal(pt.read(5).toString(), 'foogb');
t.equal(pt.read(5) + '', 'null');

console.error('need emit 0');

pt.write(new Buffer('bazy'));
console.error('should have emitted, but not again');
pt.write(new Buffer('kuel'));

console.error('should have emitted readable now 1 === %d', emits);
t.equal(emits, 1);

t.equal(pt.read(5).toString(), 'arkba');
t.equal(pt.read(5).toString(), 'zykue');
t.equal(pt.read(5), null);

console.error('need emit 1');

pt.end();

t.equal(emits, 2);

t.equal(pt.read(5).toString(), 'l');
t.equal(pt.read(5), null);

console.error('should not have emitted again');
t.equal(emits, 2);
t.end();
});

test('passthrough event emission reordered', function(t) {
var pt = new PassThrough;
var emits = 0;
pt.on('readable', function() {
console.error('emit readable', emits)
emits++;
});

pt.write(new Buffer('foog'));
pt.write(new Buffer('bark'));

t.equal(pt.read(5).toString(), 'foogb');
t.equal(pt.read(5), null);

console.error('need emit 0');
pt.once('readable', function() {
t.equal(pt.read(5).toString(), 'arkba');

t.equal(pt.read(5), null);

console.error('need emit 1');
pt.once('readable', function() {
t.equal(pt.read(5).toString(), 'zykue');
t.equal(pt.read(5), null);
pt.once('readable', function() {
t.equal(pt.read(5).toString(), 'l');
t.equal(pt.read(5), null);
t.equal(emits, 3);
t.end();
});
pt.end();
});
pt.write(new Buffer('kuel'));
});

pt.write(new Buffer('bazy'));
});

test('passthrough facaded', function(t) {
console.error('passthrough facaded');
var pt = new PassThrough;
var datas = [];
pt.on('data', function(chunk) {
datas.push(chunk.toString());
});

pt.on('end', function() {
t.same(datas, ['foog', 'bark', 'bazy', 'kuel']);
t.end();
});

pt.write(new Buffer('foog'));
setTimeout(function() {
pt.write(new Buffer('bark'));
setTimeout(function() {
pt.write(new Buffer('bazy'));
setTimeout(function() {
pt.write(new Buffer('kuel'));
setTimeout(function() {
pt.end();
}, 10);
}, 10);
}, 10);
}, 10);
});
@@ -0,0 +1,246 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common.js');
var W = require('_stream_writable');
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, 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 = [];
function test(name, fn) {
tests.push([name, fn]);
}

function run() {
var next = tests.shift();
if (!next)
return console.log('ok');

var name = next[0];
var fn = next[1];

if (!fn)
return run();

console.log('# %s', name);
fn({
same: assert.deepEqual,
equal: assert.equal,
end: run
});
}

process.nextTick(run);

test('write fast', function(t) {
var tw = new TestWriter({
lowWaterMark: 5,
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({
lowWaterMark: 5,
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({
lowWaterMark: 5,
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({
lowWaterMark: 5,
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({
lowWaterMark: 5,
highWaterMark: 100,
decodeStrings: false
});

tw._write = function(chunk, cb) {
assert(Array.isArray(chunk));
assert(typeof chunk[0] === 'string');
chunk = new Buffer(chunk[0], chunk[1]);
return TestWriter.prototype._write.call(this, chunk, 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({
lowWaterMark: 5,
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();
});
@@ -50,13 +50,6 @@ unzips.forEach(function (uz, i) {
uz.on('error', function(er) {
console.error('Error event', er);
hadError[i] = true;

// to be friendly to the Stream API, zlib objects just return true and
// ignore data on the floor after an error. It's up to the user to
// catch the 'error' event and do something intelligent. They do not
// emit any more data, however.
assert.equal(uz.write('also invalid'), true);
assert.equal(uz.end(), true);
});

uz.on('end', function(er) {