diff --git a/SportsTime/Core/Models/Domain/Sport.swift b/SportsTime/Core/Models/Domain/Sport.swift index 6a8b3fa..58c7b6a 100644 --- a/SportsTime/Core/Models/Domain/Sport.swift +++ b/SportsTime/Core/Models/Domain/Sport.swift @@ -15,9 +15,9 @@ enum Sport: String, Codable, CaseIterable, Identifiable { case wnba = "WNBA" case nwsl = "NWSL" - var id: String { rawValue } + nonisolated var id: String { rawValue } - var displayName: String { + nonisolated var displayName: String { switch self { case .mlb: return "Major League Baseball" case .nba: return "National Basketball Association" @@ -29,7 +29,7 @@ enum Sport: String, Codable, CaseIterable, Identifiable { } } - var iconName: String { + nonisolated var iconName: String { switch self { case .mlb: return "baseball.fill" case .nba: return "basketball.fill" @@ -41,7 +41,7 @@ enum Sport: String, Codable, CaseIterable, Identifiable { } } - var color: Color { + nonisolated var color: Color { switch self { case .mlb: return .red case .nba: return .orange @@ -54,7 +54,7 @@ enum Sport: String, Codable, CaseIterable, Identifiable { } /// Season start and end months (1-12). End may be less than start for seasons that wrap around the year. - var seasonMonths: (start: Int, end: Int) { + nonisolated var seasonMonths: (start: Int, end: Int) { switch self { case .mlb: return (3, 10) // March - October case .nba: return (10, 6) // October - June (wraps) @@ -66,7 +66,7 @@ enum Sport: String, Codable, CaseIterable, Identifiable { } } - func isInSeason(for date: Date) -> Bool { + nonisolated func isInSeason(for date: Date) -> Bool { let calendar = Calendar.current let month = calendar.component(.month, from: date) @@ -81,11 +81,20 @@ enum Sport: String, Codable, CaseIterable, Identifiable { } /// Currently supported sports - static var supported: [Sport] { + nonisolated static var supported: [Sport] { [.mlb, .nba, .nfl, .nhl, .mls, .wnba, .nwsl] } } +// MARK: - AnySport Conformance + +extension Sport: AnySport, @unchecked Sendable { + nonisolated var sportId: String { rawValue } + + // Note: displayName, iconName, color, seasonMonths already exist on Sport + // They need nonisolated to satisfy AnySport protocol requirements +} + // MARK: - Array Chunking extension Array { diff --git a/SportsTimeTests/Domain/SportTests.swift b/SportsTimeTests/Domain/SportTests.swift new file mode 100644 index 0000000..2e8cfeb --- /dev/null +++ b/SportsTimeTests/Domain/SportTests.swift @@ -0,0 +1,53 @@ +// +// SportTests.swift +// SportsTimeTests +// + +import Foundation +import Testing +@testable import SportsTime + +@Suite("Sport AnySport Conformance") +struct SportAnySportTests { + + @Test("Sport conforms to AnySport protocol") + func sportConformsToAnySport() { + let sport: any AnySport = Sport.mlb + #expect(sport.sportId == "MLB") + #expect(sport.displayName == "Major League Baseball") + #expect(sport.iconName == "baseball.fill") + } + + @Test("Sport.id equals Sport.sportId") + func sportIdEqualsSportId() { + for sport in Sport.allCases { + #expect(sport.id == sport.sportId) + } + } + + @Test("Sport isInSeason works correctly") + func sportIsInSeason() { + let mlb = Sport.mlb + + // April is in MLB season (March-October) + let april = Calendar.current.date(from: DateComponents(year: 2026, month: 4, day: 15))! + #expect(mlb.isInSeason(for: april)) + + // January is not in MLB season + let january = Calendar.current.date(from: DateComponents(year: 2026, month: 1, day: 15))! + #expect(!mlb.isInSeason(for: january)) + } + + @Test("Sport with wrap-around season works correctly") + func sportWrapAroundSeason() { + let nba = Sport.nba + + // December is in NBA season (October-June wraps) + let december = Calendar.current.date(from: DateComponents(year: 2026, month: 12, day: 15))! + #expect(nba.isInSeason(for: december)) + + // July is not in NBA season + let july = Calendar.current.date(from: DateComponents(year: 2026, month: 7, day: 15))! + #expect(!nba.isInSeason(for: july)) + } +}