Files
Sportstime/SportsTimeTests/Domain/StadiumTests.swift
Trey t 8162b4a029 refactor(tests): TDD rewrite of all unit tests with spec documentation
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>
2026-01-16 14:07:41 -06:00

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")
}
}