@@ -13,19 +13,59 @@ import Foundation
1313@testable import SwiftRex
1414import XCTest
1515
16- public enum Step < ActionType, StateType> {
17- case send(
18- ActionType ,
19- file: StaticString = #file,
20- line: UInt = #line,
21- stateChange: ( inout StateType ) -> Void = { _ in }
22- )
23- case receive(
24- ActionType ,
16+ public struct SendStep < ActionType, StateType> {
17+ public init (
18+ action: @autoclosure @escaping ( ) -> ActionType ,
2519 file: StaticString = #file,
2620 line: UInt = #line,
27- stateChange: ( inout StateType ) -> Void = { _ in }
28- )
21+ stateChange: @escaping ( inout StateType ) -> Void = { _ in }
22+ ) {
23+ self . action = action
24+ self . file = file
25+ self . line = line
26+ self . stateChange = stateChange
27+ }
28+
29+ let action : ( ) -> ActionType
30+ let file : StaticString
31+ let line : UInt
32+ let stateChange : ( inout StateType ) -> Void
33+ }
34+
35+ public struct ReceiveStep < ActionType, StateType> {
36+ public init ( isExpectedAction: @escaping ( ActionType ) -> Bool ,
37+ file: StaticString = #file,
38+ line: UInt = #line,
39+ stateChange: @escaping ( inout StateType ) -> Void = { _ in } ) {
40+ self . isExpectedAction = isExpectedAction
41+ self . file = file
42+ self . line = line
43+ self . stateChange = stateChange
44+ }
45+
46+ public init ( action: @autoclosure @escaping ( ) -> ActionType ,
47+ file: StaticString = #file,
48+ line: UInt = #line,
49+ stateChange: @escaping ( inout StateType ) -> Void = { _ in }
50+ ) where ActionType: Equatable {
51+ self . init (
52+ isExpectedAction: { $0 == action ( ) } ,
53+ file: file,
54+ line: line,
55+ stateChange: stateChange
56+ )
57+ }
58+
59+ let file : StaticString
60+ let line : UInt
61+ let stateChange : ( inout StateType ) -> Void
62+
63+ let isExpectedAction : ( ActionType ) -> Bool
64+ }
65+
66+ public enum Step < ActionType, StateType> {
67+ case send( SendStep < ActionType , StateType > )
68+ case receive( ReceiveStep < ActionType , StateType > )
2969 case sideEffectResult(
3070 do: ( ) -> Void
3171 )
@@ -40,7 +80,7 @@ extension XCTestCase {
4080 otherSteps: [ Step < M . InputActionType , M . StateType > ] = [ ] ,
4181 file: StaticString = #file,
4282 line: UInt = #line
43- ) where M. InputActionType == M . OutputActionType , M. InputActionType : Equatable , M . StateType: Equatable {
83+ ) where M. InputActionType == M . OutputActionType , M. StateType: Equatable {
4484 assert (
4585 initialValue: initialValue,
4686 reducer: reducer,
@@ -61,7 +101,7 @@ extension XCTestCase {
61101 stateEquating: ( M . StateType , M . StateType ) -> Bool ,
62102 file: StaticString = #file,
63103 line: UInt = #line
64- ) where M. InputActionType == M . OutputActionType , M . InputActionType : Equatable {
104+ ) where M. InputActionType == M . OutputActionType {
65105 assert (
66106 initialValue: initialValue,
67107 reducer: reducer,
@@ -81,7 +121,7 @@ extension XCTestCase {
81121 stateEquating: ( M . StateType , M . StateType ) -> Bool ,
82122 file: StaticString = #file,
83123 line: UInt = #line
84- ) where M. InputActionType == M . OutputActionType , M . InputActionType : Equatable {
124+ ) where M. InputActionType == M . OutputActionType {
85125 var state = initialValue
86126 var middlewareResponses : [ M . OutputActionType ] = [ ]
87127 let gotAction = XCTestExpectation ( description: " got action " )
@@ -92,16 +132,21 @@ extension XCTestCase {
92132 }
93133 middleware. receiveContext ( getState: { state } , output: anyActionHandler)
94134
95- steps. forEach { step in
135+ steps. forEach { outerStep in
96136 var expected = state
97137
98- switch step {
99- case let . send( action, file, line, stateChange) :
138+ switch outerStep {
139+ case let . send( step) : //action, file, line, stateChange):
140+ let file = step. file
141+ let line = step. line
142+ let stateChange = step. stateChange
143+
100144 if !middlewareResponses. isEmpty {
101145 XCTFail ( " Action sent before handling \( middlewareResponses. count) pending effect(s) " , file: file, line: line)
102146 }
103147
104148 var afterReducer : AfterReducer = . doNothing( )
149+ let action = step. action ( )
105150 middleware. handle (
106151 action: action,
107152 from: . init( file: " \( file) " , function: " " , line: line, info: nil ) ,
@@ -111,8 +156,12 @@ extension XCTestCase {
111156 afterReducer. reducerIsDone ( )
112157
113158 stateChange ( & expected)
114- ensureStateMutation ( equating: stateEquating, statusQuo: state, expected: expected)
115- case let . receive( action, file, line, stateChange) :
159+ ensureStateMutation ( equating: stateEquating, statusQuo: state, expected: expected, step: outerStep)
160+ case let . receive( step) : //action, file, line, stateChange):
161+ let file = step. file
162+ let line = step. line
163+ let stateChange = step. stateChange
164+
116165 if middlewareResponses. isEmpty {
117166 _ = XCTWaiter . wait ( for: [ gotAction] , timeout: 0.2 )
118167 }
@@ -121,19 +170,19 @@ extension XCTestCase {
121170 break
122171 }
123172 let first = middlewareResponses. removeFirst ( )
124- XCTAssertEqual ( first, action , file: file, line: line)
173+ XCTAssertTrue ( step . isExpectedAction ( first) , file: file, line: line)
125174
126175 var afterReducer : AfterReducer = . doNothing( )
127176 middleware. handle (
128- action: action ,
177+ action: first ,
129178 from: . init( file: " \( file) " , function: " " , line: line, info: nil ) ,
130179 afterReducer: & afterReducer
131180 )
132- reducer. reduce ( action , & state)
181+ reducer. reduce ( first , & state)
133182 afterReducer. reducerIsDone ( )
134183
135184 stateChange ( & expected)
136- ensureStateMutation ( equating: stateEquating, statusQuo: state, expected: expected)
185+ ensureStateMutation ( equating: stateEquating, statusQuo: state, expected: expected, step : outerStep )
137186 case let . sideEffectResult( execute) :
138187 execute ( )
139188 }
@@ -145,11 +194,12 @@ extension XCTestCase {
145194 }
146195 }
147196
148- private func ensureStateMutation< StateType> (
197+ private func ensureStateMutation< ActionType , StateType> (
149198 equating: ( StateType , StateType ) -> Bool ,
150199 statusQuo: StateType ,
151200 expected: StateType ,
152- file: StaticString = #file,
201+ step: Step < ActionType , StateType > ,
202+ file: StaticString = #filePath,
153203 line: UInt = #line
154204 ) {
155205 XCTAssertTrue (
@@ -160,7 +210,7 @@ extension XCTestCase {
160210 dump ( expected, to: & expectedString, name: nil , indent: 2 )
161211 let difference = diff ( old: expectedString, new: stateString) ?? " "
162212
163- return " Expected state different from current state \n \( difference) "
213+ return " Expected state after step \( step ) different from current state\n \( difference) "
164214 } ( ) ,
165215 file: file,
166216 line: line
0 commit comments