diff --git a/.github/workflows/swift-tests.yaml b/.github/workflows/swift-tests.yaml index 8e1d00d..846fadb 100644 --- a/.github/workflows/swift-tests.yaml +++ b/.github/workflows/swift-tests.yaml @@ -9,8 +9,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Select Xcode 26.0 - run: sudo xcode-select -s /Applications/Xcode_26.app/Contents/Developer + - name: Select Xcode 26.0.1 + run: sudo xcode-select -s /Applications/Xcode_26.0.1.app/Contents/Developer - name: Build run: swift build -v - name: Run tests diff --git a/README.md b/README.md index ab40b97..0415536 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ A Swift package that provides elegant state management for asynchronous operatio AsyncLoad provides components for handling asynchronous operations: - `AsyncLoad`: For loading data operations -- `AsyncAction`: For action-based operations - `CachedAsyncLoad`: For loading operations that preserve cached data during refreshes -- `CachedAsyncAction`: For actions that preserve cached data during retries - `AsyncLoadView`: A SwiftUI view component for displaying async states - `CachedAsyncLoadView`: A SwiftUI view component for cached async states @@ -44,7 +42,7 @@ Or add it through Xcode: An enum that represents the state of an asynchronous data loading operation. ```swift -public enum AsyncLoad: Equatable { +public enum AsyncLoad: Equatable, Sendable { case none // Initial state case loading // Loading in progress case error(Error)// Loading failed with error @@ -52,6 +50,8 @@ public enum AsyncLoad: Equatable { } ``` +> **Note**: The generic type `T` must conform to both `Equatable` and `Sendable` protocols. + #### Properties - `isLoading: Bool` - Returns true if the state is `.loading` @@ -80,53 +80,12 @@ class DataViewModel { } ``` -### AsyncAction - -Similar to AsyncLoad but designed for action-based operations (like posting data, submitting forms, etc.). - -```swift -public enum AsyncAction: Equatable { - case none // Initial state - case loading // Action in progress - case error(Error) // Action failed with error - case success(T) // Action completed successfully -} -``` - -#### Properties - -- `isLoading: Bool` - Returns true if the state is `.loading` -- `item: T?` - Returns the success result if state is `.success`, nil otherwise -- `error: Error?` - Returns the error if state is `.error`, nil otherwise - -#### Example Usage - -```swift -import AsyncLoad - -@Observable -class FormViewModel { - var submitAction: AsyncAction = .none - - func submitForm(data: FormData) async { - submitAction = .loading - - do { - let response = try await apiService.submit(data) - submitAction = .success(response) - } catch { - submitAction = .error(error) - } - } -} -``` - ### CachedAsyncLoad An enhanced version of AsyncLoad that preserves cached data during loading and error states. ```swift -public enum CachedAsyncLoad: Equatable { +public enum CachedAsyncLoad: Equatable, Sendable { case none // Initial state case loading(T? = nil) // Loading with optional cached data case error(T? = nil, Error) // Error with optional cached data @@ -134,10 +93,12 @@ public enum CachedAsyncLoad: Equatable { } ``` +> **Note**: The generic type `T` must conform to both `Equatable` and `Sendable` protocols. + #### Properties - `isLoading: Bool` - Returns true if the state is `.loading` -- `item: T?` - Returns the loaded item if state is `.loaded`, nil otherwise +- `item: T?` - Returns the item from `.loaded`, `.loading`, or `.error` states, nil for `.none` - `error: Error?` - Returns the error if state is `.error`, nil otherwise #### Example Usage @@ -169,53 +130,6 @@ class CachedDataViewModel { } ``` -### CachedAsyncAction - -Similar to AsyncAction but preserves cached data during loading and error states. - -```swift -public enum CachedAsyncAction: Equatable { - case none // Initial state - case loading(T? = nil) // Action in progress with optional cached data - case error(T? = nil, Error) // Action failed with optional cached data - case success(T) // Action completed successfully -} -``` - -#### Properties - -- `isLoading: Bool` - Returns true if the state is `.loading` -- `item: T?` - Returns the success result if state is `.success`, nil otherwise -- `error: Error?` - Returns the error if state is `.error`, nil otherwise - -#### Example Usage - -```swift -import AsyncLoad - -@Observable -class CachedFormViewModel { - var submitAction: CachedAsyncAction = .none - - func submitForm(data: FormData) async { - // Preserve previous successful response during retry - if case .success(let previousResponse) = submitAction { - submitAction = .loading(previousResponse) - } else { - submitAction = .loading() - } - - do { - let response = try await apiService.submit(data) - submitAction = .success(response) - } catch { - let previousResponse = submitAction.item - submitAction = .error(previousResponse, error) - } - } -} -``` - ### AsyncLoadView A SwiftUI view component that automatically handles the display of different async states. @@ -236,7 +150,7 @@ public init( // With default error content (Text) public init( - _ state: AsyncLoad, + _ state: AsyncLoad, @ViewBuilder content: @escaping (Item?) -> Content ) where ErrorContent == Text ``` @@ -249,7 +163,7 @@ import AsyncLoad struct UserProfileView: View { @State private var viewModel = UserProfileViewModel() - + var body: some View { AsyncLoadView(viewModel.userProfile) { user in if let user = user { @@ -277,22 +191,96 @@ struct UserProfileView: View { } ``` +### CachedAsyncLoadView + +A SwiftUI view component that handles cached async states with separate loading content. + +```swift +public struct CachedAsyncLoadView: View +``` + +#### Initializer + +```swift +public init( + _ state: CachedAsyncLoad, + @ViewBuilder content: @escaping (Item) -> Content, + @ViewBuilder loading: @escaping (Item?) -> LoadingContent, + @ViewBuilder error: @escaping (Item?, Error) -> ErrorContent +) +``` + +#### Example Usage + +```swift +import SwiftUI +import AsyncLoad + +struct CachedUserProfileView: View { + @State private var viewModel = CachedUserProfileViewModel() + + var body: some View { + CachedAsyncLoadView(viewModel.userProfile) { user in + // Content view - only called when data is loaded + VStack(alignment: .leading) { + Text(user.name) + .font(.title) + Text(user.email) + .foregroundStyle(.secondary) + } + } loading: { cachedUser in + // Loading view - receives cached data if available + VStack { + if let cachedUser { + VStack(alignment: .leading) { + Text(cachedUser.name) + .font(.title) + Text(cachedUser.email) + .foregroundStyle(.secondary) + } + .opacity(0.5) + } + ProgressView() + } + } error: { cachedUser, error in + // Error view - receives cached data if available + VStack { + if let cachedUser { + VStack(alignment: .leading) { + Text(cachedUser.name) + .font(.title) + Text(cachedUser.email) + .foregroundStyle(.secondary) + } + .opacity(0.5) + } + Text("Error: \(error.localizedDescription)") + .foregroundColor(.red) + } + } + .task { + await viewModel.loadUserProfile(id: "123") + } + } +} +``` + ## Features - **Type-safe**: Generic enums ensure type safety for your data -- **Equatable**: All async state enums conform to Equatable for easy state comparison +- **Equatable**: All async state enums and their generic types conform to Equatable for easy state comparison +- **Sendable**: Full Swift 6 concurrency support with Sendable conformance for thread-safe async operations - **SwiftUI Integration**: AsyncLoadView and CachedAsyncLoadView provide seamless integration with SwiftUI - **Error Handling**: Built-in error state management - **Loading States**: Automatic loading state handling with progress indicators -- **Cached Data**: CachedAsyncLoad and CachedAsyncAction preserve data during refreshes and errors +- **Cached Data**: CachedAsyncLoad preserves data during refreshes and errors - **Flexible UI**: Customizable content and error views ## Best Practices -1. **Use AsyncLoad for data fetching** operations (GET requests, loading content) -2. **Use AsyncAction for user actions** (POST/PUT/DELETE requests, form submissions) -3. **Use CachedAsyncLoad** when you want to preserve data during refreshes or show stale data during errors -4. **Use CachedAsyncAction** when you want to preserve previous results during action retries -5. **Always handle all states** in your UI to provide good user experience -6. **Use AsyncLoadView and CachedAsyncLoadView** for simple cases to reduce boilerplate code -7. **Reset states** appropriately (e.g., set to `.none` when appropriate) +1. **Use AsyncLoad for simple loading operations** where you don't need to preserve data during refreshes +2. **Use CachedAsyncLoad** when you want to preserve data during refreshes or show stale data during errors +3. **Ensure your data types conform to Equatable and Sendable** - All generic types used with AsyncLoad components must implement both protocols +4. **Always handle all states** in your UI to provide good user experience +5. **Use AsyncLoadView and CachedAsyncLoadView** for simple cases to reduce boilerplate code +6. **Reset states** appropriately (e.g., set to `.none` when appropriate) diff --git a/Sources/AsyncLoad/AsyncLoad/AsyncAction.swift b/Sources/AsyncLoad/AsyncLoad/AsyncAction.swift deleted file mode 100644 index 215b3d8..0000000 --- a/Sources/AsyncLoad/AsyncLoad/AsyncAction.swift +++ /dev/null @@ -1,78 +0,0 @@ -import Foundation - -public enum AsyncAction: Equatable, Sendable { - case none - case loading - case error(Error) - case success(T) - - public var isLoading: Bool { - if case .loading = self { - return true - } - return false - } - - public var item: T? { - switch self { - case let .success(item): - item - default: - nil - } - } - - public var error: Error? { - switch self { - case let .error(error): - error - default: - nil - } - } - - public static func == (lhs: AsyncAction, rhs: AsyncAction) -> Bool { - switch (lhs, rhs) { - case (.none, .none): - true - case (.loading, .loading): - true - case (.error, .error): - true - case (.success, .success): - true - default: - false - } - } - - public static func == (lhs: AsyncAction, rhs: AsyncAction) -> Bool where T : Equatable { - switch (lhs, rhs) { - case (.none, .none): - true - case (.loading, .loading): - true - case (.error, .error): - true - case let (.success(lhsItem), .success(rhsItem)): - lhsItem == rhsItem - default: - false - } - } - - public static func != (lhs: AsyncAction, rhs: AsyncAction) -> Bool where T : Equatable { - switch (lhs, rhs) { - case (.none, .none): - false - case (.loading, .loading): - false - case (.error, .error): - false - case let (.success(lhsItem), .success(rhsItem)): - lhsItem != rhsItem - default: - true - } - } -} diff --git a/Sources/AsyncLoad/AsyncLoad/AsyncLoad.swift b/Sources/AsyncLoad/AsyncLoad/AsyncLoad.swift index 2fb48f9..fb69334 100644 --- a/Sources/AsyncLoad/AsyncLoad/AsyncLoad.swift +++ b/Sources/AsyncLoad/AsyncLoad/AsyncLoad.swift @@ -1,18 +1,18 @@ import Foundation -public enum AsyncLoad: Equatable, Sendable { +public enum AsyncLoad: Equatable, Sendable { case none case loading case error(Error) case loaded(T) - + public var isLoading: Bool { if case .loading = self { return true } return false } - + public var item: T? { switch self { case let .loaded(item): @@ -21,7 +21,7 @@ public enum AsyncLoad: Equatable, Sendable { nil } } - + public var error: Error? { switch self { case let .error(error): @@ -31,21 +31,6 @@ public enum AsyncLoad: Equatable, Sendable { } } - public static func == (lhs: AsyncLoad, rhs: AsyncLoad) -> Bool { - switch (lhs, rhs) { - case (.none, .none): - true - case (.loading, .loading): - true - case (.error, .error): - true - case (.loaded, .loaded): - true - default: - false - } - } - public static func == (lhs: AsyncLoad, rhs: AsyncLoad) -> Bool where T : Equatable { switch (lhs, rhs) { case (.none, .none): @@ -60,19 +45,4 @@ public enum AsyncLoad: Equatable, Sendable { false } } - - public static func != (lhs: AsyncLoad, rhs: AsyncLoad) -> Bool where T : Equatable { - switch (lhs, rhs) { - case (.none, .none): - false - case (.loading, .loading): - false - case (.error, .error): - false - case let (.loaded(rhsItem), .loaded(lhsItem)): - lhsItem != rhsItem - default: - true - } - } } diff --git a/Sources/AsyncLoad/AsyncLoad/AsyncLoadView.swift b/Sources/AsyncLoad/AsyncLoad/AsyncLoadView.swift index 709e27b..9d13e70 100644 --- a/Sources/AsyncLoad/AsyncLoad/AsyncLoadView.swift +++ b/Sources/AsyncLoad/AsyncLoad/AsyncLoadView.swift @@ -3,7 +3,7 @@ import Foundation import SwiftUI public struct AsyncLoadView< - Item: Sendable, + Item: Equatable & Sendable, Content: View, ErrorContent: View >: View { diff --git a/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncAction.swift b/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncAction.swift deleted file mode 100644 index 162cc58..0000000 --- a/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncAction.swift +++ /dev/null @@ -1,78 +0,0 @@ -import Foundation - -public enum CachedAsyncAction: Equatable, Sendable { - case none - case loading(T? = nil) - case error(T? = nil, Error) - case success(T) - - public var isLoading: Bool { - if case .loading = self { - return true - } - return false - } - - public var item: T? { - switch self { - case let .success(item): - item - default: - nil - } - } - - public var error: Error? { - switch self { - case let .error(_, error): - error - default: - nil - } - } - - public static func == (lhs: CachedAsyncAction, rhs: CachedAsyncAction) -> Bool { - switch (lhs, rhs) { - case (.none, .none): - true - case (.loading, .loading): - true - case (.error, .error): - true - case (.success, .success): - true - default: - false - } - } - - public static func == (lhs: CachedAsyncAction, rhs: CachedAsyncAction) -> Bool where T : Equatable { - switch (lhs, rhs) { - case (.none, .none): - true - case let (.loading(lhsItem), .loading(rhsItem)): - lhsItem == rhsItem - case let (.error(lhsItem, _), .error(rhsItem, _)): - lhsItem == rhsItem - case let (.success(lhsItem), .success(rhsItem)): - lhsItem == rhsItem - default: - false - } - } - - public static func != (lhs: CachedAsyncAction, rhs: CachedAsyncAction) -> Bool where T : Equatable { - switch (lhs, rhs) { - case (.none, .none): - false - case let (.loading(lhsItem), .loading(rhsItem)): - lhsItem != rhsItem - case let (.error(lhsItem, _), .error(rhsItem, _)): - lhsItem != rhsItem - case let (.success(lhsItem), .success(rhsItem)): - lhsItem != rhsItem - default: - false - } - } -} diff --git a/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoad.swift b/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoad.swift index 826a1dc..bc1da9b 100644 --- a/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoad.swift +++ b/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoad.swift @@ -1,6 +1,6 @@ import Foundation -public enum CachedAsyncLoad: Equatable, Sendable { +public enum CachedAsyncLoad: Equatable, Sendable { case none case loading(T? = nil) case error(T? = nil, Error) @@ -36,21 +36,6 @@ public enum CachedAsyncLoad: Equatable, Sendable { } public static func == (lhs: CachedAsyncLoad, rhs: CachedAsyncLoad) -> Bool { - switch (lhs, rhs) { - case (.none, .none): - true - case (.loading, .loading): - true - case (.error, .error): - true - case (.loaded, .loaded): - true - default: - false - } - } - - public static func == (lhs: CachedAsyncLoad, rhs: CachedAsyncLoad) -> Bool where T : Equatable { switch (lhs, rhs) { case (.none, .none): true @@ -64,19 +49,4 @@ public enum CachedAsyncLoad: Equatable, Sendable { false } } - - public static func != (lhs: CachedAsyncLoad, rhs: CachedAsyncLoad) -> Bool where T : Equatable { - switch (lhs, rhs) { - case (.none, .none): - true - case let (.loading(lhsItem), .loading(rhsItem)): - lhsItem != rhsItem - case let (.error(lhsItem, _), .error(rhsItem, _)): - lhsItem != rhsItem - case let (.loaded( lhsItem), .loaded(rhsItem)): - lhsItem != rhsItem - default: - false - } - } } diff --git a/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoadView.swift b/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoadView.swift index dd4a180..9fa1e5e 100644 --- a/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoadView.swift +++ b/Sources/AsyncLoad/CachedAsyncLoad/CachedAsyncLoadView.swift @@ -3,7 +3,7 @@ import Foundation import SwiftUI public struct CachedAsyncLoadView< - Item: Sendable, + Item: Equatable & Sendable, Content: View, ErrorContent: View, LoadingContent: View @@ -32,22 +32,23 @@ public struct CachedAsyncLoadView< } public var body: some View { - switch state { - case .none: - loadingContent(nil) - - case let .loading(item): - loadingContent(item) - - case let .loaded(item): - content(item) - - case let .error(item, error): - errorContent(item, error) + ZStack { + switch state { + case .none: + loadingContent(nil) + + case let .loading(item): + loadingContent(item) + + case let .loaded(item): + content(item) + + case let .error(item, error): + errorContent(item, error) + } } } } -#endif fileprivate enum CustomError: Error { case test @@ -93,6 +94,8 @@ fileprivate enum CustomError: Error { try await Task.sleep(for: .seconds(2)) state = .loaded("Working!") try await Task.sleep(for: .seconds(2)) + state = .loaded("Working1234") + try await Task.sleep(for: .seconds(2)) state = .loading("Working!") try await Task.sleep(for: .seconds(2)) state = .error("Working!", CustomError.test) @@ -100,3 +103,4 @@ fileprivate enum CustomError: Error { } } } +#endif diff --git a/Tests/AsyncLoadTests/AsyncActionEquatableItemTests.swift b/Tests/AsyncLoadTests/AsyncActionEquatableItemTests.swift deleted file mode 100644 index 602e927..0000000 --- a/Tests/AsyncLoadTests/AsyncActionEquatableItemTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Testing -@testable import AsyncLoad - -@Suite("Test equatable AsyncAction") -struct AsyncActionEquatableItemTests { - @Test<[AsyncActionParameter]>("Should be equal ", arguments: [ - .init(.none, .none), - .init(.loading, .loading), - .init(.error(TestingError.some), .error(TestingError.some)), - .init(.error(TestingError.some), .error(TestingError.other)), - .init(.success("some"), .success("some")), - ]) - func equalString(param: AsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } - - @Test<[AsyncActionParameter]>("Should not be equal ", arguments: [ - .init(.success("some"), .success("other")), - .init(.error(TestingError.some), .success("other")), - ]) - func nonEqualString(param: AsyncActionParameter) async throws { - #expect(param.action1 != param.action2) - } - - @Test<[AsyncActionParameter]>("Should be equal ", arguments: [ - .init(.none, .none), - .init(.loading, .loading), - .init(.error(TestingError.some), .error(TestingError.some)), - .init(.error(TestingError.some), .error(TestingError.other)), - .init(.success(User(name: "some")), .success(User(name: "some"))), - ]) - func equalUser(param: AsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } - - @Test<[AsyncActionParameter]>("Should not be equal ", arguments: [ - .init(.success(User(name: "some")), .success(User(name: "other"))), - .init(.error(TestingError.some), .success(User(name: "some"))), - ]) - func nonEqualuser(param: AsyncActionParameter) async throws { - #expect(param.action1 != param.action2) - } -} diff --git a/Tests/AsyncLoadTests/AsyncActionNonEquatableItemTests.swift b/Tests/AsyncLoadTests/AsyncActionNonEquatableItemTests.swift deleted file mode 100644 index c5b45dd..0000000 --- a/Tests/AsyncLoadTests/AsyncActionNonEquatableItemTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Testing -@testable import AsyncLoad - -@Suite("Test non-equatable AsyncAction") -struct AsyncActionNonEquatableItemTests { - @Test<[AsyncActionParameter]>("Should be equal (structural)", arguments: [ - .init(.none, .none), - .init(.loading, .loading), - .init(.success(NonEquatableItem(name: "Hello")), .success(NonEquatableItem(name: "Different"))), - .init(.success(NonEquatableItem(name: "Some")), .success(NonEquatableItem(name: "Other"))), - .init(.error(TestingError.some), .error(TestingError.some)), - .init(.error(TestingError.some), .error(TestingError.other)), - ]) - func structuralEquality(param: AsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } - - @Test<[AsyncActionParameter]>("Should be equal (mixed types)", arguments: [ - .init(.loading, .loading), - .init(.error(TestingError.some), .error(TestingError.some)), - .init(.error(TestingError.some), .error(TestingError.other)), - ]) - func mixedTypeEquality(param: AsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } -} diff --git a/Tests/AsyncLoadTests/AsyncLoadNonEquatableItemTests.swift b/Tests/AsyncLoadTests/AsyncLoadNonEquatableItemTests.swift deleted file mode 100644 index 9281991..0000000 --- a/Tests/AsyncLoadTests/AsyncLoadNonEquatableItemTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Testing -@testable import AsyncLoad - -@Suite("Test non-equatable AsyncLoad") -struct AsyncLoadNonEquatableItemTests { - @Test<[AsyncLoadParameter]>("Should be equal (structural)", arguments: [ - .init(.none, .none), - .init(.loading, .loading), - .init(.loaded(NonEquatableItem(name: "Hello")), .loaded(NonEquatableItem(name: "Different"))), - .init(.loaded(NonEquatableItem(name: "Some")), .loaded(NonEquatableItem(name: "Other"))), - .init(.error(TestingError.some), .error(TestingError.some)), - .init(.error(TestingError.some), .error(TestingError.other)), - ]) - func structuralEquality(param: AsyncLoadParameter) async throws { - #expect(param.load1 == param.load2) - } - - @Test<[AsyncLoadParameter]>("Should be equal (mixed types)", arguments: [ - .init(.loading, .loading), - .init(.error(TestingError.some), .error(TestingError.some)), - .init(.error(TestingError.some), .error(TestingError.other)), - ]) - func mixedTypeEquality(param: AsyncLoadParameter) async throws { - #expect(param.load1 == param.load2) - } -} diff --git a/Tests/AsyncLoadTests/CachedAsyncActionEquatableItemTests.swift b/Tests/AsyncLoadTests/CachedAsyncActionEquatableItemTests.swift deleted file mode 100644 index 25fb8a9..0000000 --- a/Tests/AsyncLoadTests/CachedAsyncActionEquatableItemTests.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Testing -@testable import AsyncLoad - -@Suite("Test equatable CachedAsyncAction") -struct CachedAsyncActionEquatableItemTests { - @Test<[CachedAsyncActionParameter]>("Should be equal ", arguments: [ - .init(.none, .none), - .init(.loading(), .loading()), - .init(.success("some"), .success("some")), - .init(.loading("some"), .loading("some")), - .init(.error("some", TestingError.some), .error("some", TestingError.some)), - ]) - func equalString(param: CachedAsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } - - @Test<[CachedAsyncActionParameter]>("Should not be equal ", arguments: [ - .init(.success("Other"), .success("Other1")), - .init(.loading("some"), .loading("other")), - .init(.error(nil, TestingError.some), .error("some", TestingError.some)), - .init(.error(nil, TestingError.some), .error("some", TestingError.other)), - .init(.error("some", TestingError.some), .error(nil, TestingError.some)), - ]) - func nonEqualString(param: CachedAsyncActionParameter) async throws { - #expect(param.action1 != param.action2) - } - - @Test<[CachedAsyncActionParameter]>("Should be equal ", arguments: [ - .init(.none, .none), - .init(.loading(), .loading()), - .init(.success(User(name: "some")), .success(User(name: "some"))), - .init(.loading(User(name: "some")), .loading(User(name: "some"))), - .init(.error(User(name: "some"), TestingError.some), .error(User(name: "some"), TestingError.some)), - ]) - func equalUser(param: CachedAsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } - - @Test<[CachedAsyncActionParameter]>("Should not be equal ", arguments: [ - .init(.success(User(name: "Alex")), .success(User(name: "Daniel"))), - .init(.loading(User(name: "Alex")), .loading(User(name: "Daniel"))), - .init(.error(nil, TestingError.some), .error(User(name: "some"), TestingError.some)), - .init(.error(User(name: "Alex"), TestingError.some), .error(User(name: "Daniel"), TestingError.some)), - ]) - func nonEqualUser(param: CachedAsyncActionParameter) async throws { - #expect(param.action1 != param.action2) - } -} diff --git a/Tests/AsyncLoadTests/CachedAsyncActionNonEquatableItemTests.swift b/Tests/AsyncLoadTests/CachedAsyncActionNonEquatableItemTests.swift deleted file mode 100644 index e369b89..0000000 --- a/Tests/AsyncLoadTests/CachedAsyncActionNonEquatableItemTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Testing -@testable import AsyncLoad - -@Suite("Test non-equatable CachedAsyncAction") -struct CachedAsyncActionNonEquatableItemTests { - @Test<[CachedAsyncActionParameter]>("Should be equal (structural)", arguments: [ - .init(.none, .none), - .init(.loading(), .loading()), - .init(.success(NonEquatableItem(name: "Hello")), .success(NonEquatableItem(name: "Different"))), - .init(.success(NonEquatableItem(name: "Some")), .success(NonEquatableItem(name: "Other"))), - .init(.loading(NonEquatableItem(name: "Some")), .loading(NonEquatableItem(name: "Other"))), - .init(.error(nil, TestingError.some), .error(nil, TestingError.some)), - .init(.error(nil, TestingError.some), .error(NonEquatableItem(name: "Hello"), TestingError.other)), - .init(.error(NonEquatableItem(name: "Hello"), TestingError.some), .error(NonEquatableItem(name: "World"), TestingError.some)), - ]) - func structuralEquality(param: CachedAsyncActionParameter) async throws { - #expect(param.action1 == param.action2) - } -} diff --git a/Tests/AsyncLoadTests/CachedAsyncLoadNonEquatableItemTests.swift b/Tests/AsyncLoadTests/CachedAsyncLoadNonEquatableItemTests.swift deleted file mode 100644 index c55af85..0000000 --- a/Tests/AsyncLoadTests/CachedAsyncLoadNonEquatableItemTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Testing -@testable import AsyncLoad - -@Suite("Test non-equatable CachedAsyncLoad") -struct CachedAsyncLoadNonEquatableItemTests { - @Test<[CachedAsyncLoadParameter]>("Should be equal (structural)", arguments: [ - .init(.none, .none), - .init(.loading(), .loading()), - .init(.loaded(NonEquatableItem(name: "Hello")), .loaded(NonEquatableItem(name: "Different"))), - .init(.loaded(NonEquatableItem(name: "Some")), .loaded(NonEquatableItem(name: "Other"))), - .init(.loading(NonEquatableItem(name: "Some")), .loading(NonEquatableItem(name: "Other"))), - .init(.error(nil, TestingError.some), .error(nil, TestingError.some)), - .init(.error(nil, TestingError.some), .error(NonEquatableItem(name: "Hello"), TestingError.other)), - .init(.error(NonEquatableItem(name: "Hello"), TestingError.some), .error(NonEquatableItem(name: "World"), TestingError.some)), - ]) - func structuralEquality(param: CachedAsyncLoadParameter) async throws { - #expect(param.load1 == param.load2) - } -} diff --git a/Tests/AsyncLoadTests/Utils.swift b/Tests/AsyncLoadTests/Utils.swift index b3cdbb0..7742343 100644 --- a/Tests/AsyncLoadTests/Utils.swift +++ b/Tests/AsyncLoadTests/Utils.swift @@ -18,17 +18,7 @@ struct User: Equatable { let name: String } -struct AsyncActionParameter { - let action1: AsyncAction - let action2: AsyncAction - - init(_ action1: AsyncAction, _ action2: AsyncAction) { - self.action1 = action1 - self.action2 = action2 - } -} - -struct AsyncLoadParameter { +struct AsyncLoadParameter { let load1: AsyncLoad let load2: AsyncLoad @@ -38,17 +28,7 @@ struct AsyncLoadParameter { } } -struct CachedAsyncActionParameter { - let action1: CachedAsyncAction - let action2: CachedAsyncAction - - init(_ action1: CachedAsyncAction, _ action2: CachedAsyncAction) { - self.action1 = action1 - self.action2 = action2 - } -} - -struct CachedAsyncLoadParameter { +struct CachedAsyncLoadParameter { let load1: CachedAsyncLoad let load2: CachedAsyncLoad