259 lines
7.8 KiB
JavaScript
259 lines
7.8 KiB
JavaScript
'use strict';
|
|
|
|
const { LimitedPassthrough } = require('../lib/limited-passthrough');
|
|
const { PassThrough, Transform } = require('stream');
|
|
|
|
// Helper to collect stream output
|
|
const collectStream = stream =>
|
|
new Promise((resolve, reject) => {
|
|
const chunks = [];
|
|
stream.on('data', chunk => chunks.push(chunk));
|
|
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
|
stream.on('error', reject);
|
|
});
|
|
|
|
// ============================================
|
|
// Constructor tests
|
|
// ============================================
|
|
|
|
module.exports['LimitedPassthrough: constructor with options'] = test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 100 });
|
|
test.equal(stream.maxBytes, 100);
|
|
test.equal(stream.processed, 0);
|
|
test.equal(stream.limited, false);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: constructor with no options'] = test => {
|
|
let stream = new LimitedPassthrough();
|
|
test.equal(stream.maxBytes, Infinity);
|
|
test.equal(stream.processed, 0);
|
|
test.equal(stream.limited, false);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: constructor with null options'] = test => {
|
|
let stream = new LimitedPassthrough(null);
|
|
test.equal(stream.maxBytes, Infinity);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: is a Transform stream'] = test => {
|
|
let stream = new LimitedPassthrough();
|
|
test.ok(stream instanceof Transform);
|
|
test.ok(typeof stream.pipe === 'function');
|
|
test.ok(typeof stream.write === 'function');
|
|
test.done();
|
|
};
|
|
|
|
// ============================================
|
|
// _transform tests - no limit
|
|
// ============================================
|
|
|
|
module.exports['LimitedPassthrough: passes all data when no limit'] = async test => {
|
|
let stream = new LimitedPassthrough();
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('hello '));
|
|
stream.write(Buffer.from('world'));
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello world');
|
|
test.equal(stream.processed, 11);
|
|
test.equal(stream.limited, false);
|
|
test.done();
|
|
};
|
|
|
|
// ============================================
|
|
// _transform tests - with limit
|
|
// ============================================
|
|
|
|
module.exports['LimitedPassthrough: limits output to maxBytes'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 5 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('hello world'));
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello');
|
|
test.equal(stream.processed, 5);
|
|
test.equal(stream.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: limits across multiple chunks'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 8 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('hello ')); // 6 bytes
|
|
stream.write(Buffer.from('world')); // 5 bytes, only 2 should pass
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello wo');
|
|
test.equal(stream.processed, 8);
|
|
test.equal(stream.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: drops data after limit reached'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 5 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('hello')); // exactly 5 bytes
|
|
stream.write(Buffer.from(' world')); // should be dropped
|
|
stream.write(Buffer.from('!')); // should be dropped
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello');
|
|
test.equal(stream.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: handles exact boundary'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 5 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('hello')); // exactly 5 bytes
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello');
|
|
test.equal(stream.processed, 5);
|
|
test.equal(stream.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: zero maxBytes treated as Infinity'] = async test => {
|
|
// Note: maxBytes: 0 is falsy, so constructor uses Infinity instead
|
|
let stream = new LimitedPassthrough({ maxBytes: 0 });
|
|
test.equal(stream.maxBytes, Infinity);
|
|
|
|
let output = collectStream(stream);
|
|
stream.write(Buffer.from('hello'));
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
// All data passes through since 0 is treated as Infinity
|
|
test.equal(result.toString(), 'hello');
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: handles limit of 1 byte'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 1 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('hello'));
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'h');
|
|
test.equal(stream.processed, 1);
|
|
test.equal(stream.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
// ============================================
|
|
// Edge cases
|
|
// ============================================
|
|
|
|
module.exports['LimitedPassthrough: handles empty writes'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 10 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from(''));
|
|
stream.write(Buffer.from('hello'));
|
|
stream.write(Buffer.from(''));
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello');
|
|
test.equal(stream.processed, 5);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: handles no writes'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 10 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.length, 0);
|
|
test.equal(stream.processed, 0);
|
|
test.equal(stream.limited, false);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: tracks processed bytes correctly'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 100 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('12345')); // 5 bytes
|
|
test.equal(stream.processed, 5);
|
|
|
|
stream.write(Buffer.from('67890')); // 5 more bytes
|
|
test.equal(stream.processed, 10);
|
|
|
|
stream.end();
|
|
|
|
await output;
|
|
test.equal(stream.processed, 10);
|
|
test.done();
|
|
};
|
|
|
|
// ============================================
|
|
// Integration tests
|
|
// ============================================
|
|
|
|
module.exports['LimitedPassthrough: works with pipe'] = async test => {
|
|
let source = new PassThrough();
|
|
let limiter = new LimitedPassthrough({ maxBytes: 10 });
|
|
let output = collectStream(source.pipe(limiter));
|
|
|
|
source.write('hello ');
|
|
source.write('wonderful ');
|
|
source.write('world');
|
|
source.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'hello wond');
|
|
test.equal(limiter.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: handles large data'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 1000 });
|
|
let output = collectStream(stream);
|
|
|
|
// Write 100 bytes at a time
|
|
for (let i = 0; i < 20; i++) {
|
|
stream.write(Buffer.alloc(100, 'x'));
|
|
}
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.length, 1000);
|
|
test.equal(stream.limited, true);
|
|
test.done();
|
|
};
|
|
|
|
module.exports['LimitedPassthrough: single byte writes'] = async test => {
|
|
let stream = new LimitedPassthrough({ maxBytes: 3 });
|
|
let output = collectStream(stream);
|
|
|
|
stream.write(Buffer.from('a'));
|
|
stream.write(Buffer.from('b'));
|
|
stream.write(Buffer.from('c'));
|
|
stream.write(Buffer.from('d')); // should be dropped
|
|
stream.write(Buffer.from('e')); // should be dropped
|
|
stream.end();
|
|
|
|
let result = await output;
|
|
test.equal(result.toString(), 'abc');
|
|
test.done();
|
|
};
|