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>
233 lines
7.4 KiB
Swift
233 lines
7.4 KiB
Swift
//
|
|
// StadiumTests.swift
|
|
// SportsTimeTests
|
|
//
|
|
// TDD specification tests for Stadium model.
|
|
//
|
|
|
|
import Testing
|
|
import CoreLocation
|
|
@testable import SportsTime
|
|
|
|
@Suite("Stadium")
|
|
struct StadiumTests {
|
|
|
|
// 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)
|
|
|
|
private func makeStadium(
|
|
id: String = "stadium1",
|
|
latitude: Double,
|
|
longitude: Double
|
|
) -> Stadium {
|
|
Stadium(
|
|
id: id,
|
|
name: "Test Stadium",
|
|
city: "Test City",
|
|
state: "XX",
|
|
latitude: latitude,
|
|
longitude: longitude,
|
|
capacity: 40000,
|
|
sport: .mlb
|
|
)
|
|
}
|
|
|
|
// MARK: - Specification Tests: region
|
|
|
|
@Test("region: NYC longitude returns .east")
|
|
func region_nycEast() {
|
|
let stadium = makeStadium(latitude: nycCoord.latitude, longitude: nycCoord.longitude)
|
|
#expect(stadium.region == .east)
|
|
}
|
|
|
|
@Test("region: Boston longitude returns .east")
|
|
func region_bostonEast() {
|
|
let stadium = makeStadium(latitude: bostonCoord.latitude, longitude: bostonCoord.longitude)
|
|
#expect(stadium.region == .east)
|
|
}
|
|
|
|
@Test("region: Chicago longitude returns .central")
|
|
func region_chicagoCentral() {
|
|
let stadium = makeStadium(latitude: chicagoCoord.latitude, longitude: chicagoCoord.longitude)
|
|
#expect(stadium.region == .central)
|
|
}
|
|
|
|
@Test("region: LA longitude returns .west")
|
|
func region_laWest() {
|
|
let stadium = makeStadium(latitude: laCoord.latitude, longitude: laCoord.longitude)
|
|
#expect(stadium.region == .west)
|
|
}
|
|
|
|
// MARK: - Specification Tests: coordinate
|
|
|
|
@Test("coordinate returns CLLocationCoordinate2D from lat/long")
|
|
func coordinate_returnsCorrectValue() {
|
|
let stadium = makeStadium(latitude: 40.7580, longitude: -73.9855)
|
|
|
|
#expect(stadium.coordinate.latitude == 40.7580)
|
|
#expect(stadium.coordinate.longitude == -73.9855)
|
|
}
|
|
|
|
@Test("location returns CLLocation from lat/long")
|
|
func location_returnsCorrectValue() {
|
|
let stadium = makeStadium(latitude: 40.7580, longitude: -73.9855)
|
|
|
|
#expect(stadium.location.coordinate.latitude == 40.7580)
|
|
#expect(stadium.location.coordinate.longitude == -73.9855)
|
|
}
|
|
|
|
// MARK: - Specification Tests: distance
|
|
|
|
@Test("distance between NYC and Boston stadiums")
|
|
func distance_nycToBoston() {
|
|
let nycStadium = makeStadium(id: "nyc", latitude: nycCoord.latitude, longitude: nycCoord.longitude)
|
|
let bostonStadium = makeStadium(id: "boston", latitude: bostonCoord.latitude, longitude: bostonCoord.longitude)
|
|
|
|
let distance = nycStadium.distance(to: bostonStadium)
|
|
|
|
// NYC to Boston is approximately 298-300 km / ~186 miles with these coordinates
|
|
#expect(distance > 295_000, "NYC to Boston should be > 295km")
|
|
#expect(distance < 310_000, "NYC to Boston should be < 310km")
|
|
}
|
|
|
|
@Test("distance to self is zero")
|
|
func distance_toSelf() {
|
|
let stadium = makeStadium(latitude: nycCoord.latitude, longitude: nycCoord.longitude)
|
|
let distance = stadium.distance(to: stadium)
|
|
|
|
#expect(distance == 0)
|
|
}
|
|
|
|
@Test("distance from coordinate")
|
|
func distance_fromCoordinate() {
|
|
let stadium = makeStadium(latitude: nycCoord.latitude, longitude: nycCoord.longitude)
|
|
let distance = stadium.distance(from: bostonCoord)
|
|
|
|
// Same as NYC to Boston (~298-300 km depending on exact coordinates)
|
|
#expect(distance > 295_000)
|
|
#expect(distance < 310_000)
|
|
}
|
|
|
|
// MARK: - Specification Tests: Equality
|
|
|
|
@Test("equality based on id only")
|
|
func equality_basedOnId() {
|
|
let stadium1 = Stadium(
|
|
id: "stadium1",
|
|
name: "Stadium A",
|
|
city: "City A",
|
|
state: "AA",
|
|
latitude: 40.0,
|
|
longitude: -70.0,
|
|
capacity: 40000,
|
|
sport: .mlb
|
|
)
|
|
|
|
let stadium2 = Stadium(
|
|
id: "stadium1",
|
|
name: "Different Name",
|
|
city: "Different City",
|
|
state: "BB",
|
|
latitude: 30.0,
|
|
longitude: -80.0,
|
|
capacity: 50000,
|
|
sport: .nba
|
|
)
|
|
|
|
#expect(stadium1 == stadium2, "Stadiums with same id should be equal")
|
|
}
|
|
|
|
@Test("inequality when ids differ")
|
|
func inequality_differentIds() {
|
|
let stadium1 = makeStadium(id: "stadium1", latitude: 40.0, longitude: -70.0)
|
|
let stadium2 = makeStadium(id: "stadium2", latitude: 40.0, longitude: -70.0)
|
|
|
|
#expect(stadium1 != stadium2, "Stadiums with different ids should not be equal")
|
|
}
|
|
|
|
// MARK: - Invariant Tests
|
|
|
|
@Test("Invariant: region is consistent with Region.classify")
|
|
func invariant_regionConsistentWithClassify() {
|
|
let testCases: [(lat: Double, lon: Double)] = [
|
|
(40.7580, -73.9855), // NYC
|
|
(41.8827, -87.6233), // Chicago
|
|
(34.0430, -118.2673), // LA
|
|
(42.3467, -71.0972), // Boston
|
|
(33.4484, -112.0740), // Phoenix
|
|
]
|
|
|
|
for (lat, lon) in testCases {
|
|
let stadium = makeStadium(latitude: lat, longitude: lon)
|
|
let expected = Region.classify(longitude: lon)
|
|
#expect(stadium.region == expected, "Stadium at \(lon) should be in \(expected)")
|
|
}
|
|
}
|
|
|
|
@Test("Invariant: location and coordinate match lat/long")
|
|
func invariant_locationAndCoordinateMatch() {
|
|
let stadium = makeStadium(latitude: 40.7580, longitude: -73.9855)
|
|
|
|
#expect(stadium.location.coordinate.latitude == stadium.latitude)
|
|
#expect(stadium.location.coordinate.longitude == stadium.longitude)
|
|
#expect(stadium.coordinate.latitude == stadium.latitude)
|
|
#expect(stadium.coordinate.longitude == stadium.longitude)
|
|
}
|
|
|
|
// MARK: - Property Tests
|
|
|
|
@Test("Property: fullAddress combines city and state")
|
|
func property_fullAddress() {
|
|
let stadium = Stadium(
|
|
id: "test",
|
|
name: "Test Stadium",
|
|
city: "New York",
|
|
state: "NY",
|
|
latitude: 40.0,
|
|
longitude: -74.0,
|
|
capacity: 40000,
|
|
sport: .mlb
|
|
)
|
|
|
|
#expect(stadium.fullAddress == "New York, NY")
|
|
}
|
|
|
|
@Test("Property: timeZone returns nil when identifier is nil")
|
|
func property_timeZoneNil() {
|
|
let stadium = Stadium(
|
|
id: "test",
|
|
name: "Test Stadium",
|
|
city: "Test",
|
|
state: "XX",
|
|
latitude: 40.0,
|
|
longitude: -74.0,
|
|
capacity: 40000,
|
|
sport: .mlb,
|
|
timeZoneIdentifier: nil
|
|
)
|
|
|
|
#expect(stadium.timeZone == nil)
|
|
}
|
|
|
|
@Test("Property: timeZone returns TimeZone when identifier is valid")
|
|
func property_timeZoneValid() {
|
|
let stadium = Stadium(
|
|
id: "test",
|
|
name: "Test Stadium",
|
|
city: "Test",
|
|
state: "XX",
|
|
latitude: 40.0,
|
|
longitude: -74.0,
|
|
capacity: 40000,
|
|
sport: .mlb,
|
|
timeZoneIdentifier: "America/New_York"
|
|
)
|
|
|
|
#expect(stadium.timeZone?.identifier == "America/New_York")
|
|
}
|
|
}
|