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>
318 lines
9.3 KiB
Swift
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")
|
|
}
|
|
}
|