helpers_test.gno
3.19 Kb · 109 lines
1package game32
2
3import (
4 "encoding/hex"
5 "strconv"
6 "strings"
7 "testing"
8 "time"
9
10 "gno.land/p/nt/testutils/v0"
11)
12
13// Public key of the deterministic TEST-ONLY signer (scripts/game29-test-vectors.mjs,
14// seed = sha256("gnomoji-game29-test-signer")). Not used anywhere but tests.
15const testSignerPub = "faec207b91ab599b1e51652602843fcb52275922e8dab39bed3a21034cece6f1"
16
17func setup() address {
18 if admin == address("") {
19 admin = testutils.TestAddress("deployer")
20 operator = admin
21 }
22 if len(claimSignerPubKey) != 32 {
23 claimSignerPubKey, _ = hex.DecodeString(testSignerPub)
24 }
25 return admin
26}
27
28func ta(name string) address { return testutils.TestAddress(name) }
29
30func bal(a address, coin string) uint64 { return balOf(a.String(), coin) }
31
32// voucher returns (nonce, expiry, sigHex) for a server voucher. Signatures
33// come from voucherVectors (generated). A missing vector is logged so the
34// generator can sign it, and an invalid signature is returned.
35func voucher(t *testing.T, kind string, player address, payload string) (int64, int64, string) {
36 nonce := LastNonce(player.String()) + 1
37 expiry := time.Now().Unix() + 600
38 return nonce, expiry, sigFor(t, kind, player, nonce, expiry, payload)
39}
40
41// safeCompactAchPayload wraps compactAchPayload with a recover so that
42// cross-kind tests (e.g. signing an "ach" voucher over a claim payload) don't
43// crash the test helper. An unparseable payload falls back to the raw string —
44// the resulting signature will be wrong and the realm will reject it, which is
45// exactly what those rejection tests expect.
46func safeCompactAchPayload(payload string) (result string) {
47 defer func() {
48 if r := recover(); r != nil {
49 result = payload // fall back to raw payload on parse error
50 }
51 }()
52 return compactAchPayload(payload)
53}
54
55func sigFor(t *testing.T, kind string, player address, nonce, expiry int64, payload string) string {
56 // Compact the payload to match the v2 VoucherMessage format.
57 compact := payload
58 if kind == "claim" {
59 compact = compactClaimPayload(payload)
60 } else if kind == "ach" {
61 compact = safeCompactAchPayload(payload)
62 }
63 msg := VoucherMessage(kind, player.String(), nonce, expiry, compact)
64 if s, ok := voucherVectors[msg]; ok {
65 return s
66 }
67 // Regenerate with: node scripts/game29-test-vectors.mjs
68 panic("MISSING_VOUCHER " + hex.EncodeToString([]byte(msg)) + " END")
69}
70
71func give(a address, coin string, amt uint64) { creditBal(a.String(), coin, amt) }
72
73func allowanceFor(addr address, r int) uint64 {
74 js := ClaimAllowance(addr.String())
75 key := `"r` + strconv.Itoa(r) + `":`
76 i := strings.Index(js, key) + len(key)
77 j := i
78 for j < len(js) && js[j] >= '0' && js[j] <= '9' {
79 j++
80 }
81 v, _ := strconv.ParseUint(js[i:j], 10, 64)
82 return v
83}
84
85func mustAbort(t *testing.T, what string, abort any, wantSub string) {
86 if abort == nil {
87 t.Errorf("%s: expected abort, got success", what)
88 return
89 }
90 msg := ""
91 switch v := abort.(type) {
92 case string:
93 msg = v
94 case error:
95 msg = v.Error()
96 default:
97 msg = "?"
98 }
99 if wantSub != "" && !strings.Contains(msg, wantSub) {
100 t.Errorf("%s: aborted with %q, want it to contain %q", what, msg, wantSub)
101 }
102}
103
104func h(choice, salt string) string { return moveHash(choice, salt) }
105
106func h0(s string) string {
107 x := sha256Sum(s)
108 return x
109}