Skip to content

Commit 1be6782

Browse files
committed
[Test] Re-add HierarchicalMachineTests which was deleted in ef07416.
1 parent 2eeff1f commit 1be6782

File tree

2 files changed

+291
-0
lines changed

2 files changed

+291
-0
lines changed

SwiftState.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
1F198C5C19972320001C3700 /* QiitaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F198C5B19972320001C3700 /* QiitaTests.swift */; };
1111
1F1F74BC1C09FAA000675EAA /* ChainHandlerID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1F74BB1C09FAA000675EAA /* ChainHandlerID.swift */; };
1212
1F1F74C01C0A017E00675EAA /* ChainHandlerID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1F74BB1C09FAA000675EAA /* ChainHandlerID.swift */; };
13+
1F1F74C31C0A02EA00675EAA /* HierarchicalMachineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1F74C11C0A02E700675EAA /* HierarchicalMachineTests.swift */; };
14+
1F1F74C41C0A02EB00675EAA /* HierarchicalMachineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1F74C11C0A02E700675EAA /* HierarchicalMachineTests.swift */; };
1315
1F24C72C19D068B900C2FDC7 /* SwiftState.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4872D5AC19B4211900F326B5 /* SwiftState.framework */; };
1416
1F27771E1BE68D1D00C57CC9 /* RouteMappingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F27771C1BE68C7F00C57CC9 /* RouteMappingTests.swift */; };
1517
1F27771F1BE68D1E00C57CC9 /* RouteMappingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F27771C1BE68C7F00C57CC9 /* RouteMappingTests.swift */; };
@@ -76,6 +78,7 @@
7678
/* Begin PBXFileReference section */
7779
1F198C5B19972320001C3700 /* QiitaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QiitaTests.swift; sourceTree = "<group>"; };
7880
1F1F74BB1C09FAA000675EAA /* ChainHandlerID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChainHandlerID.swift; sourceTree = "<group>"; };
81+
1F1F74C11C0A02E700675EAA /* HierarchicalMachineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HierarchicalMachineTests.swift; sourceTree = "<group>"; };
7982
1F27771C1BE68C7F00C57CC9 /* RouteMappingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteMappingTests.swift; sourceTree = "<group>"; };
8083
1F70FB651BF0F46000E5AC8C /* RouteID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteID.swift; sourceTree = "<group>"; };
8184
1F70FB681BF0F46E00E5AC8C /* RouteChainID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouteChainID.swift; sourceTree = "<group>"; };
@@ -220,6 +223,7 @@
220223
1FA6202D199660CA00460108 /* RouteTests.swift */,
221224
1FA6202A199660CA00460108 /* RouteChainTests.swift */,
222225
1F27771C1BE68C7F00C57CC9 /* RouteMappingTests.swift */,
226+
1F1F74C11C0A02E700675EAA /* HierarchicalMachineTests.swift */,
223227
1FA6200D1996601000460108 /* Supporting Files */,
224228
);
225229
path = SwiftStateTests;
@@ -447,6 +451,7 @@
447451
1FA62038199660CA00460108 /* TransitionTests.swift in Sources */,
448452
1FA62033199660CA00460108 /* RouteChainTests.swift in Sources */,
449453
1FA62030199660CA00460108 /* _TestCase.swift in Sources */,
454+
1F1F74C31C0A02EA00675EAA /* HierarchicalMachineTests.swift in Sources */,
450455
1FA62036199660CA00460108 /* RouteTests.swift in Sources */,
451456
1FA62031199660CA00460108 /* BasicTests.swift in Sources */,
452457
1FA62034199660CA00460108 /* TryEventTests.swift in Sources */,
@@ -467,6 +472,7 @@
467472
4822F0AF19D008EB00F5F572 /* TryEventTests.swift in Sources */,
468473
4822F0A819D008E300F5F572 /* _TestCase.swift in Sources */,
469474
4822F0AA19D008E700F5F572 /* MyEvent.swift in Sources */,
475+
1F1F74C41C0A02EB00675EAA /* HierarchicalMachineTests.swift in Sources */,
470476
4822F0AE19D008EB00F5F572 /* RouteChainTests.swift in Sources */,
471477
4822F0B019D008EB00F5F572 /* TransitionTests.swift in Sources */,
472478
4822F0A919D008E700F5F572 /* MyState.swift in Sources */,
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
//
2+
// HierarchicalMachineTests.swift
3+
// SwiftState
4+
//
5+
// Created by Yasuhiro Inami on 2015-11-29.
6+
// Copyright © 2015 Yasuhiro Inami. All rights reserved.
7+
//
8+
9+
import SwiftState
10+
import XCTest
11+
12+
private enum _MainState: StateType
13+
{
14+
case MainState0
15+
case SubMachine1(_SubState)
16+
case SubMachine2(_SubState)
17+
18+
var hashValue: Int
19+
{
20+
switch self {
21+
case .MainState0:
22+
return "MainState0".hashValue
23+
case let .SubMachine1(state):
24+
return "SubMachine1-\(state)".hashValue
25+
case let .SubMachine2(state):
26+
return "SubMachine2-\(state)".hashValue
27+
}
28+
}
29+
}
30+
31+
private enum _SubState: StateType
32+
{
33+
case SubState0, SubState1, SubState2
34+
}
35+
36+
private func ==(lhs: _MainState, rhs: _MainState) -> Bool
37+
{
38+
switch (lhs, rhs) {
39+
case (.MainState0, .MainState0):
40+
return true
41+
case let (.SubMachine1(state1), .SubMachine1(state2)):
42+
return state1 == state2
43+
case let (.SubMachine2(state1), .SubMachine2(state2)):
44+
return state1 == state2
45+
default:
46+
return false
47+
}
48+
}
49+
50+
class HierarchicalMachineTests: _TestCase
51+
{
52+
///
53+
/// Hierarchical state machine.
54+
///
55+
/// - mainMachine
56+
/// - MainState0 (initial)
57+
/// - subMachine1
58+
/// - SubState0
59+
/// - SubState1
60+
/// - subMachine2
61+
/// - SubState0
62+
/// - SubState1
63+
///
64+
/// - Warning:
65+
/// This is a naive implementation and easily lose consistency when `subMachine.state` is changed directly, e.g. `subMachine1 <- .SubState1`.
66+
///
67+
private var mainMachine: Machine<_MainState, NoEvent>?
68+
69+
private var subMachine1: Machine<_SubState, NoEvent>?
70+
private var subMachine2: Machine<_SubState, NoEvent>?
71+
72+
override func setUp()
73+
{
74+
super.setUp()
75+
76+
let subMachine1 = Machine<_SubState, NoEvent>(state: .SubState0) { subMachine1 in
77+
// add Sub1-0 => Sub1-1
78+
subMachine1.addRoute(.SubState0 => .SubState1)
79+
80+
subMachine1.addHandler(.Any => .Any) { print("[Sub1] \($0.fromState) => \($0.toState)") }
81+
subMachine1.addErrorHandler { print("[ERROR][Sub1] \($0.fromState) => \($0.toState)") }
82+
}
83+
84+
let subMachine2 = Machine<_SubState, NoEvent>(state: .SubState0) { subMachine2 in
85+
// add Sub2-0 => Sub2-1
86+
subMachine2.addRoute(.SubState0 => .SubState1)
87+
88+
subMachine2.addHandler(.Any => .Any) { print("[Sub2] \($0.fromState) => \($0.toState)") }
89+
subMachine2.addErrorHandler { print("[ERROR][Sub2] \($0.fromState) => \($0.toState)") }
90+
}
91+
92+
let mainMachine = Machine<_MainState, NoEvent>(state: .MainState0) { mainMachine in
93+
94+
// add routes & handle for same-subMachine internal transitions
95+
mainMachine.addRoute(.Any => .Any, condition: { _, fromState, toState, userInfo in
96+
97+
switch (fromState, toState) {
98+
case let (.SubMachine1(state1), .SubMachine1(state2)):
99+
return subMachine1.hasRoute(fromState: state1, toState: state2)
100+
case let (.SubMachine2(state1), .SubMachine2(state2)):
101+
return subMachine2.hasRoute(fromState: state1, toState: state2)
102+
default:
103+
return false
104+
}
105+
106+
}, handler: { _, fromState, toState, userInfo in
107+
switch (fromState, toState) {
108+
case let (.SubMachine1, .SubMachine1(state2)):
109+
subMachine1 <- state2
110+
case let (.SubMachine2, .SubMachine2(state2)):
111+
subMachine2 <- state2
112+
default:
113+
break
114+
}
115+
})
116+
117+
// add routes for mainMachine-state transitions (submachine switching)
118+
mainMachine.addRouteMapping { _, fromState, _ -> _MainState? in
119+
120+
// NOTE: use external submachine's states only for evaluating `toState`, but not for `fromState`
121+
switch fromState {
122+
// "Main0" => "Sub1-0"
123+
case .MainState0 where subMachine1.state == .SubState0:
124+
return .SubMachine1(.SubState0)
125+
126+
// "Sub1-1" => "Sub2-0"
127+
case let .SubMachine1(state) where state == .SubState1 && subMachine2.state == .SubState0:
128+
return .SubMachine2(.SubState0)
129+
130+
// "Sub2-1" => "Main0"
131+
case let .SubMachine2(state) where state == .SubState1:
132+
return .MainState0
133+
134+
default:
135+
return nil
136+
}
137+
138+
}
139+
140+
mainMachine.addHandler(.Any => .Any) { print("[Main] \($0.fromState) => \($0.toState)") }
141+
mainMachine.addErrorHandler { print("[ERROR][Main] \($0.fromState) => \($0.toState)") }
142+
}
143+
144+
self.mainMachine = mainMachine
145+
self.subMachine1 = subMachine1
146+
self.subMachine2 = subMachine2
147+
}
148+
149+
/// `mainMachine.hasRoute()` test to check submachine's internal routes
150+
func testHasRoute_submachine_internal()
151+
{
152+
let mainMachine = self.mainMachine!
153+
let subMachine1 = self.subMachine1!
154+
let subMachine2 = self.subMachine2!
155+
156+
// initial
157+
XCTAssertTrue(mainMachine.state == .MainState0)
158+
XCTAssertTrue(subMachine1.state == .SubState0)
159+
XCTAssertTrue(subMachine2.state == .SubState0)
160+
161+
// subMachine1 internal routes
162+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState0) => .SubMachine1(.SubState0)))
163+
XCTAssertTrue(mainMachine.hasRoute(.SubMachine1(.SubState0) => .SubMachine1(.SubState1)))
164+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState1) => .SubMachine1(.SubState0)))
165+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState1) => .SubMachine1(.SubState1)))
166+
167+
// subMachine2 internal routes
168+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState0) => .SubMachine2(.SubState0)))
169+
XCTAssertTrue(mainMachine.hasRoute(.SubMachine2(.SubState0) => .SubMachine2(.SubState1)))
170+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState1) => .SubMachine2(.SubState0)))
171+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState1) => .SubMachine2(.SubState1)))
172+
}
173+
174+
/// `mainMachine.hasRoute()` test to check switchable submachines
175+
func testHasRoute_submachine_switching()
176+
{
177+
let mainMachine = self.mainMachine!
178+
let subMachine1 = self.subMachine1!
179+
let subMachine2 = self.subMachine2!
180+
181+
// NOTE: mainMachine can check switchable submachines
182+
// (external routes between submachines = SubState1, SubState2, or nil)
183+
184+
// initial
185+
XCTAssertTrue(mainMachine.state == .MainState0)
186+
XCTAssertTrue(subMachine1.state == .SubState0)
187+
XCTAssertTrue(subMachine2.state == .SubState0)
188+
189+
// from Main0
190+
XCTAssertTrue(mainMachine.hasRoute(.MainState0 => .SubMachine1(.SubState0)))
191+
XCTAssertFalse(mainMachine.hasRoute(.MainState0 => .SubMachine1(.SubState1)))
192+
XCTAssertFalse(mainMachine.hasRoute(.MainState0 => .SubMachine2(.SubState0)))
193+
XCTAssertFalse(mainMachine.hasRoute(.MainState0 => .SubMachine2(.SubState1)))
194+
195+
// from Sub1-0
196+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState0) => .SubMachine2(.SubState0)))
197+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState0) => .SubMachine2(.SubState1)))
198+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState0) => .MainState0))
199+
200+
// from Sub1-1
201+
XCTAssertTrue(mainMachine.hasRoute(.SubMachine1(.SubState1) => .SubMachine2(.SubState0)))
202+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState1) => .SubMachine2(.SubState1)))
203+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine1(.SubState1) => .MainState0))
204+
205+
// from Sub2-0
206+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState0) => .SubMachine1(.SubState0)))
207+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState0) => .SubMachine1(.SubState1)))
208+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState0) => .MainState0))
209+
210+
// from Sub2-1
211+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState1) => .SubMachine1(.SubState0)))
212+
XCTAssertFalse(mainMachine.hasRoute(.SubMachine2(.SubState1) => .SubMachine1(.SubState1)))
213+
XCTAssertTrue(mainMachine.hasRoute(.SubMachine2(.SubState1) => .MainState0))
214+
215+
}
216+
217+
func testTryState()
218+
{
219+
let mainMachine = self.mainMachine!
220+
221+
// initial
222+
XCTAssertTrue(mainMachine.state == .MainState0)
223+
224+
// Main0 => Sub1-0
225+
mainMachine <- .SubMachine1(.SubState0)
226+
XCTAssertTrue(mainMachine.state == .SubMachine1(.SubState0))
227+
228+
// Sub1-0 => Sub1-1 (Sub1 internal transition)
229+
mainMachine <- .SubMachine1(.SubState1)
230+
XCTAssertTrue(mainMachine.state == .SubMachine1(.SubState1))
231+
232+
// Sub1-1 => Sub1-2 (Sub1 internal transition, but fails)
233+
mainMachine <- .SubMachine1(.SubState2)
234+
XCTAssertTrue(mainMachine.state == .SubMachine1(.SubState1), "No change.")
235+
236+
// Sub1-1 => Sub2-2 (fails)
237+
mainMachine <- .SubMachine2(.SubState2)
238+
XCTAssertTrue(mainMachine.state == .SubMachine1(.SubState1), "No change.")
239+
240+
// Sub1-1 => Sub2-0
241+
mainMachine <- .SubMachine2(.SubState0)
242+
XCTAssertTrue(mainMachine.state == .SubMachine2(.SubState0))
243+
244+
// Sub2-0 => Main0 (fails)
245+
mainMachine <- .MainState0
246+
XCTAssertTrue(mainMachine.state == .SubMachine2(.SubState0), "No change.")
247+
248+
// Sub2-0 => Sub2-1
249+
mainMachine <- .SubMachine2(.SubState1)
250+
XCTAssertTrue(mainMachine.state == .SubMachine2(.SubState1))
251+
252+
// Sub2-1 => Main
253+
mainMachine <- .MainState0
254+
XCTAssertTrue(mainMachine.state == .MainState0)
255+
256+
}
257+
258+
func testAddHandler()
259+
{
260+
let mainMachine = self.mainMachine!
261+
262+
var didPass = false
263+
264+
// NOTE: this handler is added to mainMachine and doesn't make submachines dirty
265+
mainMachine.addHandler(.MainState0 => .SubMachine1(.SubState0)) { context in
266+
print("[Main] 1-1 => 1-2 (specific)")
267+
didPass = true
268+
}
269+
270+
// initial
271+
XCTAssertTrue(mainMachine.state == .MainState0)
272+
XCTAssertFalse(didPass)
273+
274+
// Main0 => Sub1-1 (fails)
275+
mainMachine <- .SubMachine1(.SubState1)
276+
XCTAssertTrue(mainMachine.state == .MainState0, "No change.")
277+
XCTAssertFalse(didPass)
278+
279+
// Main0 => Sub1-0
280+
mainMachine <- .SubMachine1(.SubState0)
281+
XCTAssertTrue(mainMachine.state == .SubMachine1(.SubState0))
282+
XCTAssertTrue(didPass)
283+
}
284+
285+
}

0 commit comments

Comments
 (0)