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

121 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 CardMeta, DeckMeta, GenericCard, GenericDeck 

22 

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

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

25 

26 

27class DummyCard( 

28 GenericCard[T_Ranks, T_Suits], 

29 metaclass=CardMeta, 

30 rank_type=T_Ranks, 

31 suit_type=T_Suits 

32): 

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

34 pass 

35 

36 

37class DummyDeck( 

38 GenericDeck[DummyCard], 

39 metaclass=DeckMeta, 

40 card_type=DummyCard 

41): 

42 pass 

43 

44 

45def test_deck_init(): 

46 deck1 = DummyDeck() 

47 assert len(deck1.cards) == 9 

48 assert all(isinstance(card, DummyCard) for card in deck1) 

49 

50 cards = [DummyCard(0, 0)] 

51 deck2 = DummyDeck(cards) 

52 assert deck2.cards == cards 

53 

54 

55def test_deck_count(): 

56 deck = DummyDeck() 

57 assert deck.count(DummyCard(0, 0)) == 1 

58 assert deck.count("2") == 3 # type: ignore 

59 assert deck.count("Blue") == 3 # type: ignore 

60 

61 with pytest.raises(ValueError): 

62 deck.count("InvalidName") # type: ignore 

63 

64 with pytest.raises(TypeError): 

65 deck.count(["InvalidType"]) # type: ignore 

66 

67 

68def test_deck_sort(): 

69 deck = DummyDeck().shuffle() 

70 deck.sort(by="rank") 

71 assert deck.cards == sorted(deck.cards, key=lambda c: ( 

72 not c.trump, c.rank if c.rank is not None else -1, 

73 c.suit if c.suit is not None else -1)) 

74 

75 deck.sort(by="suit") 

76 assert deck.cards == sorted(deck.cards) 

77 

78 with pytest.raises(ValueError): 

79 deck.sort(by="invalid_key") # type: ignore 

80 

81 

82def test_deck_shuffle(): 

83 deck1 = DummyDeck() 

84 original_deck1 = deck1.__copy__() 

85 deck1.shuffle() 

86 assert deck1.cards != original_deck1.cards 

87 assert len(deck1.cards) == len(original_deck1.cards) 

88 assert all(isinstance(card, DummyCard) for card in deck1.cards) 

89 

90 # Test shuffle with a seed 

91 deck2 = DummyDeck() 

92 original_deck2 = deck2.__copy__() 

93 deck2.shuffle(seed=42) 

94 assert deck2.cards != original_deck2.cards 

95 assert len(deck2.cards) == len(original_deck2.cards) 

96 assert all(isinstance(card, DummyCard) for card in deck2.cards) 

97 original_deck2.shuffle(seed=42) 

98 assert deck2.cards == original_deck2.cards 

99 

100 

101def test_deck_draw(): 

102 deck = DummyDeck() 

103 cards = deck.draw(5) 

104 assert len(cards) == 5 

105 assert len(deck.cards) == 4 

106 

107 cards = deck.draw(2) 

108 assert len(cards) == 2 

109 assert len(deck.cards) == 2 

110 

111 with pytest.raises(ValueError): 

112 deck.draw(3) 

113 

114 

115def test_deck_add(): 

116 deck = DummyDeck() 

117 cards = [DummyCard(0, 0), DummyCard(1, 1)] 

118 deck.add(*cards) 

119 assert deck.cards[-1] == cards[-1] 

120 

121 deck.add(*cards, to_top=True) 

122 assert deck.cards[0] == cards[0] 

123 

124 with pytest.raises(TypeError): 

125 deck.add(*cards, "InvalidCard") # type: ignore 

126 

127 

128def test_deck_remove(): 

129 deck = DummyDeck() 

130 card = DummyCard(0, 0) 

131 deck.remove(card) 

132 assert card not in deck.cards 

133 

134 with pytest.raises(TypeError): 

135 deck.remove("InvalidCard") # type: ignore 

136 

137 

138def test_deck_get_index(): 

139 deck = DummyDeck() 

140 card = DummyCard(0, 0) 

141 assert deck.get_index(card) == [0] 

142 

143 with pytest.raises(TypeError): 

144 deck.get_index("Red 1") # type: ignore 

145 

146 

147def test_deck_get_cards(): 

148 deck = DummyDeck() 

149 assert deck.get_cards() == deck.cards 

150 

151 

152def test_deck_get_top_card(): 

153 deck = DummyDeck() 

154 assert deck.get_top_card() == deck.cards[0] 

155 

156 

157def test_deck_str(): 

158 deck = DummyDeck() 

159 assert str(deck) == "Deck of 9 cards. Top card: Red 1" 

160 

161 

162def test_deck_repr(): 

163 deck = DummyDeck() 

164 deck_repr = repr(deck) 

165 assert deck_repr.startswith("DummyDeck(card_type=<class") 

166 assert "cards=[DummyCard(rank=0, suit=0)," in deck_repr 

167 assert deck_repr.endswith("DummyCard(rank=2, suit=2)])") 

168 

169 

170def test_deck_copy(): 

171 deck1 = DummyDeck() 

172 deck2 = deck1.__copy__() 

173 assert deck1 is not deck2 

174 assert deck1.cards == deck2.cards 

175 assert deck1.cards is not deck2.cards 

176 assert isinstance(deck2, DummyDeck) 

177 

178 

179def test_deck_equalities(): 

180 deck1 = DummyDeck() 

181 deck2 = DummyDeck() 

182 assert deck1 == deck2 

183 assert not deck1 != deck2 

184 

185 deck3 = DummyDeck([DummyCard(0, 0)]) 

186 assert not deck1 == deck3 

187 assert deck1 != deck3 

188 

189 assert not deck1 == "InvalidType" # type: ignore 

190 assert deck1 != "InvalidType" # type: ignore 

191 

192 

193def test_deck_contains(): 

194 deck = DummyDeck() 

195 card = DummyCard(0, 0) 

196 assert card in deck 

197 

198 assert "InvalidType" not in deck # type: ignore 

199 

200 

201def test_deck_getitem(): 

202 deck = DummyDeck() 

203 assert deck[0] == deck.cards[0] 

204 assert deck[1:-1:-1] == deck.cards[1:-1:-1] 

205 assert not deck == "InvalidType" # type: ignore