import { describe, expect, it } from "@suaveplan/testing/runner"; import * as fc from "fast-check"; import { fromArray } from "../../src/readable/from-array/from-array.js"; import { toArray } from "../../src/sinks/to-array/to-array.js"; import { batchStream } from "../../src/transforms/batch/batch.js"; import { filterStream } from "../../src/transforms/filter/filter.js"; import { mapStream } from "../../src/transforms/map/map.js"; describe("property-based: streams invariants", () => { it("toArray(fromArray(items)) ≡ items", { timeout: 30000 }, async () => { await fc.assert( fc.asyncProperty(fc.array(fc.integer()), async (items) => { const result = await toArray(fromArray(items)); expect(result).toEqual(items); }), { numRuns: 50 } ); }); it("batchStream completeness: flattened batches ≡ original", { timeout: 30000, }, async () => { await fc.assert( fc.asyncProperty( fc.array(fc.integer(), { minLength: 1 }), fc.integer({ min: 1, max: 20 }), async (items, size) => { const batches = await toArray( fromArray(items).pipeThrough(batchStream(size)) ); const flat = batches.flat(); expect(flat).toEqual(items); } ), { numRuns: 50 } ); }); it("mapStream composition: map(f).map(g) ≡ map(x=>g(f(x)))", { timeout: 30000, }, async () => { await fc.assert( fc.asyncProperty(fc.array(fc.integer()), async (items) => { const f = (x: number) => x * 2; const g = (x: number) => x + 1; const composed = await toArray( fromArray(items) .pipeThrough(mapStream(f)) .pipeThrough(mapStream(g)) ); const single = await toArray( fromArray(items).pipeThrough(mapStream((x) => g(f(x)))) ); expect(composed).toEqual(single); }), { numRuns: 50 } ); }); it("filterStream: no items fail predicate", { timeout: 30000, }, async () => { await fc.assert( fc.asyncProperty( fc.array(fc.integer({ min: -1000, max: 1000 })), async (items) => { const pred = (n: number) => n > 0; const result = await toArray( fromArray(items).pipeThrough(filterStream(pred)) ); expect(result.every(pred)).toBe(true); expect(result.length).toBe(items.filter(pred).length); } ), { numRuns: 50 } ); }); });