// // GameTests.swift // SportsTimeTests // // TDD specification tests for Game model. // import Testing import Foundation @testable import SportsTime @Suite("Game") @MainActor struct GameTests { // MARK: - Test Data private func makeGame(dateTime: Date) -> Game { Game( id: "game1", homeTeamId: "team1", awayTeamId: "team2", stadiumId: "stadium1", dateTime: dateTime, sport: .mlb, season: "2026", isPlayoff: false ) } // MARK: - Specification Tests: gameDate @Test("gameDate returns start of day for dateTime") func gameDate_returnsStartOfDay() { // Use TestFixtures.date which creates dates at 7:05 PM EST — safely same // calendar day in any US timezone when interpreted by Calendar.current. let dateTime = TestFixtures.date(year: 2026, month: 6, day: 15, hour: 19, minute: 5) let game = makeGame(dateTime: dateTime) // Production gameDate uses Calendar.current, so assert with the same calendar let systemCalendar = Calendar.current let expectedStart = systemCalendar.startOfDay(for: dateTime) #expect(game.gameDate == expectedStart) // Verify it's at midnight in the system calendar let components = systemCalendar.dateComponents([.hour, .minute, .second], from: game.gameDate) #expect(components.hour == 0) #expect(components.minute == 0) #expect(components.second == 0) } @Test("gameDate is same for games on same calendar day") func gameDate_sameDay() { let calendar = TestClock.calendar // Morning game let morningTime = calendar.date(from: DateComponents( year: 2026, month: 6, day: 15, hour: 10, minute: 0 ))! // Evening game let eveningTime = calendar.date(from: DateComponents( year: 2026, month: 6, day: 15, hour: 20, minute: 0 ))! let morningGame = makeGame(dateTime: morningTime) let eveningGame = makeGame(dateTime: eveningTime) #expect(morningGame.gameDate == eveningGame.gameDate) } @Test("gameDate differs for games on different calendar days") func gameDate_differentDays() { let calendar = TestClock.calendar let day1 = calendar.date(from: DateComponents( year: 2026, month: 6, day: 15, hour: 19 ))! let day2 = calendar.date(from: DateComponents( year: 2026, month: 6, day: 16, hour: 19 ))! let game1 = makeGame(dateTime: day1) let game2 = makeGame(dateTime: day2) #expect(game1.gameDate != game2.gameDate) } // MARK: - Specification Tests: startTime Alias @Test("startTime is alias for dateTime") func startTime_isAliasForDateTime() { let dateTime = TestClock.now let game = makeGame(dateTime: dateTime) #expect(game.startTime == game.dateTime) } // MARK: - Specification Tests: Equality @Test("equality based on id only") func equality_basedOnId() { let dateTime = TestClock.now let game1 = Game( id: "game1", homeTeamId: "team1", awayTeamId: "team2", stadiumId: "stadium1", dateTime: dateTime, sport: .mlb, season: "2026", isPlayoff: false ) // Same id, different fields let game2 = Game( id: "game1", homeTeamId: "different-team", awayTeamId: "different-team2", stadiumId: "different-stadium", dateTime: dateTime.addingTimeInterval(3600), sport: .nba, season: "2027", isPlayoff: true ) #expect(game1 == game2, "Games with same id should be equal") } @Test("inequality when ids differ") func inequality_differentIds() { let dateTime = TestClock.now let game1 = Game( id: "game1", homeTeamId: "team1", awayTeamId: "team2", stadiumId: "stadium1", dateTime: dateTime, sport: .mlb, season: "2026", isPlayoff: false ) let game2 = Game( id: "game2", homeTeamId: "team1", awayTeamId: "team2", stadiumId: "stadium1", dateTime: dateTime, sport: .mlb, season: "2026", isPlayoff: false ) #expect(game1 != game2, "Games with different ids should not be equal") } // MARK: - Invariant Tests @Test("Invariant: gameDate is always at midnight") func invariant_gameDateAtMidnight() { // Production gameDate uses Calendar.current, so create dates and assert // with Calendar.current to avoid cross-timezone mismatches. // Use TestFixtures.date (7pm EST default) to ensure same calendar day in any US tz. let times = [8, 12, 15, 19, 22].map { hour in TestFixtures.date(year: 2026, month: 6, day: 15, hour: hour) } let systemCalendar = Calendar.current for time in times { let game = makeGame(dateTime: time) let components = systemCalendar.dateComponents([.hour, .minute, .second], from: game.gameDate) #expect(components.hour == 0, "gameDate hour should be 0") #expect(components.minute == 0, "gameDate minute should be 0") #expect(components.second == 0, "gameDate second should be 0") } } @Test("Invariant: startTime equals dateTime") func invariant_startTimeEqualsDateTime() { for _ in 0..<10 { let dateTime = TestClock.now.addingTimeInterval(Double.random(in: -86400...86400)) let game = makeGame(dateTime: dateTime) #expect(game.startTime == game.dateTime) } } // MARK: - Property Tests @Test("Property: gameDate is in same calendar day as dateTime") func property_gameDateSameCalendarDay() { let calendar = TestClock.calendar let dateTime = calendar.date(from: DateComponents( year: 2026, month: 7, day: 4, hour: 19, minute: 5 ))! let game = makeGame(dateTime: dateTime) let dateTimeDay = calendar.component(.day, from: dateTime) let gameDateDay = calendar.component(.day, from: game.gameDate) #expect(dateTimeDay == gameDateDay) } }