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:
113
SportsTimeTests/Domain/DynamicSportTests.swift
Normal file
113
SportsTimeTests/Domain/DynamicSportTests.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user