Files
Sportstime/SportsTimeTests/Domain/RegionTests.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

165 lines
5.3 KiB
Swift

//
// RegionTests.swift
// SportsTimeTests
//
// TDD specification tests for Region enum.
//
import Testing
@testable import SportsTime
@Suite("Region")
struct RegionTests {
// MARK: - Specification Tests: classify(longitude:)
@Test("classify: longitude > -85 returns .east")
func classify_east() {
// NYC: -73.9855
#expect(Region.classify(longitude: -73.9855) == .east)
// Boston: -71.0972
#expect(Region.classify(longitude: -71.0972) == .east)
// Miami: -80.1918
#expect(Region.classify(longitude: -80.1918) == .east)
// Toronto: -79.3832
#expect(Region.classify(longitude: -79.3832) == .east)
// Atlanta: -84.3880
#expect(Region.classify(longitude: -84.3880) == .east)
// Just above boundary
#expect(Region.classify(longitude: -84.9999) == .east)
}
@Test("classify: longitude in -110...-85 returns .central")
func classify_central() {
// Chicago: -87.6233
#expect(Region.classify(longitude: -87.6233) == .central)
// Houston: -95.3698
#expect(Region.classify(longitude: -95.3698) == .central)
// Dallas: -96.7970
#expect(Region.classify(longitude: -96.7970) == .central)
// Minneapolis: -93.2650
#expect(Region.classify(longitude: -93.2650) == .central)
// Denver: -104.9903
#expect(Region.classify(longitude: -104.9903) == .central)
// Boundary: exactly -85
#expect(Region.classify(longitude: -85.0) == .central)
// Boundary: exactly -110
#expect(Region.classify(longitude: -110.0) == .central)
}
@Test("classify: longitude < -110 returns .west")
func classify_west() {
// Los Angeles: -118.2673
#expect(Region.classify(longitude: -118.2673) == .west)
// San Francisco: -122.4194
#expect(Region.classify(longitude: -122.4194) == .west)
// Seattle: -122.3321
#expect(Region.classify(longitude: -122.3321) == .west)
// Phoenix: -112.0740
#expect(Region.classify(longitude: -112.0740) == .west)
// Las Vegas: -115.1398
#expect(Region.classify(longitude: -115.1398) == .west)
// Just below boundary
#expect(Region.classify(longitude: -110.0001) == .west)
}
// MARK: - Specification Tests: Boundary Values
@Test("classify boundary: -85 is central, -84.9999 is east")
func classify_eastCentralBoundary() {
#expect(Region.classify(longitude: -85.0) == .central)
#expect(Region.classify(longitude: -84.9999) == .east)
#expect(Region.classify(longitude: -85.0001) == .central)
}
@Test("classify boundary: -110 is central, -110.0001 is west")
func classify_centralWestBoundary() {
#expect(Region.classify(longitude: -110.0) == .central)
#expect(Region.classify(longitude: -109.9999) == .central)
#expect(Region.classify(longitude: -110.0001) == .west)
}
// MARK: - Specification Tests: Edge Cases
@Test("classify: extreme east longitude (positive) returns .east")
func classify_extremeEast() {
#expect(Region.classify(longitude: 0.0) == .east)
#expect(Region.classify(longitude: 50.0) == .east)
}
@Test("classify: extreme west longitude returns .west")
func classify_extremeWest() {
#expect(Region.classify(longitude: -180.0) == .west)
#expect(Region.classify(longitude: -150.0) == .west)
}
// MARK: - Invariant Tests
@Test("Invariant: classify never returns .crossCountry")
func invariant_classifyNeverReturnsCrossCountry() {
let testLongitudes: [Double] = [-180, -150, -120, -110.0001, -110, -100, -85.0001, -85, -70, 0, 50]
for lon in testLongitudes {
let region = Region.classify(longitude: lon)
#expect(region != .crossCountry, "classify should never return crossCountry for longitude \(lon)")
}
}
@Test("Invariant: every longitude maps to exactly one region")
func invariant_everyLongitudeMapsToOneRegion() {
// Test a range of longitudes
for lon in stride(from: -180.0, through: 50.0, by: 10.0) {
let region = Region.classify(longitude: lon)
#expect([Region.east, .central, .west].contains(region), "Longitude \(lon) should map to east, central, or west")
}
}
// MARK: - Property Tests
@Test("Property: id equals rawValue")
func property_idEqualsRawValue() {
for region in Region.allCases {
#expect(region.id == region.rawValue)
}
}
@Test("Property: displayName equals rawValue")
func property_displayNameEqualsRawValue() {
for region in Region.allCases {
#expect(region.displayName == region.rawValue)
}
}
@Test("Property: all regions have iconName")
func property_allRegionsHaveIconName() {
for region in Region.allCases {
#expect(!region.iconName.isEmpty)
}
}
// MARK: - Specification Tests: Display Properties
@Test("shortName values are correct")
func shortName_values() {
#expect(Region.east.shortName == "East")
#expect(Region.central.shortName == "Central")
#expect(Region.west.shortName == "West")
#expect(Region.crossCountry.shortName == "Coast to Coast")
}
}