46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
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<Counter>({ 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 }
|
|
);
|
|
});
|
|
});
|