import { describe, it } from "@suaveplan/testing/runner"; import * as fc from "fast-check"; import { createCommand } from "../../src/command/command.js"; import { compressHistory } from "../../src/compression/history-compressor.js"; import { UndoStack } from "../../src/stack/stack.js"; interface Counter { value: number; } describe("property: compressHistory idempotency", () => { it("re-compressing does not change state or exceed original size", { timeout: 30000, }, () => { fc.assert( fc.property( fc.integer({ min: 0, max: 50 }), fc.integer({ min: 1, max: 20 }), (pushCount, depth) => { const s = new UndoStack({ value: 0 }); for (let i = 0; i < pushCount; i++) { s.push( createCommand( "Inc", (st) => ({ value: st.value + 1 }), (st) => ({ value: st.value - 1 }) ) ); } const r1 = compressHistory(s, { compressionDepth: depth }); const r2 = compressHistory(r1.stack, { compressionDepth: depth, }); // State preserved if (r1.stack.current.value !== r2.stack.current.value) return false; // Second compression adds no new squashes (all same-label entries already merged) // Size should not increase return r2.newSize <= r1.newSize; } ), { numRuns: 200 } ); }); });