Skip to content

Commit e9c1bf3

Browse files
committed
[Test] Improve 8ade68e & update README.md
1 parent 8ade68e commit e9c1bf3

File tree

6 files changed

+174
-49
lines changed

6 files changed

+174
-49
lines changed

README.md

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Any => 2, msg=Optional("Hello")
6262

6363
### Transition by Event
6464

65-
Use `<-!` operator to try transition by `Event` rather than specifying target `State` ([Test Case](https://github.com/ReactKit/SwiftState/blob/1be67826b3cc9187dfaac85c2e70613f3129fad6/SwiftStateTests/TryEventTests.swift#L32-L54)).
65+
Use `<-!` operator to try transition by `Event` rather than specifying target `State`.
6666

6767
```swift
6868
enum MyEvent: EventType {
@@ -79,7 +79,10 @@ let machine = StateMachine<MyState, MyEvent>(state: .State0) { machine in
7979
.State1 => .State2,
8080
])
8181
}
82-
82+
83+
// initial
84+
XCTAssertEqual(machine.state, MyState.State0)
85+
8386
// tryEvent
8487
machine <-! .Event0
8588
XCTAssertEqual(machine.state, MyState.State1)
@@ -88,13 +91,81 @@ XCTAssertEqual(machine.state, MyState.State1)
8891
machine <-! .Event0
8992
XCTAssertEqual(machine.state, MyState.State2)
9093

91-
// tryEvent
94+
// tryEvent (fails)
9295
machine <-! .Event0
9396
XCTAssertEqual(machine.state, MyState.State2, "Event0 doesn't have 2 => Any")
9497
```
9598

9699
If there is no `Event`-based transition, use built-in `NoEvent` instead.
97100

101+
### State & Event enums with associated values
102+
103+
Above examples use _arrow-style routing_ which are easy to understand, but it lacks in ability to handle state & event enums with associated values. In such cases, use `machine.addRouteMapping()` and pass either of the following closure types (_closure-style routing_):
104+
105+
- `EventRouteMapping`: `(event: E?, fromState: S, userInfo: Any?) -> S?`
106+
- `StateRouteMapping`: `(fromState: S, userInfo: Any?) -> [S]?`
107+
108+
For example:
109+
110+
```swift
111+
enum StrState: StateType {
112+
case Str(String) ...
113+
}
114+
enum StrEvent: EventType {
115+
case Str(String) ...
116+
}
117+
118+
let machine = Machine<StrState, StrEvent>(state: .Str("initial")) { machine in
119+
120+
// add EventRouteMapping
121+
machine.addRouteMapping { event, fromState, userInfo -> StrState? in
122+
// no route for no-event
123+
guard let event = event else { return nil }
124+
125+
switch (event, fromState) {
126+
case (.Str("gogogo"), .Str("initial")):
127+
return .Str("Phase 1")
128+
case (.Str("gogogo"), .Str("Phase 1")):
129+
return .Str("Phase 2")
130+
case (.Str("finish"), .Str("Phase 2")):
131+
return .Str("end")
132+
default:
133+
return nil
134+
}
135+
}
136+
137+
}
138+
139+
// initial
140+
XCTAssertEqual(machine.state, StrState.Str("initial"))
141+
142+
// tryEvent (fails)
143+
machine <-! .Str("go?")
144+
XCTAssertEqual(machine.state, StrState.Str("initial"), "No change.")
145+
146+
// tryEvent
147+
machine <-! .Str("gogogo")
148+
XCTAssertEqual(machine.state, StrState.Str("Phase 1"))
149+
150+
// tryEvent (fails)
151+
machine <-! .Str("finish")
152+
XCTAssertEqual(machine.state, StrState.Str("Phase 1"), "No change.")
153+
154+
// tryEvent
155+
machine <-! .Str("gogogo")
156+
XCTAssertEqual(machine.state, StrState.Str("Phase 2"))
157+
158+
// tryEvent (fails)
159+
machine <-! .Str("gogogo")
160+
XCTAssertEqual(machine.state, StrState.Str("Phase 2"), "No change.")
161+
162+
// tryEvent
163+
machine <-! .Str("finish")
164+
XCTAssertEqual(machine.state, StrState.Str("end"))
165+
```
166+
167+
This behaves very similar to JavaScript's safe state-container [rackt/Redux](https://github.com/rackt/redux), where `EventRouteMapping` can be interpretted as `Redux.Reducer`.
168+
98169
For more examples, please see XCTest cases.
99170

100171

Tests/BasicTests.swift

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ class BasicTests: _TestCase
6060
])
6161
}
6262

63+
// initial
64+
XCTAssertEqual(machine.state, MyState.State0)
65+
6366
// tryEvent
6467
machine <-! .Event0
6568
XCTAssertEqual(machine.state, MyState.State1)
@@ -68,8 +71,59 @@ class BasicTests: _TestCase
6871
machine <-! .Event0
6972
XCTAssertEqual(machine.state, MyState.State2)
7073

71-
// tryEvent
74+
// tryEvent (fails)
7275
machine <-! .Event0
7376
XCTAssertEqual(machine.state, MyState.State2, "Event0 doesn't have 2 => Any")
7477
}
78+
79+
func testREADME_routeMapping()
80+
{
81+
let machine = Machine<StrState, StrEvent>(state: .Str("initial")) { machine in
82+
83+
// add EventRouteMapping
84+
machine.addRouteMapping { event, fromState, userInfo -> StrState? in
85+
// no route for no-event
86+
guard let event = event else { return nil }
87+
88+
switch (event, fromState) {
89+
case (.Str("gogogo"), .Str("initial")):
90+
return .Str("Phase 1")
91+
case (.Str("gogogo"), .Str("Phase 1")):
92+
return .Str("Phase 2")
93+
case (.Str("finish"), .Str("Phase 2")):
94+
return .Str("end")
95+
default:
96+
return nil
97+
}
98+
}
99+
100+
}
101+
102+
// initial
103+
XCTAssertEqual(machine.state, StrState.Str("initial"))
104+
105+
// tryEvent (fails)
106+
machine <-! .Str("go?")
107+
XCTAssertEqual(machine.state, StrState.Str("initial"), "No change.")
108+
109+
// tryEvent
110+
machine <-! .Str("gogogo")
111+
XCTAssertEqual(machine.state, StrState.Str("Phase 1"))
112+
113+
// tryEvent (fails)
114+
machine <-! .Str("finish")
115+
XCTAssertEqual(machine.state, StrState.Str("Phase 1"), "No change.")
116+
117+
// tryEvent
118+
machine <-! .Str("gogogo")
119+
XCTAssertEqual(machine.state, StrState.Str("Phase 2"))
120+
121+
// tryEvent (fails)
122+
machine <-! .Str("gogogo")
123+
XCTAssertEqual(machine.state, StrState.Str("Phase 2"), "No change.")
124+
125+
// tryEvent
126+
machine <-! .Str("finish")
127+
XCTAssertEqual(machine.state, StrState.Str("end"))
128+
}
75129
}

Tests/MachineTests.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -306,63 +306,63 @@ class MachineTests: _TestCase
306306
{
307307
var invokeCount = 0
308308

309-
let machine = Machine<MyState2, MyEvent2>(state: .State0("initial")) { machine in
309+
let machine = Machine<StrState, StrEvent>(state: .Str("initial")) { machine in
310310

311311
// add EventRouteMapping
312-
machine.addRouteMapping { event, fromState, userInfo -> MyState2? in
312+
machine.addRouteMapping { event, fromState, userInfo -> StrState? in
313313
// no route for no-event
314314
guard let event = event else { return nil }
315315

316316
switch (event, fromState) {
317-
case (.Event0("gogogo"), .State0("initial")):
318-
return .State0("Phase 1")
319-
case (.Event0("gogogo"), .State0("Phase 1")):
320-
return .State0("Phase 2")
321-
case (.Event0("finish"), .State0("Phase 2")):
322-
return .State0("end")
317+
case (.Str("gogogo"), .Str("initial")):
318+
return .Str("Phase 1")
319+
case (.Str("gogogo"), .Str("Phase 1")):
320+
return .Str("Phase 2")
321+
case (.Str("finish"), .Str("Phase 2")):
322+
return .Str("end")
323323
default:
324324
return nil
325325
}
326326
}
327327

328-
machine.addHandler(event: .Event0("gogogo")) { context in
328+
machine.addHandler(event: .Str("gogogo")) { context in
329329
invokeCount++
330330
return
331331
}
332332

333333
}
334334

335335
// initial
336-
XCTAssertEqual(machine.state, MyState2.State0("initial"))
336+
XCTAssertEqual(machine.state, StrState.Str("initial"))
337337

338338
// tryEvent (fails)
339-
machine <-! .Event0("go?")
340-
XCTAssertEqual(machine.state, MyState2.State0("initial"), "No change.")
339+
machine <-! .Str("go?")
340+
XCTAssertEqual(machine.state, StrState.Str("initial"), "No change.")
341341
XCTAssertEqual(invokeCount, 0, "Handler should NOT be performed")
342342

343343
// tryEvent
344-
machine <-! .Event0("gogogo")
345-
XCTAssertEqual(machine.state, MyState2.State0("Phase 1"))
344+
machine <-! .Str("gogogo")
345+
XCTAssertEqual(machine.state, StrState.Str("Phase 1"))
346346
XCTAssertEqual(invokeCount, 1)
347347

348348
// tryEvent (fails)
349-
machine <-! .Event0("finish")
350-
XCTAssertEqual(machine.state, MyState2.State0("Phase 1"), "No change.")
349+
machine <-! .Str("finish")
350+
XCTAssertEqual(machine.state, StrState.Str("Phase 1"), "No change.")
351351
XCTAssertEqual(invokeCount, 1, "Handler should NOT be performed")
352352

353353
// tryEvent
354-
machine <-! .Event0("gogogo")
355-
XCTAssertEqual(machine.state, MyState2.State0("Phase 2"))
354+
machine <-! .Str("gogogo")
355+
XCTAssertEqual(machine.state, StrState.Str("Phase 2"))
356356
XCTAssertEqual(invokeCount, 2)
357357

358358
// tryEvent (fails)
359-
machine <-! .Event0("gogogo")
360-
XCTAssertEqual(machine.state, MyState2.State0("Phase 2"), "No change.")
359+
machine <-! .Str("gogogo")
360+
XCTAssertEqual(machine.state, StrState.Str("Phase 2"), "No change.")
361361
XCTAssertEqual(invokeCount, 2, "Handler should NOT be performed")
362362

363363
// tryEvent
364-
machine <-! .Event0("finish")
365-
XCTAssertEqual(machine.state, MyState2.State0("end"))
364+
machine <-! .Str("finish")
365+
XCTAssertEqual(machine.state, StrState.Str("end"))
366366
XCTAssertEqual(invokeCount, 2, "gogogo-Handler should NOT be performed")
367367

368368
}

Tests/MiscTests.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ class MiscTests: _TestCase
5151
// StateType + associated value
5252
func testREADME_associatedValue()
5353
{
54-
let machine = StateMachine<MyState2, MyEvent2>(state: .State0("0")) { machine in
54+
let machine = StateMachine<StrState, StrEvent>(state: .Str("0")) { machine in
5555

56-
machine.addRoute(.State0("0") => .State0("1"))
57-
machine.addRoute(.Any => .State0("2")) { context in print("Any => 2, msg=\(context.userInfo)") }
58-
machine.addRoute(.State0("2") => .Any) { context in print("2 => Any, msg=\(context.userInfo)") }
56+
machine.addRoute(.Str("0") => .Str("1"))
57+
machine.addRoute(.Any => .Str("2")) { context in print("Any => 2, msg=\(context.userInfo)") }
58+
machine.addRoute(.Str("2") => .Any) { context in print("2 => Any, msg=\(context.userInfo)") }
5959

6060
// add handler (handlerContext = (event, transition, order, userInfo))
61-
machine.addHandler(.State0("0") => .State0("1")) { context in
61+
machine.addHandler(.Str("0") => .Str("1")) { context in
6262
print("0 => 1")
6363
}
6464

@@ -70,17 +70,17 @@ class MiscTests: _TestCase
7070

7171
// tryState 0 => 1 => 2 => 1 => 0
7272

73-
machine <- .State0("1")
74-
XCTAssertEqual(machine.state, MyState2.State0("1"))
73+
machine <- .Str("1")
74+
XCTAssertEqual(machine.state, StrState.Str("1"))
7575

76-
machine <- (.State0("2"), "Hello")
77-
XCTAssertEqual(machine.state, MyState2.State0("2"))
76+
machine <- (.Str("2"), "Hello")
77+
XCTAssertEqual(machine.state, StrState.Str("2"))
7878

79-
machine <- (.State0("1"), "Bye")
80-
XCTAssertEqual(machine.state, MyState2.State0("1"))
79+
machine <- (.Str("1"), "Bye")
80+
XCTAssertEqual(machine.state, StrState.Str("1"))
8181

82-
machine <- .State0("0") // fail: no 1 => 0
83-
XCTAssertEqual(machine.state, MyState2.State0("1"))
82+
machine <- .Str("0") // fail: no 1 => 0
83+
XCTAssertEqual(machine.state, StrState.Str("1"))
8484

8585
print("machine.state = \(machine.state)")
8686
}

Tests/MyEvent.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ enum MyEvent: EventType
1313
case Event0, Event1
1414
}
1515

16-
enum MyEvent2: EventType
16+
enum StrEvent: EventType
1717
{
18-
case Event0(String)
18+
case Str(String)
1919

2020
var hashValue: Int
2121
{
2222
switch self {
23-
case .Event0(let str): return str.hashValue
23+
case .Str(let str): return str.hashValue
2424
}
2525
}
2626
}
2727

28-
func == (lhs: MyEvent2, rhs: MyEvent2) -> Bool
28+
func == (lhs: StrEvent, rhs: StrEvent) -> Bool
2929
{
3030
switch (lhs, rhs) {
31-
case let (.Event0(str1), .Event0(str2)):
31+
case let (.Str(str1), .Str(str2)):
3232
return str1 == str2
3333
// default:
3434
// return false

Tests/MyState.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ enum MyState: StateType
1313
case State0, State1, State2, State3
1414
}
1515

16-
enum MyState2: StateType
16+
enum StrState: StateType
1717
{
18-
case State0(String)
18+
case Str(String)
1919

2020
var hashValue: Int
2121
{
2222
switch self {
23-
case .State0(let str): return str.hashValue
23+
case .Str(let str): return str.hashValue
2424
}
2525
}
2626
}
2727

28-
func == (lhs: MyState2, rhs: MyState2) -> Bool
28+
func == (lhs: StrState, rhs: StrState) -> Bool
2929
{
3030
switch (lhs, rhs) {
31-
case let (.State0(str1), .State0(str2)):
31+
case let (.Str(str1), .Str(str2)):
3232
return str1 == str2
3333
}
3434
}

0 commit comments

Comments
 (0)