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

318 lines
9.3 KiB
Swift

//
// DivisionTests.swift
// SportsTimeTests
//
// TDD specification tests for Division, Conference, and LeagueStructure models.
//
import Testing
@testable import SportsTime
@Suite("Division")
struct DivisionTests {
// MARK: - Specification Tests: teamCount
@Test("teamCount: equals teamCanonicalIds.count")
func teamCount_equalsArrayCount() {
let division = Division(
id: "test_div",
name: "Test Division",
conference: "Test Conference",
conferenceId: "test_conf",
sport: .mlb,
teamCanonicalIds: ["team1", "team2", "team3"]
)
#expect(division.teamCount == 3)
}
@Test("teamCount: is 0 for empty array")
func teamCount_emptyArray() {
let division = Division(
id: "test_div",
name: "Test Division",
conference: "Test Conference",
conferenceId: "test_conf",
sport: .mlb,
teamCanonicalIds: []
)
#expect(division.teamCount == 0)
}
// MARK: - Invariant Tests
@Test("Invariant: teamCount == teamCanonicalIds.count")
func invariant_teamCountMatchesArray() {
let testCounts = [0, 1, 5, 10]
for count in testCounts {
let teamIds = (0..<count).map { "team_\($0)" }
let division = Division(
id: "div_\(count)",
name: "Division \(count)",
conference: "Conference",
conferenceId: "conf",
sport: .mlb,
teamCanonicalIds: teamIds
)
#expect(division.teamCount == division.teamCanonicalIds.count)
}
}
}
// MARK: - Conference Tests
@Suite("Conference")
struct ConferenceTests {
@Test("Property: divisionIds is accessible")
func property_divisionIds() {
let conference = Conference(
id: "test_conf",
name: "Test Conference",
abbreviation: "TC",
sport: .mlb,
divisionIds: ["div1", "div2", "div3"]
)
#expect(conference.divisionIds.count == 3)
#expect(conference.divisionIds.contains("div1"))
}
@Test("Property: abbreviation can be nil")
func property_abbreviationNil() {
let conference = Conference(
id: "test_conf",
name: "Test Conference",
abbreviation: nil,
sport: .nba,
divisionIds: []
)
#expect(conference.abbreviation == nil)
}
}
// MARK: - LeagueStructure Tests
@Suite("LeagueStructure")
struct LeagueStructureTests {
// MARK: - Specification Tests: divisions(for:)
@Test("divisions(for:): MLB returns 6 divisions")
func divisions_mlb() {
let divisions = LeagueStructure.divisions(for: .mlb)
#expect(divisions.count == 6)
}
@Test("divisions(for:): NBA returns 6 divisions")
func divisions_nba() {
let divisions = LeagueStructure.divisions(for: .nba)
#expect(divisions.count == 6)
}
@Test("divisions(for:): NHL returns 4 divisions")
func divisions_nhl() {
let divisions = LeagueStructure.divisions(for: .nhl)
#expect(divisions.count == 4)
}
@Test("divisions(for:): MLS returns empty array")
func divisions_mls() {
let divisions = LeagueStructure.divisions(for: .mls)
#expect(divisions.isEmpty)
}
@Test("divisions(for:): NFL returns empty array")
func divisions_nfl() {
let divisions = LeagueStructure.divisions(for: .nfl)
#expect(divisions.isEmpty)
}
// MARK: - Specification Tests: conferences(for:)
@Test("conferences(for:): MLB returns 2 conferences")
func conferences_mlb() {
let conferences = LeagueStructure.conferences(for: .mlb)
#expect(conferences.count == 2)
}
@Test("conferences(for:): NBA returns 2 conferences")
func conferences_nba() {
let conferences = LeagueStructure.conferences(for: .nba)
#expect(conferences.count == 2)
}
@Test("conferences(for:): NHL returns 2 conferences")
func conferences_nhl() {
let conferences = LeagueStructure.conferences(for: .nhl)
#expect(conferences.count == 2)
}
@Test("conferences(for:): MLS returns empty array")
func conferences_mls() {
let conferences = LeagueStructure.conferences(for: .mls)
#expect(conferences.isEmpty)
}
// MARK: - Specification Tests: division(byId:)
@Test("division(byId:): finds MLB division")
func divisionById_found() {
let division = LeagueStructure.division(byId: "mlb_al_east")
#expect(division != nil)
#expect(division?.name == "AL East")
#expect(division?.sport == .mlb)
}
@Test("division(byId:): finds NBA division")
func divisionById_nba() {
let division = LeagueStructure.division(byId: "nba_pacific")
#expect(division != nil)
#expect(division?.name == "Pacific")
#expect(division?.sport == .nba)
}
@Test("division(byId:): finds NHL division")
func divisionById_nhl() {
let division = LeagueStructure.division(byId: "nhl_metropolitan")
#expect(division != nil)
#expect(division?.name == "Metropolitan")
#expect(division?.sport == .nhl)
}
@Test("division(byId:): returns nil for unknown ID")
func divisionById_notFound() {
let division = LeagueStructure.division(byId: "unknown_division")
#expect(division == nil)
}
// MARK: - Specification Tests: conference(byId:)
@Test("conference(byId:): finds MLB conference")
func conferenceById_found() {
let conference = LeagueStructure.conference(byId: "mlb_nl")
#expect(conference != nil)
#expect(conference?.name == "National League")
#expect(conference?.abbreviation == "NL")
}
@Test("conference(byId:): finds NBA conference")
func conferenceById_nba() {
let conference = LeagueStructure.conference(byId: "nba_western")
#expect(conference != nil)
#expect(conference?.name == "Western Conference")
}
@Test("conference(byId:): returns nil for unknown ID")
func conferenceById_notFound() {
let conference = LeagueStructure.conference(byId: "unknown_conference")
#expect(conference == nil)
}
// MARK: - Specification Tests: stadiumCount(for:)
@Test("stadiumCount(for:): MLB returns 30")
func stadiumCount_mlb() {
#expect(LeagueStructure.stadiumCount(for: .mlb) == 30)
}
@Test("stadiumCount(for:): NBA returns 30")
func stadiumCount_nba() {
#expect(LeagueStructure.stadiumCount(for: .nba) == 30)
}
@Test("stadiumCount(for:): NHL returns 32")
func stadiumCount_nhl() {
#expect(LeagueStructure.stadiumCount(for: .nhl) == 32)
}
@Test("stadiumCount(for:): MLS returns 0")
func stadiumCount_mls() {
#expect(LeagueStructure.stadiumCount(for: .mls) == 0)
}
// MARK: - Invariant Tests
@Test("Invariant: MLB has 3 AL + 3 NL divisions")
func invariant_mlbDivisionStructure() {
let divisions = LeagueStructure.divisions(for: .mlb)
let alDivisions = divisions.filter { $0.conferenceId == "mlb_al" }
let nlDivisions = divisions.filter { $0.conferenceId == "mlb_nl" }
#expect(alDivisions.count == 3)
#expect(nlDivisions.count == 3)
}
@Test("Invariant: NBA has 3 Eastern + 3 Western divisions")
func invariant_nbaDivisionStructure() {
let divisions = LeagueStructure.divisions(for: .nba)
let eastern = divisions.filter { $0.conferenceId == "nba_eastern" }
let western = divisions.filter { $0.conferenceId == "nba_western" }
#expect(eastern.count == 3)
#expect(western.count == 3)
}
@Test("Invariant: NHL has 2 Eastern + 2 Western divisions")
func invariant_nhlDivisionStructure() {
let divisions = LeagueStructure.divisions(for: .nhl)
let eastern = divisions.filter { $0.conferenceId == "nhl_eastern" }
let western = divisions.filter { $0.conferenceId == "nhl_western" }
#expect(eastern.count == 2)
#expect(western.count == 2)
}
@Test("Invariant: each conference contains valid division IDs")
func invariant_conferenceContainsValidDivisions() {
for conference in LeagueStructure.conferences {
for divisionId in conference.divisionIds {
let division = LeagueStructure.division(byId: divisionId)
#expect(division != nil, "Division \(divisionId) in conference \(conference.id) should exist")
#expect(division?.conferenceId == conference.id, "Division \(divisionId) should belong to conference \(conference.id)")
}
}
}
@Test("Invariant: all divisions have unique IDs")
func invariant_uniqueDivisionIds() {
let allDivisions = LeagueStructure.mlbDivisions + LeagueStructure.nbaDivisions + LeagueStructure.nhlDivisions
let ids = allDivisions.map { $0.id }
let uniqueIds = Set(ids)
#expect(ids.count == uniqueIds.count, "Division IDs should be unique")
}
@Test("Invariant: all conferences have unique IDs")
func invariant_uniqueConferenceIds() {
let ids = LeagueStructure.conferences.map { $0.id }
let uniqueIds = Set(ids)
#expect(ids.count == uniqueIds.count, "Conference IDs should be unique")
}
}