// // BlackjackTests.swift // BlackjackTests // // Created by Matt Bruce on 12/17/25. // import Testing @testable import Blackjack import CasinoKit struct BlackjackTests { @Test func example() async throws { // Write your test here and use APIs like `#expect(...)` to check expected conditions. } // MARK: - Hand Value Tests @Test @MainActor func handValueCalculation() async throws { var hand = BlackjackHand() // Test empty hand #expect(hand.value == 0, "Empty hand should have value 0") // Test simple values hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .five), Card(suit: .hearts, rank: .seven) ]) #expect(hand.value == 12, "5 + 7 should equal 12") #expect(!hand.isSoft, "Hand without ace should not be soft") // Test face cards hand = BlackjackHand(cards: [ Card(suit: .clubs, rank: .king), Card(suit: .diamonds, rank: .queen) ]) #expect(hand.value == 20, "King (10) + Queen (10) should equal 20") // Test blackjack hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .king) ]) #expect(hand.value == 21, "Ace + King should equal 21") #expect(hand.isBlackjack, "Ace + King should be blackjack") #expect(hand.isSoft, "Blackjack hand should be soft") // Test soft hand (ace as 11) hand = BlackjackHand(cards: [ Card(suit: .diamonds, rank: .ace), Card(suit: .clubs, rank: .six) ]) #expect(hand.value == 17, "Ace + 6 should equal soft 17") #expect(hand.isSoft, "Ace + 6 should be soft") // Test hard hand (ace as 1) hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .five), Card(suit: .clubs, rank: .nine) ]) #expect(hand.value == 15, "Ace + 5 + 9 = 15 (ace counts as 1)") #expect(!hand.isSoft, "Hand over 21 if ace=11 should be hard") // Test bust hand = BlackjackHand(cards: [ Card(suit: .diamonds, rank: .king), Card(suit: .clubs, rank: .queen), Card(suit: .hearts, rank: .five) ]) #expect(hand.value == 25, "10 + 10 + 5 = 25") #expect(hand.isBusted, "Hand over 21 should be busted") // Test multiple aces hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .ace) ]) #expect(hand.value == 12, "Ace + Ace = 12 (one as 11, one as 1)") #expect(hand.isSoft, "Two aces should be soft") // Test three aces hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .ace), Card(suit: .clubs, rank: .ace) ]) #expect(hand.value == 13, "Three aces = 13 (one as 11, two as 1)") #expect(hand.isSoft, "Three aces should be soft") } @Test @MainActor func handBlackjackDetection() async throws { // Natural blackjack var hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .ten) ]) #expect(hand.isBlackjack, "Ace + 10 should be blackjack") // 21 with three cards is not blackjack hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .seven), Card(suit: .hearts, rank: .seven), Card(suit: .clubs, rank: .seven) ]) #expect(hand.value == 21, "Should have value 21") #expect(!hand.isBlackjack, "21 with 3 cards is not blackjack") // Split hand 21 is not blackjack hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .king) ], bet: 100) hand.isSplit = true #expect(hand.value == 21, "Should have value 21") #expect(!hand.isBlackjack, "21 after split is not blackjack") } @Test @MainActor func handSplitDetection() async throws { // Splittable pair var hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .eight), Card(suit: .hearts, rank: .eight) ]) #expect(hand.canSplit, "Pair of 8s should be splittable") // Face cards of same rank can split hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .king), Card(suit: .hearts, rank: .king) ]) #expect(hand.canSplit, "Pair of Kings should be splittable") // Face cards of different ranks cannot split hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .king), Card(suit: .hearts, rank: .queen) ]) #expect(!hand.canSplit, "King + Queen should not be splittable (different ranks)") // Not splittable - different ranks hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .nine), Card(suit: .hearts, rank: .ten) ]) #expect(!hand.canSplit, "9 + 10 should not be splittable") // Not splittable - more than 2 cards hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .five), Card(suit: .hearts, rank: .five), Card(suit: .clubs, rank: .ace) ]) #expect(!hand.canSplit, "Hand with 3 cards should not be splittable") } @Test @MainActor func handDoubleDownDetection() async throws { // Can double down with 2 cards var hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .five), Card(suit: .hearts, rank: .six) ]) #expect(hand.canDoubleDown, "Should be able to double down with 2 cards") // Cannot double down after already doubled hand.isDoubledDown = true #expect(!hand.canDoubleDown, "Should not be able to double down twice") // Cannot double down with 3+ cards hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .five), Card(suit: .hearts, rank: .six), Card(suit: .clubs, rank: .two) ]) #expect(!hand.canDoubleDown, "Should not be able to double down with 3 cards") } @Test @MainActor func handHitDetection() async throws { // Can hit with normal hand var hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .five), Card(suit: .hearts, rank: .six) ]) #expect(hand.canHit, "Should be able to hit with 11") // Cannot hit after standing hand.isStanding = true #expect(!hand.canHit, "Should not be able to hit after standing") // Cannot hit when busted hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .king), Card(suit: .hearts, rank: .queen), Card(suit: .clubs, rank: .five) ]) #expect(!hand.canHit, "Should not be able to hit when busted") // Cannot hit with blackjack hand = BlackjackHand(cards: [ Card(suit: .spades, rank: .ace), Card(suit: .hearts, rank: .king) ]) #expect(!hand.canHit, "Should not be able to hit with blackjack") } // MARK: - Card Value Tests @Test func cardHiLoValues() async throws { // Low cards (2-6) = +1 #expect(Card(suit: .spades, rank: .two).hiLoValue == 1) #expect(Card(suit: .hearts, rank: .three).hiLoValue == 1) #expect(Card(suit: .clubs, rank: .four).hiLoValue == 1) #expect(Card(suit: .diamonds, rank: .five).hiLoValue == 1) #expect(Card(suit: .spades, rank: .six).hiLoValue == 1) // Neutral cards (7-9) = 0 #expect(Card(suit: .hearts, rank: .seven).hiLoValue == 0) #expect(Card(suit: .clubs, rank: .eight).hiLoValue == 0) #expect(Card(suit: .diamonds, rank: .nine).hiLoValue == 0) // High cards (10, J, Q, K, A) = -1 #expect(Card(suit: .spades, rank: .ten).hiLoValue == -1) #expect(Card(suit: .hearts, rank: .jack).hiLoValue == -1) #expect(Card(suit: .clubs, rank: .queen).hiLoValue == -1) #expect(Card(suit: .diamonds, rank: .king).hiLoValue == -1) #expect(Card(suit: .spades, rank: .ace).hiLoValue == -1) } // MARK: - Game State Tests @Test @MainActor func gameStateInitialization() async throws { let state = GameState(settings: GameSettings()) // Initial state #expect(state.balance == 10000, "Should start with $10,000") #expect(state.currentBet == 0, "Should start with no bet") #expect(state.playerHands.isEmpty, "Should start with no hands") #expect(state.dealerHand.cards.isEmpty, "Should start with empty dealer hand") // Check phase enum switch state.currentPhase { case .betting: break // Expected default: Issue.record("Should start in betting phase") } } @Test @MainActor func gameStateBetting() async throws { let state = GameState(settings: GameSettings()) // Place a bet state.placeBet(amount: 100) #expect(state.currentBet == 100, "Bet should be placed") #expect(state.balance == 9900, "Balance should decrease") // Add to bet state.placeBet(amount: 50) #expect(state.currentBet == 150, "Bet should increase") #expect(state.balance == 9850, "Balance should decrease more") // Clear bet state.clearBet() #expect(state.currentBet == 0, "Bet should be cleared") #expect(state.balance == 10000, "Balance should be restored") } @Test @MainActor func gameStateDealing() async throws { let state = GameState(settings: GameSettings()) // Place bet and deal state.placeBet(amount: 100) await state.deal() // Verify hands were dealt #expect(state.playerHands.count == 1, "Should have 1 player hand") #expect(state.playerHands[0].cards.count == 2, "Player should have 2 cards") #expect(state.dealerHand.cards.count == 2, "Dealer should have 2 cards") // Verify values are valid #expect(state.playerHands[0].value >= 2, "Player hand should have valid value") #expect(state.playerHands[0].value <= 21, "Player hand should not exceed 21 initially") } }