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