feat(domain): add DynamicSport model for CloudKit-defined sports

Struct representing sports synced from CloudKit. Conforms to AnySport
protocol for interchangeable use with Sport enum in UI and planning.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-13 16:22:02 -06:00
parent e781eaa17c
commit dc278085de
2 changed files with 163 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
//
// DynamicSportTests.swift
// SportsTimeTests
//
import Testing
import SwiftUI
@testable import SportsTime
@Suite("DynamicSport")
struct DynamicSportTests {
@Test("DynamicSport conforms to AnySport protocol")
func dynamicSportConformsToAnySport() {
let xfl = DynamicSport(
id: "xfl",
abbreviation: "XFL",
displayName: "XFL Football",
iconName: "football.fill",
colorHex: "#E31837",
seasonStartMonth: 2,
seasonEndMonth: 5
)
let sport: any AnySport = xfl
#expect(sport.sportId == "xfl")
#expect(sport.displayName == "XFL Football")
#expect(sport.iconName == "football.fill")
}
@Test("DynamicSport color parses from hex")
func dynamicSportColorParsesFromHex() {
let sport = DynamicSport(
id: "test",
abbreviation: "TST",
displayName: "Test Sport",
iconName: "star.fill",
colorHex: "#FF0000",
seasonStartMonth: 1,
seasonEndMonth: 12
)
// Color should be red
#expect(sport.color != Color.clear)
}
@Test("DynamicSport isInSeason works correctly")
func dynamicSportIsInSeason() {
let xfl = DynamicSport(
id: "xfl",
abbreviation: "XFL",
displayName: "XFL Football",
iconName: "football.fill",
colorHex: "#E31837",
seasonStartMonth: 2,
seasonEndMonth: 5
)
// March is in XFL season (Feb-May)
let march = Calendar.current.date(from: DateComponents(year: 2026, month: 3, day: 15))!
#expect(xfl.isInSeason(for: march))
// September is not in XFL season
let september = Calendar.current.date(from: DateComponents(year: 2026, month: 9, day: 15))!
#expect(!xfl.isInSeason(for: september))
}
@Test("DynamicSport is Hashable")
func dynamicSportIsHashable() {
let sport1 = DynamicSport(
id: "xfl",
abbreviation: "XFL",
displayName: "XFL Football",
iconName: "football.fill",
colorHex: "#E31837",
seasonStartMonth: 2,
seasonEndMonth: 5
)
let sport2 = DynamicSport(
id: "xfl",
abbreviation: "XFL",
displayName: "XFL Football",
iconName: "football.fill",
colorHex: "#E31837",
seasonStartMonth: 2,
seasonEndMonth: 5
)
let set: Set<DynamicSport> = [sport1, sport2]
#expect(set.count == 1)
}
@Test("DynamicSport is Codable")
func dynamicSportIsCodable() throws {
let original = DynamicSport(
id: "xfl",
abbreviation: "XFL",
displayName: "XFL Football",
iconName: "football.fill",
colorHex: "#E31837",
seasonStartMonth: 2,
seasonEndMonth: 5
)
let encoded = try JSONEncoder().encode(original)
let decoded = try JSONDecoder().decode(DynamicSport.self, from: encoded)
#expect(decoded.id == original.id)
#expect(decoded.abbreviation == original.abbreviation)
#expect(decoded.displayName == original.displayName)
}
}