mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
test(folio): pin the window rules and the count invariant
This commit is contained in:
1 parent
e5900712b8
commit
6f7e690750
5 files changed
+586
-100
No files matched your search
@@ -13,6 +13,7 @@ test("single submit: delta matches typed amount", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 1500,
|
||||
@@ -26,6 +27,7 @@ test("double submit: delta is twice the typed amount, fires", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 2000,
|
||||
@@ -39,6 +41,7 @@ test("DoubleTap kind also caught when delta exceeds typed amount", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "DoubleTap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 1000,
|
||||
@@ -52,6 +55,7 @@ test("wrong action kind: vacuous true even with mismatch", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "InputText", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 1000,
|
||||
@@ -65,6 +69,7 @@ test("wrong target: vacuous true even with mismatch", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: "testTag:LoginScreen > testTag:LoginSubmit" },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 1000,
|
||||
@@ -78,6 +83,7 @@ test("null lastAction: vacuous true", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: null,
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 2000,
|
||||
@@ -91,6 +97,7 @@ test("zero typedAmount: vacuous true", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 0,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 1500,
|
||||
@@ -104,6 +111,7 @@ test("selector as object: coerced safely and TxnSubmit detected", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: { testTag: "TxnSubmit" } },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 1000,
|
||||
@@ -117,6 +125,7 @@ test("selector as object without TxnSubmit: vacuous true", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: { testTag: "LoginSubmit" } },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 1000,
|
||||
@@ -130,6 +139,7 @@ test("raw whole-dollar input: single submit clears", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: parseTypedAmount("50"),
|
||||
prevTotalBalance: 5000,
|
||||
currTotalBalance: 10000,
|
||||
@@ -143,6 +153,7 @@ test("raw whole-dollar input: double submit fires", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: parseTypedAmount("50"),
|
||||
prevTotalBalance: 5000,
|
||||
currTotalBalance: 15000,
|
||||
@@ -156,6 +167,7 @@ test("decimal input from empty prior balance clears", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: parseTypedAmount("5.50"),
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 550,
|
||||
@@ -169,6 +181,7 @@ test("DoubleTap kind with raw whole-dollar input fires", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "DoubleTap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: parseTypedAmount("100"),
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 20000,
|
||||
@@ -182,6 +195,7 @@ test("route gate: ledger landing with stale carrier is skipped", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "ledger",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 5000,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 0,
|
||||
@@ -195,6 +209,7 @@ test("route gate: add-transaction landing with double-submit delta is skipped",
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "add-transaction",
|
||||
lastAction: { kind: "DoubleTap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 5000,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 10000,
|
||||
@@ -208,6 +223,7 @@ test("route gate: null route is skipped", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: null,
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 5000,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 0,
|
||||
@@ -221,6 +237,7 @@ test("route gate: home landing with matching delta passes", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 5000,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 5000,
|
||||
@@ -234,6 +251,7 @@ test("route gate: home landing with double-insert delta fires", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 5000,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 10000,
|
||||
@@ -258,6 +276,7 @@ test("above 2^53 a healthy single submit is not reported", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 1600,
|
||||
prevTotalBalance: HUGE_BALANCE,
|
||||
currTotalBalance: HUGE_BALANCE + 1600,
|
||||
@@ -271,6 +290,7 @@ test("above 2^53 a double-submit delta is not reported either", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 1600,
|
||||
prevTotalBalance: HUGE_BALANCE,
|
||||
currTotalBalance: HUGE_BALANCE + 3200,
|
||||
@@ -284,6 +304,7 @@ test("an unreadable previous balance above 2^53 is not evidence", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 1600,
|
||||
prevTotalBalance: HUGE_BALANCE,
|
||||
currTotalBalance: 5000,
|
||||
@@ -300,6 +321,7 @@ test("typed amount above 2^53 is not evidence", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 1e23,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 0,
|
||||
@@ -315,6 +337,7 @@ test("boundary: a double submit landing exactly on MAX_SAFE_INTEGER still fires"
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 4503599627370495,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 9007199254740990,
|
||||
@@ -328,6 +351,7 @@ test("boundary: a single submit landing exactly on MAX_SAFE_INTEGER passes", ()
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 9007199254740991,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 9007199254740991,
|
||||
@@ -341,6 +365,7 @@ test("boundary: one cent past MAX_SAFE_INTEGER stops being evidence", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 4503599627370496,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 9007199254740992,
|
||||
@@ -357,6 +382,7 @@ test("a large but exact difference between safe balances still fires", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: -9007199254740991,
|
||||
currTotalBalance: 9007199254740991,
|
||||
@@ -372,6 +398,7 @@ test("21-digit typed amount with an unmoved balance is not a violation", () => {
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: parseTypedAmount("999999999999999999999"),
|
||||
prevTotalBalance: 220900,
|
||||
currTotalBalance: 220900,
|
||||
@@ -379,3 +406,99 @@ test("21-digit typed amount with an unmoved balance is not a violation", () => {
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
// Freshness. prevTotalBalance is the last total we READ, so the window between
|
||||
// it and now can hold more than one submit's transactions. A delta measured
|
||||
// over such a window is not evidence about the amount typed into any one of
|
||||
// them, and the android run that produced a 13000 delta against a typed 19600
|
||||
// is what that looks like: the window held a double-submit's two 19600 debits
|
||||
// and an unrelated 26200 credit.
|
||||
test("freshness: two submits in the window is vacuous, not a conviction", () => {
|
||||
assert.equal(
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "DoubleTap", on: submitOn },
|
||||
submitsInWindow: 2,
|
||||
typedAmount: 19600,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: -13000,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("freshness: two submits cannot convict even on a clean 2x delta", () => {
|
||||
assert.equal(
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 2,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 2000,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
// The boundary of the rule, from both sides. One submit is the only window the
|
||||
// property judges: zero means the total moved without a submit landing in it
|
||||
// (nothing to attribute the move to), and two or more means the move is shared.
|
||||
test("freshness boundary: exactly one submit is the window that convicts", () => {
|
||||
assert.equal(
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "DoubleTap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 19600,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: -39200,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("freshness boundary: one submit with a healthy 1x delta still passes", () => {
|
||||
assert.equal(
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 1,
|
||||
typedAmount: 19600,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: -19600,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("freshness boundary: three submits is vacuous", () => {
|
||||
assert.equal(
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 3,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 0,
|
||||
currTotalBalance: 2500,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
// A zero count would mean the step's own action was not counted as a submit,
|
||||
// which contradicts the action gate above it. Guard it anyway: a window with no
|
||||
// submit in it explains no balance move.
|
||||
test("freshness boundary: a window with no submit in it is vacuous", () => {
|
||||
assert.equal(
|
||||
submitChangesBalanceByTypedAmount({
|
||||
route: "home",
|
||||
lastAction: { kind: "Tap", on: submitOn },
|
||||
submitsInWindow: 0,
|
||||
typedAmount: 500,
|
||||
prevTotalBalance: 1000,
|
||||
currTotalBalance: 2000,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user