diff --git a/CriticalMapsKit/Package.swift b/CriticalMapsKit/Package.swift index 68be2714..b5f8e239 100644 --- a/CriticalMapsKit/Package.swift +++ b/CriticalMapsKit/Package.swift @@ -375,9 +375,6 @@ package.targets.append(contentsOf: [ .testHelper, .tca, .product(name: "MastodonKit", package: "MastodonKit") - ], - exclude: [ - "__Snapshots__" ] ) ]) diff --git a/CriticalMapsKit/Sources/AppFeature/RideEventView.swift b/CriticalMapsKit/Sources/AppFeature/RideEventView.swift index aca8eac4..2e5f31ef 100644 --- a/CriticalMapsKit/Sources/AppFeature/RideEventView.swift +++ b/CriticalMapsKit/Sources/AppFeature/RideEventView.swift @@ -58,7 +58,7 @@ struct RideEventView: View { ), slug: nil, title: "CriticalMaps Berlin", - description: "Enim magna ea nostrud irure elit pariatur ea dolore in. Enim magna ea nostrud irure elit pariatur ea dolore in.Enim magna ea nostrud irure elit pariatur ea dolore in.Enim magna ea nostrud irure elit pariatur ea dolore in.", + description: "Enim magna ea nostrud irure elit pariatur ea dolore in. Enim magna ea nostrud irure elit pariatur ea dolore in.", dateTime: Date(timeIntervalSince1970: 1727905659), location: "Berlin", latitude: 53.1235, @@ -83,7 +83,7 @@ struct RideEventView: View { ), slug: nil, title: "CriticalMaps Berlin", - description: "Enim magna ea nostrud irure elit pariatur ea dolore in. Enim magna ea nostrud irure elit pariatur ea dolore in.Enim magna ea nostrud irure elit pariatur ea dolore in.Enim magna ea nostrud irure elit pariatur ea dolore in.", + description: "Enim magna ea nostrud irure elit pariatur ea dolore in. Enim magna ea nostrud irure elit pariatur ea dolore in.", dateTime: Date(timeIntervalSince1970: 1727905659), location: "Berlin", latitude: 53.1235, diff --git a/CriticalMapsKit/Sources/ChatFeature/ChatFeatureCore.swift b/CriticalMapsKit/Sources/ChatFeature/ChatFeatureCore.swift index b34a0e6c..5e85654f 100644 --- a/CriticalMapsKit/Sources/ChatFeature/ChatFeatureCore.swift +++ b/CriticalMapsKit/Sources/ChatFeature/ChatFeatureCore.swift @@ -118,8 +118,8 @@ public struct ChatFeature { state.chatInputState.isSending = false state.alert = AlertState( - title: TextState(L10n.error), - message: TextState("Failed to send chat message") + title: { TextState(L10n.error) }, + message: { TextState("Failed to send chat message") } ) logger.debug("ChatInput Action failed with error: \(error.localizedDescription)") diff --git a/CriticalMapsKit/Sources/FeedbackGeneratorClient/FeedbackGeneratorClient.swift b/CriticalMapsKit/Sources/FeedbackGeneratorClient/FeedbackGeneratorClient.swift index 4e7e1efa..d6d76fa7 100644 --- a/CriticalMapsKit/Sources/FeedbackGeneratorClient/FeedbackGeneratorClient.swift +++ b/CriticalMapsKit/Sources/FeedbackGeneratorClient/FeedbackGeneratorClient.swift @@ -13,8 +13,8 @@ extension FeedbackGeneratorClient: DependencyKey { public static let liveValue = { let generator = UISelectionFeedbackGenerator() return Self( - prepare: { await generator.prepare() }, - selectionChanged: { await generator.selectionChanged() } + prepare: { generator.prepare() }, + selectionChanged: { generator.selectionChanged() } ) }() } diff --git a/CriticalMapsKit/Sources/MapFeature/MapFeatureCore.swift b/CriticalMapsKit/Sources/MapFeature/MapFeatureCore.swift index 82b785ec..9f0972cb 100644 --- a/CriticalMapsKit/Sources/MapFeature/MapFeatureCore.swift +++ b/CriticalMapsKit/Sources/MapFeature/MapFeatureCore.swift @@ -124,9 +124,10 @@ public struct MapFeature { case .didChangeAuthorization(.denied): if state.isRequestingCurrentLocation { - state.alert = AlertState( - title: TextState("Location makes this app better. Please consider giving us access.") - ) + state.alert = AlertState { + TextState("Location makes this app better. Please consider giving us access.") + } + state.isRequestingCurrentLocation = false } return .none @@ -294,15 +295,17 @@ extension LocationManager { public extension AlertState where Action == MapFeature.Action { static let goToSettingsAlert = Self( - title: TextState(L10n.Location.Alert.provideAccessToLocationService), - primaryButton: .default(TextState(L10n.Settings.title)), - secondaryButton: .default(TextState(L10n.ok)) + title: { TextState(L10n.Location.Alert.provideAccessToLocationService) }, + actions: { + ButtonState { TextState(L10n.Settings.title) } + ButtonState { TextState(L10n.Settings.title) } + } ) - static let provideAuth = Self(title: TextState(L10n.Location.Alert.provideAuth)) - static let servicesOff = Self(title: TextState(L10n.Location.Alert.serviceIsOff)) + static let provideAuth = Self(title: {TextState(L10n.Location.Alert.provideAuth)}) + static let servicesOff = Self(title: {TextState(L10n.Location.Alert.serviceIsOff)}) static let provideAccessToLocationService = Self( - title: TextState(L10n.Location.Alert.provideAccessToLocationService) + title: {TextState(L10n.Location.Alert.provideAccessToLocationService)} ) } diff --git a/CriticalMapsKit/Sources/MapFeature/MapOverlayView.swift b/CriticalMapsKit/Sources/MapFeature/MapOverlayView.swift index b375f060..b1a5d847 100644 --- a/CriticalMapsKit/Sources/MapFeature/MapOverlayView.swift +++ b/CriticalMapsKit/Sources/MapFeature/MapOverlayView.swift @@ -74,14 +74,20 @@ public struct MapOverlayView: View where Content: View { } } ) - .transition(.scale.animation(reduceMotion ? nil : .easeOut(duration: 0.2))) - .onChange(of: viewStore.isExpanded, perform: { newValue in - let updateAction: () -> Void = { self.isExpanded = newValue } - reduceMotion ? updateAction() : withAnimation { updateAction() } - }) - .onChange(of: viewStore.isVisible, perform: { newValue in - let updateAction: () -> Void = { self.isVisible = newValue } - reduceMotion ? updateAction() : withAnimation { updateAction() } - }) + .transition(.scale.combined(with: .opacity).animation(reduceMotion ? nil : .spring(duration: 0.2))) + .onChange( + of: viewStore.isExpanded, + perform: { newValue in + let updateAction: () -> Void = { self.isExpanded = newValue } + reduceMotion ? updateAction() : withAnimation { updateAction() } + } + ) + .onChange( + of: viewStore.isVisible, + perform: { newValue in + let updateAction: () -> Void = { self.isVisible = newValue } + reduceMotion ? updateAction() : withAnimation { updateAction() } + } + ) } } diff --git a/CriticalMapsKit/Sources/MastodonFeedFeature/MastodonFeedView.swift b/CriticalMapsKit/Sources/MastodonFeedFeature/MastodonFeedView.swift index 9f4fcb01..d05242f7 100644 --- a/CriticalMapsKit/Sources/MastodonFeedFeature/MastodonFeedView.swift +++ b/CriticalMapsKit/Sources/MastodonFeedFeature/MastodonFeedView.swift @@ -24,7 +24,10 @@ public struct MastodonFeedView: View { public init(store: StoreOf) { self.store = store viewStore = ViewStore( - store.scope(state: MastodonFeedViewState.init, action: { $0 }), + store.scope( + state: MastodonFeedViewState.init, + action: { $0 } + ), observe: { $0 } ) } diff --git a/CriticalMapsKit/Sources/MastodonFeedFeature/TootFeedFeature.swift b/CriticalMapsKit/Sources/MastodonFeedFeature/TootFeedFeature.swift index 0fc0785a..492a9118 100644 --- a/CriticalMapsKit/Sources/MastodonFeedFeature/TootFeedFeature.swift +++ b/CriticalMapsKit/Sources/MastodonFeedFeature/TootFeedFeature.swift @@ -39,7 +39,7 @@ public struct TootFeedFeature { case refresh case fetchData case fetchDataResponse(TaskResult<[Status]>) - case toot(id: TootFeature.State.ID, action: TootFeature.Action) + case toot(IdentifiedActionOf) } @@ -90,13 +90,13 @@ public struct TootFeedFeature { return .none } } - .forEach(\.toots, action: /TootFeedFeature.Action.toot) { + .forEach(\.toots, action: \.toot) { TootFeature() } } } -extension MastodonKit.Status: Identifiable { +extension MastodonKit.Status: @retroactive Identifiable { public static func == (lhs: MastodonKit.Status, rhs: MastodonKit.Status) -> Bool { lhs.id == rhs.id } diff --git a/CriticalMapsKit/Sources/MastodonFeedFeature/TootsListView.swift b/CriticalMapsKit/Sources/MastodonFeedFeature/TootsListView.swift index 6ef9d44d..3f10a229 100644 --- a/CriticalMapsKit/Sources/MastodonFeedFeature/TootsListView.swift +++ b/CriticalMapsKit/Sources/MastodonFeedFeature/TootsListView.swift @@ -64,7 +64,7 @@ public struct TootsListView: View { ForEachStore( self.store.scope( state: \.toots, - action: TootFeedFeature.Action.toot + action: \.toot ) ) { TootView(store: $0) diff --git a/CriticalMapsKit/Sources/SettingsFeature/RideEventRadius.swift b/CriticalMapsKit/Sources/SettingsFeature/RideEventRadius.swift index 8853798b..2744b533 100644 --- a/CriticalMapsKit/Sources/SettingsFeature/RideEventRadius.swift +++ b/CriticalMapsKit/Sources/SettingsFeature/RideEventRadius.swift @@ -41,27 +41,31 @@ public struct RideEventRadiusView: View { let store: StoreOf public var body: some View { - WithViewStore(self.store, observe: { $0 }) { viewStore in - SettingsRow { - Button( - action: { viewStore.send(.set(\.$isSelected, true)) }, - label: { - HStack(spacing: .grid(3)) { - Text(String(viewStore.eventDistance.displayValue)) - .accessibility(label: Text(viewStore.eventDistance.displayValue)) - .padding(.vertical, .grid(2)) - Spacer() - if viewStore.isSelected { - Image(systemName: "checkmark.circle.fill") - .accessibilityRepresentation { - Text(L10n.A11y.General.selected) - } + WithViewStore( + self.store, + observe: { $0 }, + content: { viewStore in + SettingsRow { + Button( + action: { viewStore.send(.set(\.$isSelected, true)) }, + label: { + HStack(spacing: .grid(3)) { + Text(String(viewStore.eventDistance.displayValue)) + .accessibility(label: Text(viewStore.eventDistance.displayValue)) + .padding(.vertical, .grid(2)) + Spacer() + if viewStore.isSelected { + Image(systemName: "checkmark.circle.fill") + .accessibilityRepresentation { + Text(L10n.A11y.General.selected) + } + } } + .accessibilityElement(children: .combine) } - .accessibilityElement(children: .combine) - } - ) + ) + } } - } + ) } } diff --git a/CriticalMapsKit/Sources/SettingsFeature/RideEventSettingsView.swift b/CriticalMapsKit/Sources/SettingsFeature/RideEventSettingsView.swift index b7690a74..4a05e355 100644 --- a/CriticalMapsKit/Sources/SettingsFeature/RideEventSettingsView.swift +++ b/CriticalMapsKit/Sources/SettingsFeature/RideEventSettingsView.swift @@ -7,13 +7,10 @@ import SwiftUIHelpers /// A view to render next ride event settings public struct RideEventSettingsView: View { - public typealias State = RideEventsSettingsFeature.State - public typealias Action = RideEventsSettingsFeature.Action + private let store: StoreOf + @ObservedObject var viewStore: ViewStoreOf - let store: Store - @ObservedObject var viewStore: ViewStore - - public init(store: Store) { + public init(store: StoreOf) { self.store = store viewStore = ViewStore( store, diff --git a/CriticalMapsKit/Sources/SettingsFeature/RideEventType.swift b/CriticalMapsKit/Sources/SettingsFeature/RideEventType.swift index fcbf4165..4106ffb1 100644 --- a/CriticalMapsKit/Sources/SettingsFeature/RideEventType.swift +++ b/CriticalMapsKit/Sources/SettingsFeature/RideEventType.swift @@ -34,29 +34,33 @@ public struct RideEventTypeView: View { let store: StoreOf public var body: some View { - WithViewStore(self.store, observe: { $0 }) { viewStore in - SettingsRow { - Button( - action: { - viewStore.send( - .set(\.$isEnabled, !viewStore.state.isEnabled) - ) - }, - label: { - HStack(spacing: .grid(3)) { - Text(viewStore.rideType.title) - .padding(.vertical, .grid(2)) - Spacer() - if viewStore.isEnabled { - Image(systemName: "checkmark.circle.fill") - } else { - Image(systemName: "circle") + WithViewStore( + self.store, + observe: { $0 }, + content: { viewStore in + SettingsRow { + Button( + action: { + viewStore.send( + .set(\.$isEnabled, !viewStore.state.isEnabled) + ) + }, + label: { + HStack(spacing: .grid(3)) { + Text(viewStore.rideType.title) + .padding(.vertical, .grid(2)) + Spacer() + if viewStore.isEnabled { + Image(systemName: "checkmark.circle.fill") + } else { + Image(systemName: "circle") + } } } - } - ) + ) + } + .accessibilityValue(viewStore.isEnabled ? Text(L10n.A11y.General.selected) : Text("")) } - .accessibilityValue(viewStore.isEnabled ? Text(L10n.A11y.General.selected) : Text("")) - } + ) } } diff --git a/CriticalMapsKit/Sources/UIApplicationClient/Live.swift b/CriticalMapsKit/Sources/UIApplicationClient/Live.swift index 4f6ce530..e0a0d665 100644 --- a/CriticalMapsKit/Sources/UIApplicationClient/Live.swift +++ b/CriticalMapsKit/Sources/UIApplicationClient/Live.swift @@ -6,11 +6,11 @@ import UIKit.UIApplication extension UIApplicationClient: DependencyKey { public static let liveValue = Self( alternateIconName: { UIApplication.shared.alternateIconName }, - alternateIconNameAsync: { await UIApplication.shared.alternateIconName }, + alternateIconNameAsync: { UIApplication.shared.alternateIconName }, open: { @MainActor in await UIApplication.shared.open($0, options: $1) }, - openSettingsURLString: { await UIApplication.openSettingsURLString }, + openSettingsURLString: { UIApplication.openSettingsURLString }, setAlternateIconName: { @MainActor in try await UIApplication.shared.setAlternateIconName($0) }, supportsAlternateIcons: { UIApplication.shared.supportsAlternateIcons }, - supportsAlternateIconsAsync: { await UIApplication.shared.supportsAlternateIcons } + supportsAlternateIconsAsync: { UIApplication.shared.supportsAlternateIcons } ) } diff --git a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift index 48e6e8d9..d83c9fd7 100644 --- a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift @@ -377,7 +377,7 @@ final class AppFeatureTests: XCTestCase { @MainActor func test_updatingRideEventSettingRadius_ShouldRefetchNextRideInfo() async throws { - let updatedRaduis = ActorIsolated(0) + let updatedRaduis = LockIsolated(0) let testQueue = DispatchQueue.test var state = AppFeature.State() @@ -393,7 +393,7 @@ final class AppFeatureTests: XCTestCase { $0.date = .init({ @Sendable in self.date() }) $0.mainQueue = testQueue.eraseToAnyScheduler() $0.nextRideService.nextRide = { _, radius, _ in - await updatedRaduis.setValue(radius) + updatedRaduis.setValue(radius) return [Ride(id: 123, title: "Test", dateTime: self.date(), enabled: true)] } $0.continuousClock = TestClock() @@ -408,14 +408,14 @@ final class AppFeatureTests: XCTestCase { await testQueue.advance(by: 2) await store.receive(.nextRide(.getNextRide(location.coordinate))) - await updatedRaduis.withValue { radius in + updatedRaduis.withValue { radius in XCTAssertEqual(radius, EventDistance.far.rawValue) } } @MainActor func test_viewingModePrompt() async throws { - let didSetDidShowPrompt = ActorIsolated(false) + let didSetDidShowPrompt = LockIsolated(false) let testQueue = DispatchQueue.test @@ -425,7 +425,7 @@ final class AppFeatureTests: XCTestCase { withDependencies: { $0.mainQueue = testQueue.eraseToAnyScheduler() $0.userDefaultsClient.setBool = { _, _ in - await didSetDidShowPrompt.setValue(true) + didSetDidShowPrompt.setValue(true) return () } $0.continuousClock = TestClock() @@ -434,7 +434,7 @@ final class AppFeatureTests: XCTestCase { await store.send(.alert(.presented(.observationMode(enabled: false)))) - await didSetDidShowPrompt.withValue { val in + didSetDidShowPrompt.withValue { val in XCTAssertTrue(val) } } @@ -457,14 +457,14 @@ final class AppFeatureTests: XCTestCase { @MainActor func test_bindingObservationStatus_shouldStopLocationUpdating() async { - let didStopLocationUpdating = ActorIsolated(false) + let didStopLocationUpdating = LockIsolated(false) let store = TestStore( initialState: AppFeature.State(), reducer: { AppFeature() }, withDependencies: { $0.locationManager.stopUpdatingLocation = { - await didStopLocationUpdating.setValue(true) + didStopLocationUpdating.setValue(true) } $0.continuousClock = TestClock() } @@ -477,20 +477,20 @@ final class AppFeatureTests: XCTestCase { $0.settingsState.isObservationModeEnabled = true } // assert - let didStopLocationObservationValue = await didStopLocationUpdating.value + let didStopLocationObservationValue = didStopLocationUpdating.value XCTAssertTrue(didStopLocationObservationValue) } @MainActor func test_bindingObservationStatus_shouldStartLocationUpdating() async { - let didStopLocationUpdating = ActorIsolated(false) + let didStopLocationUpdating = LockIsolated(false) let store = TestStore( initialState: AppFeature.State(), reducer: { AppFeature() }, withDependencies: { $0.locationManager.startUpdatingLocation = { - await didStopLocationUpdating.setValue(true) + didStopLocationUpdating.setValue(true) } $0.continuousClock = TestClock() } @@ -503,12 +503,13 @@ final class AppFeatureTests: XCTestCase { $0.settingsState.isObservationModeEnabled = false } // assert - let didStopLocationObservationValue = await didStopLocationUpdating.value + let didStopLocationObservationValue = didStopLocationUpdating.value XCTAssertTrue(didStopLocationObservationValue) } + @MainActor func test_didTapNextEventBanner() async { - let store = await TestStore( + let store = TestStore( initialState: AppFeature.State(nextRideState: NextRideFeature.State(nextRide: Ride.mock1)), reducer: { AppFeature() }, withDependencies: { diff --git a/CriticalMapsKit/Tests/AppFeatureTests/AppNavigationViewSnapshotTests.swift b/CriticalMapsKit/Tests/AppFeatureTests/AppNavigationViewSnapshotTests.swift index 4067c0b8..cbff79d6 100644 --- a/CriticalMapsKit/Tests/AppFeatureTests/AppNavigationViewSnapshotTests.swift +++ b/CriticalMapsKit/Tests/AppFeatureTests/AppNavigationViewSnapshotTests.swift @@ -22,7 +22,7 @@ final class AppNavigationViewSnapshotTests: XCTestCase { withSnapshotTesting(diffTool: .ksdiff) { assertSnapshots( - matching: view, + of: view, as: [ .image(precision: 0.9, layout: .device(config: .iPhoneX)) ], diff --git a/CriticalMapsKit/Tests/ChatFeatureTests/ChatFeatureCoreTests.swift b/CriticalMapsKit/Tests/ChatFeatureTests/ChatFeatureCoreTests.swift index e038b669..8677967b 100644 --- a/CriticalMapsKit/Tests/ChatFeatureTests/ChatFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/ChatFeatureTests/ChatFeatureCoreTests.swift @@ -96,16 +96,16 @@ final class ChatFeatureCore: XCTestCase { await testStore.receive(.chatInputResponse(.failure(error))) { state in state.chatInputState.isSending = false state.alert = .init( - title: .init(L10n.error), - message: .init("Failed to send chat message") + title: { .init(L10n.error) }, + message: { .init("Failed to send chat message") } ) } } @MainActor func test_didAppear_ShouldSet_appearanceTimeinterval() async { - let didWriteChatAppearanceTimeinterval = ActorIsolated(false) - let chatAppearanceTimeinterval: ActorIsolated = ActorIsolated(0) + let didWriteChatAppearanceTimeinterval = LockIsolated(false) + let chatAppearanceTimeinterval: LockIsolated = LockIsolated(0) let testStore = TestStore( initialState: ChatFeature.State(), @@ -113,8 +113,8 @@ final class ChatFeatureCore: XCTestCase { ) testStore.dependencies.apiService.getChatMessages = { mockResponse } testStore.dependencies.userDefaultsClient.setDouble = { interval, _ in - await didWriteChatAppearanceTimeinterval.setValue(true) - await chatAppearanceTimeinterval.setValue(interval) + didWriteChatAppearanceTimeinterval.setValue(true) + chatAppearanceTimeinterval.setValue(interval) return () } testStore.dependencies.uuid = .constant(uuid()) @@ -125,10 +125,10 @@ final class ChatFeatureCore: XCTestCase { await testStore.receive(.fetchChatMessagesResponse(.success(mockResponse))) { $0.chatMessages = .results(mockResponse) } - await chatAppearanceTimeinterval.withValue { interval in + chatAppearanceTimeinterval.withValue { interval in XCTAssertEqual(interval, date().timeIntervalSince1970) } - await didWriteChatAppearanceTimeinterval.withValue { val in + didWriteChatAppearanceTimeinterval.withValue { val in XCTAssertTrue(val) } } diff --git a/CriticalMapsKit/Tests/MapFeatureTests/MapFeatureCoreTests.swift b/CriticalMapsKit/Tests/MapFeatureTests/MapFeatureCoreTests.swift index b218141d..4b970e52 100644 --- a/CriticalMapsKit/Tests/MapFeatureTests/MapFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/MapFeatureTests/MapFeatureCoreTests.swift @@ -11,8 +11,8 @@ final class MapFeatureCoreTests: XCTestCase { @MainActor func test_onAppearAction() async { - let didRequestAlwaysAuthorization = ActorIsolated(false) - let didRequestLocation = ActorIsolated(false) + let didRequestAlwaysAuthorization = LockIsolated(false) + let didRequestLocation = LockIsolated(false) let locationObserver = AsyncStream.makeStream() var locationManager = LocationManager.failing @@ -21,10 +21,10 @@ final class MapFeatureCoreTests: XCTestCase { locationManager.authorizationStatus = { .notDetermined } locationManager.locationServicesEnabled = { true } locationManager.requestAlwaysAuthorization = { - await didRequestAlwaysAuthorization.setValue(true) + didRequestAlwaysAuthorization.setValue(true) } locationManager.requestLocation = { - await didRequestLocation.setValue(true) + didRequestLocation.setValue(true) } let store = TestStore( @@ -54,15 +54,14 @@ final class MapFeatureCoreTests: XCTestCase { await store.send(.onAppear) // simulate user decision of segmented control await store.receive(.locationRequested) - let didRequestAlwaysAuthorizationValue = await didRequestAlwaysAuthorization.value + let didRequestAlwaysAuthorizationValue = didRequestAlwaysAuthorization.value XCTAssertTrue(didRequestAlwaysAuthorizationValue) // Simulate being given authorized to access location locationObserver.continuation.yield(.didChangeAuthorization(.authorizedAlways)) await store.receive(.locationManager(.didChangeAuthorization(.authorizedAlways))) - let didRequestLocationValue = await - didRequestLocation.value + let didRequestLocationValue = didRequestLocation.value XCTAssertTrue(didRequestLocationValue) // Simulate finding the user's current location @@ -116,7 +115,7 @@ final class MapFeatureCoreTests: XCTestCase { @MainActor func test_deniedPermission_shouldSetAlert() async { - let didRequestAlwaysAuthorization = ActorIsolated(false) + let didRequestAlwaysAuthorization = LockIsolated(false) let locationObserver = AsyncStream.makeStream() var locationManager: LocationManager = .failing @@ -124,7 +123,7 @@ final class MapFeatureCoreTests: XCTestCase { locationManager.authorizationStatus = { .notDetermined } locationManager.locationServicesEnabled = { true } locationManager.requestAlwaysAuthorization = { - await didRequestAlwaysAuthorization.setValue(true) + didRequestAlwaysAuthorization.setValue(true) } locationManager.set = { @Sendable _ in } @@ -144,13 +143,13 @@ final class MapFeatureCoreTests: XCTestCase { await store.send(.onAppear) // simulate user decision of segmented control await store.receive(.locationRequested) - let didRequestAlwaysAuthorizationValue = await didRequestAlwaysAuthorization.value + let didRequestAlwaysAuthorizationValue = didRequestAlwaysAuthorization.value XCTAssertTrue(didRequestAlwaysAuthorizationValue) // Simulate being given authorized to access location locationObserver.continuation.yield(.didChangeAuthorization(.denied)) await store.receive(.locationManager(.didChangeAuthorization(.denied))) { $0.alert = AlertState( - title: TextState("Location makes this app better. Please consider giving us access.") + title: { TextState("Location makes this app better. Please consider giving us access.") } ) $0.isRequestingCurrentLocation = false } diff --git a/CriticalMapsKit/Tests/MastodonFeedFeatureTests/TootFeatureTests.swift b/CriticalMapsKit/Tests/MastodonFeedFeatureTests/TootFeatureTests.swift index b91d8f65..2e0cc38e 100644 --- a/CriticalMapsKit/Tests/MastodonFeedFeatureTests/TootFeatureTests.swift +++ b/CriticalMapsKit/Tests/MastodonFeedFeatureTests/TootFeatureTests.swift @@ -52,40 +52,40 @@ final class TootFeatureTests: XCTestCase { @MainActor func test_openTweet() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: status, reducer: { TootFeature() } ) store.dependencies.uiApplicationClient.open = { @Sendable url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } await store.send(.openTweet) - await openedUrl.withValue { + openedUrl.withValue { XCTAssertEqual($0?.absoluteString, "https://mastodon.social/@criticalmaps") } } @MainActor func test_openUser() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: status, reducer: { TootFeature() } ) store.dependencies.uiApplicationClient.open = { @Sendable url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } await store.send(.openUser) - await openedUrl.withValue { + openedUrl.withValue { XCTAssertEqual($0?.absoluteString, "https://mastodon.social/account") } } diff --git a/CriticalMapsKit/Tests/SettingsFeatureTests/AppearanceSettingsCoreTests.swift b/CriticalMapsKit/Tests/SettingsFeatureTests/AppearanceSettingsCoreTests.swift index 2172b4a1..9457e7e8 100644 --- a/CriticalMapsKit/Tests/SettingsFeatureTests/AppearanceSettingsCoreTests.swift +++ b/CriticalMapsKit/Tests/SettingsFeatureTests/AppearanceSettingsCoreTests.swift @@ -8,47 +8,47 @@ final class AppearanceSettingsCoreTests: XCTestCase { @MainActor func test_selectAppIcon_shouldUpdateState() async { - let overriddenIconName = ActorIsolated(nil) + let overriddenIconName = LockIsolated(nil) let store = TestStore( initialState: AppearanceSettings(), reducer: { AppearanceSettingsFeature() } ) store.dependencies.uiApplicationClient.setAlternateIconName = { newValue in - await overriddenIconName.setValue(newValue) + overriddenIconName.setValue(newValue) } await store.send(.set(\.$appIcon, .appIcon4)) { state in state.appIcon = .appIcon4 } - await overriddenIconName.withValue { iconName in + overriddenIconName.withValue { iconName in expectNoDifference(iconName, "appIcon-4") } } @MainActor func testSetColorScheme() async { - let overriddenUserInterfaceStyle = ActorIsolated(UIUserInterfaceStyle.unspecified) + let overriddenUserInterfaceStyle = LockIsolated(UIUserInterfaceStyle.unspecified) let store = TestStore( initialState: AppearanceSettings(), reducer: { AppearanceSettingsFeature() } ) store.dependencies.setUserInterfaceStyle = { newValue in - await overriddenUserInterfaceStyle.setValue(newValue) + overriddenUserInterfaceStyle.setValue(newValue) return () } await store.send(.set(\.$colorScheme, .light)) { $0.colorScheme = .light } - await overriddenUserInterfaceStyle.withValue { stlye in + overriddenUserInterfaceStyle.withValue { stlye in expectNoDifference(stlye, .light) } await store.send(.set(\.$colorScheme, .system)) { $0.colorScheme = .system } - await overriddenUserInterfaceStyle.withValue { stlye in + overriddenUserInterfaceStyle.withValue { stlye in expectNoDifference(stlye, .unspecified) } } diff --git a/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift b/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift index e7a80933..d9c684e8 100644 --- a/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/SettingsFeatureTests/SettingsFeatureCoreTests.swift @@ -8,14 +8,14 @@ final class SettingsFeatureCoreTests: XCTestCase { @MainActor func test_openURLAction_shouldCallUIApplicationClient_privacy() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: SettingsFeature.State(), reducer: { SettingsFeature() } ) store.dependencies.uiApplicationClient.open = { url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } @@ -24,21 +24,21 @@ final class SettingsFeatureCoreTests: XCTestCase { await store.send(.infoSectionRowTapped(row)) await store.receive(.openURL(row.url)) - await openedUrl.withValue { url in + openedUrl.withValue { url in XCTAssertEqual(url, row.url) } } @MainActor func test_openURLAction_shouldCallUIApplicationClient_cmWebsite() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: SettingsFeature.State(), reducer: { SettingsFeature() } ) store.dependencies.uiApplicationClient.open = { url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } @@ -47,21 +47,21 @@ final class SettingsFeatureCoreTests: XCTestCase { await store.send(.infoSectionRowTapped(row)) await store.receive(.openURL(row.url)) - await openedUrl.withValue { url in + openedUrl.withValue { url in XCTAssertEqual(url, row.url) } } @MainActor func test_openURLAction_shouldCallUIApplicationClient_cmMastodon() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: SettingsFeature.State(), reducer: { SettingsFeature() } ) store.dependencies.uiApplicationClient.open = { url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } @@ -70,21 +70,21 @@ final class SettingsFeatureCoreTests: XCTestCase { await store.send(.infoSectionRowTapped(row)) await store.receive(.openURL(row.url)) - await openedUrl.withValue { url in + openedUrl.withValue { url in XCTAssertEqual(url, row.url) } } @MainActor func test_openURLAction_shouldCallUIApplicationClient_github() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: SettingsFeature.State(), reducer: { SettingsFeature() } ) store.dependencies.uiApplicationClient.open = { url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } @@ -93,21 +93,21 @@ final class SettingsFeatureCoreTests: XCTestCase { await store.send(.supportSectionRowTapped(row)) await store.receive(.openURL(row.url)) - await openedUrl.withValue { url in + openedUrl.withValue { url in XCTAssertEqual(url, row.url) } } @MainActor func test_openURLAction_shouldCallUIApplicationClient_crowdin() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: SettingsFeature.State(), reducer: { SettingsFeature() } ) store.dependencies.uiApplicationClient.open = { url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } @@ -116,21 +116,21 @@ final class SettingsFeatureCoreTests: XCTestCase { await store.send(.supportSectionRowTapped(row)) await store.receive(.openURL(row.url)) - await openedUrl.withValue { url in + openedUrl.withValue { url in XCTAssertEqual(url, row.url) } } @MainActor func test_openURLAction_shouldCallUIApplicationClient_criticalMassDotIn() async { - let openedUrl = ActorIsolated(nil) + let openedUrl = LockIsolated(nil) let store = TestStore( initialState: SettingsFeature.State(), reducer: { SettingsFeature() } ) store.dependencies.uiApplicationClient.open = { url, _ in - await openedUrl.setValue(url) + openedUrl.setValue(url) return true } @@ -139,14 +139,14 @@ final class SettingsFeatureCoreTests: XCTestCase { await store.send(.supportSectionRowTapped(row)) await store.receive(.openURL(row.url)) - await openedUrl.withValue { url in + openedUrl.withValue { url in XCTAssertEqual(url, row.url) } } @MainActor func test_didSaveUserSettings_onRideEventSettingsChange() async throws { - let didSaveUserSettings = ActorIsolated(false) + let didSaveUserSettings = LockIsolated(false) let testQueue = DispatchQueue.immediate let testClock = TestClock() @@ -161,7 +161,7 @@ final class SettingsFeatureCoreTests: XCTestCase { $0.continuousClock = testClock $0.mainQueue = testQueue.eraseToAnyScheduler() $0.fileClient.save = { @Sendable _, _ in - await didSaveUserSettings.setValue(true) + didSaveUserSettings.setValue(true) } $0.observationModeStore.setObservationModeState = { _ in } } @@ -174,14 +174,14 @@ final class SettingsFeatureCoreTests: XCTestCase { await testClock.advance(by: .seconds(2)) // assert - await didSaveUserSettings.withValue { val in + didSaveUserSettings.withValue { val in XCTAssertTrue(val, "Expected that save is invoked") } } @MainActor func test_didSaveUserSettings_onAppearanceSettingsChange() async throws { - let didSaveUserSettings = ActorIsolated(false) + let didSaveUserSettings = LockIsolated(false) let store = TestStore( initialState: SettingsFeature.State( @@ -198,9 +198,9 @@ final class SettingsFeatureCoreTests: XCTestCase { store.dependencies.continuousClock = testClock store.dependencies.mainQueue = .immediate store.dependencies.fileClient.save = { @Sendable _, _ in - await didSaveUserSettings.setValue(true) + didSaveUserSettings.setValue(true) } - store.dependencies.observationModeStore.setObservationModeState = { _ in } + store.dependencies.observationModeStore.setObservationModeState = { @Sendable _ in } // act await store.send(.appearance(.set(\.$colorScheme, .dark))) { @@ -209,7 +209,7 @@ final class SettingsFeatureCoreTests: XCTestCase { await testClock.advance(by: .seconds(2)) // assert - await didSaveUserSettings.withValue { val in + didSaveUserSettings.withValue { val in XCTAssertTrue(val, "Expected that save is invoked") } await store.finish() @@ -217,7 +217,7 @@ final class SettingsFeatureCoreTests: XCTestCase { @MainActor func test_didSaveUserSettings_onSettingsChange() async throws { - let didSaveUserSettings = ActorIsolated(false) + let didSaveUserSettings = LockIsolated(false) let testQueue = DispatchQueue.immediate let store = TestStore( @@ -228,11 +228,11 @@ final class SettingsFeatureCoreTests: XCTestCase { ) store.dependencies.mainQueue = testQueue.eraseToAnyScheduler() store.dependencies.fileClient.save = { @Sendable _, _ in - await didSaveUserSettings.setValue(true) + didSaveUserSettings.setValue(true) } let testClock = TestClock() store.dependencies.continuousClock = testClock - store.dependencies.observationModeStore.setObservationModeState = { _ in } + store.dependencies.observationModeStore.setObservationModeState = { @Sendable _ in } // act await store.send(.set(\.$isObservationModeEnabled, true)) { @@ -241,7 +241,7 @@ final class SettingsFeatureCoreTests: XCTestCase { // assert await testClock.advance(by: .seconds(2)) - await didSaveUserSettings.withValue { val in + didSaveUserSettings.withValue { val in XCTAssertTrue(val, "Expected that save is invoked") } }