Files
swift-composable-architectu…/Tests/ComposableArchitectureTests/Reducers/BindingReducerTests.swift
Stephen Celis fc5cbeec88 Infrastructure: Address concurrency warnings in tests (#3438)
* Infrastructure: Address concurrency warnings in tests

* wip

---------

Co-authored-by: Brandon Williams <mbrandonw@hey.com>
2024-10-15 10:03:23 -07:00

133 lines
3.4 KiB
Swift

import ComposableArchitecture
import XCTest
final class BindingTests: BaseTCATestCase {
@Reducer
struct BindingTest {
struct State: Equatable {
@BindingState var nested = Nested()
struct Nested: Equatable {
var field = ""
}
}
enum Action: BindableAction, Equatable {
case binding(BindingAction<State>)
}
var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .binding(.set(\.$nested, State.Nested(field: "special"))):
state.nested.field += "*"
return .none
case .binding(\.$nested):
state.nested.field += "!"
return .none
case .binding:
return .none
}
}
}
}
func testEquality() {
struct State {
@BindingState var count = 0
}
XCTAssertEqual(
BindingAction<State>.set(\.$count, 1),
BindingAction<State>.set(\.$count, 1)
)
XCTAssertNotEqual(
BindingAction<State>.set(\.$count, 1),
BindingAction<State>.set(\.$count, 2)
)
}
@MainActor
func testViewEquality() {
struct Feature: Reducer {
struct State: Equatable {
@BindingState var count = 0
}
enum Action: BindableAction, Equatable {
case binding(BindingAction<State>)
}
var body: some ReducerOf<Self> {
BindingReducer()
}
}
struct ViewState: Equatable {
@BindingViewState var count: Int
}
let store = Store(initialState: Feature.State()) {
Feature()
}
let viewStore = ViewStore(store, observe: { ViewState(count: $0.$count) })
let initialState = viewStore.state
let count = viewStore.$count
count.wrappedValue += 1
XCTAssertNotEqual(initialState, viewStore.state)
XCTAssertEqual(count.wrappedValue, 1)
}
@MainActor
func testNestedBindingState() {
let store = Store(initialState: BindingTest.State()) { BindingTest() }
let viewStore = ViewStore(store, observe: { $0 })
viewStore.$nested.field.wrappedValue = "Hello"
XCTAssertEqual(viewStore.state, .init(nested: .init(field: "Hello!")))
}
@MainActor
func testNestedBindingViewState() {
struct ViewState: Equatable {
@BindingViewState var field: String
}
let store = Store(initialState: BindingTest.State()) { BindingTest() }
let viewStore = ViewStore(store, observe: { ViewState(field: $0.$nested.field) })
viewStore.$field.wrappedValue = "Hello"
XCTAssertEqual(store.withState { $0.nested.field }, "Hello!")
}
func testBindingActionUpdatesRespectsPatternMatching() async {
let testStore = await TestStore(
initialState: BindingTest.State(nested: BindingTest.State.Nested(field: ""))
) {
BindingTest()
}
await testStore.send(.binding(.set(\.$nested, BindingTest.State.Nested(field: "special")))) {
$0.nested = BindingTest.State.Nested(field: "special*")
}
await testStore.send(.binding(.set(\.$nested, BindingTest.State.Nested(field: "Hello")))) {
$0.nested = BindingTest.State.Nested(field: "Hello!")
}
}
struct TestMatching {
struct CounterState {
@BindingState var count = 0
}
@CasePathable
enum CounterAction: CasePathable {
case binding(BindingAction<CounterState>)
}
}
func testMatching() {
let action = TestMatching.CounterAction.binding(.set(\.$count, 42))
XCTAssertEqual(action[case: \.binding.$count], 42)
}
}