connect4_test.gno
3.34 Kb · 131 lines
1package connect4
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/avl/v0"
8 "gno.land/p/nt/testutils/v0"
9 "gno.land/p/nt/uassert/v0"
10)
11
12var (
13 alice = testutils.TestAddress("alice") // 🔴
14 bob = testutils.TestAddress("bob") // 🟡
15 carol = testutils.TestAddress("carol")
16)
17
18func resetState() {
19 games = avl.NewTree()
20 nextID = 0
21}
22
23// TestVerticalWin plays 🔴 stacking column 0 four high while 🟡 plays column 1.
24func TestVerticalWin(cur realm, t *testing.T) {
25 resetState()
26
27 testing.SetRealm(testing.NewUserRealm(alice))
28 id := NewGame(cross(cur), bob)
29 uassert.Equal(t, int64(1), id)
30
31 for i := 0; i < 3; i++ {
32 testing.SetRealm(testing.NewUserRealm(alice))
33 Drop(cross(cur), id,0)
34 testing.SetRealm(testing.NewUserRealm(bob))
35 Drop(cross(cur), id,1)
36 }
37 // alice's 4th disc in column 0 -> vertical win
38 testing.SetRealm(testing.NewUserRealm(alice))
39 Drop(cross(cur), id,0)
40
41 g, err := getGame(id)
42 uassert.NoError(t, err)
43 uassert.True(t, g.Finished)
44 uassert.Equal(t, red, g.Winner)
45
46 out := Render("1")
47 uassert.True(t, strings.Contains(out, "🔴 Red wins!"))
48}
49
50// TestTurnOrderAndErrors covers turn enforcement, non-player, full-column and range checks.
51func TestTurnOrderAndErrors(cur realm, t *testing.T) {
52 resetState()
53
54 testing.SetRealm(testing.NewUserRealm(alice))
55 id := NewGame(cross(cur), bob)
56
57 // bob cannot move first (red starts)
58 testing.SetRealm(testing.NewUserRealm(bob))
59 uassert.AbortsWithMessage(t, cur,"not your turn", func() {
60 Drop(cross(cur), id,0)
61 })
62
63 // stranger cannot play
64 testing.SetRealm(testing.NewUserRealm(carol))
65 uassert.AbortsWithMessage(t, cur,"caller is not a player in this game", func() {
66 Drop(cross(cur), id,0)
67 })
68
69 // out-of-range column
70 testing.SetRealm(testing.NewUserRealm(alice))
71 uassert.AbortsWithMessage(t, cur,"column out of range (0-6)", func() {
72 Drop(cross(cur), id,7)
73 })
74
75 // fill column 3: alice & bob alternate, 6 discs total
76 col := 3
77 for i := 0; i < 3; i++ {
78 testing.SetRealm(testing.NewUserRealm(alice))
79 Drop(cross(cur), id,col)
80 testing.SetRealm(testing.NewUserRealm(bob))
81 Drop(cross(cur), id,col)
82 }
83 // column now full; whoever is on turn overflows it
84 g, _ := getGame(id)
85 var mover address
86 if g.Turn == red {
87 mover = alice
88 } else {
89 mover = bob
90 }
91 testing.SetRealm(testing.NewUserRealm(mover))
92 uassert.AbortsWithMessage(t, cur,"column is full", func() {
93 Drop(cross(cur), id,col)
94 })
95}
96
97// TestHorizontalWin: 🔴 across columns 0-3 on the bottom row.
98func TestHorizontalWin(cur realm, t *testing.T) {
99 resetState()
100
101 testing.SetRealm(testing.NewUserRealm(alice))
102 id := NewGame(cross(cur), bob)
103
104 // alice drops cols 0,1,2 ; bob answers on row above (col 0,1,2)
105 for c := 0; c < 3; c++ {
106 testing.SetRealm(testing.NewUserRealm(alice))
107 Drop(cross(cur), id,c)
108 testing.SetRealm(testing.NewUserRealm(bob))
109 Drop(cross(cur), id,c)
110 }
111 // alice completes col 3 on bottom row -> 0,1,2,3 horizontal
112 testing.SetRealm(testing.NewUserRealm(alice))
113 Drop(cross(cur), id,3)
114
115 g, err := getGame(id)
116 uassert.NoError(t, err)
117 uassert.True(t, g.Finished)
118 uassert.Equal(t, red, g.Winner)
119}
120
121// TestRenderList checks the listing view renders created games.
122func TestRenderList(cur realm, t *testing.T) {
123 resetState()
124
125 testing.SetRealm(testing.NewUserRealm(alice))
126 NewGame(cross(cur), bob)
127
128 out := Render("")
129 uassert.True(t, strings.Contains(out, "Connect Four"))
130 uassert.True(t, strings.Contains(out, "to move"))
131}