lobby_test.gno

4.23 Kb ยท 185 lines
  1package chess
  2
  3import (
  4	"os"
  5	"std"
  6	"testing"
  7	"time"
  8
  9	"gno.land/p/morgan/chess/glicko2"
 10)
 11
 12func TestLobbyJoin(t *testing.T) {
 13	cleanup()
 14	testing.SetRealm(std.NewUserRealm(white))
 15	LobbyJoin(cross, 10*60, 5)
 16	os.Sleep(time.Second * 5)
 17	testing.SetRealm(std.NewUserRealm(black))
 18	LobbyJoin(cross, 10*60, 5)
 19	res := LobbyGameFound(cross)
 20	if res == "null" {
 21		t.Errorf("LobbyGameFound is null")
 22	}
 23}
 24
 25func sublobbyToIDs(pl []lobbyPlayer) []string {
 26	s := make([]string, len(pl))
 27	for idx, p := range pl {
 28		s[idx] = string(p.player.Address)
 29	}
 30	return s
 31}
 32
 33func TestLobbyGameFound(t *testing.T) {
 34	check := func(checker ...func(t *testing.T)) func(t *testing.T) {
 35		return func(t *testing.T) {
 36			for _, ck := range checker {
 37				ck(t)
 38			}
 39		}
 40	}
 41	ids := func(ids ...std.Address) func(t *testing.T) {
 42		return func(t *testing.T) {
 43			if len(ids) != len(lobby[0]) {
 44				t.Errorf("lobby doesn't match expected ids: lobby: %v, newIDs: %v", sublobbyToIDs(lobby[0]), ids)
 45				return
 46			}
 47			for idx, i := range ids {
 48				if pa := lobby[0][idx].player.Address; pa != i {
 49					t.Errorf("check pos %d: player id doesnt match (got %q want %q)", idx, pa, i)
 50				}
 51			}
 52		}
 53	}
 54	numGames := func(n int) func(t *testing.T) {
 55		return func(t *testing.T) {
 56			l := gameStore.Size()
 57			if l != n {
 58				t.Errorf("invalid gameStore size; want %d got %d", n, l)
 59			}
 60		}
 61	}
 62
 63	type pl struct {
 64		id     std.Address
 65		rating float64
 66		// use negative values here to indicate how many seconds in the past;
 67		// ie: joinedAt: -1, means player joined 1 second ago.
 68		joinedAt int
 69		seenAt   int
 70	}
 71	tt := []struct {
 72		name   string
 73		pre    []pl
 74		caller std.Address
 75		check  func(t *testing.T)
 76	}{
 77		{
 78			"equalRating",
 79			[]pl{{"1", 1200, -1, -1}, {"2", 1200, 0, 0}},
 80			"1",
 81			check(ids(), numGames(1)),
 82		},
 83		{
 84			"minimumApart", // delta <= 25
 85			[]pl{{"1", 1200, 0, 0}, {"2", 1225, 0, 0}},
 86			"2",
 87			check(ids(), numGames(1)),
 88		},
 89		{
 90			"tooFarApart", // delta > 25
 91			[]pl{{"1", 1200, 0, 0}, {"2", 1230, 0, 0}},
 92			"2",
 93			check(ids("1", "2"), numGames(0)),
 94		},
 95		{
 96			"oldHighPriority",
 97			// kicked hasn't been seen in too long, so should not be considered.
 98			// 1 is active and has been looking for 30s, so it gets priority, even if 2-3 is
 99			// a closer match.
100			[]pl{{"kicked", 1800, -60, -50}, {"1", 1900, -30, -10}, {"2", 1400, 0, 0}, {"3", 1420, 0, 0}},
101			"3",
102			check(ids("2"), numGames(1)),
103		},
104		{
105			"oldHighPriority2",
106			[]pl{{"comeback", 1800, -60, -50}, {"1", 1900, -30, -10}, {"2", 1400, 0, 0}, {"3", 1420, 0, 0}},
107			// same as last one, except the player who was kicked last time, because
108			// he's the caller, has their seenAt set back to the current time, so they're matched with 1.
109			"comeback",
110			check(ids("2", "3"), numGames(1)),
111		},
112		{
113			"alone",
114			[]pl{{"1", 1200, 0, 0}},
115			"1",
116			check(ids("1"), numGames(0)),
117		},
118		{
119			"brackFail",
120			[]pl{{"1", 1200, -4, -4}, {"2", 1450, -5, -5}},
121			"1",
122			check(ids("1", "2"), numGames(0)),
123		},
124		{
125			"brackFail2",
126			[]pl{{"1", 1200, -5, -5}, {"2", 1450, -4, -4}},
127			"1",
128			check(ids("1", "2"), numGames(0)),
129		},
130		{
131			"brackSuccess",
132			[]pl{{"1", 1200, -5, -5}, {"2", 1450, -5, -5}},
133			"1",
134			check(ids(), numGames(1)),
135		},
136	}
137
138	for _, tc := range tt {
139		t.Run(tc.name, func(t *testing.T) {
140			cleanup()
141			now := time.Now()
142			for _, p := range tc.pre {
143				lobby[0] = append(lobby[0], lobbyPlayer{
144					joinedAt: now.Add(time.Duration(p.joinedAt) * time.Second),
145					seenAt:   now.Add(time.Duration(p.seenAt) * time.Second),
146					player: &Player{
147						Address: p.id,
148						CategoryInfo: [CategoryMax]CategoryInfo{
149							Blitz: {PlayerRating: &glicko2.PlayerRating{Rating: p.rating}},
150						},
151					},
152				})
153			}
154
155			testing.SetRealm(std.NewUserRealm(tc.caller))
156			LobbyGameFound(cross)
157
158			if tc.check != nil {
159				tc.check(t)
160			}
161		})
162	}
163}
164
165func TestLobbyJoin_HasOpenGames(t *testing.T) {
166	cleanup()
167	g := &Game{
168		ID:    "123",
169		White: white,
170		Black: black,
171		State: GameStateOpen,
172	}
173	gameStore.Set(g.ID, g)
174	addToUser2Games(white, g)
175	addToUser2Games(black, g)
176
177	testing.SetRealm(std.NewUserRealm(white))
178	LobbyJoin(cross, 10*60, 5)
179	if g.State != GameStateAborted {
180		t.Errorf("state wrong: want %d got %d", GameStateAborted, g.State)
181	}
182	if g.Winner != WinnerNone {
183		t.Errorf("winner wrong: want %q got %q", "none", g.Winner)
184	}
185}