render_test.gno
3.12 Kb · 94 lines
1package bullscows
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/uassert/v0"
8)
9
10// clear restores the globals to their init() state so assertions do not depend
11// on which tests ran first. Realm globals live for the whole test binary.
12func clear() {
13 round = 1
14 attempts = 0
15 history = nil
16 records = nil
17 secret = newSecret(seedFor(round))
18}
19
20// ExampleRender pins the fresh-round view: no guesses, empty leaderboard.
21func ExampleRender() {
22 clear()
23 print(Render(""))
24 // Output:
25 // # Bulls & Cows
26 //
27 // One shared secret 4-digit code (no repeated digits). Call `Guess("1972")` to get **bulls** (right digit, right spot) and **cows** (right digit, wrong spot). First to 4 bulls wins the round; `GiveUp()` reveals the code and starts over.
28 //
29 // ## Round 1
30 //
31 // Attempts so far: **0**
32 //
33 // _No guesses yet this round — be the first._
34 //
35 // ## Leaderboard (fastest solves)
36 //
37 // _Nobody has cracked a code yet._
38}
39
40// TestRenderHistoryNewestFirst checks the guess table is reverse-chronological.
41func TestRenderHistoryNewestFirst(t *testing.T) {
42 clear()
43 addHistory(guessLog{player: "alice", guess: "1234", bulls: 1, cows: 2})
44 addHistory(guessLog{player: "bob", guess: "5678", bulls: 0, cows: 1})
45
46 out := Render("")
47 uassert.True(t, strings.Contains(out, "### Recent guesses"), "history section should appear")
48 uassert.True(t, strings.Contains(out, "| `bob` | 5678 | 0 | 1 |\n| `alice` | 1234 | 1 | 2 |\n"),
49 "newest guess should be listed first")
50 uassert.False(t, strings.Contains(out, "_No guesses yet"), "empty-history notice should be gone")
51}
52
53// TestRenderLeaderboard checks solved records render in rank order.
54func TestRenderLeaderboard(t *testing.T) {
55 clear()
56 addRecord(record{player: "carol", attempts: 3, round: 1})
57 addRecord(record{player: "dave", attempts: 7, round: 2})
58
59 out := Render("")
60 uassert.True(t, strings.Contains(out, "| 1 | `carol` | 3 | 1 |\n| 2 | `dave` | 7 | 2 |\n"),
61 "leaderboard should rank fastest first")
62 uassert.False(t, strings.Contains(out, "_Nobody has cracked a code yet._"),
63 "empty-leaderboard notice should be gone")
64}
65
66// TestRenderShortensLongAddresses checks the bech32 addresses players actually
67// have get elided rather than blowing out the table.
68func TestRenderShortensLongAddresses(t *testing.T) {
69 clear()
70 long := "g1manfred47kzduec920z88wfr64ylksmdcedlf5"
71 addHistory(guessLog{player: long, guess: "1234", bulls: 0, cows: 0})
72
73 out := Render("")
74 uassert.False(t, strings.Contains(out, long), "full address should not be rendered")
75 uassert.True(t, strings.Contains(out, "| `"+long[:8]+"…"+long[len(long)-4:]+"` | 1234 |"),
76 "address should be shortened to prefix…suffix")
77}
78
79// TestRenderTracksRoundAndAttempts checks the counters reach the page.
80func TestRenderTracksRoundAndAttempts(t *testing.T) {
81 clear()
82 round = 4
83 attempts = 11
84
85 out := Render("")
86 uassert.True(t, strings.Contains(out, "## Round 4\n"), "round should be shown")
87 uassert.True(t, strings.Contains(out, "Attempts so far: **11**"), "attempts should be shown")
88}
89
90// TestRenderIgnoresPath documents that Render has no sub-routes.
91func TestRenderIgnoresPath(t *testing.T) {
92 clear()
93 uassert.Equal(t, Render(""), Render("/anything"))
94}