// // TripPlanningEngineTests.swift // SportsTimeTests // // TDD specification tests for TripPlanningEngine. // import Testing import Foundation import CoreLocation @testable import SportsTime @Suite("TripPlanningEngine") struct TripPlanningEngineTests { // MARK: - Test Data private let nycCoord = CLLocationCoordinate2D(latitude: 40.7580, longitude: -73.9855) private let bostonCoord = CLLocationCoordinate2D(latitude: 42.3467, longitude: -71.0972) private let chicagoCoord = CLLocationCoordinate2D(latitude: 41.8827, longitude: -87.6233) private let laCoord = CLLocationCoordinate2D(latitude: 34.0430, longitude: -118.2673) // MARK: - Specification Tests: Planning Mode Selection @Test("planningMode: dateRange is valid mode") func planningMode_dateRange() { let prefs = TripPreferences( planningMode: .dateRange, sports: [.mlb] ) #expect(prefs.planningMode == .dateRange) } @Test("planningMode: gameFirst is valid mode") func planningMode_gameFirst() { let prefs = TripPreferences( planningMode: .gameFirst, sports: [.mlb], mustSeeGameIds: ["game1"] ) #expect(prefs.planningMode == .gameFirst) } @Test("planningMode: followTeam is valid mode") func planningMode_followTeam() { let prefs = TripPreferences( planningMode: .followTeam, sports: [.mlb], followTeamId: "yankees" ) #expect(prefs.planningMode == .followTeam) } @Test("planningMode: locations is valid mode") func planningMode_locations() { let prefs = TripPreferences( planningMode: .locations, startLocation: LocationInput(name: "Chicago", coordinate: chicagoCoord), endLocation: LocationInput(name: "New York", coordinate: nycCoord), sports: [.mlb] ) #expect(prefs.planningMode == .locations) } // MARK: - Specification Tests: Driving Constraints @Test("DrivingConstraints: calculates maxDailyDrivingHours correctly") func drivingConstraints_maxDailyHours() { let constraints = DrivingConstraints(numberOfDrivers: 2, maxHoursPerDriverPerDay: 6.0) #expect(constraints.maxDailyDrivingHours == 12.0) } @Test("DrivingConstraints: clamps negative drivers to 1") func drivingConstraints_clampsNegativeDrivers() { let constraints = DrivingConstraints(numberOfDrivers: -5, maxHoursPerDriverPerDay: 8.0) #expect(constraints.numberOfDrivers == 1) #expect(constraints.maxDailyDrivingHours >= 1.0) } @Test("DrivingConstraints: clamps zero hours to minimum") func drivingConstraints_clampsZeroHours() { let constraints = DrivingConstraints(numberOfDrivers: 1, maxHoursPerDriverPerDay: 0) #expect(constraints.maxHoursPerDriverPerDay == 1.0) } // MARK: - Specification Tests: Trip Preferences Computed Properties @Test("totalDriverHoursPerDay: defaults to 8 hours when nil") func totalDriverHoursPerDay_default() { let prefs = TripPreferences( numberOfDrivers: 1, maxDrivingHoursPerDriver: nil ) #expect(prefs.totalDriverHoursPerDay == 8.0) } @Test("totalDriverHoursPerDay: multiplies by number of drivers") func totalDriverHoursPerDay_multipleDrivers() { let prefs = TripPreferences( numberOfDrivers: 2, maxDrivingHoursPerDriver: 6.0 ) #expect(prefs.totalDriverHoursPerDay == 12.0) } @Test("effectiveTripDuration: uses explicit tripDuration when set") func effectiveTripDuration_explicit() { let prefs = TripPreferences( tripDuration: 5 ) #expect(prefs.effectiveTripDuration == 5) } @Test("effectiveTripDuration: calculates from date range when tripDuration is nil") func effectiveTripDuration_calculated() { let calendar = Calendar.current let startDate = calendar.date(from: DateComponents(year: 2026, month: 6, day: 15))! let endDate = calendar.date(from: DateComponents(year: 2026, month: 6, day: 22))! let prefs = TripPreferences( startDate: startDate, endDate: endDate, tripDuration: nil ) #expect(prefs.effectiveTripDuration == 8) // 8 days inclusive (15th through 22nd) } // MARK: - Invariant Tests @Test("Invariant: totalDriverHoursPerDay > 0") func invariant_totalDriverHoursPositive() { let prefs1 = TripPreferences(numberOfDrivers: 1) #expect(prefs1.totalDriverHoursPerDay > 0) let prefs2 = TripPreferences(numberOfDrivers: 3, maxDrivingHoursPerDriver: 4) #expect(prefs2.totalDriverHoursPerDay > 0) } @Test("Invariant: effectiveTripDuration >= 1") func invariant_effectiveTripDurationMinimum() { let testCases: [Int?] = [nil, 1, 5, 10] for duration in testCases { let prefs = TripPreferences(tripDuration: duration) #expect(prefs.effectiveTripDuration >= 1) } } // MARK: - Helper Methods private func makeStadium( id: String, city: String, coordinate: CLLocationCoordinate2D ) -> Stadium { Stadium( id: id, name: "\(city) Stadium", city: city, state: "XX", latitude: coordinate.latitude, longitude: coordinate.longitude, capacity: 40000, sport: .mlb ) } private func makeGame( id: String, stadiumId: String, dateTime: Date ) -> Game { Game( id: id, homeTeamId: "team1", awayTeamId: "team2", stadiumId: stadiumId, dateTime: dateTime, sport: .mlb, season: "2026" ) } }