sflow
Version:
sflow is a powerful and highly-extensible library designed for processing and manipulating streams of data effortlessly. Inspired by the functional programming paradigm, it provides a rich set of utilities for transforming streams, including chunking, fil
149 lines (119 loc) • 4.42 kB
text/typescript
// To thoroughly test the `lazyMergeStream` function, we need to write comprehensive tests that check for its correct behavior. We need tests that verify the merging functionality, the lazy pulling behavior, and the proper termination and cancellation of the streams. For this, we can use a testing framework like Jest along with some helper functions to create readable streams.
import { lazyMergeStream } from "./lazyMergeStream";
import { sleep } from "./utils";
// Here is a detailed `test.ts` that demonstrates how to do this:
// ```typescript
// Helper function to create a readable stream from an array of values
function toReadableStream(values: any[]) {
let index = 0;
return new ReadableStream({
pull(controller) {
if (index < values.length) {
controller.enqueue(values[index++]);
} else {
controller.close();
}
},
});
}
test("Streams merge correctly", async () => {
const stream1 = toReadableStream([1, 2, 3]);
const stream2 = toReadableStream([4, 5, 6]);
const mergedStream = lazyMergeStream(stream1, stream2);
const reader = mergedStream.getReader();
let result = [];
let done = false;
while (!done) {
const { value, done: isDone } = await reader.read();
done = isDone;
if (value !== undefined) {
result.push(value);
}
}
expect(result).toEqual([1, 4, 2, 5, 3, 6]);
});
test("Pull occurs lazily with highWaterMark: 0", async () => {
let stream1PullCount = 0;
const stream1 = new ReadableStream(
{
async pull(controller) {
await sleep(0);
stream1PullCount++;
controller.enqueue("s1_" + stream1PullCount);
if (stream1PullCount === 3) {
controller.close();
}
},
},
{ highWaterMark: 0 },
);
let stream2PullCount = 0;
const stream2 = new ReadableStream(
{
async pull(controller) {
await sleep(0);
stream2PullCount++;
controller.enqueue("s2_" + stream2PullCount);
if (stream2PullCount === 3) {
controller.close();
}
},
},
{ highWaterMark: 0 },
);
const mergedStream = lazyMergeStream(stream1, stream2);
await sleep(10);
expect(stream1PullCount).toBe(0);
expect(stream2PullCount).toBe(0);
const reader = mergedStream.getReader();
expect(stream1PullCount).toBe(0);
expect(stream2PullCount).toBe(0);
expect((await reader.read()).value).toBe("s1_1"); // trigger first pull
expect(stream1PullCount).toBe(1);
expect(stream2PullCount).toBe(0);
await sleep(10);
expect(stream1PullCount).toBe(1);
expect(stream2PullCount).toBe(1);
expect((await reader.read()).value).toBe("s2_1");
expect(stream1PullCount).toBe(1);
expect(stream2PullCount).toBe(1);
expect((await reader.read()).value).toBe("s1_2");
expect(stream1PullCount).toBe(2);
expect(stream2PullCount).toBe(1);
await sleep(10);
expect(stream1PullCount).toBe(2);
expect(stream2PullCount).toBe(2);
});
test("Stream terminates correctly", async () => {
const stream1 = toReadableStream([1]);
const stream2 = toReadableStream([2, 3]);
const mergedStream = lazyMergeStream(stream1, stream2);
const reader = mergedStream.getReader();
let result = [];
let done = false;
while (!done) {
const { value, done: isDone } = await reader.read();
done = isDone;
if (value !== undefined) {
result.push(value);
}
}
expect(result).toEqual([1, 2, 3]);
});
test("Stream cancels correctly", async () => {
const stream1 = toReadableStream([1, 2, 3]);
const stream2 = toReadableStream([4, 5, 6]);
const mergedStream = lazyMergeStream(stream1, stream2);
const reader = mergedStream.getReader();
await reader.read(); // trigger some reads
await reader.read();
await reader.cancel("Test cancellation");
// Now ensure that cancel has been called properly.
});
// ```
// Key points included in the tests:
// 1. **Merge Correctness**: Ensure that values from both streams are interleaved as expected.
// 2. **Lazy Pulling**: Guarantee that pulling from the merged stream causes the original streams to only pull when necessary.
// 3. **Termination**: When all streams are done, the merged stream should close correctly.
// 4. **Cancellation**: Ensure that the cancelation is propagated to the underlying streams.
// This test suite covers the primary aspects to confirm that `lazyMergeStream` operates as specified.