refactor(tests): TDD rewrite of all unit tests with spec documentation
Complete rewrite of unit test suite using TDD methodology: Planning Engine Tests: - GameDAGRouterTests: Beam search, anchor games, transitions - ItineraryBuilderTests: Stop connection, validators, EV enrichment - RouteFiltersTests: Region, time window, scoring filters - ScenarioA/B/C/D PlannerTests: All planning scenarios - TravelEstimatorTests: Distance, duration, travel days - TripPlanningEngineTests: Orchestration, caching, preferences Domain Model Tests: - AchievementDefinitionsTests, AnySportTests, DivisionTests - GameTests, ProgressTests, RegionTests, StadiumTests - TeamTests, TravelSegmentTests, TripTests, TripPollTests - TripPreferencesTests, TripStopTests, SportTests Service Tests: - FreeScoreAPITests, RouteDescriptionGeneratorTests - SuggestedTripsGeneratorTests Export Tests: - ShareableContentTests (card types, themes, dimensions) Bug fixes discovered through TDD: - ShareCardDimensions: mapSnapshotSize exceeded available width (960x480) - ScenarioBPlanner: Added anchor game validation filter All tests include: - Specification tests (expected behavior) - Invariant tests (properties that must always hold) - Edge case tests (boundary conditions) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
211
SportsTimeTests/Domain/GameTests.swift
Normal file
211
SportsTimeTests/Domain/GameTests.swift
Normal file
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// 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() {
|
||||
let calendar = Calendar.current
|
||||
|
||||
// Game at 7:05 PM
|
||||
let dateTime = calendar.date(from: DateComponents(
|
||||
year: 2026, month: 6, day: 15,
|
||||
hour: 19, minute: 5, second: 0
|
||||
))!
|
||||
|
||||
let game = makeGame(dateTime: dateTime)
|
||||
|
||||
let expectedStart = calendar.startOfDay(for: dateTime)
|
||||
#expect(game.gameDate == expectedStart)
|
||||
|
||||
// Verify it's at midnight
|
||||
let components = calendar.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 = Calendar.current
|
||||
|
||||
// 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 = Calendar.current
|
||||
|
||||
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 = Date()
|
||||
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 = Date()
|
||||
|
||||
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 = Date()
|
||||
|
||||
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() {
|
||||
let calendar = Calendar.current
|
||||
|
||||
// Test various times throughout the day
|
||||
let times = [0, 6, 12, 18, 23].map { hour in
|
||||
calendar.date(from: DateComponents(year: 2026, month: 6, day: 15, hour: hour))!
|
||||
}
|
||||
|
||||
for time in times {
|
||||
let game = makeGame(dateTime: time)
|
||||
let components = calendar.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 = Date().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 = Calendar.current
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user