1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
package game
// Regression: when the economy journal is unavailable, a payout paid
// through the character file must record the round's stake-resolution
// evidence in that same file. Otherwise a crash before the games' own
// ResolveStakes call leaves the wager records open with checkpoint
// balances that no longer match, and recovery refunds chip stakes the
// paid settlement had already consumed — duplicating the round's value.
import (
"testing"
"thehouseoficarus/internal/player"
)
func TestUnjournalablePayoutCrashDoesNotRefundChips(t *testing.T) {
h := newHarness(t)
h.seedAccount("alice")
p := h.seedCharacter("alice", "alice")
h.g.RunOnOwner(func() {
p.Credits = 100
p.SetInvSlot(0, &player.InventorySlot{ItemID: "chips", Quantity: 10})
w := casinoWallet{g: h.g, p: p}
if _, err := w.Wager(10); err != nil {
t.Error(err)
return
}
path := h.g.Economy.path
h.g.Economy.path = h.dir // persistent append failure
if err := w.PayCredits(20); err != nil {
t.Errorf("fallback payout failed: %v", err)
return
}
h.g.Economy.path = path
// Process loss BEFORE the game's own ResolveStakes call: the
// fallback payout itself must be the durable resolution.
h.g.recoverEconomy()
loaded, err := h.g.AccountStore.LoadCharacter("alice")
if err != nil {
t.Error(err)
return
}
if loaded.Credits != 120 || countChips(loaded) != 0 {
t.Errorf("recovered credits=%d chips=%d; want 120 credits and no chips (the paid settlement consumed the stake)", loaded.Credits, countChips(loaded))
}
if open := h.g.Economy.mustLoadOpen(t); len(open) != 0 {
t.Errorf("records left open after recovery: %+v", open)
}
})
}
// The stakes-open count is a proxy for "recovery did not silently refund":
// with the fix the wager record settles through the file-side evidence.
func TestUnjournalablePayoutEvidenceRecorded(t *testing.T) {
h := newHarness(t)
h.seedAccount("alice")
p := h.seedCharacter("alice", "alice")
h.g.RunOnOwner(func() {
p.Credits = 100
w := casinoWallet{g: h.g, p: p}
if _, err := w.Wager(10); err != nil {
t.Error(err)
return
}
path := h.g.Economy.path
h.g.Economy.path = h.dir
if err := w.PayCredits(20); err != nil {
t.Errorf("fallback payout failed: %v", err)
return
}
h.g.Economy.path = path
if len(p.ResolvedStakes) == 0 {
t.Error("fallback payout recorded no stake-resolution evidence; a crash before ResolveStakes would double-refund chips")
}
})
}
|