Skip to content

Commit 7cfcca0

Browse files
stephencelisp4checo
authored andcommitted
Remove and update a few deprecated, flakey tests (#1816)
* Remove and update a few deprecated, flakey tests * wip (cherry picked from commit f2f3a2558d5d63108420b5413d2cc94a850f7b92) # Conflicts: # Tests/ComposableArchitectureTests/BindingTests.swift # Tests/ComposableArchitectureTests/CompatibilityTests.swift # Tests/ComposableArchitectureTests/ComposableArchitectureTests.swift # Tests/ComposableArchitectureTests/ReducerTests.swift # Tests/ComposableArchitectureTests/RuntimeWarningTests.swift # Tests/ComposableArchitectureTests/StoreTests.swift # Tests/ComposableArchitectureTests/ViewStoreTests.swift
1 parent 7995dcf commit 7cfcca0

File tree

8 files changed

+960
-1084
lines changed

8 files changed

+960
-1084
lines changed
Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
#if canImport(SwiftUI)
2-
import ComposableArchitecture
3-
import XCTest
4-
5-
@MainActor
6-
final class BindingTests: XCTestCase {
7-
#if swift(>=5.7)
8-
func testNestedBindableState() {
9-
struct BindingTest: ReducerProtocol {
10-
struct State: Equatable {
11-
@BindableState var nested = Nested()
12-
13-
struct Nested: Equatable {
14-
var field = ""
15-
}
2+
import ComposableArchitecture
3+
import XCTest
4+
5+
@MainActor
6+
final class BindingTests: XCTestCase {
7+
#if swift(>=5.7)
8+
func testNestedBindableState() {
9+
struct BindingTest: ReducerProtocol {
10+
struct State: Equatable {
11+
@BindableState var nested = Nested()
12+
13+
struct Nested: Equatable {
14+
var field = ""
1615
}
16+
}
1717

18-
enum Action: BindableAction, Equatable {
19-
case binding(BindingAction<State>)
20-
}
18+
enum Action: BindableAction, Equatable {
19+
case binding(BindingAction<State>)
20+
}
2121

22-
var body: some ReducerProtocol<State, Action> {
23-
BindingReducer()
24-
Reduce { state, action in
25-
switch action {
26-
case .binding(\.$nested.field):
27-
state.nested.field += "!"
28-
return .none
29-
default:
30-
return .none
31-
}
22+
var body: some ReducerProtocol<State, Action> {
23+
BindingReducer()
24+
Reduce { state, action in
25+
switch action {
26+
case .binding(\.$nested.field):
27+
state.nested.field += "!"
28+
return .none
29+
default:
30+
return .none
3231
}
3332
}
3433
}
34+
}
3535

36-
let store = Store(initialState: BindingTest.State(), reducer: BindingTest())
36+
let store = Store(initialState: BindingTest.State(), reducer: BindingTest())
3737

38-
let viewStore = ViewStore(store)
38+
let viewStore = ViewStore(store, observe: { $0 })
3939

40-
viewStore.binding(\.$nested.field).wrappedValue = "Hello"
40+
viewStore.binding(\.$nested.field).wrappedValue = "Hello"
4141

42-
XCTAssertEqual(viewStore.state, .init(nested: .init(field: "Hello!")))
43-
}
44-
#endif
45-
}
42+
XCTAssertEqual(viewStore.state, .init(nested: .init(field: "Hello!")))
43+
}
44+
#endif
45+
}
4646
#endif

Tests/ComposableArchitectureTests/CompatibilityTests.swift

Lines changed: 91 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,122 +4,120 @@ import XCTest
44

55
// `@MainActor` introduces issues gathering tests on Linux
66
#if !os(Linux)
7-
@MainActor
8-
final class CompatibilityTests: XCTestCase {
9-
// Actions can be re-entrantly sent into the store if an action is sent that holds an object
10-
// which sends an action on deinit. In order to prevent a simultaneous access exception for this
11-
// case we need to use `withExtendedLifetime` on the buffered actions when clearing them out.
12-
func testCaseStudy_ActionReentranceFromClearedBufferCausingDeinitAction() {
13-
let cancelID = UUID()
14-
15-
struct State: Equatable {}
16-
enum Action: Equatable {
17-
case start
18-
case kickOffAction
19-
case actionSender(OnDeinit)
20-
case stop
21-
22-
var description: String {
23-
switch self {
24-
case .start:
25-
return "start"
26-
case .kickOffAction:
27-
return "kickOffAction"
28-
case .actionSender:
29-
return "actionSender"
30-
case .stop:
31-
return "stop"
32-
}
7+
@MainActor
8+
final class CompatibilityTests: XCTestCase {
9+
// Actions can be re-entrantly sent into the store if an action is sent that holds an object
10+
// which sends an action on deinit. In order to prevent a simultaneous access exception for this
11+
// case we need to use `withExtendedLifetime` on the buffered actions when clearing them out.
12+
func testCaseStudy_ActionReentranceFromClearedBufferCausingDeinitAction() {
13+
let cancelID = UUID()
14+
15+
struct State: Equatable {}
16+
enum Action: Equatable {
17+
case start
18+
case kickOffAction
19+
case actionSender(OnDeinit)
20+
case stop
21+
22+
var description: String {
23+
switch self {
24+
case .start:
25+
return "start"
26+
case .kickOffAction:
27+
return "kickOffAction"
28+
case .actionSender:
29+
return "actionSender"
30+
case .stop:
31+
return "stop"
3332
}
3433
}
34+
}
3535
let (signal, observer) = Signal<Action, Never>.pipe()
3636

37-
var handledActions: [String] = []
37+
var handledActions: [String] = []
3838

39-
let reducer = AnyReducer<State, Action, Void> { state, action, env in
40-
handledActions.append(action.description)
39+
let reducer = Reduce<State, Action> { state, action in
40+
handledActions.append(action.description)
4141

42-
switch action {
43-
case .start:
42+
switch action {
43+
case .start:
4444
return signal.producer
45-
.eraseToEffect()
46-
.cancellable(id: cancelID)
45+
.eraseToEffect()
46+
.cancellable(id: cancelID)
4747

48-
case .kickOffAction:
48+
case .kickOffAction:
4949
return EffectTask(value: .actionSender(OnDeinit { observer.send(value: .stop) }))
5050

51-
case .actionSender:
52-
return .none
51+
case .actionSender:
52+
return .none
5353

54-
case .stop:
55-
return .cancel(id: cancelID)
56-
}
54+
case .stop:
55+
return .cancel(id: cancelID)
5756
}
58-
59-
let store = Store(
60-
initialState: .init(),
61-
reducer: reducer,
62-
environment: ()
63-
)
64-
65-
let viewStore = ViewStore(store)
66-
67-
viewStore.send(.start)
68-
viewStore.send(.kickOffAction)
69-
70-
XCTAssertEqual(
71-
handledActions,
72-
[
73-
"start",
74-
"kickOffAction",
75-
"actionSender",
76-
"stop",
77-
]
78-
)
7957
}
8058

81-
// Actions can be re-entrantly sent into the store while observing changes to the store's state.
82-
// In such cases we need to take special care that those re-entrant actions are handled _after_
83-
// the original action.
84-
//
85-
// In particular, this means that in the implementation of `Store.send` we need to flip
86-
// `isSending` to false _after_ the store's state mutation is made so that re-entrant actions
87-
// are buffered rather than immediately handled.
88-
func testCaseStudy_ActionReentranceFromStateObservation() {
89-
let store = Store<Int, Int>(
90-
initialState: 0,
91-
reducer: .init { state, action, _ in
92-
state = action
93-
return .none
94-
},
95-
environment: ()
96-
)
97-
98-
let viewStore = ViewStore(store)
59+
let store = Store(
60+
initialState: .init(),
61+
reducer: reducer
62+
)
63+
64+
let viewStore = ViewStore(store, observe: { $0 })
65+
66+
viewStore.send(.start)
67+
viewStore.send(.kickOffAction)
68+
69+
XCTAssertEqual(
70+
handledActions,
71+
[
72+
"start",
73+
"kickOffAction",
74+
"actionSender",
75+
"stop",
76+
]
77+
)
78+
}
79+
80+
// Actions can be re-entrantly sent into the store while observing changes to the store's state.
81+
// In such cases we need to take special care that those re-entrant actions are handled _after_
82+
// the original action.
83+
//
84+
// In particular, this means that in the implementation of `Store.send` we need to flip
85+
// `isSending` to false _after_ the store's state mutation is made so that re-entrant actions
86+
// are buffered rather than immediately handled.
87+
func testCaseStudy_ActionReentranceFromStateObservation() {
88+
let store = Store<Int, Int>(
89+
initialState: 0,
90+
reducer: Reduce { state, action in
91+
state = action
92+
return .none
93+
}
94+
)
95+
96+
let viewStore = ViewStore(store, observe: { $0 })
9997

10098
viewStore.produced.producer
10199
.startWithValues { value in
102-
if value == 1 {
103-
viewStore.send(0)
104-
}
100+
if value == 1 {
101+
viewStore.send(0)
105102
}
103+
}
106104

107-
var stateChanges: [Int] = []
105+
var stateChanges: [Int] = []
108106
viewStore.produced.producer
109107
.startWithValues { stateChanges.append($0) }
110108

111-
XCTAssertEqual(stateChanges, [0])
112-
viewStore.send(1)
113-
XCTAssertEqual(stateChanges, [0, 1, 0])
114-
}
109+
XCTAssertEqual(stateChanges, [0])
110+
viewStore.send(1)
111+
XCTAssertEqual(stateChanges, [0, 1, 0])
115112
}
113+
}
116114

117-
private final class OnDeinit: Equatable {
118-
private let onDeinit: () -> Void
119-
init(onDeinit: @escaping () -> Void) {
120-
self.onDeinit = onDeinit
121-
}
122-
deinit { self.onDeinit() }
123-
static func == (lhs: OnDeinit, rhs: OnDeinit) -> Bool { true }
115+
private final class OnDeinit: Equatable {
116+
private let onDeinit: () -> Void
117+
init(onDeinit: @escaping () -> Void) {
118+
self.onDeinit = onDeinit
124119
}
120+
deinit { self.onDeinit() }
121+
static func == (lhs: OnDeinit, rhs: OnDeinit) -> Bool { true }
122+
}
125123
#endif

0 commit comments

Comments
 (0)