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>
212 lines
6.0 KiB
Swift
212 lines
6.0 KiB
Swift
//
|
|
// 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)
|
|
}
|
|
}
|