import AppTypes import ComposableArchitecture import CoreGraphics import Dao import DependenciesTestSupport import Foundation import ScreenControl import Testing @testable import EditSettingsNew_TopLevel @MainActor @Suite("ScreenOffSetting Feature Tests", .dependencies { // .syncedSetting reads the database at State init and stamps lastModified // on every schedule write. $0.defaultDatabase = try! $0.appDatabase() $0.uuid = .incrementing $0.date = .constant(Date(timeIntervalSince1970: 0)) }) struct ScreenOffSettingTests { @Test("initial state has nil schedule") func initialState() async { let state = ScreenOffSettingFeature.State() #expect(state.schedule == nil) } // MARK: - Set Actions @Test("setStartTime updates start time directly") func setStartTime() async { var state = ScreenOffSettingFeature.State() state.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 22, startMinute: 0, endHour: 6, endMinute: 0) } let store = TestStore(initialState: state) { ScreenOffSettingFeature() } await store.send(.setStartTime(hour: 21, minute: 30)) { $0.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 21, startMinute: 30, endHour: 6, endMinute: 0) } } } @Test("setEndTime updates end time directly") func setEndTime() async { var state = ScreenOffSettingFeature.State() state.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 22, startMinute: 0, endHour: 6, endMinute: 0) } let store = TestStore(initialState: state) { ScreenOffSettingFeature() } await store.send(.setEndTime(hour: 7, minute: 15)) { $0.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 22, startMinute: 0, endHour: 7, endMinute: 15) } } } @Test("setSchedule updates both times directly") func setSchedule() async { var state = ScreenOffSettingFeature.State() state.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 22, startMinute: 0, endHour: 6, endMinute: 0) } let store = TestStore(initialState: state) { ScreenOffSettingFeature() } await store.send(.setSchedule(startHour: 23, startMinute: 30, endHour: 7, endMinute: 45)) { $0.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 23, startMinute: 30, endHour: 7, endMinute: 45) } } } @Test("setStartTime with nil schedule produces no state changes") func setStartTimeNilSchedule() async { let store = TestStore(initialState: ScreenOffSettingFeature.State()) { ScreenOffSettingFeature() } await store.send(.setStartTime(hour: 10, minute: 30)) } @Test("setStartTime clamps negative values") func setStartTimeClamps() async { var state = ScreenOffSettingFeature.State() state.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 22, startMinute: 0, endHour: 6, endMinute: 0) } let store = TestStore(initialState: state) { ScreenOffSettingFeature() } await store.send(.setStartTime(hour: -1, minute: -5)) { $0.$schedule.withLock { $0 = ScreenOffSchedule(startHour: 23, startMinute: 55, endHour: 6, endMinute: 0) } } } // MARK: - Nil schedule guard @Test("actions with nil schedule produce no state changes") func nilScheduleNoOp() async { let store = TestStore(initialState: ScreenOffSettingFeature.State()) { ScreenOffSettingFeature() } await store.send(.setStartTime(hour: 10, minute: 30)) await store.send(.setEndTime(hour: 7, minute: 0)) await store.send(.setSchedule(startHour: 22, startMinute: 0, endHour: 6, endMinute: 0)) } // MARK: - Test Screen Off @Test("testScreenOff dims and restores brightness with countdown") func testScreenOff() async { var state = ScreenOffSettingFeature.State() state.$schedule.withLock { $0 = .default } let brightnessValues = LockIsolated<[CGFloat]>([]) let clock = TestClock() let store = TestStore(initialState: state) { ScreenOffSettingFeature() } withDependencies: { $0.continuousClock = clock $0.screenControl.getBrightness = { 0.75 } $0.screenControl.setBrightness = { value in brightnessValues.withValue { $0.append(value) } } } await store.send(.testScreenOff) { $0.isTesting = true $0.testStatus = "Saving brightness…" } // Receive "Dimming screen…" progress await store.receive(\._testProgress) { $0.testStatus = "Dimming screen…" } // Advance through the 10-second countdown for remaining in stride(from: 10, through: 1, by: -1) { await store.receive(\._testProgress) { $0.testStatus = "Screen off — restoring in \(remaining)s" } await clock.advance(by: .seconds(1)) } // Receive "Restoring brightness…" progress await store.receive(\._testProgress) { $0.testStatus = "Restoring brightness…" } await store.receive(\._testComplete) { $0.isTesting = false $0.testStatus = nil } #expect(brightnessValues.value == [0.0, 0.75]) } @Test("testScreenOff ignored while already testing") func testScreenOffWhileTesting() async { var state = ScreenOffSettingFeature.State() state.$schedule.withLock { $0 = .default } state.isTesting = true let store = TestStore(initialState: state) { ScreenOffSettingFeature() } await store.send(.testScreenOff) } }