// // RuleModelTests.swift // OpenAppLockTests // import Foundation import SwiftData import Testing @testable import OpenAppLock @MainActor @Suite("BlockingRule model & persistence") struct RuleModelTests { @Test("Defaults match the reference app's new-rule defaults") func defaults() { let rule = BlockingRule(name: "In the Zone") #expect(rule.kind == .schedule) #expect(rule.isEnabled) #expect(!rule.hardMode) #expect(!rule.blockAdultContent) #expect(rule.selectionMode == .block) #expect(rule.days == Weekday.weekdays) #expect(rule.startMinutes == 9 * 60) #expect(rule.endMinutes == 17 * 60) #expect(rule.pausedUntil == nil) } @Test("Days survive the raw-storage round trip") func daysRoundTrip() { let rule = BlockingRule(name: "Test") rule.days = [.sunday, .wednesday, .saturday] #expect(rule.days == [.sunday, .wednesday, .saturday]) #expect(rule.dayNumbers == [1, 4, 7]) } @Test("Kind and selection mode survive raw storage, with safe fallbacks") func enumRoundTrip() { let rule = BlockingRule(name: "Test", kind: .openLimit, selectionMode: .allowOnly) #expect(rule.kind == .openLimit) #expect(rule.selectionMode == .allowOnly) rule.kindRaw = "garbage" rule.selectionModeRaw = "garbage" #expect(rule.kind == .schedule) #expect(rule.selectionMode == .block) } @Test("Rules persist and fetch through SwiftData") func persistence() throws { let container = try ModelContainer( for: BlockingRule.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true) ) let context = container.mainContext let rule = BlockingRule( name: "Deep Sleep", hardMode: true, days: Weekday.everyDay, startMinutes: 22 * 60, endMinutes: 6 * 60 ) context.insert(rule) try context.save() let fetched = try context.fetch(FetchDescriptor()) #expect(fetched.count == 1) let saved = try #require(fetched.first) #expect(saved.name == "Deep Sleep") #expect(saved.hardMode) #expect(saved.days == Weekday.everyDay) #expect(saved.schedule.crossesMidnight) } } @MainActor @Suite("RuleDraft") struct RuleDraftTests { @Test("New drafts use the kind's defaults") func newDraftDefaults() { let draft = RuleDraft(kind: .timeLimit) #expect(draft.name == "Time Keeper") #expect(draft.kind == .timeLimit) #expect(draft.dailyLimitMinutes == 45) #expect(draft.days == Weekday.weekdays) #expect(!draft.hardMode) } @Test("Draft → rule → draft round-trips every field") func roundTrip() { var draft = RuleDraft(kind: .schedule) draft.name = "Locked In" draft.days = Weekday.everyDay draft.startMinutes = 22 * 60 draft.endMinutes = 6 * 60 draft.hardMode = true draft.blockAdultContent = true draft.selectionMode = .allowOnly draft.selectionCount = 3 let rule = draft.makeRule() #expect(rule.blockAdultContent) #expect(RuleDraft(rule: rule) == draft) } @Test("Applying a draft updates an existing rule") func applyToExisting() { let rule = BlockingRule(name: "Old Name") var draft = RuleDraft(rule: rule) draft.name = "New Name" draft.hardMode = true draft.apply(to: rule) #expect(rule.name == "New Name") #expect(rule.hardMode) } @Test("Sanitizing trims whitespace and falls back to the kind default") func sanitizedName() { var draft = RuleDraft(kind: .schedule) draft.name = " Deep Work " #expect(draft.sanitized().name == "Deep Work") draft.name = " " #expect(draft.sanitized().name == "In the Zone") var limitDraft = RuleDraft(kind: .timeLimit) limitDraft.name = "" #expect(limitDraft.sanitized().name == "Time Keeper") } @Test("Preset drafts copy the preset's schedule") func presetDraft() throws { let preset = try #require( RulePresetSection.all .flatMap(\.presets) .first { $0.id == "deep-sleep" } ) let draft = RuleDraft(preset: preset) #expect(draft.name == "Deep Sleep") #expect(draft.startMinutes == 22 * 60) #expect(draft.endMinutes == 6 * 60) #expect(draft.kind == .schedule) } } @MainActor @Suite("Weekday summaries") struct WeekdayTests { @Test("Named sets") func namedSets() { #expect(Weekday.weekdays.summary == "Weekdays") #expect(Weekday.weekends.summary == "Weekends") #expect(Weekday.everyDay.summary == "Every day") #expect(Set().summary == "Never") } @Test("Custom sets list days in display order") func customSets() { let days: Set = [.friday, .monday, .wednesday] #expect(days.summary == "Mon, Wed, Fri") } @Test("Picker display order starts on Sunday") func displayOrder() { #expect(Weekday.displayOrder.first == .sunday) #expect(Weekday.displayOrder.count == 7) #expect(Weekday.displayOrder.map(\.shortLabel) == ["S", "M", "T", "W", "T", "F", "S"]) } }