package main import ( "reflect" "testing" ) func TestNewHand(t *testing.T) { tests := []struct { input string expected *Hand expectedErr bool }{ { input: "H2 S3 C4 D5 H6", expected: &Hand{Cards: []Card{ {Suit: "H", Value: 2}, {Suit: "S", Value: 3}, {Suit: "C", Value: 4}, {Suit: "D", Value: 5}, {Suit: "H", Value: 6}, }}, expectedErr: false, }, { input: "CT CJ CQ CK CA", expected: &Hand{Cards: []Card{ {Suit: "C", Value: 10}, {Suit: "C", Value: 11}, {Suit: "C", Value: 12}, {Suit: "C", Value: 13}, {Suit: "C", Value: 14}, }}, expectedErr: false, }, { input: "Invalid Input", expected: nil, expectedErr: true, }, { input: "H2 S3 C4 D5", // Not 5 cards expected: nil, expectedErr: true, }, { input: "H2 S3 C4 D5 Hx", // Invalid card value expected: nil, expectedErr: true, }, } for _, tt := range tests { hand, err := NewHand(tt.input) if (err != nil) != tt.expectedErr { t.Errorf("NewHand(%q) error = %v, expectedErr %v", tt.input, err, tt.expectedErr) continue } if !tt.expectedErr && !reflect.DeepEqual(hand, tt.expected) { t.Errorf("NewHand(%q) got = %v, want %v", tt.input, hand, tt.expected) } } } func TestEvaluateHandValues(t *testing.T) { tests := []struct { name string input string expected HandCategory }{ {"Royal Flush", "CT CJ CQ CK CA", RoyalFlush}, {"Straight Flush", "D8 D9 DT DJ DQ", StraightFlush}, {"Four of a Kind", "HT SA ST DT CT", FourOfAKind}, {"Full House", "H2 SQ C2 D2 CQ", FullHouse}, {"Flush", "HK HQ H2 H4 H5", Flush}, {"Straight", "H3 S7 H5 D6 C4", Straight}, {"Three of a Kind", "H2 SQ S2 D2 CK", ThreeOfAKind}, {"Two Pair", "H5 SQ C5 DT CT", TwoPair}, {"Pair", "H3 S8 H5 D8 CA", Pair}, {"High Card", "H3 S8 H5 D4 CA", HighCard}, {"Straight Wheel", "H4 S5 HA D3 C2", Straight}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { hand, err := NewHand(tt.input) if err != nil { t.Fatalf("Failed to create hand for %s: %v", tt.input, err) } result := hand.Evaluate() if result.Category != tt.expected { t.Errorf("Hand: %s, Expected %s, got %s", tt.input, handNames[tt.expected], handNames[result.Category]) } }) } } func TestCompareHands(t *testing.T) { tests := []struct { name string hand1 string hand2 string expected int // 1 if hand1 wins, 2 if hand2 wins, 0 for tie }{ {"Royal Flush vs Straight Flush", "CT CJ CQ CK CA", "D8 D9 DT DJ DQ", 1}, {"Straight Flush vs Four of a Kind", "D8 D9 DT DJ DQ", "HT SA ST DT CT", 1}, {"Four of a Kind vs Full House", "HT SA ST DT CT", "H2 SQ C2 D2 CQ", 1}, {"Full House vs Flush", "H2 SQ C2 D2 CQ", "HK HQ H2 H4 H5", 1}, {"Flush vs Straight", "HK HQ H2 H4 H5", "H3 S7 H5 D6 C4", 1}, {"Straight vs Three of a Kind", "H3 S7 H5 D6 C4", "H2 SQ S2 D2 CK", 1}, {"Three of a Kind vs Two Pair", "H2 SQ S2 D2 CK", "H5 SQ C5 DT CT", 1}, {"Two Pair vs Pair", "H5 SQ C5 DT CT", "H3 S8 H5 D8 CA", 1}, {"Pair vs High Card", "H3 S8 H5 D8 CA", "H3 S8 H5 D4 C2", 1}, {"Tie - Same Royal Flush", "CT CJ CQ CK CA", "CT CJ CQ CK CA", 0}, {"Tie - Same Straight Flush", "D8 D9 DT DJ DQ", "D8 D9 DT DJ DQ", 0}, {"Tie - Higher Straight Flush", "S8 S9 ST SJ SQ", "D8 D9 DT DJ DQ", 0}, {"Tie - Four of a Kind (higher value)", "HA SA DA CA H2", "HK SK DK CK H2", 1}, {"Tie - Four of a Kind (same value, higher kicker)", "HA SA DA CA H3", "HA SA DA CA H2", 1}, {"Tie - Full House (higher trips)", "HA SA DA H2 C2", "HK SK DK H2 C2", 1}, {"Tie - Full House (same trips, higher pair)", "HA SA DA H3 C3", "HA SA DA H2 C2", 1}, {"Tie - Flush (higher card)", "HA H9 H8 H7 H5", "HA H9 H8 H7 H4", 1}, {"Tie - Straight (higher card)", "S9 ST SJ SQ SK", "S8 S9 ST SJ SQ", 1}, {"Tie - Three of a Kind (higher trips)", "HA SA DA H3 C4", "HK SK DK H3 C4", 1}, {"Tie - Three of a Kind (same trips, higher kicker)", "HA SA DA H5 C4", "HA SA DA H3 C2", 1}, {"Tie - Two Pair (higher top pair)", "HA SA H2 C2 DK", "HK SK H2 C2 DA", 1}, {"Tie - Two Pair (same top pair, higher second pair)", "HA SA H3 C3 DK", "HA SA H2 C2 DK", 1}, {"Tie - Two Pair (same pairs, higher kicker)", "HA SA H2 C2 DQ", "HA SA H2 C2 DJ", 1}, {"Tie - Pair (higher pair)", "HA SA H2 C3 D4", "HK SK H2 C3 D4", 1}, {"Tie - Pair (same pair, higher kicker)", "HA SA H5 C3 D4", "HA SA H4 C2 D5", 1}, {"Tie - High Card (higher card)", "HA SK CJ D9 H7", "HQ SK CJ D9 H7", 1}, {"Tie - High Card (all equal)", "HA SK CJ D9 H7", "HA SK CJ D9 H7", 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { hand1, err1 := NewHand(tt.hand1) hand2, err2 := NewHand(tt.hand2) if err1 != nil || err2 != nil { t.Fatalf("Failed to create hands: %v, %v", err1, err2) } result := hand1.Compare(hand2) if result != tt.expected { t.Errorf("CompareHands(%s, %s) Expected %d, got %d", tt.hand1, tt.hand2, tt.expected, result) } }) } } func TestFindBestHand(t *testing.T) { tests := []struct { name string sevenCards []Card expected *Hand expectedErr bool }{ { name: "Royal Flush from 7 cards", sevenCards: []Card{ {Suit: "C", Value: 2}, {Suit: "C", Value: 10}, {Suit: "C", Value: 11}, {Suit: "C", Value: 12}, {Suit: "C", Value: 13}, {Suit: "C", Value: 14}, {Suit: "H", Value: 7}, }, expected: &Hand{Cards: []Card{{Suit: "C", Value: 14}, {Suit: "C", Value: 13}, {Suit: "C", Value: 12}, {Suit: "C", Value: 11}, {Suit: "C", Value: 10}}}, expectedErr: false, }, { name: "Straight Flush from 7 cards", sevenCards: []Card{ {Suit: "D", Value: 8}, {Suit: "D", Value: 9}, {Suit: "D", Value: 10}, {Suit: "D", Value: 11}, {Suit: "D", Value: 12}, {Suit: "S", Value: 5}, {Suit: "C", Value: 2}, }, expected: &Hand{Cards: []Card{{Suit: "D", Value: 12}, {Suit: "D", Value: 11}, {Suit: "D", Value: 10}, {Suit: "D", Value: 9}, {Suit: "D", Value: 8}}}, expectedErr: false, }, { name: "Four of a Kind from 7 cards", sevenCards: []Card{ {Suit: "H", Value: 10}, {Suit: "S", Value: 10}, {Suit: "D", Value: 10}, {Suit: "C", Value: 10}, {Suit: "H", Value: 2}, {Suit: "S", Value: 3}, {Suit: "D", Value: 4}, }, expected: &Hand{Cards: []Card{{Suit: "H", Value: 10}, {Suit: "S", Value: 10}, {Suit: "D", Value: 10}, {Suit: "C", Value: 10}, {Suit: "D", Value: 4}}}, expectedErr: false, }, { name: "Full House from 7 cards", sevenCards: []Card{ {Suit: "H", Value: 2}, {Suit: "S", Value: 2}, {Suit: "D", Value: 2}, {Suit: "C", Value: 3}, {Suit: "H", Value: 3}, {Suit: "S", Value: 7}, {Suit: "D", Value: 8}, }, expected: &Hand{Cards: []Card{{Suit: "H", Value: 3}, {Suit: "C", Value: 3}, {Suit: "H", Value: 2}, {Suit: "S", Value: 2}, {Suit: "D", Value: 2}}}, expectedErr: false, }, { name: "Flush from 7 cards", sevenCards: []Card{ {Suit: "H", Value: 14}, {Suit: "H", Value: 12}, {Suit: "H", Value: 10}, {Suit: "H", Value: 8}, {Suit: "H", Value: 6}, {Suit: "S", Value: 5}, {Suit: "D", Value: 4}, }, expected: &Hand{Cards: []Card{{Suit: "H", Value: 14}, {Suit: "H", Value: 12}, {Suit: "H", Value: 10}, {Suit: "H", Value: 8}, {Suit: "H", Value: 6}}}, expectedErr: false, }, { name: "Straight from 7 cards", sevenCards: []Card{ {Suit: "H", Value: 5}, {Suit: "S", Value: 6}, {Suit: "C", Value: 7}, {Suit: "D", Value: 8}, {Suit: "H", Value: 9}, {Suit: "S", Value: 2}, {Suit: "C", Value: 3}, }, expected: &Hand{Cards: []Card{{Suit: "H", Value: 9}, {Suit: "D", Value: 8}, {Suit: "C", Value: 7}, {Suit: "S", Value: 6}, {Suit: "H", Value: 5}}}, expectedErr: false, }, { name: "Three of a Kind from 7 cards", sevenCards: []Card{ {Suit: "H", Value: 2}, {Suit: "S", Value: 2}, {Suit: "D", Value: 2}, {Suit: "C", Value: 7}, {Suit: "H", Value: 8}, {Suit: "S", Value: 9}, {Suit: "D", Value: 10}, }, expected: &Hand{Cards: []Card{{Suit: "D", Value: 10}, {Suit: "S", Value: 9}, {Suit: "H", Value: 8}, {Suit: "H", Value: 2}, {Suit: "S", Value: 2}, {Suit: "D", Value: 2}}}, expectedErr: false, // expected cards will be sorted by value inside Evaluate() }, { name: "High Card from 7 cards", sevenCards: []Card{ {Suit: "H", Value: 2}, {Suit: "S", Value: 4}, {Suit: "C", Value: 6}, {Suit: "D", Value: 8}, {Suit: "H", Value: 10}, {Suit: "S", Value: 3}, {Suit: "C", Value: 5}, }, expected: &Hand{Cards: []Card{{Suit: "C", Value: 6}, {Suit: "C", Value: 5}, {Suit: "S", Value: 4}, {Suit: "S", Value: 3}, {Suit: "H", Value: 2}}}, expectedErr: false, }, { name: "Invalid number of cards (less than 7)", sevenCards: []Card{ {Suit: "H", Value: 2}, {Suit: "S", Value: 4}, {Suit: "C", Value: 6}, {Suit: "D", Value: 8}, {Suit: "H", Value: 10}, {Suit: "S", Value: 3}, }, expected: nil, expectedErr: true, }, { name: "Invalid number of cards (more than 7)", sevenCards: []Card{ {Suit: "H", Value: 2}, {Suit: "S", Value: 4}, {Suit: "C", Value: 6}, {Suit: "D", Value: 8}, {Suit: "H", Value: 10}, {Suit: "S", Value: 3}, {Suit: "C", Value: 5}, {Suit: "D", Value: 7}, }, expected: nil, expectedErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { hand, err := FindBestHand(tt.sevenCards) if (err != nil) != tt.expectedErr { t.Errorf("FindBestHand() error = %v, expectedErr %v", err, tt.expectedErr) return } if !tt.expectedErr { // The order of cards in the expected hand might not exactly match due to sorting, // so we compare the evaluated categories and tie-breakers. if hand == nil { t.Fatalf("FindBestHand() returned nil hand for valid input") } expectedHandResult := (&Hand{Cards: tt.expected.Cards}).Evaluate() actualHandResult := hand.Evaluate() if expectedHandResult.Category != actualHandResult.Category { t.Errorf("FindBestHand() for %s: expected category %s, got %s", tt.name, handNames[expectedHandResult.Category], handNames[actualHandResult.Category]) } if !reflect.DeepEqual(expectedHandResult.TieBreakers, actualHandResult.TieBreakers) { t.Errorf("FindBestHand() for %s: expected tie-breakers %v, got %v", tt.name, expectedHandResult.TieBreakers, actualHandResult.TieBreakers) } } }) } }