""" Tests for Short Deck Hand Evaluator """ import pytest from poker.card import Card, ShortDeckRank, Suit # 使用统一的Card类 from shortdeck.hand_evaluator import ShortDeckHandEvaluator from shortdeck.hand_ranking import ShortDeckHandType, ShortDeckHandRanking class TestShortDeckHandEvaluator: """Test cases for ShortDeckHandEvaluator class""" def test_evaluate_hand_insufficient_cards(self): """Test evaluation with less than 5 cards""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.HEARTS), Card(ShortDeckRank.QUEEN, Suit.DIAMONDS), Card(ShortDeckRank.JACK, Suit.CLUBS) ] with pytest.raises(ValueError, match="Need at least 5 cards"): ShortDeckHandEvaluator.evaluate_hand(cards) def test_evaluate_hand_exactly_five_cards(self): """Test evaluation with exactly 5 cards""" # Royal flush cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.QUEEN, Suit.SPADES), Card(ShortDeckRank.JACK, Suit.SPADES), Card(ShortDeckRank.TEN, Suit.SPADES) ] result = ShortDeckHandEvaluator.evaluate_hand(cards) assert result.hand_type == ShortDeckHandType.ROYAL_FLUSH def test_evaluate_hand_seven_cards(self): """Test evaluation with 7 cards - should find best 5""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.ACE, Suit.DIAMONDS), Card(ShortDeckRank.ACE, Suit.CLUBS), # Four Aces Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.SIX, Suit.HEARTS), Card(ShortDeckRank.SEVEN, Suit.DIAMONDS) ] result = ShortDeckHandEvaluator.evaluate_hand(cards) assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND assert result.key_ranks[0] == ShortDeckRank.ACE def test_evaluate_five_cards_wrong_count(self): """Test evaluate5Cards with wrong number of cards""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.HEARTS) ] with pytest.raises(ValueError, match="Must provide exactly 5 cards"): ShortDeckHandEvaluator.evaluate_5_cards(cards) def test_royal_flush(self): """Test royal flush detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.QUEEN, Suit.SPADES), Card(ShortDeckRank.JACK, Suit.SPADES), Card(ShortDeckRank.TEN, Suit.SPADES) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.ROYAL_FLUSH assert result.key_ranks[0] == ShortDeckRank.ACE def test_straight_flush(self): """Test straight flush detection""" cards = [ Card(ShortDeckRank.KING, Suit.HEARTS), Card(ShortDeckRank.QUEEN, Suit.HEARTS), Card(ShortDeckRank.JACK, Suit.HEARTS), Card(ShortDeckRank.TEN, Suit.HEARTS), Card(ShortDeckRank.NINE, Suit.HEARTS) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.STRAIGHT_FLUSH assert result.key_ranks[0] == ShortDeckRank.KING def test_four_of_a_kind(self): """Test four of a kind detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.ACE, Suit.DIAMONDS), Card(ShortDeckRank.ACE, Suit.CLUBS), Card(ShortDeckRank.KING, Suit.SPADES) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND assert result.key_ranks[0] == ShortDeckRank.ACE assert result.key_ranks[1] == ShortDeckRank.KING # Kicker def test_flush_beats_full_house(self): """Test that flush beats full house in short deck""" # Flush flush_cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.QUEEN, Suit.SPADES), Card(ShortDeckRank.JACK, Suit.SPADES), Card(ShortDeckRank.NINE, Suit.SPADES) ] # Full house full_house_cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.ACE, Suit.DIAMONDS), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.KING, Suit.HEARTS) ] flush_result = ShortDeckHandEvaluator.evaluate_5_cards(flush_cards) full_house_result = ShortDeckHandEvaluator.evaluate_5_cards(full_house_cards) assert flush_result.hand_type == ShortDeckHandType.FLUSH assert full_house_result.hand_type == ShortDeckHandType.FULL_HOUSE assert flush_result > full_house_result # Flush beats Full House in Short Deck! def test_full_house(self): """Test full house detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.ACE, Suit.DIAMONDS), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.KING, Suit.HEARTS) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.FULL_HOUSE assert result.key_ranks[0] == ShortDeckRank.ACE # Trips assert result.key_ranks[1] == ShortDeckRank.KING # Pair def test_flush(self): """Test flush detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.QUEEN, Suit.SPADES), Card(ShortDeckRank.JACK, Suit.SPADES), Card(ShortDeckRank.NINE, Suit.SPADES) # Not a straight ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.FLUSH assert result.key_ranks[0] == ShortDeckRank.ACE def test_straight_regular(self): """Test regular straight detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.HEARTS), Card(ShortDeckRank.QUEEN, Suit.DIAMONDS), Card(ShortDeckRank.JACK, Suit.CLUBS), Card(ShortDeckRank.TEN, Suit.SPADES) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.STRAIGHT assert result.key_ranks[0] == ShortDeckRank.ACE def test_straight_low_wheel(self): """Test short deck wheel straight: A-6-7-8-9""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.NINE, Suit.HEARTS), Card(ShortDeckRank.EIGHT, Suit.DIAMONDS), Card(ShortDeckRank.SEVEN, Suit.CLUBS), Card(ShortDeckRank.SIX, Suit.SPADES) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.STRAIGHT assert result.key_ranks[0] == ShortDeckRank.NINE # 9-high straight in short deck wheel def test_three_of_a_kind(self): """Test three of a kind detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.ACE, Suit.DIAMONDS), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.QUEEN, Suit.HEARTS) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.THREE_OF_A_KIND assert result.key_ranks[0] == ShortDeckRank.ACE assert ShortDeckRank.KING in result.key_ranks assert ShortDeckRank.QUEEN in result.key_ranks def test_two_pair(self): """Test two pair detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.KING, Suit.DIAMONDS), Card(ShortDeckRank.KING, Suit.SPADES), Card(ShortDeckRank.QUEEN, Suit.HEARTS) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.TWO_PAIR assert result.key_ranks[0] == ShortDeckRank.ACE # Higher pair first assert result.key_ranks[1] == ShortDeckRank.KING # Lower pair second assert result.key_ranks[2] == ShortDeckRank.QUEEN # Kicker def test_one_pair(self): """Test one pair detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.ACE, Suit.HEARTS), Card(ShortDeckRank.KING, Suit.DIAMONDS), Card(ShortDeckRank.QUEEN, Suit.SPADES), Card(ShortDeckRank.JACK, Suit.HEARTS) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.ONE_PAIR assert result.key_ranks[0] == ShortDeckRank.ACE assert ShortDeckRank.KING in result.key_ranks assert ShortDeckRank.QUEEN in result.key_ranks assert ShortDeckRank.JACK in result.key_ranks def test_high_card(self): """Test high card detection""" cards = [ Card(ShortDeckRank.ACE, Suit.SPADES), Card(ShortDeckRank.KING, Suit.HEARTS), Card(ShortDeckRank.QUEEN, Suit.DIAMONDS), Card(ShortDeckRank.JACK, Suit.CLUBS), Card(ShortDeckRank.NINE, Suit.HEARTS) # Not a straight (missing 10) ] result = ShortDeckHandEvaluator.evaluate_5_cards(cards) assert result.hand_type == ShortDeckHandType.HIGH_CARD assert result.key_ranks[0] == ShortDeckRank.ACE def test_is_straight_regular_straights(self): """Test isStraight with regular straights""" # T-J-Q-K-A ranks1 = [ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN] is_straight1, high1 = ShortDeckHandEvaluator.is_straight(ranks1) assert is_straight1 == True assert high1 == ShortDeckRank.ACE # 6-7-8-9-T ranks2 = [ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX] is_straight2, high2 = ShortDeckHandEvaluator.is_straight(ranks2) assert is_straight2 == True assert high2 == ShortDeckRank.TEN def test_is_straight_wheel(self): """Test isStraight with short deck wheel: A-6-7-8-9""" ranks = [ShortDeckRank.ACE, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX] is_straight, high = ShortDeckHandEvaluator.is_straight(ranks) assert is_straight == True assert high == ShortDeckRank.NINE # 9-high straight in short deck wheel def test_is_straight_not_straight(self): """Test isStraight with non-straight""" ranks = [ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.NINE] is_straight, high = ShortDeckHandEvaluator.is_straight(ranks) assert is_straight == False assert high is None def test_is_straight_insufficient_cards(self): """Test isStraight with less than 5 unique ranks""" ranks = [ShortDeckRank.ACE, ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.KING] # Only 2 unique is_straight, high = ShortDeckHandEvaluator.is_straight(ranks) assert is_straight == False assert high is None def test_evaluate_from_input_valid(self): """Test evaluateFromInput with valid input""" # Four of a kind result = ShortDeckHandEvaluator.evaluate_from_input("AsAhAdAc Ks") assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND assert result.key_ranks[0] == ShortDeckRank.ACE def test_evaluate_from_input_seven_cards(self): """Test evaluateFromInput with 7 cards""" result = ShortDeckHandEvaluator.evaluate_from_input("AsAhAdAc KsQsJs") assert result.hand_type == ShortDeckHandType.FOUR_OF_A_KIND assert result.key_ranks[0] == ShortDeckRank.ACE def test_evaluate_from_input_invalid_cards(self): """Test evaluateFromInput with invalid cards (should reject 2,3,4,5)""" with pytest.raises(ValueError, match="Invalid rank for short deck"): ShortDeckHandEvaluator.evaluate_from_input("2s3s4s5s6s") def test_all_possible_straights(self): """Test all possible straights in short deck""" # All possible short deck straights: # A-6-7-8-9, 6-7-8-9-T, 7-8-9-T-J, 8-9-T-J-Q, 9-T-J-Q-K, T-J-Q-K-A straight_combinations = [ ([ShortDeckRank.ACE, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX], ShortDeckRank.NINE), ([ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN, ShortDeckRank.SIX], ShortDeckRank.TEN), ([ShortDeckRank.JACK, ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT, ShortDeckRank.SEVEN], ShortDeckRank.JACK), ([ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN, ShortDeckRank.NINE, ShortDeckRank.EIGHT], ShortDeckRank.QUEEN), ([ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN, ShortDeckRank.NINE], ShortDeckRank.KING), ([ShortDeckRank.ACE, ShortDeckRank.KING, ShortDeckRank.QUEEN, ShortDeckRank.JACK, ShortDeckRank.TEN], ShortDeckRank.ACE), ] for ranks, expected_high in straight_combinations: is_straight, high = ShortDeckHandEvaluator.is_straight(ranks) assert is_straight == True, f"Failed to detect straight: {[r.symbol for r in ranks]}" assert high == expected_high, f"Wrong high card for {[r.symbol for r in ranks]}: expected {expected_high.symbol}, got {high.symbol if high else None}"