Harden planning test suite with realistic fixtures and output sanity checks
Adds messy/realistic data factories to TestFixtures, new PlannerOutputSanityTests, and updates all scenario planner tests with improved coverage and assertions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -467,3 +467,108 @@ extension TestFixtures {
|
||||
static let centralCities = ["Chicago", "Houston", "Dallas", "Minneapolis", "Detroit"]
|
||||
static let westCoastCities = ["Los Angeles", "San Francisco", "Seattle", "Phoenix"]
|
||||
}
|
||||
|
||||
// MARK: - Messy / Realistic Data Factories
|
||||
|
||||
extension TestFixtures {
|
||||
|
||||
/// Creates games that are all in the past relative to a reference date.
|
||||
static func pastGames(
|
||||
count: Int,
|
||||
sport: Sport = .mlb,
|
||||
cities: [String] = ["New York", "Boston", "Chicago"],
|
||||
referenceDate: Date = TestClock.now
|
||||
) -> [Game] {
|
||||
(0..<count).map { i in
|
||||
let city = cities[i % cities.count]
|
||||
let daysAgo = 30 + (i * 2) // 30-60 days in the past
|
||||
let gameDate = TestClock.calendar.date(byAdding: .day, value: -daysAgo, to: referenceDate)!
|
||||
return game(sport: sport, city: city, dateTime: gameDate)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a mix of past and future games, returning them categorized.
|
||||
static func mixedPastFutureGames(
|
||||
pastCount: Int = 5,
|
||||
futureCount: Int = 5,
|
||||
sport: Sport = .mlb,
|
||||
cities: [String] = ["New York", "Boston", "Chicago", "Philadelphia"],
|
||||
referenceDate: Date = TestClock.now
|
||||
) -> (past: [Game], future: [Game], all: [Game]) {
|
||||
let past = (0..<pastCount).map { i in
|
||||
let city = cities[i % cities.count]
|
||||
let gameDate = TestClock.calendar.date(byAdding: .day, value: -(i + 1) * 5, to: referenceDate)!
|
||||
return game(id: "past_\(i)", sport: sport, city: city, dateTime: gameDate)
|
||||
}
|
||||
let future = (0..<futureCount).map { i in
|
||||
let city = cities[i % cities.count]
|
||||
let gameDate = TestClock.calendar.date(byAdding: .day, value: (i + 1) * 2, to: referenceDate)!
|
||||
return game(id: "future_\(i)", sport: sport, city: city, dateTime: gameDate)
|
||||
}
|
||||
return (past, future, past + future)
|
||||
}
|
||||
|
||||
/// Creates games from sports the user didn't select (for testing sport filtering).
|
||||
static func gamesWithWrongSport(
|
||||
selectedSport: Sport = .mlb,
|
||||
wrongSport: Sport = .nba,
|
||||
correctCount: Int = 3,
|
||||
wrongCount: Int = 3,
|
||||
cities: [String] = ["New York", "Boston", "Chicago"]
|
||||
) -> (correct: [Game], wrong: [Game], all: [Game]) {
|
||||
let start = TestClock.addingDays(1)
|
||||
let correct = (0..<correctCount).map { i in
|
||||
let city = cities[i % cities.count]
|
||||
let dt = TestClock.calendar.date(byAdding: .day, value: i, to: start)!
|
||||
return game(id: "correct_\(i)", sport: selectedSport, city: city, dateTime: dt)
|
||||
}
|
||||
let wrong = (0..<wrongCount).map { i in
|
||||
let city = cities[i % cities.count]
|
||||
let dt = TestClock.calendar.date(byAdding: .day, value: i, to: start)!
|
||||
return game(id: "wrong_\(i)", sport: wrongSport, city: city, dateTime: dt)
|
||||
}
|
||||
return (correct, wrong, correct + wrong)
|
||||
}
|
||||
|
||||
/// Creates games referencing stadium IDs that don't exist in any stadium map.
|
||||
static func gamesWithMissingStadium(
|
||||
count: Int = 3,
|
||||
sport: Sport = .mlb
|
||||
) -> [Game] {
|
||||
let start = TestClock.addingDays(1)
|
||||
return (0..<count).map { i in
|
||||
let dt = TestClock.calendar.date(byAdding: .day, value: i, to: start)!
|
||||
return game(
|
||||
id: "orphan_\(i)",
|
||||
sport: sport,
|
||||
city: "Atlantis",
|
||||
dateTime: dt,
|
||||
stadiumId: "stadium_nonexistent_\(i)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates two different games sharing the same ID (simulates rescheduled games).
|
||||
static func duplicateIdGames(sport: Sport = .mlb) -> [Game] {
|
||||
let dt1 = TestClock.addingDays(2)
|
||||
let dt2 = TestClock.addingDays(3)
|
||||
return [
|
||||
game(id: "dup_game_001", sport: sport, city: "New York", dateTime: dt1),
|
||||
game(id: "dup_game_001", sport: sport, city: "Boston", dateTime: dt2),
|
||||
]
|
||||
}
|
||||
|
||||
/// Creates games spread over many days for long-trip duration testing.
|
||||
static func longTripGames(
|
||||
days: Int = 30,
|
||||
sport: Sport = .mlb,
|
||||
cities: [String] = ["New York", "Boston", "Chicago", "Philadelphia", "Atlanta"]
|
||||
) -> [Game] {
|
||||
let start = TestClock.addingDays(1)
|
||||
return (0..<days).map { i in
|
||||
let city = cities[i % cities.count]
|
||||
let dt = TestClock.calendar.date(byAdding: .day, value: i, to: start)!
|
||||
return game(id: "long_\(i)", sport: sport, city: city, dateTime: dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user