1
|
|
|
<?php |
|
|
|
|
2
|
|
|
App::uses('StateMachineBehavior', 'StateMachine.Model/Behavior'); |
3
|
|
|
|
4
|
|
|
class BaseVehicle extends CakeTestModel { |
|
|
|
|
5
|
|
|
|
6
|
|
|
public $useTable = 'vehicles'; |
7
|
|
|
|
8
|
|
|
public $actsAs = array('StateMachine.StateMachine'); |
9
|
|
|
|
10
|
|
|
public $initialState = 'parked'; |
11
|
|
|
|
12
|
|
|
public $transitions = array( |
13
|
|
|
'ignite' => array( |
14
|
|
|
'parked' => 'idling', |
15
|
|
|
'stalled' => 'stalled' |
16
|
|
|
), |
17
|
|
|
'park' => array( |
18
|
|
|
'idling' => 'parked', |
19
|
|
|
'first_gear' => 'parked' |
20
|
|
|
), |
21
|
|
|
'shift_up' => array( |
22
|
|
|
'idling' => 'first_gear', |
23
|
|
|
'first_gear' => 'second_gear', |
24
|
|
|
'second_gear' => 'third_gear' |
25
|
|
|
), |
26
|
|
|
'shift_down' => array( |
27
|
|
|
'first_gear' => 'idling', |
28
|
|
|
'second_gear' => 'first_gear', |
29
|
|
|
'third_gear' => 'second_gear' |
30
|
|
|
), |
31
|
|
|
'crash' => array( |
32
|
|
|
'first_gear' => 'stalled', |
33
|
|
|
'second_gear' => 'stalled', |
34
|
|
|
'third_gear' => 'stalled' |
35
|
|
|
), |
36
|
|
|
'repair' => array( |
37
|
|
|
'stalled' => 'parked' |
38
|
|
|
), |
39
|
|
|
'idle' => array( |
40
|
|
|
'first_gear' => 'idling' |
41
|
|
|
), |
42
|
|
|
'turn_off' => array( |
43
|
|
|
'all' => 'parked' |
44
|
|
|
), |
45
|
|
|
'baz' => array() |
46
|
|
|
); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
class Vehicle extends BaseVehicle { |
|
|
|
|
50
|
|
|
|
51
|
|
|
public function onStateChange($newState) { |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
public function onStateIdling($newState) { |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
public function onBeforeTransition($currentState, $previousState, $transition) { |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
public function onAfterTransition($currentState, $previousState, $transition) { |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
public function onBeforeIgnite($currentState, $previousState, $transition) { |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
class RulesVehicle extends BaseVehicle { |
|
|
|
|
69
|
|
|
|
70
|
|
|
public $transitionRules = array( |
71
|
|
|
'hardwire' => array( |
72
|
|
|
'role' => array('thief'), |
73
|
|
|
), |
74
|
|
|
'ignite' => array( |
75
|
|
|
'role' => array('driver'), |
76
|
|
|
'depends' => 'has_key' |
77
|
|
|
), |
78
|
|
|
'park' => array( |
79
|
|
|
'role' => array('driver', 'thief'), |
80
|
|
|
'depends' => 'available_parking' |
81
|
|
|
), |
82
|
|
|
'repair' => array( |
83
|
|
|
'role' => array('mechanic'), |
84
|
|
|
'depends' => 'has_tools' |
85
|
|
|
) |
86
|
|
|
); |
87
|
|
|
|
88
|
|
|
public function __construct($id = false, $table = null, $ds = null) { |
89
|
|
|
$this->transitions += array( |
90
|
|
|
'hardwire' => array( |
91
|
|
|
'parked' => 'idling', |
92
|
|
|
'stalled' => 'stalled' |
93
|
|
|
) |
94
|
|
|
); |
95
|
|
|
|
96
|
|
|
parent::__construct($id, $table, $ds); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
public function hasKey($role) { |
100
|
|
|
if ($role == 'driver') { |
101
|
|
|
return true; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
return false; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
public function availableParking($role) { |
108
|
|
|
return $role == 'thief'; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
class ValidationsVehicle extends Vehicle { |
|
|
|
|
114
|
|
|
|
115
|
|
|
public $validate = array( |
116
|
|
|
'title' => array( |
117
|
|
|
'custom' => array( |
118
|
|
|
'rule' => array('custom', '/toyota yaris/i') |
119
|
|
|
) |
120
|
|
|
) |
121
|
|
|
); |
122
|
|
|
|
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
class StateMachineBehaviorTest extends CakeTestCase { |
|
|
|
|
126
|
|
|
|
127
|
|
|
public $fixtures = array( |
128
|
|
|
'plugin.state_machine.vehicle' |
129
|
|
|
); |
130
|
|
|
|
131
|
|
|
public $Vehicle; |
132
|
|
|
|
133
|
|
|
public $StateMachine; |
134
|
|
|
|
135
|
|
|
public function setUp() { |
136
|
|
|
parent::setUp(); |
137
|
|
|
|
138
|
|
|
$this->Vehicle = new Vehicle(1); |
139
|
|
|
$this->StateMachine = $this->Vehicle->Behaviors->StateMachine; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
public function testGetAllTransitions() { |
143
|
|
|
$this->assertCount(9, $this->Vehicle->getAllTransitions()); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
public function testAvailableStates() { |
147
|
|
|
$this->assertCount(6, $this->Vehicle->getAvailableStates()); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
public function testTransitionById() { |
151
|
|
|
$this->Vehicle->ignite(1); |
152
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState(1)); |
153
|
|
|
$this->assertEquals("parked", $this->Vehicle->getPreviousState(1)); |
154
|
|
|
$this->assertEquals("ignite", $this->Vehicle->getLastTransition(1)); |
155
|
|
|
$this->assertEquals("", $this->Vehicle->getLastRole(1)); |
156
|
|
|
$this->Vehicle->shiftUp(1); |
157
|
|
|
$this->assertEquals("first_gear", $this->Vehicle->getCurrentState(1)); |
158
|
|
|
$this->assertEquals("idling", $this->Vehicle->getPreviousState(1)); |
159
|
|
|
$this->Vehicle->shiftUp(1); |
160
|
|
|
$this->assertEquals("second_gear", $this->Vehicle->getCurrentState(1)); |
161
|
|
|
$this->assertEquals("first_gear", $this->Vehicle->getPreviousState(1)); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
public function testIgnoreValidationOnTransition() { |
165
|
|
|
$this->Vehicle = new ValidationsVehicle(1); |
166
|
|
|
|
167
|
|
|
$this->assertFalse($this->Vehicle->ignite()); |
168
|
|
|
$this->assertEquals("parked", $this->Vehicle->getCurrentState()); |
169
|
|
|
|
170
|
|
|
$this->assertTrue($this->Vehicle->ignite(null, null, false)); |
171
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState()); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
public function testValidateOnTransition() { |
175
|
|
|
$this->Vehicle = new ValidationsVehicle(1); |
176
|
|
|
$this->assertFalse($this->Vehicle->ignite()); |
177
|
|
|
|
178
|
|
|
$this->Vehicle = new ValidationsVehicle(2); |
179
|
|
|
$this->assertTrue($this->Vehicle->ignite()); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
public function testStateListener() { |
183
|
|
|
// test state listener on transition failed |
184
|
|
|
$this->Vehicle = $this->getMock('ValidationsVehicle', array( |
185
|
|
|
'onStateChange', 'onStateIdling', 'onBeforeTransition', 'onAfterTransition')); |
186
|
|
|
$this->Vehicle->id = 1; |
187
|
|
|
$this->Vehicle->expects($this->once())->method('onBeforeTransition'); |
188
|
|
|
$this->Vehicle->expects($this->never())->method('onAfterTransition'); |
189
|
|
|
$this->Vehicle->expects($this->never())->method('onStateChange'); |
190
|
|
|
$this->Vehicle->expects($this->never())->method('onStateIdling'); |
191
|
|
|
$this->assertFalse($this->Vehicle->ignite()); |
192
|
|
|
|
193
|
|
|
// test state listener on transition success |
194
|
|
|
$this->Vehicle = $this->getMock('ValidationsVehicle', array( |
195
|
|
|
'onStateChange', 'onStateIdling', 'onBeforeTransition', 'onAfterTransition')); |
196
|
|
|
$this->Vehicle->id = 2; |
197
|
|
|
$this->Vehicle->expects($this->once())->method('onBeforeTransition'); |
198
|
|
|
$this->Vehicle->expects($this->once())->method('onAfterTransition'); |
199
|
|
|
$this->Vehicle->expects($this->once())->method('onStateChange'); |
200
|
|
|
$this->Vehicle->expects($this->once())->method('onStateIdling'); |
201
|
|
|
$this->assertTrue($this->Vehicle->ignite()); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
public function testCanTransitionById() { |
205
|
|
|
$this->assertTrue($this->Vehicle->is('parked')); |
206
|
|
|
|
207
|
|
|
$this->assertEquals($this->Vehicle->can('shift_up', 1), $this->Vehicle->canShiftUp(1)); |
208
|
|
|
$this->assertFalse($this->Vehicle->can('shift_up', 1)); |
209
|
|
|
|
210
|
|
|
$this->assertTrue($this->Vehicle->can('ignite', 1)); |
211
|
|
|
$this->Vehicle->ignite(); |
212
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState()); |
213
|
|
|
|
214
|
|
|
$this->assertEquals($this->Vehicle->can('shift_up', 1), $this->Vehicle->canShiftUp(1)); |
215
|
|
|
$this->assertTrue($this->Vehicle->canShiftUp(1)); |
216
|
|
|
$this->assertFalse($this->Vehicle->canShiftDown(1)); |
217
|
|
|
|
218
|
|
|
$this->assertFalse($this->Vehicle->canShiftUp(2)); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
View Code Duplication |
public function testFindAllByState() { |
|
|
|
|
222
|
|
|
$this->assertFalse($this->Vehicle->findAllByState()); |
223
|
|
|
$this->assertFalse($this->Vehicle->findAllByState('illegal_state_should_not_be_possible')); |
224
|
|
|
$this->assertFalse($this->Vehicle->findAllByState(array('illegal_state_should_not_be_possible', 'parked'))); |
225
|
|
|
$this->assertCount(2, $this->Vehicle->findAllByState('parked')); |
226
|
|
|
$this->assertCount(1, $this->Vehicle->findAllByState('parked', array('conditions' => array('Vehicle.title' => 'Audi Q4')))); |
227
|
|
|
$this->assertCount(4, $this->Vehicle->findAllByState('all')); |
228
|
|
|
$this->assertCount(1, $this->Vehicle->findAllByState('idling')); |
229
|
|
|
$this->assertCount(3, $this->Vehicle->findAllByState(array('idling', 'parked'))); |
230
|
|
|
|
231
|
|
|
// test with transition array |
232
|
|
|
$testTransitions = $this->Vehicle->findAllByState('parked'); |
233
|
|
|
$this->assertTrue(is_array($testTransitions[0]['Vehicle']['Transitions'])); |
234
|
|
|
$this->assertCount(2, $testTransitions[0]['Vehicle']['Transitions']); |
235
|
|
|
|
236
|
|
|
// test without transitions array |
237
|
|
|
$testTransitions = $this->Vehicle->findAllByState('parked', array(), false); |
238
|
|
|
$this->assertFalse(isset($testTransitions[0]['Vehicle']['Transitions'])); |
239
|
|
|
|
240
|
|
|
$this->Vehicle = new RulesVehicle(1); |
241
|
|
|
$testTransitions = $this->Vehicle->findAllByState('parked', array(), true, 'driver'); |
242
|
|
|
$this->assertEqual(array('ignite', 'turn_off'), $testTransitions[0]['RulesVehicle']['Transitions']); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
public function testFindCountByState() { |
246
|
|
|
$this->assertFalse($this->Vehicle->findCountByState()); |
247
|
|
|
$this->assertFalse($this->Vehicle->findCountByState('illegal_state_should_not_be_possible')); |
248
|
|
|
$this->assertFalse($this->Vehicle->findCountByState(array('illegal_state_should_not_be_possible', 'parked'))); |
249
|
|
|
$this->assertEqual(2, $this->Vehicle->findCountByState('parked')); |
250
|
|
|
$this->assertEqual(1, $this->Vehicle->findCountByState('parked', array('conditions' => array('Vehicle.title' => 'Audi Q4')))); |
251
|
|
|
$this->assertEqual(4, $this->Vehicle->findCountByState('all')); |
252
|
|
|
$this->assertEqual(1, $this->Vehicle->findCountByState('idling')); |
253
|
|
|
$this->assertEqual(3, $this->Vehicle->findCountByState(array('idling', 'parked'))); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
View Code Duplication |
public function testFindFirstByState() { |
|
|
|
|
257
|
|
|
$this->assertFalse($this->Vehicle->findFirstByState()); |
258
|
|
|
$this->assertFalse($this->Vehicle->findFirstByState('illegal_state_should_not_be_possible')); |
259
|
|
|
$this->assertFalse($this->Vehicle->findFirstByState(array('illegal_state_should_not_be_possible', 'parked'))); |
260
|
|
|
$this->assertCount(1, $this->Vehicle->findFirstByState('parked')); |
261
|
|
|
$this->assertCount(1, $this->Vehicle->findFirstByState('parked', array('conditions' => array('Vehicle.title' => 'Audi Q4')))); |
262
|
|
|
$this->assertCount(1, $this->Vehicle->findFirstByState('all')); |
263
|
|
|
$this->assertCount(1, $this->Vehicle->findFirstByState('idling')); |
264
|
|
|
$this->assertCount(1, $this->Vehicle->findFirstByState(array('idling', 'parked'))); |
265
|
|
|
|
266
|
|
|
// test with transition array |
267
|
|
|
$testTransitions = $this->Vehicle->findFirstByState('parked'); |
268
|
|
|
$this->assertTrue(is_array($testTransitions[0]['Vehicle']['Transitions'])); |
269
|
|
|
$this->assertCount(2, $testTransitions[0]['Vehicle']['Transitions']); |
270
|
|
|
|
271
|
|
|
// test without transitions array |
272
|
|
|
$testTransitions = $this->Vehicle->findFirstByState('parked', array(), false); |
273
|
|
|
$this->assertFalse(isset($testTransitions[0]['Vehicle']['Transitions'])); |
274
|
|
|
|
275
|
|
|
$this->Vehicle = new RulesVehicle(1); |
276
|
|
|
$testTransitions = $this->Vehicle->findFirstByState('parked', array(), true, 'driver'); |
277
|
|
|
$this->assertEqual(array('ignite', 'turn_off'), $testTransitions[0]['RulesVehicle']['Transitions']); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
public function testInitialState() { |
281
|
|
|
$this->assertEquals("parked", $this->Vehicle->getCurrentState()); |
282
|
|
|
$this->assertEquals('parked', $this->Vehicle->getStates('turn_off')); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
public function testIsMethodsById() { |
286
|
|
|
$this->assertEquals("parked", $this->Vehicle->getCurrentState()); |
287
|
|
|
$this->assertEquals($this->Vehicle->isParked(1), $this->Vehicle->is('parked', 1)); |
288
|
|
|
$this->assertTrue($this->Vehicle->isParked(1)); |
289
|
|
|
|
290
|
|
|
$this->Vehicle->ignite(); |
291
|
|
|
|
292
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState()); |
293
|
|
|
$this->assertEquals($this->Vehicle->isIdling(1), $this->Vehicle->is('idling', 1)); |
294
|
|
|
$this->assertTrue($this->Vehicle->isIdling(1)); |
295
|
|
|
|
296
|
|
|
$this->assertEquals("parked", $this->Vehicle->getCurrentState(2)); |
297
|
|
|
$this->assertEquals($this->Vehicle->isParked(2), $this->Vehicle->is('parked', 2)); |
298
|
|
|
$this->assertTrue($this->Vehicle->isParked(2)); |
299
|
|
|
$this->assertFalse($this->Vehicle->isIdling(2)); |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
public function testIsMethods() { |
303
|
|
|
$this->assertEquals($this->Vehicle->isParked(), $this->Vehicle->is('parked')); |
304
|
|
|
$this->assertEquals($this->Vehicle->isIdling(), $this->Vehicle->is('idling')); |
305
|
|
|
$this->assertEquals($this->Vehicle->isStalled(), $this->Vehicle->is('stalled')); |
306
|
|
|
$this->assertEquals($this->Vehicle->isIdling(), $this->Vehicle->is('idling')); |
307
|
|
|
|
308
|
|
|
$this->assertEquals($this->Vehicle->canShiftUp(), $this->Vehicle->can('shift_up')); |
309
|
|
|
$this->assertFalse($this->Vehicle->canShiftUp()); |
310
|
|
|
|
311
|
|
|
$this->assertTrue($this->Vehicle->canIgnite()); |
312
|
|
|
$this->Vehicle->ignite(); |
313
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState()); |
314
|
|
|
|
315
|
|
|
$this->assertTrue($this->Vehicle->canShiftUp()); |
316
|
|
|
$this->assertFalse($this->Vehicle->canShiftDown()); |
317
|
|
|
|
318
|
|
|
$this->assertTrue($this->Vehicle->isIdling()); |
319
|
|
|
$this->assertFalse($this->Vehicle->canCrash()); |
320
|
|
|
$this->Vehicle->shiftUp(); |
321
|
|
|
$this->Vehicle->crash(); |
322
|
|
|
$this->assertEquals("stalled", $this->Vehicle->getCurrentState()); |
323
|
|
|
$this->assertTrue($this->Vehicle->isStalled()); |
324
|
|
|
$this->Vehicle->repair(); |
325
|
|
|
$this->assertTrue($this->Vehicle->isParked()); |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
public function testOnMethods() { |
329
|
|
|
$scope = $this; |
330
|
|
|
$this->Vehicle->onIgnite('before', function ($currentState, $previousState, $transition) use ($scope) { |
331
|
|
|
$scope->assertEquals("parked", $currentState); |
332
|
|
|
$scope->assertNull($previousState); |
333
|
|
|
$scope->assertEquals("ignite", $transition); |
334
|
|
|
}); |
335
|
|
|
|
336
|
|
|
$this->Vehicle->on('ignite', 'after', function ($currentState, $previousState, $transition) use ($scope) { |
337
|
|
|
$scope->assertEquals("idling", $currentState); |
338
|
|
|
$scope->assertEquals("parked", $previousState); |
339
|
|
|
$scope->assertEquals("ignite", $transition); |
340
|
|
|
}); |
341
|
|
|
|
342
|
|
|
$this->Vehicle->ignite(); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
public function testBadMethodCall() { |
346
|
|
|
$this->setExpectedException('PDOException'); |
347
|
|
|
$this->Vehicle->isFoobar(); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
public function whenParked() { |
351
|
|
|
$this->assertEquals('parked', $this->Vehicle->getCurrentState()); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
public function testWhenMethods() { |
355
|
|
|
$this->Vehicle->whenStalled(function () { |
356
|
|
|
$this->assertEquals("stalled", $this->Vehicle->getCurrentState()); |
357
|
|
|
}); |
358
|
|
|
|
359
|
|
|
$this->Vehicle->when('parked', array($this, 'whenParked')); |
360
|
|
|
|
361
|
|
|
$this->Vehicle->ignite(); |
362
|
|
|
$this->Vehicle->shiftUp(); |
363
|
|
|
$this->Vehicle->crash(); |
364
|
|
|
$this->Vehicle->repair(); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
public function testBubble() { |
368
|
|
|
$scope = $this; |
369
|
|
|
$this->Vehicle->on('ignite', 'before', function () use ($scope) { |
370
|
|
|
$scope->assertEquals("parked", $scope->Vehicle->getCurrentState()); |
371
|
|
|
}, false); |
372
|
|
|
|
373
|
|
|
$this->Vehicle->on('transition', 'before', function () use ($scope) { |
374
|
|
|
// this should never be called |
375
|
|
|
$scope->assertTrue(false); |
376
|
|
|
}); |
377
|
|
|
|
378
|
|
|
$this->Vehicle->ignite(); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
public function testInvalidTransition() { |
382
|
|
|
$this->assertFalse($this->Vehicle->getStates('foobar')); |
383
|
|
|
$this->assertFalse($this->Vehicle->getStates('baz')); |
384
|
|
|
$this->assertFalse($this->Vehicle->baz()); |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
public function testVehicleTitle() { |
388
|
|
|
$this->Vehicle = new Vehicle(3); |
389
|
|
|
|
390
|
|
|
$this->assertEquals("Opel Astra", $this->Vehicle->field('title')); |
391
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState()); |
392
|
|
|
$this->Vehicle->shiftUp(); |
393
|
|
|
$this->assertEquals("first_gear", $this->Vehicle->getCurrentState()); |
394
|
|
|
|
395
|
|
|
$this->Vehicle = new Vehicle(4); |
396
|
|
|
$this->assertEquals("Nissan Leaf", $this->Vehicle->field('title')); |
397
|
|
|
$this->assertEquals("stalled", $this->Vehicle->getCurrentState()); |
398
|
|
|
$this->assertTrue($this->Vehicle->canRepair()); |
399
|
|
|
$this->assertTrue($this->Vehicle->repair()); |
400
|
|
|
$this->assertEquals("parked", $this->Vehicle->getCurrentState()); |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
public function testCreateVehicle() { |
404
|
|
|
$this->Vehicle->create(); |
405
|
|
|
$this->Vehicle->save(array( |
406
|
|
|
'Vehicle' => array( |
407
|
|
|
'title' => 'Toybota' |
408
|
|
|
) |
409
|
|
|
)); |
410
|
|
|
$this->Vehicle->id = $this->Vehicle->getLastInsertID(); |
411
|
|
|
$this->assertEquals($this->Vehicle->initialState, $this->Vehicle->getCurrentState()); |
412
|
|
|
} |
413
|
|
|
|
414
|
|
|
public function testAddToPrepareArrayNoRoles() { |
415
|
|
|
$this->Vehicle = new Vehicle(1); |
416
|
|
|
|
417
|
|
|
$dataArrayToFill = array(); |
418
|
|
|
$dataToAdd = array( |
419
|
|
|
'stateFrom' => 'initial', |
420
|
|
|
'stateTo' => 'second', |
421
|
|
|
'transition' => 'launch' |
422
|
|
|
); |
423
|
|
|
|
424
|
|
|
// Case 1 - illegal parameters |
425
|
|
|
$this->assertFalse($this->Vehicle->addToPrepareArray(null, $dataArrayToFill)); |
426
|
|
|
$this->assertFalse($this->Vehicle->addToPrepareArray(array(), $dataArrayToFill)); |
427
|
|
|
|
428
|
|
|
// Case 2 - adding first array |
429
|
|
|
$expected[] = $dataToAdd; |
|
|
|
|
430
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
431
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
432
|
|
|
|
433
|
|
|
// Case 3 - adding second array |
434
|
|
|
$dataToAdd = array( |
435
|
|
|
'stateFrom' => 'second', |
436
|
|
|
'stateTo' => 'third', |
437
|
|
|
'transition' => 'launch2', |
438
|
|
|
'not_care' => 'anyvalue' |
439
|
|
|
); |
440
|
|
|
$expected[] = $dataToAdd; |
441
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
442
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
443
|
|
|
|
444
|
|
|
// Case 4 - adding same array should not increase |
445
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
446
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
447
|
|
|
|
448
|
|
|
// Case 5 - adding depends |
449
|
|
|
$dataToAdd = array( |
450
|
|
|
'stateFrom' => 'second', |
451
|
|
|
'stateTo' => 'third', |
452
|
|
|
'transition' => 'launch2', |
453
|
|
|
'depends' => 'hasValid' |
454
|
|
|
); |
455
|
|
|
$expected[] = $dataToAdd; |
456
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
457
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
458
|
|
|
|
459
|
|
|
// Case 6 - adding same depends should skip it |
460
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
461
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
public function testAddToPrepareArrayWithRoles() { |
465
|
|
|
$this->Vehicle = new Vehicle(1); |
466
|
|
|
$expected = $dataArrayToFill = array(); |
467
|
|
|
|
468
|
|
|
// Case 1 - adding role without depends, we reset the data |
469
|
|
|
$dataToAdd = array( |
470
|
|
|
'stateFrom' => 'initial', |
471
|
|
|
'stateTo' => 'second', |
472
|
|
|
'transition' => 'launch', |
473
|
|
|
'roles' => array('role1') |
474
|
|
|
); |
475
|
|
|
$dataArrayToFill[] = $expected[] = $dataToAdd; |
476
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
477
|
|
|
//debug($dataArrayToFill); |
478
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
479
|
|
|
|
480
|
|
|
// Case 2 - adding same role twice shoud not duplicate |
481
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
482
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
483
|
|
|
|
484
|
|
|
// Case 3 - Adding same state&Transition but with additional role |
485
|
|
|
$dataToAdd = array( |
486
|
|
|
'stateFrom' => 'initial', |
487
|
|
|
'stateTo' => 'second', |
488
|
|
|
'transition' => 'launch', |
489
|
|
|
'roles' => array('role2') |
490
|
|
|
); |
491
|
|
|
$expected = array(); |
492
|
|
|
$expected[] = array( |
493
|
|
|
'stateFrom' => 'initial', |
494
|
|
|
'stateTo' => 'second', |
495
|
|
|
'transition' => 'launch', |
496
|
|
|
'roles' => array('role1', 'role2') |
497
|
|
|
); |
498
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
499
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
500
|
|
|
|
501
|
|
|
// Case 4 - Adding same state&Transition but with additional role |
502
|
|
|
$dataToAdd = array( |
503
|
|
|
'stateFrom' => 'initial', |
504
|
|
|
'stateTo' => 'second', |
505
|
|
|
'transition' => 'launch', |
506
|
|
|
'roles' => array('role3', 'role4') |
507
|
|
|
); |
508
|
|
|
$expected = array(); |
509
|
|
|
$expected[] = array( |
510
|
|
|
'stateFrom' => 'initial', |
511
|
|
|
'stateTo' => 'second', |
512
|
|
|
'transition' => 'launch', |
513
|
|
|
'roles' => array('role1', 'role2', 'role3', 'role4') |
514
|
|
|
); |
515
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
516
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
public function testAddToPrepareArrayWithDependsAndRoles() { |
520
|
|
|
$this->Vehicle = new Vehicle(1); |
521
|
|
|
$expected = $dataArrayToFill = array(); |
522
|
|
|
|
523
|
|
|
// Case 1 - adding role without depends, we reset the data |
524
|
|
|
$dataToAdd = array( |
525
|
|
|
'stateFrom' => 'initial', |
526
|
|
|
'stateTo' => 'second', |
527
|
|
|
'transition' => 'launch', |
528
|
|
|
'depends' => 'is_allowed', |
529
|
|
|
'roles' => array('role1') |
530
|
|
|
); |
531
|
|
|
$dataArrayToFill[] = $expected[] = $dataToAdd; |
532
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
533
|
|
|
//debug($dataArrayToFill); |
534
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
535
|
|
|
|
536
|
|
|
// Case 2 - adding same role twice shoud not duplicate |
537
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
538
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
539
|
|
|
|
540
|
|
|
// Case 3 - Adding same state&Transition&depends but with additional role |
541
|
|
|
$dataToAdd = array( |
542
|
|
|
'stateFrom' => 'initial', |
543
|
|
|
'stateTo' => 'second', |
544
|
|
|
'transition' => 'launch', |
545
|
|
|
'depends' => 'is_allowed', |
546
|
|
|
'roles' => array('role2') |
547
|
|
|
); |
548
|
|
|
$expected = array(); |
549
|
|
|
$expected[] = array( |
550
|
|
|
'stateFrom' => 'initial', |
551
|
|
|
'stateTo' => 'second', |
552
|
|
|
'transition' => 'launch', |
553
|
|
|
'depends' => 'is_allowed', |
554
|
|
|
'roles' => array('role1', 'role2') |
555
|
|
|
); |
556
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
557
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
558
|
|
|
|
559
|
|
|
// Case 4 - Adding same state&Transition&depends but with additional role |
560
|
|
|
$dataToAdd = array( |
561
|
|
|
'stateFrom' => 'initial', |
562
|
|
|
'stateTo' => 'second', |
563
|
|
|
'transition' => 'launch', |
564
|
|
|
'depends' => 'is_allowed', |
565
|
|
|
'roles' => array('role3', 'role4') |
566
|
|
|
); |
567
|
|
|
$expected = array(); |
568
|
|
|
$expected[] = array( |
569
|
|
|
'stateFrom' => 'initial', |
570
|
|
|
'stateTo' => 'second', |
571
|
|
|
'transition' => 'launch', |
572
|
|
|
'depends' => 'is_allowed', |
573
|
|
|
'roles' => array('role1', 'role2', 'role3', 'role4') |
574
|
|
|
); |
575
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
576
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
577
|
|
|
|
578
|
|
|
// Case 5 - Adding same state&Transition&depends but with different depends |
579
|
|
|
$dataToAdd = array( |
580
|
|
|
'stateFrom' => 'initial', |
581
|
|
|
'stateTo' => 'second', |
582
|
|
|
'transition' => 'launch', |
583
|
|
|
'depends' => 'different_is_allowed', |
584
|
|
|
'roles' => array('role3', 'role4') |
585
|
|
|
); |
586
|
|
|
$expected[] = array( |
587
|
|
|
'stateFrom' => 'initial', |
588
|
|
|
'stateTo' => 'second', |
589
|
|
|
'transition' => 'launch', |
590
|
|
|
'depends' => 'different_is_allowed', |
591
|
|
|
'roles' => array('role3', 'role4') |
592
|
|
|
); |
593
|
|
|
$dataArrayToFill = $this->Vehicle->addToPrepareArray($dataToAdd, $dataArrayToFill); |
594
|
|
|
$this->assertEqual($expected, $dataArrayToFill); |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
public function testToDot() { |
598
|
|
|
$this->Vehicle->toDot(); |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
public function testCreateDotFileForRoles() { |
602
|
|
|
$this->Vehicle = new RulesVehicle(1); |
603
|
|
|
|
604
|
|
|
$expected = <<<EOT |
605
|
|
|
digraph finite_state_machine { |
606
|
|
|
fontsize=12; |
607
|
|
|
node [shape = oval, style=filled, color = "lightgrey"]; |
608
|
|
|
style=filled; |
609
|
|
|
label="Statemachine for RulesVehicle role(s) : Driver, Thief" |
610
|
|
|
"Parked" [ color = green ]; |
611
|
|
|
"Parked" -> "Idling" [ style = bold, fontsize = 9, arrowType = normal, label = "Ignite by (Driver) |
612
|
|
|
if Has Key" color = "blue"]; |
613
|
|
|
"Stalled" -> "Stalled" [ style = bold, fontsize = 9, arrowType = normal, label = "Ignite by (Driver) |
614
|
|
|
if Has Key" color = "blue"]; |
615
|
|
|
"Idling" -> "Parked" [ style = bold, fontsize = 9, arrowType = normal, label = "Park by All |
616
|
|
|
if Available Parking" ]; |
617
|
|
|
"First Gear" -> "Parked" [ style = bold, fontsize = 9, arrowType = normal, label = "Park by All |
618
|
|
|
if Available Parking" ]; |
619
|
|
|
"Idling" -> "First Gear" [ style = bold, fontsize = 9, arrowType = normal, label = "Shift Up by All" ]; |
620
|
|
|
"First Gear" -> "Second Gear" [ style = bold, fontsize = 9, arrowType = normal, label = "Shift Up by All" ]; |
621
|
|
|
"Second Gear" -> "Third Gear" [ style = bold, fontsize = 9, arrowType = normal, label = "Shift Up by All" ]; |
622
|
|
|
"First Gear" -> "Idling" [ style = bold, fontsize = 9, arrowType = normal, label = "Shift Down by All" ]; |
623
|
|
|
"Second Gear" -> "First Gear" [ style = bold, fontsize = 9, arrowType = normal, label = "Shift Down by All" ]; |
624
|
|
|
"Third Gear" -> "Second Gear" [ style = bold, fontsize = 9, arrowType = normal, label = "Shift Down by All" ]; |
625
|
|
|
"First Gear" -> "Stalled" [ style = bold, fontsize = 9, arrowType = normal, label = "Crash by All" ]; |
626
|
|
|
"Second Gear" -> "Stalled" [ style = bold, fontsize = 9, arrowType = normal, label = "Crash by All" ]; |
627
|
|
|
"Third Gear" -> "Stalled" [ style = bold, fontsize = 9, arrowType = normal, label = "Crash by All" ]; |
628
|
|
|
"First Gear" -> "Idling" [ style = bold, fontsize = 9, arrowType = normal, label = "Idle by All" ]; |
629
|
|
|
"All" -> "Parked" [ style = bold, fontsize = 9, arrowType = normal, label = "Turn Off by All" ]; |
630
|
|
|
"Parked" -> "Idling" [ style = bold, fontsize = 9, arrowType = normal, label = "Hardwire by (Thief)" color = "red"]; |
631
|
|
|
"Stalled" -> "Stalled" [ style = bold, fontsize = 9, arrowType = normal, label = "Hardwire by (Thief)" color = "red"]; |
632
|
|
|
} |
633
|
|
|
|
634
|
|
|
EOT; |
635
|
|
|
$this->assertEqual($expected, $this->Vehicle->createDotFileForRoles(array( |
636
|
|
|
'driver' => array( |
637
|
|
|
'color' => 'blue'), |
638
|
|
|
'thief' => array( |
639
|
|
|
'color' => 'red') |
640
|
|
|
), array( |
641
|
|
|
'color' => 'lightgrey', |
642
|
|
|
'activeColor' => 'green' |
643
|
|
|
) |
644
|
|
|
)); |
645
|
|
|
} |
646
|
|
|
|
647
|
|
|
public function testCallable() { |
648
|
|
|
$this->Vehicle->addMethod('whatIsMyName', function (Model $model, $method, $name) { |
649
|
|
|
return $model->alias . '-' . $method . '-' . $name; |
650
|
|
|
}); |
651
|
|
|
|
652
|
|
|
$this->assertEquals("Vehicle-whatIsMyName-Toybota", $this->Vehicle->whatIsMyName("Toybota")); |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
public function testExistingCallable() { |
656
|
|
|
$this->Vehicle->addMethod('foobar', function () { |
657
|
|
|
}); |
658
|
|
|
|
659
|
|
|
$this->setExpectedException('InvalidArgumentException'); |
660
|
|
|
$this->Vehicle->addMethod('foobar', function () { |
661
|
|
|
}); |
662
|
|
|
} |
663
|
|
|
|
664
|
|
|
public function testUnhandled() { |
665
|
|
|
$this->setExpectedException('PDOException'); |
666
|
|
|
$this->assertEquals(array("unhandled"), $this->Vehicle->handleMethodCall("foobar")); |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
public function testInvalidOnStateChange() { |
670
|
|
|
$this->Vehicle = new BaseVehicle(1); |
671
|
|
|
$this->Vehicle->ignite(); |
672
|
|
|
} |
673
|
|
|
|
674
|
|
|
public function testOnStateChange() { |
675
|
|
|
$this->Vehicle = $this->getMock('Vehicle', array( |
676
|
|
|
'onStateChange', 'onStateIdling', 'onBeforeTransition', 'onAfterTransition')); |
677
|
|
|
$this->Vehicle->id = 1; |
678
|
|
|
$this->Vehicle->expects($this->once())->method('onBeforeTransition'); |
679
|
|
|
$this->Vehicle->expects($this->once())->method('onAfterTransition'); |
680
|
|
|
$this->Vehicle->expects($this->once())->method('onStateChange'); |
681
|
|
|
$this->Vehicle->expects($this->once())->method('onStateIdling'); |
682
|
|
|
|
683
|
|
|
$this->assertTrue($this->Vehicle->ignite()); |
684
|
|
|
} |
685
|
|
|
|
686
|
|
|
public function testRules() { |
687
|
|
|
$this->Vehicle = new RulesVehicle(1); |
688
|
|
|
|
689
|
|
|
$this->assertTrue($this->Vehicle->canIgnite(null, 'driver')); |
690
|
|
|
$this->assertFalse($this->Vehicle->canIgnite(null, 'thief')); |
691
|
|
|
$this->assertTrue($this->Vehicle->canHardwire(null, 'thief')); |
692
|
|
|
$this->assertFalse($this->Vehicle->canHardwire(null, 'driver')); |
693
|
|
|
|
694
|
|
|
$this->Vehicle->ignite(null, 'driver'); |
695
|
|
|
|
696
|
|
|
$this->Vehicle->ignite(1, 'driver'); |
697
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState(1)); |
698
|
|
|
$this->assertEquals("parked", $this->Vehicle->getPreviousState(1)); |
699
|
|
|
$this->assertEquals("ignite", $this->Vehicle->getLastTransition(1)); |
700
|
|
|
$this->assertEquals("driver", $this->Vehicle->getLastRole(1)); |
701
|
|
|
|
702
|
|
|
$this->assertFalse($this->Vehicle->canPark(null, 'driver')); |
703
|
|
|
$this->assertTrue($this->Vehicle->canPark(null, 'thief')); |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
public function testRulesWithCanTransitionById() { |
707
|
|
|
$this->Vehicle = new RulesVehicle(1); |
708
|
|
|
|
709
|
|
|
$this->assertTrue($this->Vehicle->canIgnite(1, 'driver')); |
710
|
|
|
$this->assertFalse($this->Vehicle->canIgnite(1, 'thief')); |
711
|
|
|
$this->assertTrue($this->Vehicle->canHardwire(1, 'thief')); |
712
|
|
|
$this->assertFalse($this->Vehicle->canHardwire(1, 'driver')); |
713
|
|
|
|
714
|
|
|
$this->Vehicle->ignite(null, 'driver'); |
715
|
|
|
|
716
|
|
|
$this->Vehicle->ignite(1, 'driver'); |
717
|
|
|
$this->assertEquals("idling", $this->Vehicle->getCurrentState(1)); |
718
|
|
|
$this->assertEquals("parked", $this->Vehicle->getPreviousState(1)); |
719
|
|
|
$this->assertEquals("ignite", $this->Vehicle->getLastTransition(1)); |
720
|
|
|
$this->assertEquals("driver", $this->Vehicle->getLastRole(1)); |
721
|
|
|
|
722
|
|
|
$this->assertFalse($this->Vehicle->canPark(1, 'driver')); |
723
|
|
|
$this->assertTrue($this->Vehicle->canPark(1, 'thief')); |
724
|
|
|
} |
725
|
|
|
|
726
|
|
|
public function testRuleWithCallback() { |
727
|
|
|
$this->Vehicle = new RulesVehicle(1); |
728
|
|
|
$this->Vehicle->ignite(null, 'driver'); |
729
|
|
|
$this->Vehicle->shiftUp(); |
730
|
|
|
$this->Vehicle->crash(); |
731
|
|
|
|
732
|
|
|
$this->Vehicle->addMethod('hasTools', function ($role) { |
733
|
|
|
return $role == 'mechanic'; |
734
|
|
|
}); |
735
|
|
|
|
736
|
|
|
$this->assertTrue($this->Vehicle->canRepair(null, 'mechanic')); |
737
|
|
|
$this->assertTrue($this->Vehicle->repair(null, 'mechanic')); |
738
|
|
|
} |
739
|
|
|
|
740
|
|
|
public function testInvalidRules() { |
741
|
|
|
$this->setExpectedException('InvalidArgumentException'); |
742
|
|
|
|
743
|
|
|
$this->Vehicle = new RulesVehicle(1); |
744
|
|
|
$this->Vehicle->ignite(); |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
public function testWrongRole() { |
748
|
|
|
$this->Vehicle = new RulesVehicle(1); |
749
|
|
|
$this->assertFalse($this->Vehicle->ignite(null, 'thief')); |
750
|
|
|
} |
751
|
|
|
|
752
|
|
|
public function tearDown() { |
753
|
|
|
parent::tearDown(); |
754
|
|
|
unset($this->Vehicle, $this->StateMachine); |
755
|
|
|
} |
756
|
|
|
} |
757
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.