diff --git a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift index 67285435..9259646a 100644 --- a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift @@ -204,8 +204,8 @@ final class AppFeatureTests: XCTestCase { var state = AppFeature.State() let location = Location(coordinate: .make(), timestamp: 42) state.mapFeatureState.location = location - state.settingsState.userSettings.rideEventSettings.isEnabled = true - state.settingsState.userSettings.rideEventSettings.eventDistance = .close + state.settingsState.rideEventSettings.isEnabled = true + state.settingsState.rideEventSettings.eventSearchRadius = .close let store = TestStore( initialState: state, @@ -219,8 +219,8 @@ final class AppFeatureTests: XCTestCase { [Ride(id: 123, title: "Test", dateTime: Date(timeIntervalSince1970: 0), enabled: true)] } - await store.send(.settings(.rideevent(.setRideEventRadius(.far)))) { - $0.settingsState.userSettings.rideEventSettings.eventDistance = .far + await store.send(.settings(.rideevent(.set(\.$eventSearchRadius, .far)))) { + $0.settingsState.rideEventSettings.eventSearchRadius = .far } await testQueue.advance(by: 2) await store.receive(.nextRide(.getNextRide(location.coordinate))) @@ -237,7 +237,7 @@ final class AppFeatureTests: XCTestCase { ) var state = AppFeature.State() - state.settingsState.userSettings.rideEventSettings.isEnabled = true + state.settingsState.rideEventSettings.isEnabled = true state.nextRideState.userLocation = nil state.mapFeatureState.location = sharedModelLocation @@ -246,7 +246,7 @@ final class AppFeatureTests: XCTestCase { reducer: AppFeature() ) store.exhaustivity = .off - store.dependencies.date = .init(date) + store.dependencies.date = .init({ @Sendable in self.date() }) let locations: [ComposableCoreLocation.Location] = [location] await store.send(.map(.locationManager(.didUpdateLocations(locations)))) { @@ -289,7 +289,6 @@ final class AppFeatureTests: XCTestCase { initialState: state, reducer: AppFeature() ) - store.exhaustivity = .off store.dependencies.mainQueue = .immediate let coordinate = Coordinate.make() @@ -297,9 +296,12 @@ final class AppFeatureTests: XCTestCase { await store.send(.map(.focusRideEvent(coordinate))) { $0.mapFeatureState.eventCenter = CoordinateRegion(center: coordinate.asCLLocationCoordinate) } - await store.receive(.set(\.$bottomSheetPosition, .relative(0.4))) { + await store.receive(.binding(.set(\.$bottomSheetPosition, .relative(CGFloat(0.4))))) { $0.bottomSheetPosition = .relative(0.4) } + await store.receive(.map(.resetRideEventCenter)) { + $0.mapFeatureState.eventCenter = nil + } } func test_requestTimerTick_fireUpFetchLocations() async { @@ -336,7 +338,7 @@ final class AppFeatureTests: XCTestCase { var state = AppFeature.State() let location = Location(coordinate: .make(), timestamp: 42) state.mapFeatureState.location = location - state.settingsState.userSettings.rideEventSettings.isEnabled = true + state.settingsState.rideEventSettings.isEnabled = true let store = TestStore( initialState: state, @@ -350,8 +352,8 @@ final class AppFeatureTests: XCTestCase { [Ride(id: 123, title: "Test", dateTime: Date(timeIntervalSince1970: 0), enabled: true)] } - await store.send(.settings(.rideevent(.setRideEventsEnabled(true)))) { - $0.settingsState.userSettings.rideEventSettings.isEnabled = true + await store.send(.settings(.rideevent(.set(\.$isEnabled, true)))) { + $0.settingsState.rideEventSettings.isEnabled = true } await testQueue.advance(by: 2) await store.receive(.nextRide(.getNextRide(location.coordinate))) @@ -363,9 +365,9 @@ final class AppFeatureTests: XCTestCase { var state = AppFeature.State() let location = Location(coordinate: .make(), timestamp: 42) - state.settingsState.userSettings.rideEventSettings.eventDistance = .close + state.settingsState.rideEventSettings.eventSearchRadius = .close state.mapFeatureState.location = location - state.settingsState.userSettings.rideEventSettings.isEnabled = true + state.settingsState.rideEventSettings.isEnabled = true let store = TestStore( initialState: state, @@ -378,9 +380,9 @@ final class AppFeatureTests: XCTestCase { await updatedRaduis.setValue(radius) return [Ride(id: 123, title: "Test", dateTime: self.date(), enabled: true)] } - - await store.send(.settings(.rideevent(.setRideEventRadius(.far)))) { - $0.settingsState.userSettings.rideEventSettings.eventDistance = .far + + await store.send(.settings(.rideevent(.set(\.$eventSearchRadius, .far)))) { + $0.settingsState.rideEventSettings.eventSearchRadius = .far } await testQueue.advance(by: 2) await store.receive(.nextRide(.getNextRide(location.coordinate))) @@ -390,34 +392,6 @@ final class AppFeatureTests: XCTestCase { } } - func test_didSaveUserSettings() async throws { - let didSaveUserSettings = ActorIsolated(false) - let didSaveObserverPromptSetting = ActorIsolated(false) - - let testQueue = DispatchQueue.test - - let store = TestStore( - initialState: AppFeature.State(), - reducer: AppFeature() - ) - store.dependencies.mainQueue = testQueue.eraseToAnyScheduler() - store.dependencies.fileClient.save = { @Sendable _, _ in - await didSaveUserSettings.setValue(true) - } - store.dependencies.userDefaultsClient.setBool = { @Sendable value, _ in - await didSaveObserverPromptSetting.setValue(value) - } - - await store.send(.setObservationMode(false)) - - await didSaveUserSettings.withValue { val in - XCTAssertTrue(val, "Expected that save is invoked") - } - await didSaveObserverPromptSetting.withValue { val in - XCTAssertTrue(val, "Expected to store that user prompt has been seen") - } - } - func test_viewingModePrompt() async throws { let didSetDidShowPrompt = ActorIsolated(false) @@ -442,18 +416,13 @@ final class AppFeatureTests: XCTestCase { func test_postLocation_shouldNotPostLocationWhenObserverModeIsEnabled() async { var state = AppFeature.State() - state.settingsState.userSettings.isObservationModeEnabled = true + state.settingsState.isObservationModeEnabled = true let store = TestStore( initialState: state, reducer: AppFeature() ) store.dependencies.date = .init({ @Sendable in self.date() }) - - let location = ComposableCoreLocation.Location( - coordinate: .init(latitude: 11, longitude: 21), - timestamp: Date(timeIntervalSince1970: 2) - ) await store.send(.postLocation) } } diff --git a/CriticalMapsKit/Tests/ChatFeatureTests/IdentifiedMessageTests.swift b/CriticalMapsKit/Tests/ChatFeatureTests/IdentifiedMessageTests.swift index 8ad98383..86859383 100644 --- a/CriticalMapsKit/Tests/ChatFeatureTests/IdentifiedMessageTests.swift +++ b/CriticalMapsKit/Tests/ChatFeatureTests/IdentifiedMessageTests.swift @@ -16,13 +16,6 @@ final class IdentifiedMessagesTests: XCTestCase { )! func test_chatTime_Format() { - let sut = ChatMessage( - identifier: "ID", - device: "DEVICE", - message: "Hello World", - timestamp: date.timeIntervalSince1970 - ) - var cal = Calendar.current cal.timeZone = .init(secondsFromGMT: 0)! let chatTime = date.formatted(Date.FormatStyle.chatTime(cal)) diff --git a/CriticalMapsKit/Tests/NextRideFeatureTests/NextRideCoreTests.swift b/CriticalMapsKit/Tests/NextRideFeatureTests/NextRideCoreTests.swift index ebd78ff2..3f9fccb7 100644 --- a/CriticalMapsKit/Tests/NextRideFeatureTests/NextRideCoreTests.swift +++ b/CriticalMapsKit/Tests/NextRideFeatureTests/NextRideCoreTests.swift @@ -72,11 +72,11 @@ final class NextRideCoreTests: XCTestCase { initialState: .init(), reducer: NextRideFeature() ) - store.dependencies.date = .init(now) + store.dependencies.date = .init({ @Sendable in self.now() }) store.dependencies.userDefaultsClient.dataForKey = { _ in try? RideEventSettings( isEnabled: false, - typeSettings: [], + typeSettings: [:], eventDistance: .near ) .encoded() @@ -116,7 +116,7 @@ final class NextRideCoreTests: XCTestCase { store.dependencies.userDefaultsClient.dataForKey = { _ in try? RideEventSettings( isEnabled: true, - typeSettings: [], + typeSettings: [:], eventDistance: .near ) .encoded() @@ -144,9 +144,7 @@ final class NextRideCoreTests: XCTestCase { store.dependencies.userDefaultsClient.dataForKey = { _ in try? RideEventSettings( isEnabled: true, - typeSettings: [ - RideEventSettings.RideEventTypeSetting(type: Ride.RideType.kidicalMass, isEnabled: true) - ], + typeSettings: [.kidicalMass: true], eventDistance: .near ) .encoded() diff --git a/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsCoreTests.swift b/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsCoreTests.swift index 1efa8e55..38438a65 100644 --- a/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsCoreTests.swift +++ b/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsCoreTests.swift @@ -7,61 +7,50 @@ import XCTest final class RideEventSettingsCoreTests: XCTestCase { func test_setRideEventsEnabled() { let store = TestStore( - initialState: RideEventSettings( - isEnabled: true, - typeSettings: .all, - eventDistance: .close + initialState: .init( + settings: RideEventSettings( + isEnabled: true, + typeSettings: .all(), + eventDistance: .close + ) ), reducer: RideEventsSettingsFeature() ) - store.send(.setRideEventsEnabled(false)) { + store.send(.set(\.$isEnabled, false)) { $0.isEnabled = false } - store.send(.setRideEventsEnabled(true)) { + store.send(.set(\.$isEnabled, true)) { $0.isEnabled = true } } func test_setRideEventsTypeEnabled() { let store = TestStore( - initialState: RideEventSettings( - isEnabled: true, - typeSettings: .all, - eventDistance: .close - ), - reducer: RideEventsSettingsFeature() + initialState: RideEventType.State(rideType: .criticalMass, isEnabled: false), + reducer: RideEventType() ) - var updatedType = RideEventSettings.RideEventTypeSetting(type: .kidicalMass, isEnabled: false) - store.send(.setRideEventTypeEnabled(updatedType)) { - var updatedSettings: [RideEventSettings.RideEventTypeSetting] = .all - let index = try XCTUnwrap(updatedSettings.firstIndex(where: { setting in - setting.type == updatedType.type - })) - updatedSettings[index] = updatedType - $0.typeSettings = updatedSettings - } - - updatedType.isEnabled = true - store.send(.setRideEventTypeEnabled(updatedType)) { - $0.typeSettings = .all + store.send(.set(\.$isEnabled, true)) { + $0.isEnabled = true } } func test_setRideEventsRadius() { let store = TestStore( - initialState: RideEventSettings( - isEnabled: true, - typeSettings: .all, - eventDistance: .close + initialState: .init( + settings: RideEventSettings( + isEnabled: true, + typeSettings: .all(), + eventDistance: .close + ) ), reducer: RideEventsSettingsFeature() ) - store.send(.setRideEventRadius(.near)) { - $0.eventDistance = .near + store.send(.set(\.$eventSearchRadius, .near)) { + $0.eventSearchRadius = .near } } } diff --git a/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsViewSnapshotTests.swift b/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsViewSnapshotTests.swift index eab6d60e..626c6a0a 100644 --- a/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsViewSnapshotTests.swift +++ b/CriticalMapsKit/Tests/SettingsFeatureTests/RideEventSettingsViewSnapshotTests.swift @@ -7,10 +7,12 @@ final class RideEventSettingsViewSnapshotTests: XCTestCase { func test_rideEventSettingsView_light() { let settingsView = RideEventSettingsView( store: .init( - initialState: RideEventSettings( - isEnabled: true, - typeSettings: .all, - eventDistance: .close + initialState: .init( + settings: RideEventSettings( + isEnabled: true, + typeSettings: .all(), + eventDistance: .close + ) ), reducer: RideEventsSettingsFeature() ) @@ -22,10 +24,12 @@ final class RideEventSettingsViewSnapshotTests: XCTestCase { func test_rideEventSettingsView_disabled() { let settingsView = RideEventSettingsView( store: .init( - initialState: RideEventSettings( - isEnabled: false, - typeSettings: .all, - eventDistance: .close + initialState: .init( + settings: RideEventSettings( + isEnabled: true, + typeSettings: .all(), + eventDistance: .close + ) ), reducer: RideEventsSettingsFeature() ) diff --git a/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift b/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift index aea86297..6d4ac9b8 100644 --- a/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift @@ -137,4 +137,89 @@ final class SettingsFeatureCoreTests: XCTestCase { XCTAssertEqual(url, row.url) } } + + func test_didSaveUserSettings_onRideEventSettingsChange() async throws { + let didSaveUserSettings = ActorIsolated(false) + let testQueue = DispatchQueue.immediate + + let store = TestStore( + initialState: SettingsFeature.State( + userSettings: .init( + rideEventSettings: .init(eventDistance: .close) + ) + ), + reducer: SettingsFeature() + ) + store.dependencies.mainQueue = testQueue.eraseToAnyScheduler() + store.dependencies.fileClient.save = { @Sendable _, _ in + await didSaveUserSettings.setValue(true) + } + + // act + await store.send(.rideevent(.set(\.$eventSearchRadius, .far))) { + $0.rideEventSettings.eventSearchRadius = .far + } + + // assert + await didSaveUserSettings.withValue { val in + XCTAssertTrue(val, "Expected that save is invoked") + } + } + + func test_didSaveUserSettings_onAppearanceSettingsChange() async throws { + let didSaveUserSettings = ActorIsolated(false) + let testQueue = DispatchQueue.immediate + + let store = TestStore( + initialState: SettingsFeature.State( + userSettings: .init( + appearanceSettings: .init( + appIcon: .appIcon1, + colorScheme: .light + ) + ) + ), + reducer: SettingsFeature() + ) + store.dependencies.mainQueue = testQueue.eraseToAnyScheduler() + store.dependencies.fileClient.save = { @Sendable _, _ in + await didSaveUserSettings.setValue(true) + } + + // act + await store.send(.appearance(.set(\.$colorScheme, .dark))) { + $0.appearanceSettings.colorScheme = .dark + } + + // assert + await didSaveUserSettings.withValue { val in + XCTAssertTrue(val, "Expected that save is invoked") + } + } + + func test_didSaveUserSettings_onSettingsChange() async throws { + let didSaveUserSettings = ActorIsolated(false) + let testQueue = DispatchQueue.immediate + + let store = TestStore( + initialState: SettingsFeature.State( + userSettings: .init(enableObservationMode: false) + ), + reducer: SettingsFeature() + ) + store.dependencies.mainQueue = testQueue.eraseToAnyScheduler() + store.dependencies.fileClient.save = { @Sendable _, _ in + await didSaveUserSettings.setValue(true) + } + + // act + await store.send(.set(\.$isObservationModeEnabled, true)) { + $0.isObservationModeEnabled = true + } + + // assert + await didSaveUserSettings.withValue { val in + XCTAssertTrue(val, "Expected that save is invoked") + } + } } diff --git a/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsViewSnapshotTests.swift b/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsViewSnapshotTests.swift index cf5d672c..b59693cd 100644 --- a/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsViewSnapshotTests.swift +++ b/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsViewSnapshotTests.swift @@ -6,7 +6,7 @@ final class SettingsViewSnapshotTests: XCTestCase { func test_settingsView_light() { let settingsView = SettingsView( store: .init( - initialState: .init(), + initialState: .init(userSettings: .init()), reducer: SettingsFeature() ) )