From e3eb6fcf0a17806c8ded0d1a11879d8882e16994 Mon Sep 17 00:00:00 2001 From: Erk Ekin Date: Sat, 26 Jul 2025 18:50:50 +0100 Subject: [PATCH 1/2] adds utils and example tests --- Package.swift | 12 +++++ Sources/tinyTCA/tinyTCA.swift | 1 - Sources/tinyTCATestUtils/TestStore.swift | 23 +++++++++ Tests/tinyTCATests/tinyTCATests.swift | 60 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 Sources/tinyTCATestUtils/TestStore.swift create mode 100644 Tests/tinyTCATests/tinyTCATests.swift diff --git a/Package.swift b/Package.swift index 524a4db..805a6aa 100644 --- a/Package.swift +++ b/Package.swift @@ -14,6 +14,10 @@ let package = Package( name: "tinyTCA", targets: ["tinyTCA"] ), + .library( + name: "tinyTCATestUtils", + targets: ["tinyTCATestUtils"] + ) ], targets: [ .target( @@ -22,6 +26,14 @@ let package = Package( // Strict concurrency checking (recommended for Swift 6) .enableExperimentalFeature("StrictConcurrency") ] + ), + .target( + name: "tinyTCATestUtils", + dependencies: ["tinyTCA"] + ), + .testTarget( + name: "tinyTCATests", + dependencies: ["tinyTCA", "tinyTCATestUtils"] ) ] ) diff --git a/Sources/tinyTCA/tinyTCA.swift b/Sources/tinyTCA/tinyTCA.swift index d0fa786..c1c3556 100644 --- a/Sources/tinyTCA/tinyTCA.swift +++ b/Sources/tinyTCA/tinyTCA.swift @@ -50,7 +50,6 @@ public final class Store: ObservableObject { } } - /// A two-way binding to the store's state for SwiftUI public var binding: Binding { Binding( diff --git a/Sources/tinyTCATestUtils/TestStore.swift b/Sources/tinyTCATestUtils/TestStore.swift new file mode 100644 index 0000000..2c0e37b --- /dev/null +++ b/Sources/tinyTCATestUtils/TestStore.swift @@ -0,0 +1,23 @@ +import Foundation +import Combine +@testable import tinyTCA + +/// A test store for testing state changes and effects in isolation. +public final class TestStore { + public init(state: F.State, feature: F) { + self.state = state + self.feature = feature + } + + public init(feature: F) { + self.state = feature.initialState + self.feature = feature + } + + let feature: F + public private(set) var state: F.State + + public func send(_ action: F.Action) { + try? feature.reducer(state: &state, action: action) + } +} diff --git a/Tests/tinyTCATests/tinyTCATests.swift b/Tests/tinyTCATests/tinyTCATests.swift new file mode 100644 index 0000000..5b21916 --- /dev/null +++ b/Tests/tinyTCATests/tinyTCATests.swift @@ -0,0 +1,60 @@ +@testable import tinyTCA +import tinyTCATestUtils +import Testing + +@Suite("Counter Feature Tests") +struct CounterFeatureTests { + @Test("Counter increments and decrements correctly") + func testCounter() async throws { + let testStore = TestStore(feature: CounterFeature()) + + testStore.send(.increment) + #expect(testStore.state.count == 1) + + testStore.send(.decrement) + #expect(testStore.state.count == 0) + + testStore.send(.delayedIncrement) + #expect(testStore.state.count == 0) + } +} + +struct CounterFeature: Feature { + struct State: Equatable { + var count = 0 + } + + enum Action: Equatable { + case increment + case decrement + case delayedIncrement + case delayedIncrementResponse + } + + var initialState: State { State() } + + func reducer(state: inout State, action: Action) throws { + switch action { + case .increment: + state.count += 1 + case .decrement: + state.count -= 1 + case .delayedIncrement: + // No state change, the effect handles the logic + break + case .delayedIncrementResponse: + state.count += 1 + } + } + + // not tested yet + func effect(for action: Action, state: State) async throws -> Action? { + switch action { + case .delayedIncrement: + try await Task.sleep(nanoseconds: 1_000_000_000) // 1 second + return .delayedIncrementResponse + default: + return nil + } + } +} From bb7c5f8999240c9aa8aac5a0320a978929fd2551 Mon Sep 17 00:00:00 2001 From: Erk Ekin Date: Sat, 26 Jul 2025 18:59:51 +0100 Subject: [PATCH 2/2] Update Sources/tinyTCATestUtils/TestStore.swift --- Sources/tinyTCATestUtils/TestStore.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/tinyTCATestUtils/TestStore.swift b/Sources/tinyTCATestUtils/TestStore.swift index 2c0e37b..83f09ca 100644 --- a/Sources/tinyTCATestUtils/TestStore.swift +++ b/Sources/tinyTCATestUtils/TestStore.swift @@ -2,7 +2,7 @@ import Foundation import Combine @testable import tinyTCA -/// A test store for testing state changes and effects in isolation. +/// A test store for testing state changes in isolation. public final class TestStore { public init(state: F.State, feature: F) { self.state = state