Coverage for app/pycardgame/tests/base/test_game.py: 100.0%

214 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-04-07 20:57 +0000

1# PyCardGame - A base library for creating card games in Python 

2# Copyright (C) 2025 Popa-42 

3# 

4# This program is free software: you can redistribute it and/or modify 

5# it under the terms of the GNU General Public License as published by 

6# the Free Software Foundation, either version 3 of the License, or 

7# (at your option) any later version. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU General Public License for more details. 

13# 

14# You should have received a copy of the GNU General Public License 

15# along with this program. If not, see <https://www.gnu.org/licenses/>. 

16 

17from typing import Literal 

18 

19import pytest 

20 

21from ...src.base import ( 

22 CardMeta, 

23 DeckMeta, 

24 GenericCard, 

25 GenericDeck, 

26 GenericGame, 

27 GenericPlayer, 

28) 

29 

30T_Ranks = Literal["1", "2", "3"] 

31T_Suits = Literal["Red", "Green", "Blue"] 

32 

33 

34class DummyCard( 

35 GenericCard[T_Ranks, T_Suits], 

36 metaclass=CardMeta, 

37 rank_type=T_Ranks, 

38 suit_type=T_Suits 

39): 

40 def effect(self, game, player, *args): # pragma: no cover 

41 pass 

42 

43 

44class DummyDeck( 

45 GenericDeck[DummyCard], 

46 metaclass=DeckMeta, 

47 card_type=DummyCard 

48): 

49 pass 

50 

51 

52class DummyPlayer(GenericPlayer[DummyCard]): 

53 pass 

54 

55 

56class DummyGame(GenericGame[DummyCard]): 

57 def __init__(self, *players, draw_pile=None, discard_pile=None, trump=None, 

58 hand_size=4, starting_player_index=0, do_not_shuffle=False): 

59 super().__init__(DummyCard, DummyDeck, draw_pile, discard_pile, trump, 

60 hand_size, starting_player_index, do_not_shuffle, 

61 *players) 

62 

63 def check_valid_play(self, card1, card2): 

64 return card1.suit == card2.suit or card1.rank == card2.rank 

65 

66 def start_game(self): ... 

67 def end_game(self): ... 

68 

69 

70def test_game_init(): 

71 deck = DummyDeck() 

72 empty_deck = DummyDeck(cards=[]) 

73 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

74 

75 game = DummyGame(*players, draw_pile=deck, discard_pile=empty_deck, 

76 trump="Green", hand_size=2, starting_player_index=1) 

77 assert game.draw_pile == deck 

78 assert game.discard_pile == empty_deck 

79 assert game.trump == "Green" 

80 assert game.hand_size == 2 

81 assert game.players == players 

82 assert game.current_player_index == 1 

83 

84 # Invalid trump suit 

85 with pytest.raises(ValueError): 

86 DummyGame(*players, trump="InvalidSuit") 

87 

88 # Invalid player count 

89 with pytest.raises(ValueError): 

90 DummyGame(*players, starting_player_index=10) 

91 

92 

93def test_game_check_valid_play(): 

94 card1 = DummyCard(0, 0) 

95 card2 = DummyCard(0, 1) 

96 card3 = DummyCard(1, 0) 

97 game = DummyGame() 

98 

99 assert game.check_valid_play(card1, card2) is True 

100 assert game.check_valid_play(card1, card3) is True 

101 assert game.check_valid_play(card2, card3) is False 

102 

103 

104def test_game_discard_cards(): 

105 game = DummyGame() 

106 discard_card = DummyCard(0, 0) 

107 game.discard_cards(discard_card) 

108 assert discard_card in game.discard_pile 

109 

110 

111def test_game_get_discard_pile(): 

112 deck = DummyDeck() 

113 discard_pile = DummyDeck(cards=[]) 

114 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

115 game = DummyGame(*players, draw_pile=deck, discard_pile=discard_pile) 

116 assert game.get_discard_pile() == discard_pile 

117 

118 

119def test_game_get_top_card(): 

120 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

121 game = DummyGame(*players) 

122 top_card = game.get_top_card() 

123 assert top_card is None 

124 game.discard_pile.add(DummyCard(0, 0)) 

125 top_card = game.get_top_card() 

126 assert isinstance(top_card, DummyCard) 

127 assert top_card in game.draw_pile 

128 

129 

130def test_game_reshuffle_discard_pile(): 

131 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

132 deck = DummyDeck([]) 

133 discard_pile = DummyDeck([DummyCard(0, 0), DummyCard(1, 1)]) 

134 game = DummyGame(*players, draw_pile=deck, discard_pile=discard_pile) 

135 game.reshuffle_discard_pile() 

136 assert len(game.draw_pile) > 0 

137 assert len(game.discard_pile) == 0 

138 assert all(card in game.draw_pile for card in discard_pile.cards) 

139 

140 

141def test_game_draw_cards(): 

142 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

143 deck = DummyDeck([DummyCard(0, 0), DummyCard(1, 1)]) 

144 discard_pile = DummyDeck([DummyCard(2, 2)]) 

145 game = DummyGame(*players, draw_pile=deck, discard_pile=discard_pile) 

146 game.draw_cards(n=2) 

147 assert len(players[0].hand) == 2 

148 assert len(game.draw_pile) == 0 

149 assert len(game.discard_pile) == 1 

150 game.draw_cards(players[0]) 

151 assert len(players[0].hand) == 3 

152 

153 

154def test_game_deal_initial_cards(): 

155 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

156 deck = DummyDeck() 

157 game = DummyGame(*players, hand_size=2) 

158 game.deal_initial_cards() 

159 assert all(len(player.hand) == 2 for player in players) 

160 assert len(game.draw_pile) < len(deck) 

161 

162 

163def test_game_add_players(): 

164 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

165 game = DummyGame(*players, hand_size=2) 

166 new_players = [DummyPlayer("Charlie"), DummyPlayer("David")] 

167 game.add_players(*new_players) 

168 assert game.players == players + new_players 

169 

170 

171def test_game_remove_players(): 

172 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

173 game = DummyGame(*players, hand_size=2) 

174 game.remove_players(players[0]) 

175 assert game.players == players[1:] 

176 

177 

178def test_game_deal(): 

179 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

180 

181 game = DummyGame(*players, hand_size=2) 

182 game.deal(3) 

183 assert all(len(player.hand) == 3 for player in game.players) 

184 

185 

186def test_game_shuffle(): 

187 deck = DummyDeck() 

188 game = DummyGame(draw_pile=deck) 

189 game.shuffle() 

190 assert list(game.draw_pile) != sorted(game.draw_pile) 

191 assert len(game.draw_pile) == len(deck) 

192 assert all(card in deck for card in game.draw_pile) 

193 

194 

195def test_game_play(): 

196 player1 = DummyPlayer("Alice", [DummyCard(0, 0)]) 

197 player2 = DummyPlayer("Bob", [DummyCard(1, 1)]) 

198 players = [player1, player2] 

199 game = DummyGame(*players, hand_size=2) 

200 dealt_card = player1.hand[0] 

201 game.discard_cards(dealt_card) 

202 assert game.play_card(dealt_card, player1) is True 

203 assert len(player1.hand) == 0 

204 assert len(game.discard_pile) == 2 

205 assert (dealt_card in game.discard_pile and dealt_card not in 

206 player1.hand) 

207 

208 assert game.play_card(player2.hand[0], player2) is False 

209 

210 

211def test_game_get_trump(): 

212 game1 = DummyGame() 

213 assert game1.get_trump() is None 

214 

215 game2 = DummyGame(trump="Red") 

216 assert game2.get_trump() == "Red" 

217 

218 

219def test_game_set_trump(): 

220 game = DummyGame() 

221 game.set_trump("Red") 

222 assert game.trump == "Red" 

223 

224 with pytest.raises(ValueError): 

225 game.set_trump("InvalidSuit") 

226 

227 

228def test_game_apply_trump(): 

229 player1 = DummyPlayer("Alice", [DummyCard(0, 0)]) 

230 player2 = DummyPlayer("Bob", [DummyCard(1, 1)]) 

231 players = [player1, player2] 

232 deck = DummyDeck([DummyCard(0, 0), DummyCard(1, 1)]) 

233 discard_pile = DummyDeck([DummyCard(0, 2), DummyCard(1, 2)]) 

234 game = DummyGame(*players, trump="Red", draw_pile=deck, 

235 discard_pile=discard_pile) 

236 

237 game.apply_trump() 

238 

239 assert all(card.is_trump() for card in game.draw_pile 

240 if card.get_suit() == "Red") 

241 assert not any(card.is_trump() for card in game.draw_pile 

242 if card.get_suit() != "Red") 

243 

244 assert all(card.is_trump() for card in game.discard_pile 

245 if card.get_suit() == "Red") 

246 assert not any(card.is_trump() for card in game.discard_pile 

247 if card.get_suit() != "Red") 

248 

249 assert all(card.trump for player in game.players for card in player.hand 

250 if card.get_suit() == "Red") 

251 assert not any(card.trump for player in game.players for card in 

252 player.hand if card.get_suit() != "Red") 

253 

254 

255def test_game_change_trump(): 

256 player1 = DummyPlayer("Alice", [DummyCard(0, 0)]) 

257 player2 = DummyPlayer("Bob", [DummyCard(1, 1)]) 

258 players = [player1, player2] 

259 deck = DummyDeck([DummyCard(0, 0), DummyCard(1, 1)]) 

260 discard_pile = DummyDeck([DummyCard(0, 2), DummyCard(1, 2)]) 

261 game = DummyGame(*players, trump="Red", draw_pile=deck, 

262 discard_pile=discard_pile) 

263 

264 game.change_trump("Green") 

265 assert game.trump == "Green" 

266 

267 assert all(card.trump for card in game.draw_pile 

268 if card.get_suit() == "Green") 

269 assert not any(card.trump for card in game.draw_pile 

270 if card.get_suit() != "Green") 

271 

272 assert all(card.trump for card in game.discard_pile 

273 if card.get_suit() == "Green") 

274 assert not any(card.trump for card in game.discard_pile 

275 if card.get_suit() != "Green") 

276 

277 assert all(card.trump for player in game.players for card in player.hand 

278 if card.get_suit() == "Green") 

279 assert not any(card.trump for player in game.players for card in 

280 player.hand if card.get_suit() != "Green") 

281 

282 with pytest.raises(ValueError): 

283 game.change_trump("InvalidSuit") 

284 

285 

286def test_game_get_current_player(): 

287 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

288 game = DummyGame(*players, hand_size=2) 

289 assert game.get_current_player() == players[0] 

290 

291 

292def test_game_set_current_player(): 

293 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

294 game = DummyGame(*players, hand_size=2) 

295 game.set_current_player(players[1]) 

296 assert game.current_player_index == 1 

297 

298 game.set_current_player(0) 

299 assert game.current_player_index == 0 

300 

301 with pytest.raises(ValueError): 

302 game.set_current_player(10) 

303 

304 with pytest.raises(TypeError): 

305 game.set_current_player("InvalidPlayer") # type: ignore 

306 

307 

308def test_game_get_players(): 

309 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

310 game = DummyGame(*players, hand_size=2) 

311 assert game.get_players() == players 

312 

313 

314def test_game_get_deck(): 

315 deck = DummyDeck() 

316 game = DummyGame(draw_pile=deck) 

317 assert game.get_draw_pile() == deck 

318 

319 

320def test_game_set_deck(): 

321 deck = DummyDeck() 

322 game = DummyGame(draw_pile=DummyDeck([])) 

323 assert game.draw_pile != deck 

324 game.set_draw_pile(deck) 

325 assert game.draw_pile == deck 

326 

327 

328def test_game_str(): 

329 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

330 game = DummyGame(*players, hand_size=2) 

331 assert str(game) == "Game of 2 players" 

332 

333 

334def test_game_repr(): 

335 deck = DummyDeck() 

336 discard_pile = DummyDeck([]) 

337 players = [DummyPlayer("Alice"), DummyPlayer("Bob")] 

338 game = DummyGame(*players, draw_pile=deck, discard_pile=discard_pile, 

339 trump="Green", hand_size=2, starting_player_index=1) 

340 game_repr = repr(game) 

341 

342 assert game_repr.startswith("DummyGame(card_type=<class ") 

343 assert "deck_type=<class " in game_repr 

344 assert "draw_pile=DummyDeck(card_type=<class " in game_repr 

345 assert "cards=[DummyCard(" in game_repr 

346 assert "DummyCard(rank=0, suit=0)" in game_repr 

347 assert "discard_pile=DummyDeck(card_type=<class " in game_repr 

348 assert "trump='Green'" in game_repr 

349 assert "hand_size=2" in game_repr 

350 assert "starting_player_index=1" in game_repr 

351 assert "DummyPlayer('Alice', hand=[], score=0)" in game_repr 

352 assert "DummyPlayer('Alice', hand=[], score=0)" in game_repr