bufferstreams
Version:
Abstract streams to deal with the whole buffered contents.
329 lines • 13 kB
JavaScript
import { describe, expect, test } from '@jest/globals';
import { YError } from 'yerror';
import StreamTest from 'streamtest';
import { BufferStream } from './index.js';
// Helpers
function syncBufferPrefixer(headerText) {
return new BufferStream((err, buf, cb) => {
expect(err).toBeNull();
if (null === buf) {
cb(null, Buffer.from(headerText));
return;
}
cb(null, Buffer.concat([Buffer.from(headerText), buf]));
}, {
objectMode: false,
});
}
function syncObjectsPrefixer(prefixObject) {
return new BufferStream((err, objs, cb) => {
expect(err).toBeNull();
if (null === objs) {
cb(null, [prefixObject]);
return;
}
cb(null, [prefixObject, ...objs]);
}, {
objectMode: true,
});
}
function asyncBufferPrefixer(headerText) {
return new BufferStream((err, buf, cb) => {
expect(err).toBeNull();
if (null === buf) {
setTimeout(() => {
cb(null, Buffer.from(headerText));
}, 0);
}
else {
setTimeout(() => {
cb(null, Buffer.concat([Buffer.from(headerText), buf]));
}, 0);
}
}, {
objectMode: false,
});
}
describe('bufferstreams', () => {
test('should fail when callback is not a function', () => {
try {
new BufferStream(undefined);
throw new YError('E_UNEXPECTED_SUCCESS');
}
catch (err) {
expect(err.code).toEqual('E_BAD_CALLBACK');
}
});
describe('in buffer mode', () => {
describe('synchonously', () => {
test('should work with one pipe', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(syncBufferPrefixer('plop'))
.pipe(stream);
expect(await result).toEqual('ploptest');
});
test('should work when returning a null buffer', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(new BufferStream((err, buf, cb) => {
if (err) {
cb(err);
return;
}
cb(null, null);
}))
.pipe(stream);
expect(await result).toEqual('');
});
test('should work with an async handler', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(new BufferStream(async (buf) => {
return buf;
}))
.pipe(stream);
expect(await result).toEqual('test');
});
test('should work with multiple pipes', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(syncBufferPrefixer('plop'))
.pipe(syncBufferPrefixer('plip'))
.pipe(syncBufferPrefixer('plap'))
.pipe(stream);
expect(await result).toEqual('plapplipploptest');
});
});
describe('asynchonously', () => {
test('should work with one pipe', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(asyncBufferPrefixer('plop'))
.pipe(stream);
expect(await result).toEqual('ploptest');
});
test('should work when returning a null buffer', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(new BufferStream((err, _buf, cb) => {
if (err) {
cb(err);
return;
}
cb(null, null);
}))
.pipe(stream);
expect(await result).toEqual('');
});
test('should work with multiple pipes', async () => {
const [stream, result] = StreamTest.toText();
StreamTest.fromChunks([Buffer.from('te'), Buffer.from('st')])
.pipe(asyncBufferPrefixer('plop'))
.pipe(asyncBufferPrefixer('plip'))
.pipe(asyncBufferPrefixer('plap'))
.pipe(stream);
expect(await result).toEqual('plapplipploptest');
});
test('should report stream errors', async () => {
const [stream, result] = StreamTest.toText();
const bufferStream = new BufferStream((err, _objs, cb) => {
expect(err.code).toEqual('E_ERROR');
cb(null, []);
}, {
objectMode: true,
});
StreamTest.fromErroredChunks(new YError('E_ERROR'), [
Buffer.from('ou'),
Buffer.from('de'),
Buffer.from('la'),
Buffer.from('li'),
])
.on('error', (err) => {
bufferStream.emit('error', err);
})
.pipe(bufferStream)
.pipe(stream);
expect(await result).toEqual('');
});
test('should emit callback errors', async () => {
const [stream, result] = StreamTest.toText();
let caughtError = new YError('E_UNEXPECTED_SUCCESS');
StreamTest.fromChunks([
Buffer.from('ou'),
Buffer.from('de'),
Buffer.from('la'),
Buffer.from('li'),
])
.pipe(new BufferStream((err, _objs, cb) => {
if (err) {
cb(err);
return;
}
cb(new YError('E_ERROR'), Buffer.from(''));
}))
.on('error', (err) => {
caughtError = err;
})
.pipe(stream);
expect(await result).toEqual('');
expect(caughtError.code).toEqual('E_ERROR');
});
});
});
describe('in object mode', () => {
const object1 = { txt: 'te' };
const object2 = { txt: 'st' };
const object3 = { txt: 'e' };
const object4 = { txt: 'd' };
const object5 = { txt: 'u' };
const object6 = { txt: 'ni' };
const object7 = { txt: 't' };
describe('synchonously', () => {
test('should work with one pipe', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(syncObjectsPrefixer(object4))
.pipe(stream);
expect(await result).toEqual([object4, object1, object2]);
});
test('should work when returning an empty array', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(new BufferStream((err, _objs, cb) => {
if (err) {
cb(err);
return;
}
cb(null, []);
}, {
objectMode: true,
}))
.pipe(stream);
expect((await result).length).toEqual(0);
});
test('should work with multiple pipes', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(syncObjectsPrefixer(object4))
.pipe(syncObjectsPrefixer(object5))
.pipe(syncObjectsPrefixer(object6))
.pipe(stream);
expect(await result).toEqual([
object6,
object5,
object4,
object1,
object2,
]);
});
});
describe('asynchonously', () => {
test('should work with one pipe', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(syncObjectsPrefixer(object4))
.pipe(stream);
expect(await result).toEqual([object4, object1, object2]);
});
test('should work when returning an empty array', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(new BufferStream((err, _objs, cb) => {
if (err) {
cb(err);
return;
}
cb(null, []);
}, {
objectMode: true,
}))
.pipe(stream);
expect((await result).length).toEqual(0);
});
test('should work when returning legacy null', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(new BufferStream((err, _objs, cb) => {
if (err) {
cb(err);
return;
}
cb(null, null);
}, {
objectMode: true,
}))
.pipe(stream);
expect((await result).length).toEqual(0);
});
test('should work with multiple pipes', async () => {
const [stream, result] = StreamTest.toObjects();
StreamTest.fromObjects([object1, object2])
.pipe(syncObjectsPrefixer(object4))
.pipe(syncObjectsPrefixer(object5))
.pipe(syncObjectsPrefixer(object6))
.pipe(stream);
expect(await result).toEqual([
object6,
object5,
object4,
object1,
object2,
]);
});
test('should report stream errors', async () => {
const [stream, result] = StreamTest.toObjects();
const bufferStream = new BufferStream((err, _objs, cb) => {
expect(err.code).toEqual('E_ERROR');
cb(null, []);
}, {
objectMode: true,
});
StreamTest.fromErroredObjects(new YError('E_ERROR'), [
object1,
object2,
object3,
object4,
object5,
object6,
object7,
])
.on('error', (err) => {
bufferStream.emit('error', err);
})
.pipe(bufferStream)
.pipe(stream);
expect(await result).toEqual([]);
});
test('should emit callback errors', async () => {
const [stream, result] = StreamTest.toObjects();
let caughtError = new YError('E_UNEXPECTED_SUCCESS');
StreamTest.fromObjects([
object1,
object2,
object3,
object4,
object5,
object6,
object7,
])
.pipe(new BufferStream((err, _objs, cb) => {
if (err) {
cb(err, []);
return;
}
cb(new YError('E_ERROR'), []);
}, {
objectMode: true,
}))
.on('error', (err) => {
caughtError = err;
})
.pipe(stream);
expect(await result).toEqual([]);
expect(caughtError.code).toEqual('E_ERROR');
});
});
});
});
//# sourceMappingURL=index.test.js.map