Initial Commit
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { describe, it } from "@suaveplan/testing/runner";
|
||||
import * as fc from "fast-check";
|
||||
import { createCommand } from "../../src/command/command.js";
|
||||
import { UndoStack } from "../../src/stack/stack.js";
|
||||
|
||||
interface Counter {
|
||||
value: number;
|
||||
}
|
||||
|
||||
describe("property: UndoStack invariants", () => {
|
||||
it("push N, undo all, redo all: final state = after-push state", {
|
||||
timeout: 30000,
|
||||
}, () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 1, max: 10 }), {
|
||||
minLength: 1,
|
||||
maxLength: 20,
|
||||
}),
|
||||
(deltas) => {
|
||||
const s = new UndoStack<Counter>({ value: 0 });
|
||||
for (const d of deltas) {
|
||||
s.push(
|
||||
createCommand(
|
||||
"D",
|
||||
(st) => ({ value: st.value + d }),
|
||||
(st) => ({ value: st.value - d })
|
||||
)
|
||||
);
|
||||
}
|
||||
const afterPush = s.current.value;
|
||||
for (let i = 0; i < deltas.length; i++) s.undo();
|
||||
for (let i = 0; i < deltas.length; i++) s.redo();
|
||||
return s.current.value === afterPush;
|
||||
}
|
||||
),
|
||||
{ numRuns: 200 }
|
||||
);
|
||||
});
|
||||
|
||||
it("undoSize never exceeds maxEntries", { timeout: 30000 }, () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.integer({ min: 1, max: 20 }),
|
||||
fc.array(fc.integer({ min: 1, max: 5 }), {
|
||||
minLength: 0,
|
||||
maxLength: 50,
|
||||
}),
|
||||
(maxEntries, deltas) => {
|
||||
const s = new UndoStack<Counter>(
|
||||
{ value: 0 },
|
||||
{ maxEntries }
|
||||
);
|
||||
for (const d of deltas) {
|
||||
s.push(
|
||||
createCommand(
|
||||
"D",
|
||||
(st) => ({ value: st.value + d }),
|
||||
(st) => ({ value: st.value - d })
|
||||
)
|
||||
);
|
||||
}
|
||||
return s.undoSize <= maxEntries;
|
||||
}
|
||||
),
|
||||
{ numRuns: 200 }
|
||||
);
|
||||
});
|
||||
|
||||
it("undoSize + redoSize = total pushed (within maxEntries limit)", {
|
||||
timeout: 30000,
|
||||
}, () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 1, max: 5 }), {
|
||||
minLength: 0,
|
||||
maxLength: 15,
|
||||
}),
|
||||
fc.integer({ min: 0, max: 15 }),
|
||||
(deltas, undoSteps) => {
|
||||
const s = new UndoStack<Counter>({ value: 0 });
|
||||
for (const d of deltas) {
|
||||
s.push(
|
||||
createCommand(
|
||||
"D",
|
||||
(st) => ({ value: st.value + d }),
|
||||
(st) => ({ value: st.value - d })
|
||||
)
|
||||
);
|
||||
}
|
||||
const steps = Math.min(undoSteps, deltas.length);
|
||||
for (let i = 0; i < steps; i++) s.undo();
|
||||
return s.undoSize + s.redoSize === deltas.length;
|
||||
}
|
||||
),
|
||||
{ numRuns: 200 }
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user