import Testing import Foundation @testable import CalendarProvider @Suite("Monatsraster") struct MonthGridTests { private var calendar: Calendar { var c = Calendar(identifier: .gregorian) c.timeZone = TimeZone(identifier: "Europe/Berlin")! c.firstWeekday = 2 // Montag return c } private func date(_ string: String) -> Date { let f = DateFormatter() f.calendar = calendar f.timeZone = calendar.timeZone f.dateFormat = "yyyy-MM-dd" return f.date(from: string)! } // MARK: - Aufbau @Test("August 2026 beginnt an einem Samstag und braucht deshalb fünf Vortage") func leadingDaysForAugust2026() { let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) // 1. August 2026 ist ein Samstag; bei Wochenstart Montag stehen davor // Mo–Fr aus dem Juli. #expect(grid.days.first?.date == date("2026-07-27")) #expect(grid.days.prefix(5).allSatisfy { !$0.isInMonth }) } @Test("Das Raster besteht immer aus vollen Wochen") func gridIsWholeWeeks() { for month in ["2026-01-15", "2026-02-15", "2026-08-10", "2026-12-01"] { let grid = MonthGrid(containing: date(month), calendar: calendar) #expect(grid.days.count % 7 == 0, "Monat \(month) ergibt keine vollen Wochen") } } @Test("Februar 2027 hat 28 Tage im Monat, egal wie viele Zellen das Raster hat") func februaryHasCorrectDayCount() { let grid = MonthGrid(containing: date("2027-02-10"), calendar: calendar) #expect(grid.days.filter(\.isInMonth).count == 28) } @Test("Ein Schaltjahr wird korrekt behandelt") func leapYear() { let grid = MonthGrid(containing: date("2028-02-10"), calendar: calendar) #expect(grid.days.filter(\.isInMonth).count == 29) } @Test("Bei Wochenstart Sonntag verschiebt sich die erste Zeile") func sundayStart() { var sundayFirst = calendar sundayFirst.firstWeekday = 1 let grid = MonthGrid(containing: date("2026-08-10"), calendar: sundayFirst) #expect(grid.days.first?.date == date("2026-07-26")) } @Test("Tage außerhalb des Monats sind als solche markiert") func outOfMonthDaysAreMarked() { let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let inMonth = grid.days.filter(\.isInMonth) #expect(inMonth.count == 31) #expect(grid.days.count > inMonth.count) } // MARK: - Abdeckung: der Unterschied zwischen „frei" und „unbekannt" @Test("Ohne Abdeckungsgrenze gilt jeder Tag als bekannt") func unlimitedCoverageKnowsEverything() { let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let status = grid.status(for: date("2026-08-10"), coverage: nil, busyDays: []) #expect(status == .free) } @Test("Ein Tag innerhalb der Abdeckung ohne Termine ist frei") func dayInCoverageWithoutEventsIsFree() { let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let coverage = DateInterval(start: date("2026-08-01"), end: date("2026-09-01")) #expect(grid.status(for: date("2026-08-10"), coverage: coverage, busyDays: []) == .free) } @Test("Ein Tag AUSSERHALB der Abdeckung ist unbekannt, nicht frei") func dayOutsideCoverageIsUnknown() { // Der Kernpunkt. Ein leerer März sieht überzeugend echt aus und ist // falsch, wenn die Quelle dort gar nichts weiß. let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let coverage = DateInterval(start: date("2026-08-01"), end: date("2026-08-15")) #expect(grid.status(for: date("2026-08-20"), coverage: coverage, busyDays: []) == .unknown) } @Test("Der letzte Tag der Abdeckung gehört nicht mehr dazu") func coverageEndIsExclusive() { // [start, end) — so ist es in der Calendarr-Anleitung festgelegt. let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let coverage = DateInterval(start: date("2026-08-01"), end: date("2026-08-15")) #expect(grid.status(for: date("2026-08-14"), coverage: coverage, busyDays: []) == .free) #expect(grid.status(for: date("2026-08-15"), coverage: coverage, busyDays: []) == .unknown) } @Test("Ein Tag vor Beginn der Abdeckung ist ebenfalls unbekannt") func dayBeforeCoverageIsUnknown() { let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let coverage = DateInterval(start: date("2026-08-05"), end: date("2026-08-30")) #expect(grid.status(for: date("2026-08-01"), coverage: coverage, busyDays: []) == .unknown) } @Test("Ein Tag mit Terminen ist belegt") func dayWithEventsIsBusy() { let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let busy: Set = [calendar.startOfDay(for: date("2026-08-10"))] #expect(grid.status(for: date("2026-08-10"), coverage: nil, busyDays: busy) == .busy) } @Test("Termine außerhalb der Abdeckung ändern nichts — sie dürften gar nicht existieren") func busyOutsideCoverageStaysUnknown() { // Widersprüchliche Eingabe: die Quelle liefert einen Termin für einen // Tag, den sie nach eigener Angabe nicht abdeckt. Die Abdeckung gewinnt, // sonst behauptet die Anzeige mehr zu wissen, als belegt ist. let grid = MonthGrid(containing: date("2026-08-10"), calendar: calendar) let coverage = DateInterval(start: date("2026-08-01"), end: date("2026-08-15")) let busy: Set = [calendar.startOfDay(for: date("2026-08-20"))] #expect(grid.status(for: date("2026-08-20"), coverage: coverage, busyDays: busy) == .unknown) } }