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:
Trey T
2026-04-04 13:38:41 -05:00
parent 188076717b
commit 9b622f8bbb
13 changed files with 2174 additions and 446 deletions

View File

@@ -129,12 +129,15 @@ struct ScenarioBPlannerTests {
let result = planner.plan(request: request)
if case .success(let options) = result {
for option in options {
let gameIds = option.stops.flatMap { $0.games }
#expect(gameIds.contains("nyc-game"), "Every route must contain selected NYC game")
#expect(gameIds.contains("boston-game"), "Every route must contain selected Boston game")
}
guard case .success(let options) = result else {
Issue.record("Expected .success, got \(result)")
return
}
for option in options {
let gameIds = option.stops.flatMap { $0.games }
#expect(gameIds.contains("nyc-game"), "Every route must contain selected NYC game")
#expect(gameIds.contains("boston-game"), "Every route must contain selected Boston game")
}
}
@@ -291,10 +294,12 @@ struct ScenarioBPlannerTests {
let result = planner.plan(request: request)
// Should succeed even without explicit dates because of sliding window
if case .success(let options) = result {
#expect(!options.isEmpty)
guard case .success(let options) = result else {
Issue.record("Expected .success, got \(result)")
return
}
// May also fail if no valid date ranges, which is acceptable
#expect(!options.isEmpty)
}
@Test("plan: explicit date range with out-of-range selected game returns dateRangeViolation")
@@ -418,12 +423,15 @@ struct ScenarioBPlannerTests {
let result = planner.plan(request: request)
if case .success(let options) = result {
for option in options {
let gameIds = Set(option.stops.flatMap { $0.games })
#expect(gameIds.contains("nyc-anchor"), "Anchor game cannot be dropped: nyc-anchor")
#expect(gameIds.contains("boston-anchor"), "Anchor game cannot be dropped: boston-anchor")
}
guard case .success(let options) = result else {
Issue.record("Expected .success, got \(result)")
return
}
for option in options {
let gameIds = Set(option.stops.flatMap { $0.games })
#expect(gameIds.contains("nyc-anchor"), "Anchor game cannot be dropped: nyc-anchor")
#expect(gameIds.contains("boston-anchor"), "Anchor game cannot be dropped: boston-anchor")
}
}
@@ -458,12 +466,47 @@ struct ScenarioBPlannerTests {
let result = planner.plan(request: request)
if case .success(let options) = result {
#expect(!options.isEmpty, "Success must have options")
for option in options {
let allGames = option.stops.flatMap { $0.games }
#expect(allGames.contains("anchor1"), "Every option must include anchor")
}
guard case .success(let options) = result else {
Issue.record("Expected .success, got \(result)")
return
}
#expect(!options.isEmpty, "Success must have options")
for option in options {
let allGames = option.stops.flatMap { $0.games }
#expect(allGames.contains("anchor1"), "Every option must include anchor")
}
}
@Test("plan: anchor game in past — handled gracefully")
func plan_anchorGameInPast_handledGracefully() {
let nycStadium = makeStadium(id: "nyc", city: "New York", coordinate: nycCoord)
let pastAnchor = makeGame(id: "past_anchor", stadiumId: "nyc", dateTime: TestClock.addingDays(-1))
let prefs = TripPreferences(
planningMode: .gameFirst,
sports: [.mlb],
mustSeeGameIds: ["past_anchor"],
startDate: TestClock.addingDays(-3),
endDate: TestClock.addingDays(5),
numberOfDrivers: 1
)
let request = PlanningRequest(
preferences: prefs,
availableGames: [pastAnchor],
teams: [:],
stadiums: ["nyc": nycStadium]
)
// Should not crash. May include past anchor (it's explicitly selected) or fail gracefully.
let result = planner.plan(request: request)
switch result {
case .success:
break
case .failure(let f):
Issue.record("Unexpected failure: \(f)")
}
}