UNPKG

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

356 lines (306 loc) 9.44 kB
import { describe, expect, it } from "vitest"; import { filters } from "./filters"; describe("filters", () => { describe("without predicate function", () => { it("should filter out null values", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(1); controller.enqueue(null); controller.enqueue(2); controller.enqueue(3); controller.close(); }, }); const filtered = stream.pipeThrough(filters()); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([1, 2, 3]); }); it("should filter out undefined values", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue("a"); controller.enqueue(undefined); controller.enqueue("b"); controller.enqueue("c"); controller.close(); }, }); const filtered = stream.pipeThrough(filters()); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual(["a", "b", "c"]); }); it("should keep falsy values that are not null or undefined", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(0); controller.enqueue(false); controller.enqueue(""); controller.enqueue(null); controller.enqueue(undefined); controller.enqueue("valid"); controller.close(); }, }); const filtered = stream.pipeThrough(filters()); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([0, false, "", "valid"]); }); }); describe("with predicate function", () => { it("should filter based on predicate function", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(1); controller.enqueue(2); controller.enqueue(3); controller.enqueue(4); controller.enqueue(5); controller.close(); }, }); const filtered = stream.pipeThrough(filters((x: number) => x % 2 === 0)); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([2, 4]); }); it("should pass index to predicate function", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue("a"); controller.enqueue("b"); controller.enqueue("c"); controller.enqueue("d"); controller.close(); }, }); const indices: number[] = []; const filtered = stream.pipeThrough( filters((_x: string, i: number) => { indices.push(i); return i % 2 === 0; // Keep items at even indices }), ); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual(["a", "c"]); expect(indices).toEqual([0, 1, 2, 3]); }); it("should handle async predicate functions", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(1); controller.enqueue(2); controller.enqueue(3); controller.enqueue(4); controller.close(); }, }); const filtered = stream.pipeThrough( filters(async (x: number) => { await new Promise((resolve) => setTimeout(resolve, 1)); return x > 2; }), ); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([3, 4]); }); it("should filter based on truthy/falsy return values", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue("keep"); controller.enqueue("skip"); controller.enqueue("keep2"); controller.enqueue("skip2"); controller.close(); }, }); const filtered = stream.pipeThrough( filters((x: string) => x.includes("keep")), ); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual(["keep", "keep2"]); }); it("should handle empty stream", async () => { const stream = new ReadableStream({ start(controller) { controller.close(); }, }); const filtered = stream.pipeThrough(filters((_x: unknown) => true)); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([]); }); it("should handle predicate that always returns false", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(1); controller.enqueue(2); controller.enqueue(3); controller.close(); }, }); const filtered = stream.pipeThrough(filters(() => false)); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([]); }); it("should handle predicate that always returns true", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(1); controller.enqueue(2); controller.enqueue(3); controller.close(); }, }); const filtered = stream.pipeThrough(filters(() => true)); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([1, 2, 3]); }); }); describe("edge cases", () => { it("should handle complex objects", async () => { const obj1 = { id: 1, name: "Alice" }; const obj2 = { id: 2, name: "Bob" }; const obj3 = { id: 3, name: "Charlie" }; const stream = new ReadableStream({ start(controller) { controller.enqueue(obj1); controller.enqueue(obj2); controller.enqueue(obj3); controller.close(); }, }); const filtered = stream.pipeThrough( filters((obj: unknown) => (obj as { id: number }).id % 2 === 1), ); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([obj1, obj3]); }); it("should handle arrays", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue([1, 2]); controller.enqueue([]); controller.enqueue([3, 4, 5]); controller.enqueue(null); controller.close(); }, }); const filtered = stream.pipeThrough( filters((arr: unknown) => Array.isArray(arr) && arr.length > 0), ); const reader = filtered.getReader(); const results = []; let done = false; while (!done) { const { value, done: readerDone } = await reader.read(); done = readerDone; if (!done) { results.push(value); } } expect(results).toEqual([ [1, 2], [3, 4, 5], ]); }); }); });