enum_state_machine 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. metadata +83 -130
  6. data/.rvmrc +0 -1
  7. data/enum_state_machine.gemspec +0 -25
  8. data/lib/enum_state_machine.rb +0 -9
  9. data/lib/enum_state_machine/assertions.rb +0 -36
  10. data/lib/enum_state_machine/branch.rb +0 -225
  11. data/lib/enum_state_machine/callback.rb +0 -232
  12. data/lib/enum_state_machine/core.rb +0 -12
  13. data/lib/enum_state_machine/core_ext.rb +0 -2
  14. data/lib/enum_state_machine/core_ext/class/state_machine.rb +0 -5
  15. data/lib/enum_state_machine/error.rb +0 -13
  16. data/lib/enum_state_machine/eval_helpers.rb +0 -87
  17. data/lib/enum_state_machine/event.rb +0 -257
  18. data/lib/enum_state_machine/event_collection.rb +0 -141
  19. data/lib/enum_state_machine/extensions.rb +0 -149
  20. data/lib/enum_state_machine/graph.rb +0 -92
  21. data/lib/enum_state_machine/helper_module.rb +0 -17
  22. data/lib/enum_state_machine/initializers.rb +0 -4
  23. data/lib/enum_state_machine/initializers/rails.rb +0 -22
  24. data/lib/enum_state_machine/integrations.rb +0 -97
  25. data/lib/enum_state_machine/integrations/active_model.rb +0 -585
  26. data/lib/enum_state_machine/integrations/active_model/locale.rb +0 -11
  27. data/lib/enum_state_machine/integrations/active_model/observer.rb +0 -33
  28. data/lib/enum_state_machine/integrations/active_model/observer_update.rb +0 -42
  29. data/lib/enum_state_machine/integrations/active_model/versions.rb +0 -31
  30. data/lib/enum_state_machine/integrations/active_record.rb +0 -548
  31. data/lib/enum_state_machine/integrations/active_record/locale.rb +0 -20
  32. data/lib/enum_state_machine/integrations/active_record/versions.rb +0 -123
  33. data/lib/enum_state_machine/integrations/base.rb +0 -100
  34. data/lib/enum_state_machine/machine.rb +0 -2292
  35. data/lib/enum_state_machine/machine_collection.rb +0 -86
  36. data/lib/enum_state_machine/macro_methods.rb +0 -518
  37. data/lib/enum_state_machine/matcher.rb +0 -123
  38. data/lib/enum_state_machine/matcher_helpers.rb +0 -54
  39. data/lib/enum_state_machine/node_collection.rb +0 -222
  40. data/lib/enum_state_machine/path.rb +0 -120
  41. data/lib/enum_state_machine/path_collection.rb +0 -90
  42. data/lib/enum_state_machine/state.rb +0 -297
  43. data/lib/enum_state_machine/state_collection.rb +0 -112
  44. data/lib/enum_state_machine/state_context.rb +0 -138
  45. data/lib/enum_state_machine/state_enum.rb +0 -23
  46. data/lib/enum_state_machine/transition.rb +0 -470
  47. data/lib/enum_state_machine/transition_collection.rb +0 -245
  48. data/lib/enum_state_machine/version.rb +0 -3
  49. data/lib/enum_state_machine/yard.rb +0 -8
  50. data/lib/enum_state_machine/yard/handlers.rb +0 -12
  51. data/lib/enum_state_machine/yard/handlers/base.rb +0 -32
  52. data/lib/enum_state_machine/yard/handlers/event.rb +0 -25
  53. data/lib/enum_state_machine/yard/handlers/machine.rb +0 -344
  54. data/lib/enum_state_machine/yard/handlers/state.rb +0 -25
  55. data/lib/enum_state_machine/yard/handlers/transition.rb +0 -47
  56. data/lib/enum_state_machine/yard/templates.rb +0 -3
  57. data/lib/enum_state_machine/yard/templates/default/class/html/setup.rb +0 -30
  58. data/lib/enum_state_machine/yard/templates/default/class/html/state_machines.erb +0 -12
  59. data/lib/tasks/enum_state_machine.rake +0 -1
  60. data/lib/tasks/enum_state_machine.rb +0 -24
  61. data/lib/yard-enum_state_machine.rb +0 -2
  62. data/test/functional/state_machine_test.rb +0 -1066
  63. data/test/unit/integrations/active_model_test.rb +0 -1245
  64. data/test/unit/integrations/active_record_test.rb +0 -2551
  65. data/test/unit/integrations/base_test.rb +0 -104
  66. data/test/unit/integrations_test.rb +0 -71
  67. data/test/unit/invalid_event_test.rb +0 -20
  68. data/test/unit/invalid_parallel_transition_test.rb +0 -18
  69. data/test/unit/invalid_transition_test.rb +0 -115
  70. data/test/unit/machine_collection_test.rb +0 -603
  71. data/test/unit/machine_test.rb +0 -3395
  72. data/test/unit/state_machine_test.rb +0 -31
@@ -1,3395 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
-
3
- class MachineByDefaultTest < Test::Unit::TestCase
4
- def setup
5
- @klass = Class.new
6
- @machine = EnumStateMachine::Machine.new(@klass)
7
- @object = @klass.new
8
- end
9
-
10
- def test_should_have_an_owner_class
11
- assert_equal @klass, @machine.owner_class
12
- end
13
-
14
- def test_should_have_a_name
15
- assert_equal :state, @machine.name
16
- end
17
-
18
- def test_should_have_an_attribute
19
- assert_equal :state, @machine.attribute
20
- end
21
-
22
- def test_should_prefix_custom_attributes_with_attribute
23
- assert_equal :state_event, @machine.attribute(:event)
24
- end
25
-
26
- def test_should_have_an_initial_state
27
- assert_not_nil @machine.initial_state(@object)
28
- end
29
-
30
- def test_should_have_a_nil_initial_state
31
- assert_nil @machine.initial_state(@object).value
32
- end
33
-
34
- def test_should_not_have_any_events
35
- assert !@machine.events.any?
36
- end
37
-
38
- def test_should_not_have_any_before_callbacks
39
- assert @machine.callbacks[:before].empty?
40
- end
41
-
42
- def test_should_not_have_any_after_callbacks
43
- assert @machine.callbacks[:after].empty?
44
- end
45
-
46
- def test_should_not_have_any_failure_callbacks
47
- assert @machine.callbacks[:failure].empty?
48
- end
49
-
50
- def test_should_not_have_an_action
51
- assert_nil @machine.action
52
- end
53
-
54
- def test_should_use_tranactions
55
- assert_equal true, @machine.use_transactions
56
- end
57
-
58
- def test_should_not_have_a_namespace
59
- assert_nil @machine.namespace
60
- end
61
-
62
- def test_should_have_a_nil_state
63
- assert_equal [nil], @machine.states.keys
64
- end
65
-
66
- def test_should_set_initial_on_nil_state
67
- assert @machine.state(nil).initial
68
- end
69
-
70
- def test_should_generate_default_messages
71
- assert_equal 'is invalid', @machine.generate_message(:invalid)
72
- assert_equal 'cannot transition when parked', @machine.generate_message(:invalid_event, [[:state, :parked]])
73
- assert_equal 'cannot transition via "park"', @machine.generate_message(:invalid_transition, [[:event, :park]])
74
- end
75
-
76
- def test_should_not_be_extended_by_the_base_integration
77
- assert !(class << @machine; ancestors; end).include?(EnumStateMachine::Integrations::Base)
78
- end
79
-
80
- def test_should_not_be_extended_by_the_active_model_integration
81
- assert !(class << @machine; ancestors; end).include?(EnumStateMachine::Integrations::ActiveModel)
82
- end
83
-
84
- def test_should_not_be_extended_by_the_active_record_integration
85
- assert !(class << @machine; ancestors; end).include?(EnumStateMachine::Integrations::ActiveRecord)
86
- end
87
-
88
- def test_should_define_a_reader_attribute_for_the_attribute
89
- assert @object.respond_to?(:state)
90
- end
91
-
92
- def test_should_define_a_writer_attribute_for_the_attribute
93
- assert @object.respond_to?(:state=)
94
- end
95
-
96
- def test_should_define_a_predicate_for_the_attribute
97
- assert @object.respond_to?(:state?)
98
- end
99
-
100
- def test_should_define_a_name_reader_for_the_attribute
101
- assert @object.respond_to?(:state_name)
102
- end
103
-
104
- def test_should_define_an_event_reader_for_the_attribute
105
- assert @object.respond_to?(:state_events)
106
- end
107
-
108
- def test_should_define_a_transition_reader_for_the_attribute
109
- assert @object.respond_to?(:state_transitions)
110
- end
111
-
112
- def test_should_define_a_path_reader_for_the_attribute
113
- assert @object.respond_to?(:state_paths)
114
- end
115
-
116
- def test_should_define_an_event_runner_for_the_attribute
117
- assert @object.respond_to?(:fire_state_event)
118
- end
119
-
120
- def test_should_not_define_an_event_attribute_reader
121
- assert !@object.respond_to?(:state_event)
122
- end
123
-
124
- def test_should_not_define_an_event_attribute_writer
125
- assert !@object.respond_to?(:state_event=)
126
- end
127
-
128
- def test_should_not_define_an_event_transition_attribute_reader
129
- assert !@object.respond_to?(:state_event_transition)
130
- end
131
-
132
- def test_should_not_define_an_event_transition_attribute_writer
133
- assert !@object.respond_to?(:state_event_transition=)
134
- end
135
-
136
- def test_should_define_a_human_attribute_name_reader_for_the_attribute
137
- assert @klass.respond_to?(:human_state_name)
138
- end
139
-
140
- def test_should_define_a_human_event_name_reader_for_the_attribute
141
- assert @klass.respond_to?(:human_state_event_name)
142
- end
143
-
144
- def test_should_not_define_singular_with_scope
145
- assert !@klass.respond_to?(:with_state)
146
- end
147
-
148
- def test_should_not_define_singular_without_scope
149
- assert !@klass.respond_to?(:without_state)
150
- end
151
-
152
- def test_should_not_define_plural_with_scope
153
- assert !@klass.respond_to?(:with_states)
154
- end
155
-
156
- def test_should_not_define_plural_without_scope
157
- assert !@klass.respond_to?(:without_states)
158
- end
159
-
160
- def test_should_extend_owner_class_with_class_methods
161
- assert((class << @klass; ancestors; end).include?(EnumStateMachine::ClassMethods))
162
- end
163
-
164
- def test_should_include_instance_methods_in_owner_class
165
- assert @klass.included_modules.include?(EnumStateMachine::InstanceMethods)
166
- end
167
-
168
- def test_should_define_state_machines_reader
169
- expected = {:state => @machine}
170
- assert_equal expected, @klass.state_machines
171
- end
172
- end
173
-
174
- class MachineWithCustomNameTest < Test::Unit::TestCase
175
- def setup
176
- @klass = Class.new
177
- @machine = EnumStateMachine::Machine.new(@klass, :status)
178
- @object = @klass.new
179
- end
180
-
181
- def test_should_use_custom_name
182
- assert_equal :status, @machine.name
183
- end
184
-
185
- def test_should_use_custom_name_for_attribute
186
- assert_equal :status, @machine.attribute
187
- end
188
-
189
- def test_should_prefix_custom_attributes_with_custom_name
190
- assert_equal :status_event, @machine.attribute(:event)
191
- end
192
-
193
- def test_should_define_a_reader_attribute_for_the_attribute
194
- assert @object.respond_to?(:status)
195
- end
196
-
197
- def test_should_define_a_writer_attribute_for_the_attribute
198
- assert @object.respond_to?(:status=)
199
- end
200
-
201
- def test_should_define_a_predicate_for_the_attribute
202
- assert @object.respond_to?(:status?)
203
- end
204
-
205
- def test_should_define_a_name_reader_for_the_attribute
206
- assert @object.respond_to?(:status_name)
207
- end
208
-
209
- def test_should_define_an_event_reader_for_the_attribute
210
- assert @object.respond_to?(:status_events)
211
- end
212
-
213
- def test_should_define_a_transition_reader_for_the_attribute
214
- assert @object.respond_to?(:status_transitions)
215
- end
216
-
217
- def test_should_define_an_event_runner_for_the_attribute
218
- assert @object.respond_to?(:fire_status_event)
219
- end
220
-
221
- def test_should_define_a_human_attribute_name_reader_for_the_attribute
222
- assert @klass.respond_to?(:human_status_name)
223
- end
224
-
225
- def test_should_define_a_human_event_name_reader_for_the_attribute
226
- assert @klass.respond_to?(:human_status_event_name)
227
- end
228
- end
229
-
230
- class MachineWithoutInitializationTest < Test::Unit::TestCase
231
- def setup
232
- @klass = Class.new do
233
- def initialize(attributes = {})
234
- attributes.each {|attr, value| send("#{attr}=", value)}
235
- super()
236
- end
237
- end
238
-
239
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked, :initialize => false)
240
- end
241
-
242
- def test_should_not_have_an_initial_state
243
- object = @klass.new
244
- assert_nil object.state
245
- end
246
-
247
- def test_should_still_allow_manual_initialization
248
- @klass.send(:include, Module.new do
249
- def initialize(attributes = {})
250
- super()
251
- initialize_state_machines
252
- end
253
- end)
254
-
255
- object = @klass.new
256
- assert_equal 'parked', object.state
257
- end
258
- end
259
-
260
- class MachineWithStaticInitialStateTest < Test::Unit::TestCase
261
- def setup
262
- @klass = Class.new
263
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
264
- end
265
-
266
- def test_should_not_have_dynamic_initial_state
267
- assert !@machine.dynamic_initial_state?
268
- end
269
-
270
- def test_should_have_an_initial_state
271
- object = @klass.new
272
- assert_equal 'parked', @machine.initial_state(object).value
273
- end
274
-
275
- def test_should_write_to_attribute_when_initializing_state
276
- object = @klass.allocate
277
- @machine.initialize_state(object)
278
- assert_equal 'parked', object.state
279
- end
280
-
281
- def test_should_set_initial_on_state_object
282
- assert @machine.state(:parked).initial
283
- end
284
-
285
- def test_should_set_initial_state_on_created_object
286
- assert_equal 'parked', @klass.new.state
287
- end
288
-
289
- def test_not_set_initial_state_even_if_not_empty
290
- @klass.class_eval do
291
- def initialize(attributes = {})
292
- self.state = 'idling'
293
- super()
294
- end
295
- end
296
- object = @klass.new
297
- assert_equal 'idling', object.state
298
- end
299
-
300
- def test_should_set_initial_state_prior_to_initialization
301
- base = Class.new do
302
- attr_accessor :state_on_init
303
-
304
- def initialize
305
- self.state_on_init = state
306
- end
307
- end
308
- klass = Class.new(base)
309
- EnumStateMachine::Machine.new(klass, :initial => :parked)
310
-
311
- assert_equal 'parked', klass.new.state_on_init
312
- end
313
-
314
- def test_should_be_included_in_known_states
315
- assert_equal [:parked], @machine.states.keys
316
- end
317
- end
318
-
319
- class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
320
- def setup
321
- @klass = Class.new do
322
- attr_accessor :initial_state
323
- end
324
- @machine = EnumStateMachine::Machine.new(@klass, :initial => lambda {|object| object.initial_state || :default})
325
- @machine.state :parked, :idling, :default
326
- @object = @klass.new
327
- end
328
-
329
- def test_should_have_dynamic_initial_state
330
- assert @machine.dynamic_initial_state?
331
- end
332
-
333
- def test_should_use_the_record_for_determining_the_initial_state
334
- @object.initial_state = :parked
335
- assert_equal :parked, @machine.initial_state(@object).name
336
-
337
- @object.initial_state = :idling
338
- assert_equal :idling, @machine.initial_state(@object).name
339
- end
340
-
341
- def test_should_write_to_attribute_when_initializing_state
342
- object = @klass.allocate
343
- object.initial_state = :parked
344
- @machine.initialize_state(object)
345
- assert_equal 'parked', object.state
346
- end
347
-
348
- def test_should_set_initial_state_on_created_object
349
- assert_equal 'default', @object.state
350
- end
351
-
352
- def test_should_not_set_initial_state_even_if_not_empty
353
- @klass.class_eval do
354
- def initialize(attributes = {})
355
- self.state = 'parked'
356
- super()
357
- end
358
- end
359
- object = @klass.new
360
- assert_equal 'parked', object.state
361
- end
362
-
363
- def test_should_set_initial_state_after_initialization
364
- base = Class.new do
365
- attr_accessor :state_on_init
366
-
367
- def initialize
368
- self.state_on_init = state
369
- end
370
- end
371
- klass = Class.new(base)
372
- machine = EnumStateMachine::Machine.new(klass, :initial => lambda {|object| :parked})
373
- machine.state :parked
374
-
375
- assert_nil klass.new.state_on_init
376
- end
377
-
378
- def test_should_not_be_included_in_known_states
379
- assert_equal [:parked, :idling, :default], @machine.states.map {|state| state.name}
380
- end
381
- end
382
-
383
- class MachineStateInitializationTest < Test::Unit::TestCase
384
- def setup
385
- @klass = Class.new
386
- @machine = EnumStateMachine::Machine.new(@klass, :state, :initial => :parked, :initialize => false)
387
-
388
- @object = @klass.new
389
- @object.state = nil
390
- end
391
-
392
- def test_should_set_states_if_nil
393
- @machine.initialize_state(@object)
394
-
395
- assert_equal 'parked', @object.state
396
- end
397
-
398
- def test_should_set_states_if_empty
399
- @object.state = ''
400
- @machine.initialize_state(@object)
401
-
402
- assert_equal 'parked', @object.state
403
- end
404
-
405
- def test_should_not_set_states_if_not_empty
406
- @object.state = 'idling'
407
- @machine.initialize_state(@object)
408
-
409
- assert_equal 'idling', @object.state
410
- end
411
-
412
- def test_should_set_states_if_not_empty_and_forced
413
- @object.state = 'idling'
414
- @machine.initialize_state(@object, :force => true)
415
-
416
- assert_equal 'parked', @object.state
417
- end
418
-
419
- def test_should_not_set_state_if_nil_and_nil_is_valid_state
420
- @machine.state :initial, :value => nil
421
- @machine.initialize_state(@object)
422
-
423
- assert_nil @object.state
424
- end
425
-
426
- def test_should_write_to_hash_if_specified
427
- @machine.initialize_state(@object, :to => hash = {})
428
- assert_equal({'state' => 'parked'}, hash)
429
- end
430
-
431
- def test_should_not_write_to_object_if_writing_to_hash
432
- @machine.initialize_state(@object, :to => {})
433
- assert_nil @object.state
434
- end
435
- end
436
-
437
- class MachineWithCustomActionTest < Test::Unit::TestCase
438
- def setup
439
- @machine = EnumStateMachine::Machine.new(Class.new, :action => :save)
440
- end
441
-
442
- def test_should_use_the_custom_action
443
- assert_equal :save, @machine.action
444
- end
445
- end
446
-
447
- class MachineWithNilActionTest < Test::Unit::TestCase
448
- def setup
449
- integration = Module.new do
450
- include EnumStateMachine::Integrations::Base
451
-
452
- @defaults = {:action => :save}
453
- end
454
- EnumStateMachine::Integrations.const_set('Custom', integration)
455
- @machine = EnumStateMachine::Machine.new(Class.new, :action => nil, :integration => :custom)
456
- end
457
-
458
- def test_should_have_a_nil_action
459
- assert_nil @machine.action
460
- end
461
-
462
- def teardown
463
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
464
- end
465
- end
466
-
467
- class MachineWithoutIntegrationTest < Test::Unit::TestCase
468
- def setup
469
- @klass = Class.new
470
- @machine = EnumStateMachine::Machine.new(@klass)
471
- @object = @klass.new
472
- end
473
-
474
- def test_transaction_should_yield
475
- @yielded = false
476
- @machine.within_transaction(@object) do
477
- @yielded = true
478
- end
479
-
480
- assert @yielded
481
- end
482
-
483
- def test_invalidation_should_do_nothing
484
- assert_nil @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']])
485
- end
486
-
487
- def test_reset_should_do_nothing
488
- assert_nil @machine.reset(@object)
489
- end
490
-
491
- def test_errors_for_should_be_empty
492
- assert_equal '', @machine.errors_for(@object)
493
- end
494
- end
495
-
496
- class MachineWithCustomIntegrationTest < Test::Unit::TestCase
497
- def setup
498
- integration = Module.new do
499
- include EnumStateMachine::Integrations::Base
500
-
501
- def self.matching_ancestors
502
- ['MachineWithCustomIntegrationTest::Vehicle']
503
- end
504
- end
505
-
506
- EnumStateMachine::Integrations.const_set('Custom', integration)
507
-
508
- superclass = Class.new
509
- self.class.const_set('Vehicle', superclass)
510
-
511
- @klass = Class.new(superclass)
512
- end
513
-
514
- def test_should_be_extended_by_the_integration_if_explicit
515
- machine = EnumStateMachine::Machine.new(@klass, :integration => :custom)
516
- assert((class << machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
517
- end
518
-
519
- def test_should_not_be_extended_by_the_integration_if_implicit_but_not_available
520
- EnumStateMachine::Integrations::Custom.class_eval do
521
- class << self; remove_method :matching_ancestors; end
522
- def self.matching_ancestors
523
- []
524
- end
525
- end
526
-
527
- machine = EnumStateMachine::Machine.new(@klass)
528
- assert(!(class << machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
529
- end
530
-
531
- def test_should_not_be_extended_by_the_integration_if_implicit_but_not_matched
532
- EnumStateMachine::Integrations::Custom.class_eval do
533
- class << self; remove_method :matching_ancestors; end
534
- def self.matching_ancestors
535
- []
536
- end
537
- end
538
-
539
- machine = EnumStateMachine::Machine.new(@klass)
540
- assert(!(class << machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
541
- end
542
-
543
- def test_should_be_extended_by_the_integration_if_implicit_and_available_and_matches
544
- machine = EnumStateMachine::Machine.new(@klass)
545
- assert((class << machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
546
- end
547
-
548
- def test_should_not_be_extended_by_the_integration_if_nil
549
- machine = EnumStateMachine::Machine.new(@klass, :integration => nil)
550
- assert(!(class << machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
551
- end
552
-
553
- def test_should_not_be_extended_by_the_integration_if_false
554
- machine = EnumStateMachine::Machine.new(@klass, :integration => false)
555
- assert(!(class << machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
556
- end
557
-
558
- def teardown
559
- self.class.send(:remove_const, 'Vehicle')
560
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
561
- end
562
- end
563
-
564
- class MachineWithIntegrationTest < Test::Unit::TestCase
565
- def setup
566
- EnumStateMachine::Integrations.const_set('Custom', Module.new do
567
- include EnumStateMachine::Integrations::Base
568
-
569
- @defaults = {:action => :save, :use_transactions => false}
570
-
571
- attr_reader :initialized, :with_scopes, :without_scopes, :ran_transaction
572
-
573
- def after_initialize
574
- @initialized = true
575
- end
576
-
577
- def create_with_scope(name)
578
- (@with_scopes ||= []) << name
579
- lambda {}
580
- end
581
-
582
- def create_without_scope(name)
583
- (@without_scopes ||= []) << name
584
- lambda {}
585
- end
586
-
587
- def transaction(object)
588
- @ran_transaction = true
589
- yield
590
- end
591
- end)
592
-
593
- @machine = EnumStateMachine::Machine.new(Class.new, :integration => :custom)
594
- end
595
-
596
- def test_should_call_after_initialize_hook
597
- assert @machine.initialized
598
- end
599
-
600
- def test_should_use_the_default_action
601
- assert_equal :save, @machine.action
602
- end
603
-
604
- def test_should_use_the_custom_action_if_specified
605
- machine = EnumStateMachine::Machine.new(Class.new, :integration => :custom, :action => :save!)
606
- assert_equal :save!, machine.action
607
- end
608
-
609
- def test_should_use_the_default_use_transactions
610
- assert_equal false, @machine.use_transactions
611
- end
612
-
613
- def test_should_use_the_custom_use_transactions_if_specified
614
- machine = EnumStateMachine::Machine.new(Class.new, :integration => :custom, :use_transactions => true)
615
- assert_equal true, machine.use_transactions
616
- end
617
-
618
- def test_should_define_a_singular_and_plural_with_scope
619
- assert_equal %w(with_state with_states), @machine.with_scopes
620
- end
621
-
622
- def test_should_define_a_singular_and_plural_without_scope
623
- assert_equal %w(without_state without_states), @machine.without_scopes
624
- end
625
-
626
- def teardown
627
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
628
- end
629
- end
630
-
631
- class MachineWithActionUndefinedTest < Test::Unit::TestCase
632
- def setup
633
- @klass = Class.new
634
- @machine = EnumStateMachine::Machine.new(@klass, :action => :save)
635
- @object = @klass.new
636
- end
637
-
638
- def test_should_define_an_event_attribute_reader
639
- assert @object.respond_to?(:state_event)
640
- end
641
-
642
- def test_should_define_an_event_attribute_writer
643
- assert @object.respond_to?(:state_event=)
644
- end
645
-
646
- def test_should_define_an_event_transition_attribute_reader
647
- assert @object.respond_to?(:state_event_transition, true)
648
- end
649
-
650
- def test_should_define_an_event_transition_attribute_writer
651
- assert @object.respond_to?(:state_event_transition=, true)
652
- end
653
-
654
- def test_should_not_define_action
655
- assert !@object.respond_to?(:save)
656
- end
657
-
658
- def test_should_not_mark_action_hook_as_defined
659
- assert !@machine.action_hook?
660
- end
661
- end
662
-
663
- class MachineWithActionDefinedInClassTest < Test::Unit::TestCase
664
- def setup
665
- @klass = Class.new do
666
- def save
667
- end
668
- end
669
-
670
- @machine = EnumStateMachine::Machine.new(@klass, :action => :save)
671
- @object = @klass.new
672
- end
673
-
674
- def test_should_define_an_event_attribute_reader
675
- assert @object.respond_to?(:state_event)
676
- end
677
-
678
- def test_should_define_an_event_attribute_writer
679
- assert @object.respond_to?(:state_event=)
680
- end
681
-
682
- def test_should_define_an_event_transition_attribute_reader
683
- assert @object.respond_to?(:state_event_transition, true)
684
- end
685
-
686
- def test_should_define_an_event_transition_attribute_writer
687
- assert @object.respond_to?(:state_event_transition=, true)
688
- end
689
-
690
- def test_should_not_define_action
691
- assert !@klass.ancestors.any? {|ancestor| ancestor != @klass && ancestor.method_defined?(:save)}
692
- end
693
-
694
- def test_should_not_mark_action_hook_as_defined
695
- assert !@machine.action_hook?
696
- end
697
- end
698
-
699
- class MachineWithActionDefinedInIncludedModuleTest < Test::Unit::TestCase
700
- def setup
701
- @mod = mod = Module.new do
702
- def save
703
- end
704
- end
705
-
706
- @klass = Class.new do
707
- include mod
708
- end
709
-
710
- @machine = EnumStateMachine::Machine.new(@klass, :action => :save)
711
- @object = @klass.new
712
- end
713
-
714
- def test_should_define_an_event_attribute_reader
715
- assert @object.respond_to?(:state_event)
716
- end
717
-
718
- def test_should_define_an_event_attribute_writer
719
- assert @object.respond_to?(:state_event=)
720
- end
721
-
722
- def test_should_define_an_event_transition_attribute_reader
723
- assert @object.respond_to?(:state_event_transition, true)
724
- end
725
-
726
- def test_should_define_an_event_transition_attribute_writer
727
- assert @object.respond_to?(:state_event_transition=, true)
728
- end
729
-
730
- def test_should_define_action
731
- assert @klass.ancestors.any? {|ancestor| ![@klass, @mod].include?(ancestor) && ancestor.method_defined?(:save)}
732
- end
733
-
734
- def test_should_keep_action_public
735
- assert @klass.public_method_defined?(:save)
736
- end
737
-
738
- def test_should_mark_action_hook_as_defined
739
- assert @machine.action_hook?
740
- end
741
- end
742
-
743
- class MachineWithActionDefinedInSuperclassTest < Test::Unit::TestCase
744
- def setup
745
- @superclass = Class.new do
746
- def save
747
- end
748
- end
749
- @klass = Class.new(@superclass)
750
-
751
- @machine = EnumStateMachine::Machine.new(@klass, :action => :save)
752
- @object = @klass.new
753
- end
754
-
755
- def test_should_define_an_event_attribute_reader
756
- assert @object.respond_to?(:state_event)
757
- end
758
-
759
- def test_should_define_an_event_attribute_writer
760
- assert @object.respond_to?(:state_event=)
761
- end
762
-
763
- def test_should_define_an_event_transition_attribute_reader
764
- assert @object.respond_to?(:state_event_transition, true)
765
- end
766
-
767
- def test_should_define_an_event_transition_attribute_writer
768
- assert @object.respond_to?(:state_event_transition=, true)
769
- end
770
-
771
- def test_should_define_action
772
- assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}
773
- end
774
-
775
- def test_should_keep_action_public
776
- assert @klass.public_method_defined?(:save)
777
- end
778
-
779
- def test_should_mark_action_hook_as_defined
780
- assert @machine.action_hook?
781
- end
782
- end
783
-
784
- class MachineWithPrivateActionTest < Test::Unit::TestCase
785
- def setup
786
- @superclass = Class.new do
787
- private
788
- def save
789
- end
790
- end
791
- @klass = Class.new(@superclass)
792
-
793
- @machine = EnumStateMachine::Machine.new(@klass, :action => :save)
794
- @object = @klass.new
795
- end
796
-
797
- def test_should_define_an_event_attribute_reader
798
- assert @object.respond_to?(:state_event)
799
- end
800
-
801
- def test_should_define_an_event_attribute_writer
802
- assert @object.respond_to?(:state_event=)
803
- end
804
-
805
- def test_should_define_an_event_transition_attribute_reader
806
- assert @object.respond_to?(:state_event_transition, true)
807
- end
808
-
809
- def test_should_define_an_event_transition_attribute_writer
810
- assert @object.respond_to?(:state_event_transition=, true)
811
- end
812
-
813
- def test_should_define_action
814
- assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.private_method_defined?(:save)}
815
- end
816
-
817
- def test_should_keep_action_private
818
- assert @klass.private_method_defined?(:save)
819
- end
820
-
821
- def test_should_mark_action_hook_as_defined
822
- assert @machine.action_hook?
823
- end
824
- end
825
-
826
- class MachineWithActionAlreadyOverriddenTest < Test::Unit::TestCase
827
- def setup
828
- @superclass = Class.new do
829
- def save
830
- end
831
- end
832
- @klass = Class.new(@superclass)
833
-
834
- EnumStateMachine::Machine.new(@klass, :action => :save)
835
- @machine = EnumStateMachine::Machine.new(@klass, :status, :action => :save)
836
- @object = @klass.new
837
- end
838
-
839
- def test_should_not_redefine_action
840
- assert_equal 1, @klass.ancestors.select {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}.length
841
- end
842
-
843
- def test_should_mark_action_hook_as_defined
844
- assert @machine.action_hook?
845
- end
846
- end
847
-
848
- class MachineWithCustomPluralTest < Test::Unit::TestCase
849
- def setup
850
- @integration = Module.new do
851
- include EnumStateMachine::Integrations::Base
852
-
853
- class << self; attr_accessor :with_scopes, :without_scopes; end
854
- @with_scopes = []
855
- @without_scopes = []
856
-
857
- def create_with_scope(name)
858
- EnumStateMachine::Integrations::Custom.with_scopes << name
859
- lambda {}
860
- end
861
-
862
- def create_without_scope(name)
863
- EnumStateMachine::Integrations::Custom.without_scopes << name
864
- lambda {}
865
- end
866
- end
867
-
868
- EnumStateMachine::Integrations.const_set('Custom', @integration)
869
- end
870
-
871
- def test_should_define_a_singular_and_plural_with_scope
872
- EnumStateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
873
- assert_equal %w(with_state with_staties), @integration.with_scopes
874
- end
875
-
876
- def test_should_define_a_singular_and_plural_without_scope
877
- EnumStateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
878
- assert_equal %w(without_state without_staties), @integration.without_scopes
879
- end
880
-
881
- def test_should_define_single_with_scope_if_singular_same_as_plural
882
- EnumStateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'state')
883
- assert_equal %w(with_state), @integration.with_scopes
884
- end
885
-
886
- def test_should_define_single_without_scope_if_singular_same_as_plural
887
- EnumStateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'state')
888
- assert_equal %w(without_state), @integration.without_scopes
889
- end
890
-
891
- def teardown
892
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
893
- end
894
- end
895
-
896
- class MachineWithCustomInvalidationTest < Test::Unit::TestCase
897
- def setup
898
- @integration = Module.new do
899
- include EnumStateMachine::Integrations::Base
900
-
901
- def invalidate(object, attribute, message, values = [])
902
- object.error = generate_message(message, values)
903
- end
904
- end
905
- EnumStateMachine::Integrations.const_set('Custom', @integration)
906
-
907
- @klass = Class.new do
908
- attr_accessor :error
909
- end
910
-
911
- @machine = EnumStateMachine::Machine.new(@klass, :integration => :custom, :messages => {:invalid_transition => 'cannot %s'})
912
- @machine.state :parked
913
-
914
- @object = @klass.new
915
- @object.state = 'parked'
916
- end
917
-
918
- def test_generate_custom_message
919
- assert_equal 'cannot park', @machine.generate_message(:invalid_transition, [[:event, :park]])
920
- end
921
-
922
- def test_use_custom_message
923
- @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']])
924
- assert_equal 'cannot park', @object.error
925
- end
926
-
927
- def teardown
928
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
929
- end
930
- end
931
-
932
- class MachineTest < Test::Unit::TestCase
933
- def test_should_raise_exception_if_invalid_option_specified
934
- assert_raise(ArgumentError) {EnumStateMachine::Machine.new(Class.new, :invalid => true)}
935
- end
936
-
937
- def test_should_not_raise_exception_if_custom_messages_specified
938
- assert_nothing_raised {EnumStateMachine::Machine.new(Class.new, :messages => {:invalid_transition => 'custom'})}
939
- end
940
-
941
- def test_should_evaluate_a_block_during_initialization
942
- called = true
943
- EnumStateMachine::Machine.new(Class.new) do
944
- called = respond_to?(:event)
945
- end
946
-
947
- assert called
948
- end
949
-
950
- def test_should_provide_matcher_helpers_during_initialization
951
- matchers = []
952
-
953
- EnumStateMachine::Machine.new(Class.new) do
954
- matchers = [all, any, same]
955
- end
956
-
957
- assert_equal [EnumStateMachine::AllMatcher.instance, EnumStateMachine::AllMatcher.instance, EnumStateMachine::LoopbackMatcher.instance], matchers
958
- end
959
- end
960
-
961
- class MachineAfterBeingCopiedTest < Test::Unit::TestCase
962
- def setup
963
- @machine = EnumStateMachine::Machine.new(Class.new, :state, :initial => :parked)
964
- @machine.event(:ignite) {}
965
- @machine.before_transition(lambda {})
966
- @machine.after_transition(lambda {})
967
- @machine.around_transition(lambda {})
968
- @machine.after_failure(lambda {})
969
-
970
- @copied_machine = @machine.clone
971
- end
972
-
973
- def test_should_not_have_the_same_collection_of_states
974
- assert_not_same @copied_machine.states, @machine.states
975
- end
976
-
977
- def test_should_copy_each_state
978
- assert_not_same @copied_machine.states[:parked], @machine.states[:parked]
979
- end
980
-
981
- def test_should_update_machine_for_each_state
982
- assert_equal @copied_machine, @copied_machine.states[:parked].machine
983
- end
984
-
985
- def test_should_not_update_machine_for_original_state
986
- assert_equal @machine, @machine.states[:parked].machine
987
- end
988
-
989
- def test_should_not_have_the_same_collection_of_events
990
- assert_not_same @copied_machine.events, @machine.events
991
- end
992
-
993
- def test_should_copy_each_event
994
- assert_not_same @copied_machine.events[:ignite], @machine.events[:ignite]
995
- end
996
-
997
- def test_should_update_machine_for_each_event
998
- assert_equal @copied_machine, @copied_machine.events[:ignite].machine
999
- end
1000
-
1001
- def test_should_not_update_machine_for_original_event
1002
- assert_equal @machine, @machine.events[:ignite].machine
1003
- end
1004
-
1005
- def test_should_not_have_the_same_callbacks
1006
- assert_not_same @copied_machine.callbacks, @machine.callbacks
1007
- end
1008
-
1009
- def test_should_not_have_the_same_before_callbacks
1010
- assert_not_same @copied_machine.callbacks[:before], @machine.callbacks[:before]
1011
- end
1012
-
1013
- def test_should_not_have_the_same_after_callbacks
1014
- assert_not_same @copied_machine.callbacks[:after], @machine.callbacks[:after]
1015
- end
1016
-
1017
- def test_should_not_have_the_same_failure_callbacks
1018
- assert_not_same @copied_machine.callbacks[:failure], @machine.callbacks[:failure]
1019
- end
1020
- end
1021
-
1022
- class MachineAfterChangingOwnerClassTest < Test::Unit::TestCase
1023
- def setup
1024
- @original_class = Class.new
1025
- @machine = EnumStateMachine::Machine.new(@original_class)
1026
-
1027
- @new_class = Class.new(@original_class)
1028
- @new_machine = @machine.clone
1029
- @new_machine.owner_class = @new_class
1030
-
1031
- @object = @new_class.new
1032
- end
1033
-
1034
- def test_should_update_owner_class
1035
- assert_equal @new_class, @new_machine.owner_class
1036
- end
1037
-
1038
- def test_should_not_change_original_owner_class
1039
- assert_equal @original_class, @machine.owner_class
1040
- end
1041
-
1042
- def test_should_change_the_associated_machine_in_the_new_class
1043
- assert_equal @new_machine, @new_class.state_machines[:state]
1044
- end
1045
-
1046
- def test_should_not_change_the_associated_machine_in_the_original_class
1047
- assert_equal @machine, @original_class.state_machines[:state]
1048
- end
1049
- end
1050
-
1051
- class MachineAfterChangingInitialState < Test::Unit::TestCase
1052
- def setup
1053
- @klass = Class.new
1054
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
1055
- @machine.initial_state = :idling
1056
-
1057
- @object = @klass.new
1058
- end
1059
-
1060
- def test_should_change_the_initial_state
1061
- assert_equal :idling, @machine.initial_state(@object).name
1062
- end
1063
-
1064
- def test_should_include_in_known_states
1065
- assert_equal [:parked, :idling], @machine.states.map {|state| state.name}
1066
- end
1067
-
1068
- def test_should_reset_original_initial_state
1069
- assert !@machine.state(:parked).initial
1070
- end
1071
-
1072
- def test_should_set_new_state_to_initial
1073
- assert @machine.state(:idling).initial
1074
- end
1075
- end
1076
-
1077
- class MachineWithHelpersTest < Test::Unit::TestCase
1078
- def setup
1079
- @klass = Class.new
1080
- @machine = EnumStateMachine::Machine.new(@klass)
1081
- @object = @klass.new
1082
- end
1083
-
1084
- def test_should_throw_exception_with_invalid_scope
1085
- assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.define_helper(:invalid, :park) {} }
1086
- end
1087
- end
1088
-
1089
- class MachineWithInstanceHelpersTest < Test::Unit::TestCase
1090
- def setup
1091
- @klass = Class.new
1092
- @machine = EnumStateMachine::Machine.new(@klass)
1093
- @object = @klass.new
1094
- end
1095
-
1096
- def test_should_not_redefine_existing_public_methods
1097
- @klass.class_eval do
1098
- def park
1099
- true
1100
- end
1101
- end
1102
-
1103
- @machine.define_helper(:instance, :park) {}
1104
- assert_equal true, @object.park
1105
- end
1106
-
1107
- def test_should_not_redefine_existing_protected_methods
1108
- @klass.class_eval do
1109
- protected
1110
- def park
1111
- true
1112
- end
1113
- end
1114
-
1115
- @machine.define_helper(:instance, :park) {}
1116
- assert_equal true, @object.send(:park)
1117
- end
1118
-
1119
- def test_should_not_redefine_existing_private_methods
1120
- @klass.class_eval do
1121
- private
1122
- def park
1123
- true
1124
- end
1125
- end
1126
-
1127
- @machine.define_helper(:instance, :park) {}
1128
- assert_equal true, @object.send(:park)
1129
- end
1130
-
1131
- def test_should_warn_if_defined_in_superclass
1132
- require 'stringio'
1133
- @original_stderr, $stderr = $stderr, StringIO.new
1134
-
1135
- superclass = Class.new do
1136
- def park
1137
- end
1138
- end
1139
- klass = Class.new(superclass)
1140
- machine = EnumStateMachine::Machine.new(klass)
1141
-
1142
- machine.define_helper(:instance, :park) {}
1143
- assert_equal "Instance method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1144
- ensure
1145
- $stderr = @original_stderr
1146
- end
1147
-
1148
- def test_should_warn_if_defined_in_multiple_superclasses
1149
- require 'stringio'
1150
- @original_stderr, $stderr = $stderr, StringIO.new
1151
-
1152
- superclass1 = Class.new do
1153
- def park
1154
- end
1155
- end
1156
- superclass2 = Class.new(superclass1) do
1157
- def park
1158
- end
1159
- end
1160
- klass = Class.new(superclass2)
1161
- machine = EnumStateMachine::Machine.new(klass)
1162
-
1163
- machine.define_helper(:instance, :park) {}
1164
- assert_equal "Instance method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1165
- ensure
1166
- $stderr = @original_stderr
1167
- end
1168
-
1169
- def test_should_warn_if_defined_in_module_prior_to_helper_module
1170
- require 'stringio'
1171
- @original_stderr, $stderr = $stderr, StringIO.new
1172
-
1173
- mod = Module.new do
1174
- def park
1175
- end
1176
- end
1177
- klass = Class.new do
1178
- include mod
1179
- end
1180
- machine = EnumStateMachine::Machine.new(klass)
1181
-
1182
- machine.define_helper(:instance, :park) {}
1183
- assert_equal "Instance method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1184
- ensure
1185
- $stderr = @original_stderr
1186
- end
1187
-
1188
- def test_should_not_warn_if_defined_in_module_after_helper_module
1189
- require 'stringio'
1190
- @original_stderr, $stderr = $stderr, StringIO.new
1191
-
1192
- klass = Class.new
1193
- machine = EnumStateMachine::Machine.new(klass)
1194
-
1195
- mod = Module.new do
1196
- def park
1197
- end
1198
- end
1199
- klass.class_eval do
1200
- include mod
1201
- end
1202
-
1203
- machine.define_helper(:instance, :park) {}
1204
- assert_equal '', $stderr.string
1205
- ensure
1206
- $stderr = @original_stderr
1207
- end
1208
-
1209
- def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass
1210
- require 'stringio'
1211
- @original_stderr, $stderr = $stderr, StringIO.new
1212
- EnumStateMachine::Machine.ignore_method_conflicts = true
1213
-
1214
- superclass = Class.new do
1215
- def park
1216
- end
1217
- end
1218
- klass = Class.new(superclass)
1219
- machine = EnumStateMachine::Machine.new(klass)
1220
-
1221
- machine.define_helper(:instance, :park) {true}
1222
- assert_equal '', $stderr.string
1223
- assert_equal true, klass.new.park
1224
- ensure
1225
- EnumStateMachine::Machine.ignore_method_conflicts = false
1226
- $stderr = @original_stderr
1227
- end
1228
-
1229
- def test_should_define_nonexistent_methods
1230
- @machine.define_helper(:instance, :park) {false}
1231
- assert_equal false, @object.park
1232
- end
1233
-
1234
- def test_should_warn_if_defined_multiple_times
1235
- require 'stringio'
1236
- @original_stderr, $stderr = $stderr, StringIO.new
1237
-
1238
- @machine.define_helper(:instance, :park) {}
1239
- @machine.define_helper(:instance, :park) {}
1240
-
1241
- assert_equal "Instance method \"park\" is already defined in #{@klass} :state instance helpers, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1242
- ensure
1243
- $stderr = @original_stderr
1244
- end
1245
-
1246
- def test_should_pass_context_as_arguments
1247
- helper_args = nil
1248
- @machine.define_helper(:instance, :park) {|*args| helper_args = args}
1249
- @object.park
1250
- assert_equal 2, helper_args.length
1251
- assert_equal [@machine, @object], helper_args
1252
- end
1253
-
1254
- def test_should_pass_method_arguments_through
1255
- helper_args = nil
1256
- @machine.define_helper(:instance, :park) {|*args| helper_args = args}
1257
- @object.park(1, 2, 3)
1258
- assert_equal 5, helper_args.length
1259
- assert_equal [@machine, @object, 1, 2, 3], helper_args
1260
- end
1261
-
1262
- def test_should_allow_string_evaluation
1263
- @machine.define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
1264
- def park
1265
- false
1266
- end
1267
- end_eval
1268
- assert_equal false, @object.park
1269
- end
1270
- end
1271
-
1272
- class MachineWithClassHelpersTest < Test::Unit::TestCase
1273
- def setup
1274
- @klass = Class.new
1275
- @machine = EnumStateMachine::Machine.new(@klass)
1276
- end
1277
-
1278
- def test_should_not_redefine_existing_public_methods
1279
- class << @klass
1280
- def states
1281
- []
1282
- end
1283
- end
1284
-
1285
- @machine.define_helper(:class, :states) {}
1286
- assert_equal [], @klass.states
1287
- end
1288
-
1289
- def test_should_not_redefine_existing_protected_methods
1290
- class << @klass
1291
- protected
1292
- def states
1293
- []
1294
- end
1295
- end
1296
-
1297
- @machine.define_helper(:class, :states) {}
1298
- assert_equal [], @klass.send(:states)
1299
- end
1300
-
1301
- def test_should_not_redefine_existing_private_methods
1302
- class << @klass
1303
- private
1304
- def states
1305
- []
1306
- end
1307
- end
1308
-
1309
- @machine.define_helper(:class, :states) {}
1310
- assert_equal [], @klass.send(:states)
1311
- end
1312
-
1313
- def test_should_warn_if_defined_in_superclass
1314
- require 'stringio'
1315
- @original_stderr, $stderr = $stderr, StringIO.new
1316
-
1317
- superclass = Class.new do
1318
- def self.park
1319
- end
1320
- end
1321
- klass = Class.new(superclass)
1322
- machine = EnumStateMachine::Machine.new(klass)
1323
-
1324
- machine.define_helper(:class, :park) {}
1325
- assert_equal "Class method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1326
- ensure
1327
- $stderr = @original_stderr
1328
- end
1329
-
1330
- def test_should_warn_if_defined_in_multiple_superclasses
1331
- require 'stringio'
1332
- @original_stderr, $stderr = $stderr, StringIO.new
1333
-
1334
- superclass1 = Class.new do
1335
- def self.park
1336
- end
1337
- end
1338
- superclass2 = Class.new(superclass1) do
1339
- def self.park
1340
- end
1341
- end
1342
- klass = Class.new(superclass2)
1343
- machine = EnumStateMachine::Machine.new(klass)
1344
-
1345
- machine.define_helper(:class, :park) {}
1346
- assert_equal "Class method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1347
- ensure
1348
- $stderr = @original_stderr
1349
- end
1350
-
1351
- def test_should_warn_if_defined_in_module_prior_to_helper_module
1352
- require 'stringio'
1353
- @original_stderr, $stderr = $stderr, StringIO.new
1354
-
1355
- mod = Module.new do
1356
- def park
1357
- end
1358
- end
1359
- klass = Class.new do
1360
- extend mod
1361
- end
1362
- machine = EnumStateMachine::Machine.new(klass)
1363
-
1364
- machine.define_helper(:class, :park) {}
1365
- assert_equal "Class method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1366
- ensure
1367
- $stderr = @original_stderr
1368
- end
1369
-
1370
- def test_should_not_warn_if_defined_in_module_after_helper_module
1371
- require 'stringio'
1372
- @original_stderr, $stderr = $stderr, StringIO.new
1373
-
1374
- klass = Class.new
1375
- machine = EnumStateMachine::Machine.new(klass)
1376
-
1377
- mod = Module.new do
1378
- def park
1379
- end
1380
- end
1381
- klass.class_eval do
1382
- extend mod
1383
- end
1384
-
1385
- machine.define_helper(:class, :park) {}
1386
- assert_equal '', $stderr.string
1387
- ensure
1388
- $stderr = @original_stderr
1389
- end
1390
-
1391
- def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass
1392
- require 'stringio'
1393
- @original_stderr, $stderr = $stderr, StringIO.new
1394
- EnumStateMachine::Machine.ignore_method_conflicts = true
1395
-
1396
- superclass = Class.new do
1397
- def self.park
1398
- end
1399
- end
1400
- klass = Class.new(superclass)
1401
- machine = EnumStateMachine::Machine.new(klass)
1402
-
1403
- machine.define_helper(:class, :park) {true}
1404
- assert_equal '', $stderr.string
1405
- assert_equal true, klass.park
1406
- ensure
1407
- EnumStateMachine::Machine.ignore_method_conflicts = false
1408
- $stderr = @original_stderr
1409
- end
1410
-
1411
- def test_should_define_nonexistent_methods
1412
- @machine.define_helper(:class, :states) {[]}
1413
- assert_equal [], @klass.states
1414
- end
1415
-
1416
- def test_should_warn_if_defined_multiple_times
1417
- require 'stringio'
1418
- @original_stderr, $stderr = $stderr, StringIO.new
1419
-
1420
- @machine.define_helper(:class, :states) {}
1421
- @machine.define_helper(:class, :states) {}
1422
-
1423
- assert_equal "Class method \"states\" is already defined in #{@klass} :state class helpers, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
1424
- ensure
1425
- $stderr = @original_stderr
1426
- end
1427
-
1428
- def test_should_pass_context_as_arguments
1429
- helper_args = nil
1430
- @machine.define_helper(:class, :states) {|*args| helper_args = args}
1431
- @klass.states
1432
- assert_equal 2, helper_args.length
1433
- assert_equal [@machine, @klass], helper_args
1434
- end
1435
-
1436
- def test_should_pass_method_arguments_through
1437
- helper_args = nil
1438
- @machine.define_helper(:class, :states) {|*args| helper_args = args}
1439
- @klass.states(1, 2, 3)
1440
- assert_equal 5, helper_args.length
1441
- assert_equal [@machine, @klass, 1, 2, 3], helper_args
1442
- end
1443
-
1444
- def test_should_allow_string_evaluation
1445
- @machine.define_helper :class, <<-end_eval, __FILE__, __LINE__ + 1
1446
- def states
1447
- []
1448
- end
1449
- end_eval
1450
- assert_equal [], @klass.states
1451
- end
1452
- end
1453
-
1454
- class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
1455
- def setup
1456
- require 'stringio'
1457
- @original_stderr, $stderr = $stderr, StringIO.new
1458
-
1459
- @superclass = Class.new do
1460
- def self.with_state
1461
- :with_state
1462
- end
1463
-
1464
- def self.with_states
1465
- :with_states
1466
- end
1467
-
1468
- def self.without_state
1469
- :without_state
1470
- end
1471
-
1472
- def self.without_states
1473
- :without_states
1474
- end
1475
-
1476
- def self.human_state_name
1477
- :human_state_name
1478
- end
1479
-
1480
- def self.human_state_event_name
1481
- :human_state_event_name
1482
- end
1483
-
1484
- attr_accessor :status
1485
-
1486
- def state
1487
- 'parked'
1488
- end
1489
-
1490
- def state=(value)
1491
- self.status = value
1492
- end
1493
-
1494
- def state?
1495
- true
1496
- end
1497
-
1498
- def state_name
1499
- :parked
1500
- end
1501
-
1502
- def human_state_name
1503
- 'parked'
1504
- end
1505
-
1506
- def state_events
1507
- [:ignite]
1508
- end
1509
-
1510
- def state_transitions
1511
- [{:parked => :idling}]
1512
- end
1513
-
1514
- def state_paths
1515
- [[{:parked => :idling}]]
1516
- end
1517
-
1518
- def fire_state_event
1519
- true
1520
- end
1521
- end
1522
- @klass = Class.new(@superclass)
1523
-
1524
- EnumStateMachine::Integrations.const_set('Custom', Module.new do
1525
- include EnumStateMachine::Integrations::Base
1526
-
1527
- def create_with_scope(name)
1528
- lambda {|klass, values| []}
1529
- end
1530
-
1531
- def create_without_scope(name)
1532
- lambda {|klass, values| []}
1533
- end
1534
- end)
1535
-
1536
- @machine = EnumStateMachine::Machine.new(@klass, :integration => :custom)
1537
- @machine.state :parked, :idling
1538
- @machine.event :ignite
1539
- @object = @klass.new
1540
- end
1541
-
1542
- def test_should_not_redefine_singular_with_scope
1543
- assert_equal :with_state, @klass.with_state
1544
- end
1545
-
1546
- def test_should_not_redefine_plural_with_scope
1547
- assert_equal :with_states, @klass.with_states
1548
- end
1549
-
1550
- def test_should_not_redefine_singular_without_scope
1551
- assert_equal :without_state, @klass.without_state
1552
- end
1553
-
1554
- def test_should_not_redefine_plural_without_scope
1555
- assert_equal :without_states, @klass.without_states
1556
- end
1557
-
1558
- def test_should_not_redefine_human_attribute_name_reader
1559
- assert_equal :human_state_name, @klass.human_state_name
1560
- end
1561
-
1562
- def test_should_not_redefine_human_event_name_reader
1563
- assert_equal :human_state_event_name, @klass.human_state_event_name
1564
- end
1565
-
1566
- def test_should_not_redefine_attribute_reader
1567
- assert_equal 'parked', @object.state
1568
- end
1569
-
1570
- def test_should_not_redefine_attribute_writer
1571
- @object.state = 'parked'
1572
- assert_equal 'parked', @object.status
1573
- end
1574
-
1575
- def test_should_not_define_attribute_predicate
1576
- assert @object.state?
1577
- end
1578
-
1579
- def test_should_not_redefine_attribute_name_reader
1580
- assert_equal :parked, @object.state_name
1581
- end
1582
-
1583
- def test_should_not_redefine_attribute_human_name_reader
1584
- assert_equal 'parked', @object.human_state_name
1585
- end
1586
-
1587
- def test_should_not_redefine_attribute_events_reader
1588
- assert_equal [:ignite], @object.state_events
1589
- end
1590
-
1591
- def test_should_not_redefine_attribute_transitions_reader
1592
- assert_equal [{:parked => :idling}], @object.state_transitions
1593
- end
1594
-
1595
- def test_should_not_redefine_attribute_paths_reader
1596
- assert_equal [[{:parked => :idling}]], @object.state_paths
1597
- end
1598
-
1599
- def test_should_not_redefine_event_runner
1600
- assert_equal true, @object.fire_state_event
1601
- end
1602
-
1603
- def test_should_output_warning
1604
- expected = [
1605
- 'Instance method "state_events"',
1606
- 'Instance method "state_transitions"',
1607
- 'Instance method "fire_state_event"',
1608
- 'Instance method "state_paths"',
1609
- 'Class method "human_state_name"',
1610
- 'Class method "human_state_event_name"',
1611
- 'Instance method "state_name"',
1612
- 'Instance method "human_state_name"',
1613
- 'Class method "with_state"',
1614
- 'Class method "with_states"',
1615
- 'Class method "without_state"',
1616
- 'Class method "without_states"'
1617
- ].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead or set EnumStateMachine::Machine.ignore_method_conflicts = true.\n"}.join
1618
-
1619
- assert_equal expected, $stderr.string
1620
- end
1621
-
1622
- def teardown
1623
- $stderr = @original_stderr
1624
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
1625
- end
1626
- end
1627
-
1628
- class MachineWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
1629
- def setup
1630
- require 'stringio'
1631
- @original_stderr, $stderr = $stderr, StringIO.new
1632
-
1633
- @klass = Class.new do
1634
- def self.with_state
1635
- :with_state
1636
- end
1637
-
1638
- def self.with_states
1639
- :with_states
1640
- end
1641
-
1642
- def self.without_state
1643
- :without_state
1644
- end
1645
-
1646
- def self.without_states
1647
- :without_states
1648
- end
1649
-
1650
- def self.human_state_name
1651
- :human_state_name
1652
- end
1653
-
1654
- def self.human_state_event_name
1655
- :human_state_event_name
1656
- end
1657
-
1658
- attr_accessor :status
1659
-
1660
- def state
1661
- 'parked'
1662
- end
1663
-
1664
- def state=(value)
1665
- self.status = value
1666
- end
1667
-
1668
- def state?
1669
- true
1670
- end
1671
-
1672
- def state_name
1673
- :parked
1674
- end
1675
-
1676
- def human_state_name
1677
- 'parked'
1678
- end
1679
-
1680
- def state_events
1681
- [:ignite]
1682
- end
1683
-
1684
- def state_transitions
1685
- [{:parked => :idling}]
1686
- end
1687
-
1688
- def state_paths
1689
- [[{:parked => :idling}]]
1690
- end
1691
-
1692
- def fire_state_event
1693
- true
1694
- end
1695
- end
1696
-
1697
- EnumStateMachine::Integrations.const_set('Custom', Module.new do
1698
- include EnumStateMachine::Integrations::Base
1699
-
1700
- def create_with_scope(name)
1701
- lambda {|klass, values| []}
1702
- end
1703
-
1704
- def create_without_scope(name)
1705
- lambda {|klass, values| []}
1706
- end
1707
- end)
1708
-
1709
- @machine = EnumStateMachine::Machine.new(@klass, :integration => :custom)
1710
- @machine.state :parked, :idling
1711
- @machine.event :ignite
1712
- @object = @klass.new
1713
- end
1714
-
1715
- def test_should_not_redefine_singular_with_scope
1716
- assert_equal :with_state, @klass.with_state
1717
- end
1718
-
1719
- def test_should_not_redefine_plural_with_scope
1720
- assert_equal :with_states, @klass.with_states
1721
- end
1722
-
1723
- def test_should_not_redefine_singular_without_scope
1724
- assert_equal :without_state, @klass.without_state
1725
- end
1726
-
1727
- def test_should_not_redefine_plural_without_scope
1728
- assert_equal :without_states, @klass.without_states
1729
- end
1730
-
1731
- def test_should_not_redefine_human_attribute_name_reader
1732
- assert_equal :human_state_name, @klass.human_state_name
1733
- end
1734
-
1735
- def test_should_not_redefine_human_event_name_reader
1736
- assert_equal :human_state_event_name, @klass.human_state_event_name
1737
- end
1738
-
1739
- def test_should_not_redefine_attribute_reader
1740
- assert_equal 'parked', @object.state
1741
- end
1742
-
1743
- def test_should_not_redefine_attribute_writer
1744
- @object.state = 'parked'
1745
- assert_equal 'parked', @object.status
1746
- end
1747
-
1748
- def test_should_not_define_attribute_predicate
1749
- assert @object.state?
1750
- end
1751
-
1752
- def test_should_not_redefine_attribute_name_reader
1753
- assert_equal :parked, @object.state_name
1754
- end
1755
-
1756
- def test_should_not_redefine_attribute_human_name_reader
1757
- assert_equal 'parked', @object.human_state_name
1758
- end
1759
-
1760
- def test_should_not_redefine_attribute_events_reader
1761
- assert_equal [:ignite], @object.state_events
1762
- end
1763
-
1764
- def test_should_not_redefine_attribute_transitions_reader
1765
- assert_equal [{:parked => :idling}], @object.state_transitions
1766
- end
1767
-
1768
- def test_should_not_redefine_attribute_paths_reader
1769
- assert_equal [[{:parked => :idling}]], @object.state_paths
1770
- end
1771
-
1772
- def test_should_not_redefine_event_runner
1773
- assert_equal true, @object.fire_state_event
1774
- end
1775
-
1776
- def test_should_allow_super_chaining
1777
- @klass.class_eval do
1778
- def self.with_state(*states)
1779
- super
1780
- end
1781
-
1782
- def self.with_states(*states)
1783
- super
1784
- end
1785
-
1786
- def self.without_state(*states)
1787
- super
1788
- end
1789
-
1790
- def self.without_states(*states)
1791
- super
1792
- end
1793
-
1794
- def self.human_state_name(state)
1795
- super
1796
- end
1797
-
1798
- def self.human_state_event_name(event)
1799
- super
1800
- end
1801
-
1802
- attr_accessor :status
1803
-
1804
- def state
1805
- super
1806
- end
1807
-
1808
- def state=(value)
1809
- super
1810
- end
1811
-
1812
- def state?(state)
1813
- super
1814
- end
1815
-
1816
- def state_name
1817
- super
1818
- end
1819
-
1820
- def human_state_name
1821
- super
1822
- end
1823
-
1824
- def state_events
1825
- super
1826
- end
1827
-
1828
- def state_transitions
1829
- super
1830
- end
1831
-
1832
- def state_paths
1833
- super
1834
- end
1835
-
1836
- def fire_state_event(event)
1837
- super
1838
- end
1839
- end
1840
-
1841
- assert_equal [], @klass.with_state
1842
- assert_equal [], @klass.with_states
1843
- assert_equal [], @klass.without_state
1844
- assert_equal [], @klass.without_states
1845
- assert_equal 'parked', @klass.human_state_name(:parked)
1846
- assert_equal 'ignite', @klass.human_state_event_name(:ignite)
1847
-
1848
- assert_equal nil, @object.state
1849
- @object.state = 'idling'
1850
- assert_equal 'idling', @object.state
1851
- assert_equal nil, @object.status
1852
- assert_equal false, @object.state?(:parked)
1853
- assert_equal :idling, @object.state_name
1854
- assert_equal 'idling', @object.human_state_name
1855
- assert_equal [], @object.state_events
1856
- assert_equal [], @object.state_transitions
1857
- assert_equal [], @object.state_paths
1858
- assert_equal false, @object.fire_state_event(:ignite)
1859
- end
1860
-
1861
- def test_should_not_output_warning
1862
- assert_equal '', $stderr.string
1863
- end
1864
-
1865
- def teardown
1866
- $stderr = @original_stderr
1867
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
1868
- end
1869
- end
1870
-
1871
- class MachineWithSuperclassConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
1872
- def setup
1873
- require 'stringio'
1874
- @original_stderr, $stderr = $stderr, StringIO.new
1875
-
1876
- @superclass = Class.new
1877
- @klass = Class.new(@superclass)
1878
-
1879
- @machine = EnumStateMachine::Machine.new(@klass)
1880
- @machine.state :parked, :idling
1881
- @machine.event :ignite
1882
-
1883
- @superclass.class_eval do
1884
- def state?
1885
- true
1886
- end
1887
- end
1888
-
1889
- @object = @klass.new
1890
- end
1891
-
1892
- def test_should_call_superclass_attribute_predicate_without_arguments
1893
- assert @object.state?
1894
- end
1895
-
1896
- def test_should_define_attribute_predicate_with_arguments
1897
- assert !@object.state?(:parked)
1898
- end
1899
-
1900
- def teardown
1901
- $stderr = @original_stderr
1902
- end
1903
- end
1904
-
1905
- class MachineWithoutInitializeTest < Test::Unit::TestCase
1906
- def setup
1907
- @klass = Class.new
1908
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
1909
- @object = @klass.new
1910
- end
1911
-
1912
- def test_should_initialize_state
1913
- assert_equal 'parked', @object.state
1914
- end
1915
- end
1916
-
1917
- class MachineWithInitializeWithoutSuperTest < Test::Unit::TestCase
1918
- def setup
1919
- @klass = Class.new do
1920
- def initialize
1921
- end
1922
- end
1923
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
1924
- @object = @klass.new
1925
- end
1926
-
1927
- def test_should_not_initialize_state
1928
- assert_nil @object.state
1929
- end
1930
- end
1931
-
1932
- class MachineWithInitializeAndSuperTest < Test::Unit::TestCase
1933
- def setup
1934
- @klass = Class.new do
1935
- def initialize
1936
- super()
1937
- end
1938
- end
1939
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
1940
- @object = @klass.new
1941
- end
1942
-
1943
- def test_should_initialize_state
1944
- assert_equal 'parked', @object.state
1945
- end
1946
- end
1947
-
1948
- class MachineWithInitializeArgumentsAndBlockTest < Test::Unit::TestCase
1949
- def setup
1950
- @superclass = Class.new do
1951
- attr_reader :args
1952
- attr_reader :block_given
1953
-
1954
- def initialize(*args)
1955
- @args = args
1956
- @block_given = block_given?
1957
- end
1958
- end
1959
- @klass = Class.new(@superclass)
1960
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
1961
- @object = @klass.new(1, 2, 3) {}
1962
- end
1963
-
1964
- def test_should_initialize_state
1965
- assert_equal 'parked', @object.state
1966
- end
1967
-
1968
- def test_should_preserve_arguments
1969
- assert_equal [1, 2, 3], @object.args
1970
- end
1971
-
1972
- def test_should_preserve_block
1973
- assert @object.block_given
1974
- end
1975
- end
1976
-
1977
- class MachineWithCustomInitializeTest < Test::Unit::TestCase
1978
- def setup
1979
- @klass = Class.new do
1980
- def initialize(state = nil, options = {})
1981
- @state = state
1982
- initialize_state_machines(options)
1983
- end
1984
- end
1985
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
1986
- @object = @klass.new
1987
- end
1988
-
1989
- def test_should_initialize_state
1990
- assert_equal 'parked', @object.state
1991
- end
1992
-
1993
- def test_should_allow_custom_options
1994
- @machine.state :idling
1995
- @object = @klass.new('idling', :static => :force)
1996
- assert_equal 'parked', @object.state
1997
- end
1998
- end
1999
-
2000
- class MachinePersistenceTest < Test::Unit::TestCase
2001
- def setup
2002
- @klass = Class.new do
2003
- attr_accessor :state_event
2004
- end
2005
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2006
- @object = @klass.new
2007
- end
2008
-
2009
- def test_should_allow_reading_state
2010
- assert_equal 'parked', @machine.read(@object, :state)
2011
- end
2012
-
2013
- def test_should_allow_reading_custom_attributes
2014
- assert_nil @machine.read(@object, :event)
2015
-
2016
- @object.state_event = 'ignite'
2017
- assert_equal 'ignite', @machine.read(@object, :event)
2018
- end
2019
-
2020
- def test_should_allow_reading_custom_instance_variables
2021
- @klass.class_eval do
2022
- attr_writer :state_value
2023
- end
2024
-
2025
- @object.state_value = 1
2026
- assert_raise(NoMethodError) { @machine.read(@object, :value) }
2027
- assert_equal 1, @machine.read(@object, :value, true)
2028
- end
2029
-
2030
- def test_should_allow_writing_state
2031
- @machine.write(@object, :state, 'idling')
2032
- assert_equal 'idling', @object.state
2033
- end
2034
-
2035
- def test_should_allow_writing_custom_attributes
2036
- @machine.write(@object, :event, 'ignite')
2037
- assert_equal 'ignite', @object.state_event
2038
- end
2039
-
2040
- def test_should_allow_writing_custom_instance_variables
2041
- @klass.class_eval do
2042
- attr_reader :state_value
2043
- end
2044
-
2045
- assert_raise(NoMethodError) { @machine.write(@object, :value, 1) }
2046
- assert_equal 1, @machine.write(@object, :value, 1, true)
2047
- assert_equal 1, @object.state_value
2048
- end
2049
- end
2050
-
2051
-
2052
- class MachineWithStatesTest < Test::Unit::TestCase
2053
- def setup
2054
- @klass = Class.new
2055
- @machine = EnumStateMachine::Machine.new(@klass)
2056
- @parked, @idling = @machine.state :parked, :idling
2057
-
2058
- @object = @klass.new
2059
- end
2060
-
2061
- def test_should_have_states
2062
- assert_equal [nil, :parked, :idling], @machine.states.map {|state| state.name}
2063
- end
2064
-
2065
- def test_should_allow_state_lookup_by_name
2066
- assert_equal @parked, @machine.states[:parked]
2067
- end
2068
-
2069
- def test_should_allow_state_lookup_by_value
2070
- assert_equal @parked, @machine.states['parked', :value]
2071
- end
2072
-
2073
- def test_should_allow_human_state_name_lookup
2074
- assert_equal 'parked', @klass.human_state_name(:parked)
2075
- end
2076
-
2077
- def test_should_raise_exception_on_invalid_human_state_name_lookup
2078
- exception = assert_raise(IndexError) {@klass.human_state_name(:invalid)}
2079
- assert_equal ':invalid is an invalid name', exception.message
2080
- end
2081
-
2082
- def test_should_use_stringified_name_for_value
2083
- assert_equal 'parked', @parked.value
2084
- end
2085
-
2086
- def test_should_not_use_custom_matcher
2087
- assert_nil @parked.matcher
2088
- end
2089
-
2090
- def test_should_raise_exception_if_invalid_option_specified
2091
- exception = assert_raise(ArgumentError) {@machine.state(:first_gear, :invalid => true)}
2092
- assert_equal 'Invalid key(s): invalid', exception.message
2093
- end
2094
-
2095
- def test_should_raise_exception_if_conflicting_type_used_for_name
2096
- exception = assert_raise(ArgumentError) { @machine.state 'first_gear' }
2097
- assert_equal '"first_gear" state defined as String, :parked defined as Symbol; all states must be consistent', exception.message
2098
- end
2099
-
2100
- def test_should_not_raise_exception_if_conflicting_type_is_nil_for_name
2101
- assert_nothing_raised { @machine.state nil }
2102
- end
2103
- end
2104
-
2105
- class MachineWithStatesWithCustomValuesTest < Test::Unit::TestCase
2106
- def setup
2107
- @klass = Class.new
2108
- @machine = EnumStateMachine::Machine.new(@klass)
2109
- @state = @machine.state :parked, :value => 1
2110
-
2111
- @object = @klass.new
2112
- @object.state = 1
2113
- end
2114
-
2115
- def test_should_use_custom_value
2116
- assert_equal 1, @state.value
2117
- end
2118
-
2119
- def test_should_allow_lookup_by_custom_value
2120
- assert_equal @state, @machine.states[1, :value]
2121
- end
2122
- end
2123
-
2124
- class MachineWithStatesWithCustomHumanNamesTest < Test::Unit::TestCase
2125
- def setup
2126
- @klass = Class.new
2127
- @machine = EnumStateMachine::Machine.new(@klass)
2128
- @state = @machine.state :parked, :human_name => 'stopped'
2129
- end
2130
-
2131
- def test_should_use_custom_human_name
2132
- assert_equal 'stopped', @state.human_name
2133
- end
2134
-
2135
- def test_should_allow_human_state_name_lookup
2136
- assert_equal 'stopped', @klass.human_state_name(:parked)
2137
- end
2138
- end
2139
-
2140
- class MachineWithStatesWithRuntimeDependenciesTest < Test::Unit::TestCase
2141
- def setup
2142
- @klass = Class.new
2143
- @machine = EnumStateMachine::Machine.new(@klass)
2144
- @machine.state :parked
2145
- end
2146
-
2147
- def test_should_not_evaluate_value_during_definition
2148
- assert_nothing_raised { @machine.state :parked, :value => lambda {raise ArgumentError} }
2149
- end
2150
-
2151
- def test_should_not_evaluate_if_not_initial_state
2152
- @machine.state :parked, :value => lambda {raise ArgumentError}
2153
- assert_nothing_raised { @klass.new }
2154
- end
2155
- end
2156
-
2157
- class MachineWithStateWithMatchersTest < Test::Unit::TestCase
2158
- def setup
2159
- @klass = Class.new
2160
- @machine = EnumStateMachine::Machine.new(@klass)
2161
- @state = @machine.state :parked, :if => lambda {|value| !value.nil?}
2162
-
2163
- @object = @klass.new
2164
- @object.state = 1
2165
- end
2166
-
2167
- def test_should_use_custom_matcher
2168
- assert_not_nil @state.matcher
2169
- assert @state.matches?(1)
2170
- assert !@state.matches?(nil)
2171
- end
2172
- end
2173
-
2174
- class MachineWithCachedStateTest < Test::Unit::TestCase
2175
- def setup
2176
- @klass = Class.new
2177
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2178
- @state = @machine.state :parked, :value => lambda {Object.new}, :cache => true
2179
-
2180
- @object = @klass.new
2181
- end
2182
-
2183
- def test_should_use_evaluated_value
2184
- assert_instance_of Object, @object.state
2185
- end
2186
-
2187
- def test_use_same_value_across_multiple_objects
2188
- assert_equal @object.state, @klass.new.state
2189
- end
2190
- end
2191
-
2192
- class MachineWithStatesWithBehaviorsTest < Test::Unit::TestCase
2193
- def setup
2194
- @klass = Class.new
2195
- @machine = EnumStateMachine::Machine.new(@klass)
2196
-
2197
- @parked, @idling = @machine.state :parked, :idling do
2198
- def speed
2199
- 0
2200
- end
2201
- end
2202
- end
2203
-
2204
- def test_should_define_behaviors_for_each_state
2205
- assert_not_nil @parked.context_methods[:speed]
2206
- assert_not_nil @idling.context_methods[:speed]
2207
- end
2208
-
2209
- def test_should_define_different_behaviors_for_each_state
2210
- assert_not_equal @parked.context_methods[:speed], @idling.context_methods[:speed]
2211
- end
2212
- end
2213
-
2214
- class MachineWithExistingStateTest < Test::Unit::TestCase
2215
- def setup
2216
- @klass = Class.new
2217
- @machine = EnumStateMachine::Machine.new(@klass)
2218
- @state = @machine.state :parked
2219
- @same_state = @machine.state :parked, :value => 1
2220
- end
2221
-
2222
- def test_should_not_create_a_new_state
2223
- assert_same @state, @same_state
2224
- end
2225
-
2226
- def test_should_update_attributes
2227
- assert_equal 1, @state.value
2228
- end
2229
-
2230
- def test_should_no_longer_be_able_to_look_up_state_by_original_value
2231
- assert_nil @machine.states['parked', :value]
2232
- end
2233
-
2234
- def test_should_be_able_to_look_up_state_by_new_value
2235
- assert_equal @state, @machine.states[1, :value]
2236
- end
2237
- end
2238
-
2239
- class MachineWithStateMatchersTest < Test::Unit::TestCase
2240
- def setup
2241
- @klass = Class.new
2242
- @machine = EnumStateMachine::Machine.new(@klass)
2243
- end
2244
-
2245
- def test_should_empty_array_for_all_matcher
2246
- assert_equal [], @machine.state(EnumStateMachine::AllMatcher.instance)
2247
- end
2248
-
2249
- def test_should_return_referenced_states_for_blacklist_matcher
2250
- assert_instance_of EnumStateMachine::State, @machine.state(EnumStateMachine::BlacklistMatcher.new([:parked]))
2251
- end
2252
-
2253
- def test_should_not_allow_configurations
2254
- exception = assert_raise(ArgumentError) { @machine.state(EnumStateMachine::BlacklistMatcher.new([:parked]), :human_name => 'Parked') }
2255
- assert_equal 'Cannot configure states when using matchers (using {:human_name=>"Parked"})', exception.message
2256
- end
2257
-
2258
- def test_should_track_referenced_states
2259
- @machine.state(EnumStateMachine::BlacklistMatcher.new([:parked]))
2260
- assert_equal [nil, :parked], @machine.states.map {|state| state.name}
2261
- end
2262
-
2263
- def test_should_eval_context_for_matching_states
2264
- contexts_run = []
2265
- @machine.event(EnumStateMachine::BlacklistMatcher.new([:parked])) { contexts_run << self.name }
2266
-
2267
- @machine.event :parked
2268
- assert_equal [], contexts_run
2269
-
2270
- @machine.event :idling
2271
- assert_equal [:idling], contexts_run
2272
-
2273
- @machine.event :first_gear, :second_gear
2274
- assert_equal [:idling, :first_gear, :second_gear], contexts_run
2275
- end
2276
- end
2277
-
2278
- class MachineWithOtherStates < Test::Unit::TestCase
2279
- def setup
2280
- @klass = Class.new
2281
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2282
- @parked, @idling = @machine.other_states(:parked, :idling)
2283
- end
2284
-
2285
- def test_should_include_other_states_in_known_states
2286
- assert_equal [@parked, @idling], @machine.states.to_a
2287
- end
2288
-
2289
- def test_should_use_default_value
2290
- assert_equal 'idling', @idling.value
2291
- end
2292
-
2293
- def test_should_not_create_matcher
2294
- assert_nil @idling.matcher
2295
- end
2296
- end
2297
-
2298
- class MachineWithEventsTest < Test::Unit::TestCase
2299
- def setup
2300
- @klass = Class.new
2301
- @machine = EnumStateMachine::Machine.new(@klass)
2302
- end
2303
-
2304
- def test_should_return_the_created_event
2305
- assert_instance_of EnumStateMachine::Event, @machine.event(:ignite)
2306
- end
2307
-
2308
- def test_should_create_event_with_given_name
2309
- event = @machine.event(:ignite) {}
2310
- assert_equal :ignite, event.name
2311
- end
2312
-
2313
- def test_should_evaluate_block_within_event_context
2314
- responded = false
2315
- @machine.event :ignite do
2316
- responded = respond_to?(:transition)
2317
- end
2318
-
2319
- assert responded
2320
- end
2321
-
2322
- def test_should_be_aliased_as_on
2323
- event = @machine.on(:ignite) {}
2324
- assert_equal :ignite, event.name
2325
- end
2326
-
2327
- def test_should_have_events
2328
- event = @machine.event(:ignite)
2329
- assert_equal [event], @machine.events.to_a
2330
- end
2331
-
2332
- def test_should_allow_human_state_name_lookup
2333
- @machine.event(:ignite)
2334
- assert_equal 'ignite', @klass.human_state_event_name(:ignite)
2335
- end
2336
-
2337
- def test_should_raise_exception_on_invalid_human_state_event_name_lookup
2338
- exception = assert_raise(IndexError) {@klass.human_state_event_name(:invalid)}
2339
- assert_equal ':invalid is an invalid name', exception.message
2340
- end
2341
-
2342
- def test_should_raise_exception_if_conflicting_type_used_for_name
2343
- @machine.event :park
2344
- exception = assert_raise(ArgumentError) { @machine.event 'ignite' }
2345
- assert_equal '"ignite" event defined as String, :park defined as Symbol; all events must be consistent', exception.message
2346
- end
2347
- end
2348
-
2349
- class MachineWithExistingEventTest < Test::Unit::TestCase
2350
- def setup
2351
- @machine = EnumStateMachine::Machine.new(Class.new)
2352
- @event = @machine.event(:ignite)
2353
- @same_event = @machine.event(:ignite)
2354
- end
2355
-
2356
- def test_should_not_create_new_event
2357
- assert_same @event, @same_event
2358
- end
2359
-
2360
- def test_should_allow_accessing_event_without_block
2361
- assert_equal @event, @machine.event(:ignite)
2362
- end
2363
- end
2364
-
2365
- class MachineWithEventsWithCustomHumanNamesTest < Test::Unit::TestCase
2366
- def setup
2367
- @klass = Class.new
2368
- @machine = EnumStateMachine::Machine.new(@klass)
2369
- @event = @machine.event(:ignite, :human_name => 'start')
2370
- end
2371
-
2372
- def test_should_use_custom_human_name
2373
- assert_equal 'start', @event.human_name
2374
- end
2375
-
2376
- def test_should_allow_human_state_name_lookup
2377
- assert_equal 'start', @klass.human_state_event_name(:ignite)
2378
- end
2379
- end
2380
-
2381
- class MachineWithEventMatchersTest < Test::Unit::TestCase
2382
- def setup
2383
- @klass = Class.new
2384
- @machine = EnumStateMachine::Machine.new(@klass)
2385
- end
2386
-
2387
- def test_should_empty_array_for_all_matcher
2388
- assert_equal [], @machine.event(EnumStateMachine::AllMatcher.instance)
2389
- end
2390
-
2391
- def test_should_return_referenced_events_for_blacklist_matcher
2392
- assert_instance_of EnumStateMachine::Event, @machine.event(EnumStateMachine::BlacklistMatcher.new([:park]))
2393
- end
2394
-
2395
- def test_should_not_allow_configurations
2396
- exception = assert_raise(ArgumentError) { @machine.event(EnumStateMachine::BlacklistMatcher.new([:park]), :human_name => 'Park') }
2397
- assert_equal 'Cannot configure events when using matchers (using {:human_name=>"Park"})', exception.message
2398
- end
2399
-
2400
- def test_should_track_referenced_events
2401
- @machine.event(EnumStateMachine::BlacklistMatcher.new([:park]))
2402
- assert_equal [:park], @machine.events.map {|event| event.name}
2403
- end
2404
-
2405
- def test_should_eval_context_for_matching_events
2406
- contexts_run = []
2407
- @machine.event(EnumStateMachine::BlacklistMatcher.new([:park])) { contexts_run << self.name }
2408
-
2409
- @machine.event :park
2410
- assert_equal [], contexts_run
2411
-
2412
- @machine.event :ignite
2413
- assert_equal [:ignite], contexts_run
2414
-
2415
- @machine.event :shift_up, :shift_down
2416
- assert_equal [:ignite, :shift_up, :shift_down], contexts_run
2417
- end
2418
- end
2419
-
2420
- class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
2421
- def setup
2422
- @klass = Class.new
2423
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2424
- @event = @machine.event(:ignite) do
2425
- transition :parked => :idling
2426
- transition :stalled => :idling
2427
- end
2428
- end
2429
-
2430
- def test_should_have_events
2431
- assert_equal [@event], @machine.events.to_a
2432
- end
2433
-
2434
- def test_should_track_states_defined_in_event_transitions
2435
- assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
2436
- end
2437
-
2438
- def test_should_not_duplicate_states_defined_in_multiple_event_transitions
2439
- @machine.event :park do
2440
- transition :idling => :parked
2441
- end
2442
-
2443
- assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
2444
- end
2445
-
2446
- def test_should_track_state_from_new_events
2447
- @machine.event :shift_up do
2448
- transition :idling => :first_gear
2449
- end
2450
-
2451
- assert_equal [:parked, :idling, :stalled, :first_gear], @machine.states.map {|state| state.name}
2452
- end
2453
- end
2454
-
2455
- class MachineWithMultipleEventsTest < Test::Unit::TestCase
2456
- def setup
2457
- @klass = Class.new
2458
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2459
- @park, @shift_down = @machine.event(:park, :shift_down) do
2460
- transition :first_gear => :parked
2461
- end
2462
- end
2463
-
2464
- def test_should_have_events
2465
- assert_equal [@park, @shift_down], @machine.events.to_a
2466
- end
2467
-
2468
- def test_should_define_transitions_for_each_event
2469
- [@park, @shift_down].each {|event| assert_equal 1, event.branches.size}
2470
- end
2471
-
2472
- def test_should_transition_the_same_for_each_event
2473
- object = @klass.new
2474
- object.state = 'first_gear'
2475
- object.park
2476
- assert_equal 'parked', object.state
2477
-
2478
- object = @klass.new
2479
- object.state = 'first_gear'
2480
- object.shift_down
2481
- assert_equal 'parked', object.state
2482
- end
2483
- end
2484
-
2485
- class MachineWithTransitionsTest < Test::Unit::TestCase
2486
- def setup
2487
- @klass = Class.new
2488
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2489
- end
2490
-
2491
- def test_should_require_on_event
2492
- exception = assert_raise(ArgumentError) { @machine.transition(:parked => :idling) }
2493
- assert_equal 'Must specify :on event', exception.message
2494
- end
2495
-
2496
- def test_should_not_allow_except_on_option
2497
- exception = assert_raise(ArgumentError) {@machine.transition(:except_on => :ignite, :on => :ignite)}
2498
- assert_equal 'Invalid key(s): except_on', exception.message
2499
- end
2500
-
2501
- def test_should_allow_transitioning_without_a_to_state
2502
- assert_nothing_raised {@machine.transition(:from => :parked, :on => :ignite)}
2503
- end
2504
-
2505
- def test_should_allow_transitioning_without_a_from_state
2506
- assert_nothing_raised {@machine.transition(:to => :idling, :on => :ignite)}
2507
- end
2508
-
2509
- def test_should_allow_except_from_option
2510
- assert_nothing_raised {@machine.transition(:except_from => :idling, :on => :ignite)}
2511
- end
2512
-
2513
- def test_should_allow_except_to_option
2514
- assert_nothing_raised {@machine.transition(:except_to => :parked, :on => :ignite)}
2515
- end
2516
-
2517
- def test_should_allow_implicit_options
2518
- branch = @machine.transition(:first_gear => :second_gear, :on => :shift_up)
2519
- assert_instance_of EnumStateMachine::Branch, branch
2520
-
2521
- state_requirements = branch.state_requirements
2522
- assert_equal 1, state_requirements.length
2523
-
2524
- assert_instance_of EnumStateMachine::WhitelistMatcher, state_requirements[0][:from]
2525
- assert_equal [:first_gear], state_requirements[0][:from].values
2526
- assert_instance_of EnumStateMachine::WhitelistMatcher, state_requirements[0][:to]
2527
- assert_equal [:second_gear], state_requirements[0][:to].values
2528
- assert_instance_of EnumStateMachine::WhitelistMatcher, branch.event_requirement
2529
- assert_equal [:shift_up], branch.event_requirement.values
2530
- end
2531
-
2532
- def test_should_allow_multiple_implicit_options
2533
- branch = @machine.transition(:first_gear => :second_gear, :second_gear => :third_gear, :on => :shift_up)
2534
-
2535
- state_requirements = branch.state_requirements
2536
- assert_equal 2, state_requirements.length
2537
- end
2538
-
2539
- def test_should_allow_verbose_options
2540
- branch = @machine.transition(:from => :parked, :to => :idling, :on => :ignite)
2541
- assert_instance_of EnumStateMachine::Branch, branch
2542
- end
2543
-
2544
- def test_should_include_all_transition_states_in_machine_states
2545
- @machine.transition(:parked => :idling, :on => :ignite)
2546
-
2547
- assert_equal [:parked, :idling], @machine.states.map {|state| state.name}
2548
- end
2549
-
2550
- def test_should_include_all_transition_events_in_machine_events
2551
- @machine.transition(:parked => :idling, :on => :ignite)
2552
-
2553
- assert_equal [:ignite], @machine.events.map {|event| event.name}
2554
- end
2555
-
2556
- def test_should_allow_multiple_events
2557
- branches = @machine.transition(:parked => :ignite, :on => [:ignite, :shift_up])
2558
-
2559
- assert_equal 2, branches.length
2560
- assert_equal [:ignite, :shift_up], @machine.events.map {|event| event.name}
2561
- end
2562
-
2563
- def test_should_not_modify_options
2564
- options = {:parked => :idling, :on => :ignite}
2565
- @machine.transition(options)
2566
-
2567
- assert_equal options, {:parked => :idling, :on => :ignite}
2568
- end
2569
- end
2570
-
2571
- class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
2572
- def setup
2573
- @klass = Class.new do
2574
- attr_accessor :callbacks
2575
- end
2576
-
2577
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2578
- @event = @machine.event :ignite do
2579
- transition :parked => :idling
2580
- end
2581
-
2582
- @object = @klass.new
2583
- @object.callbacks = []
2584
- end
2585
-
2586
- def test_should_not_raise_exception_if_implicit_option_specified
2587
- assert_nothing_raised {@machine.before_transition :invalid => :valid, :do => lambda {}}
2588
- end
2589
-
2590
- def test_should_raise_exception_if_method_not_specified
2591
- exception = assert_raise(ArgumentError) {@machine.before_transition :to => :idling}
2592
- assert_equal 'Method(s) for callback must be specified', exception.message
2593
- end
2594
-
2595
- def test_should_invoke_callbacks_during_transition
2596
- @machine.before_transition lambda {|object| object.callbacks << 'before'}
2597
- @machine.after_transition lambda {|object| object.callbacks << 'after'}
2598
- @machine.around_transition lambda {|object, transition, block| object.callbacks << 'before_around'; block.call; object.callbacks << 'after_around'}
2599
-
2600
- @event.fire(@object)
2601
- assert_equal %w(before before_around after_around after), @object.callbacks
2602
- end
2603
-
2604
- def test_should_allow_multiple_callbacks
2605
- @machine.before_transition lambda {|object| object.callbacks << 'before1'}, lambda {|object| object.callbacks << 'before2'}
2606
- @machine.after_transition lambda {|object| object.callbacks << 'after1'}, lambda {|object| object.callbacks << 'after2'}
2607
- @machine.around_transition(
2608
- lambda {|object, transition, block| object.callbacks << 'before_around1'; block.call; object.callbacks << 'after_around1'},
2609
- lambda {|object, transition, block| object.callbacks << 'before_around2'; block.call; object.callbacks << 'after_around2'}
2610
- )
2611
-
2612
- @event.fire(@object)
2613
- assert_equal %w(before1 before2 before_around1 before_around2 after_around2 after_around1 after1 after2), @object.callbacks
2614
- end
2615
-
2616
- def test_should_allow_multiple_callbacks_with_requirements
2617
- @machine.before_transition lambda {|object| object.callbacks << 'before_parked1'}, lambda {|object| object.callbacks << 'before_parked2'}, :from => :parked
2618
- @machine.before_transition lambda {|object| object.callbacks << 'before_idling1'}, lambda {|object| object.callbacks << 'before_idling2'}, :from => :idling
2619
- @machine.after_transition lambda {|object| object.callbacks << 'after_parked1'}, lambda {|object| object.callbacks << 'after_parked2'}, :from => :parked
2620
- @machine.after_transition lambda {|object| object.callbacks << 'after_idling1'}, lambda {|object| object.callbacks << 'after_idling2'}, :from => :idling
2621
- @machine.around_transition(
2622
- lambda {|object, transition, block| object.callbacks << 'before_around_parked1'; block.call; object.callbacks << 'after_around_parked1'},
2623
- lambda {|object, transition, block| object.callbacks << 'before_around_parked2'; block.call; object.callbacks << 'after_around_parked2'},
2624
- :from => :parked
2625
- )
2626
- @machine.around_transition(
2627
- lambda {|object, transition, block| object.callbacks << 'before_around_idling1'; block.call; object.callbacks << 'after_around_idling1'},
2628
- lambda {|object, transition, block| object.callbacks << 'before_around_idling2'; block.call; object.callbacks << 'after_around_idling2'},
2629
- :from => :idling
2630
- )
2631
-
2632
- @event.fire(@object)
2633
- assert_equal %w(before_parked1 before_parked2 before_around_parked1 before_around_parked2 after_around_parked2 after_around_parked1 after_parked1 after_parked2), @object.callbacks
2634
- end
2635
-
2636
- def test_should_support_from_requirement
2637
- @machine.before_transition :from => :parked, :do => lambda {|object| object.callbacks << :parked}
2638
- @machine.before_transition :from => :idling, :do => lambda {|object| object.callbacks << :idling}
2639
-
2640
- @event.fire(@object)
2641
- assert_equal [:parked], @object.callbacks
2642
- end
2643
-
2644
- def test_should_support_except_from_requirement
2645
- @machine.before_transition :except_from => :parked, :do => lambda {|object| object.callbacks << :parked}
2646
- @machine.before_transition :except_from => :idling, :do => lambda {|object| object.callbacks << :idling}
2647
-
2648
- @event.fire(@object)
2649
- assert_equal [:idling], @object.callbacks
2650
- end
2651
-
2652
- def test_should_support_to_requirement
2653
- @machine.before_transition :to => :parked, :do => lambda {|object| object.callbacks << :parked}
2654
- @machine.before_transition :to => :idling, :do => lambda {|object| object.callbacks << :idling}
2655
-
2656
- @event.fire(@object)
2657
- assert_equal [:idling], @object.callbacks
2658
- end
2659
-
2660
- def test_should_support_except_to_requirement
2661
- @machine.before_transition :except_to => :parked, :do => lambda {|object| object.callbacks << :parked}
2662
- @machine.before_transition :except_to => :idling, :do => lambda {|object| object.callbacks << :idling}
2663
-
2664
- @event.fire(@object)
2665
- assert_equal [:parked], @object.callbacks
2666
- end
2667
-
2668
- def test_should_support_on_requirement
2669
- @machine.before_transition :on => :park, :do => lambda {|object| object.callbacks << :park}
2670
- @machine.before_transition :on => :ignite, :do => lambda {|object| object.callbacks << :ignite}
2671
-
2672
- @event.fire(@object)
2673
- assert_equal [:ignite], @object.callbacks
2674
- end
2675
-
2676
- def test_should_support_except_on_requirement
2677
- @machine.before_transition :except_on => :park, :do => lambda {|object| object.callbacks << :park}
2678
- @machine.before_transition :except_on => :ignite, :do => lambda {|object| object.callbacks << :ignite}
2679
-
2680
- @event.fire(@object)
2681
- assert_equal [:park], @object.callbacks
2682
- end
2683
-
2684
- def test_should_support_implicit_requirement
2685
- @machine.before_transition :parked => :idling, :do => lambda {|object| object.callbacks << :parked}
2686
- @machine.before_transition :idling => :parked, :do => lambda {|object| object.callbacks << :idling}
2687
-
2688
- @event.fire(@object)
2689
- assert_equal [:parked], @object.callbacks
2690
- end
2691
-
2692
- def test_should_track_states_defined_in_transition_callbacks
2693
- @machine.before_transition :parked => :idling, :do => lambda {}
2694
- @machine.after_transition :first_gear => :second_gear, :do => lambda {}
2695
- @machine.around_transition :third_gear => :fourth_gear, :do => lambda {}
2696
-
2697
- assert_equal [:parked, :idling, :first_gear, :second_gear, :third_gear, :fourth_gear], @machine.states.map {|state| state.name}
2698
- end
2699
-
2700
- def test_should_not_duplicate_states_defined_in_multiple_event_transitions
2701
- @machine.before_transition :parked => :idling, :do => lambda {}
2702
- @machine.after_transition :first_gear => :second_gear, :do => lambda {}
2703
- @machine.after_transition :parked => :idling, :do => lambda {}
2704
- @machine.around_transition :parked => :idling, :do => lambda {}
2705
-
2706
- assert_equal [:parked, :idling, :first_gear, :second_gear], @machine.states.map {|state| state.name}
2707
- end
2708
-
2709
- def test_should_define_predicates_for_each_state
2710
- [:parked?, :idling?].each {|predicate| assert @object.respond_to?(predicate)}
2711
- end
2712
- end
2713
-
2714
- class MachineWithFailureCallbacksTest < Test::Unit::TestCase
2715
- def setup
2716
- @klass = Class.new do
2717
- attr_accessor :callbacks
2718
- end
2719
-
2720
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2721
- @event = @machine.event :ignite
2722
-
2723
- @object = @klass.new
2724
- @object.callbacks = []
2725
- end
2726
-
2727
- def test_should_raise_exception_if_implicit_option_specified
2728
- exception = assert_raise(ArgumentError) {@machine.after_failure :invalid => :valid, :do => lambda {}}
2729
- assert_equal 'Invalid key(s): invalid', exception.message
2730
- end
2731
-
2732
- def test_should_raise_exception_if_method_not_specified
2733
- exception = assert_raise(ArgumentError) {@machine.after_failure :on => :ignite}
2734
- assert_equal 'Method(s) for callback must be specified', exception.message
2735
- end
2736
-
2737
- def test_should_invoke_callbacks_during_failed_transition
2738
- @machine.after_failure lambda {|object| object.callbacks << 'failure'}
2739
-
2740
- @event.fire(@object)
2741
- assert_equal %w(failure), @object.callbacks
2742
- end
2743
-
2744
- def test_should_allow_multiple_callbacks
2745
- @machine.after_failure lambda {|object| object.callbacks << 'failure1'}, lambda {|object| object.callbacks << 'failure2'}
2746
-
2747
- @event.fire(@object)
2748
- assert_equal %w(failure1 failure2), @object.callbacks
2749
- end
2750
-
2751
- def test_should_allow_multiple_callbacks_with_requirements
2752
- @machine.after_failure lambda {|object| object.callbacks << 'failure_ignite1'}, lambda {|object| object.callbacks << 'failure_ignite2'}, :on => :ignite
2753
- @machine.after_failure lambda {|object| object.callbacks << 'failure_park1'}, lambda {|object| object.callbacks << 'failure_park2'}, :on => :park
2754
-
2755
- @event.fire(@object)
2756
- assert_equal %w(failure_ignite1 failure_ignite2), @object.callbacks
2757
- end
2758
- end
2759
-
2760
- class MachineWithPathsTest < Test::Unit::TestCase
2761
- def setup
2762
- @klass = Class.new
2763
- @machine = EnumStateMachine::Machine.new(@klass)
2764
- @machine.event :ignite do
2765
- transition :parked => :idling
2766
- end
2767
- @machine.event :shift_up do
2768
- transition :first_gear => :second_gear
2769
- end
2770
-
2771
- @object = @klass.new
2772
- @object.state = 'parked'
2773
- end
2774
-
2775
- def test_should_have_paths
2776
- assert_equal [[EnumStateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)]], @machine.paths_for(@object)
2777
- end
2778
-
2779
- def test_should_allow_requirement_configuration
2780
- assert_equal [[EnumStateMachine::Transition.new(@object, @machine, :shift_up, :first_gear, :second_gear)]], @machine.paths_for(@object, :from => :first_gear)
2781
- end
2782
- end
2783
-
2784
- class MachineWithOwnerSubclassTest < Test::Unit::TestCase
2785
- def setup
2786
- @klass = Class.new
2787
- @machine = EnumStateMachine::Machine.new(@klass)
2788
- @subclass = Class.new(@klass)
2789
- end
2790
-
2791
- def test_should_have_a_different_collection_of_state_machines
2792
- assert_not_same @klass.state_machines, @subclass.state_machines
2793
- end
2794
-
2795
- def test_should_have_the_same_attribute_associated_state_machines
2796
- assert_equal @klass.state_machines, @subclass.state_machines
2797
- end
2798
- end
2799
-
2800
- class MachineWithExistingMachinesOnOwnerClassTest < Test::Unit::TestCase
2801
- def setup
2802
- @klass = Class.new
2803
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2804
- @second_machine = EnumStateMachine::Machine.new(@klass, :status, :initial => :idling)
2805
- @object = @klass.new
2806
- end
2807
-
2808
- def test_should_track_each_state_machine
2809
- expected = {:state => @machine, :status => @second_machine}
2810
- assert_equal expected, @klass.state_machines
2811
- end
2812
-
2813
- def test_should_initialize_state_for_both_machines
2814
- assert_equal 'parked', @object.state
2815
- assert_equal 'idling', @object.status
2816
- end
2817
- end
2818
-
2819
- class MachineWithExistingMachinesWithSameAttributesOnOwnerClassTest < Test::Unit::TestCase
2820
- def setup
2821
- @klass = Class.new
2822
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2823
- @second_machine = EnumStateMachine::Machine.new(@klass, :public_state, :initial => :idling, :attribute => :state)
2824
- @object = @klass.new
2825
- end
2826
-
2827
- def test_should_track_each_state_machine
2828
- expected = {:state => @machine, :public_state => @second_machine}
2829
- assert_equal expected, @klass.state_machines
2830
- end
2831
-
2832
- def test_should_write_to_state_only_once
2833
- @klass.class_eval do
2834
- attr_reader :write_count
2835
-
2836
- def state=(value)
2837
- @write_count ||= 0
2838
- @write_count += 1
2839
- end
2840
- end
2841
- object = @klass.new
2842
-
2843
- assert_equal 1, object.write_count
2844
- end
2845
-
2846
- def test_should_initialize_based_on_first_machine
2847
- assert_equal 'parked', @object.state
2848
- end
2849
-
2850
- def test_should_not_allow_second_machine_to_initialize_state
2851
- @object.state = nil
2852
- @second_machine.initialize_state(@object)
2853
- assert_nil @object.state
2854
- end
2855
-
2856
- def test_should_allow_transitions_on_both_machines
2857
- @machine.event :ignite do
2858
- transition :parked => :idling
2859
- end
2860
-
2861
- @second_machine.event :park do
2862
- transition :idling => :parked
2863
- end
2864
-
2865
- @object.ignite
2866
- assert_equal 'idling', @object.state
2867
-
2868
- @object.park
2869
- assert_equal 'parked', @object.state
2870
- end
2871
-
2872
- def test_should_copy_new_states_to_sibling_machines
2873
- @first_gear = @machine.state :first_gear
2874
- assert_equal @first_gear, @second_machine.state(:first_gear)
2875
-
2876
- @second_gear = @second_machine.state :second_gear
2877
- assert_equal @second_gear, @machine.state(:second_gear)
2878
- end
2879
-
2880
- def test_should_copy_all_existing_states_to_new_machines
2881
- third_machine = EnumStateMachine::Machine.new(@klass, :protected_state, :attribute => :state)
2882
-
2883
- assert_equal @machine.state(:parked), third_machine.state(:parked)
2884
- assert_equal @machine.state(:idling), third_machine.state(:idling)
2885
- end
2886
- end
2887
-
2888
- class MachineWithExistingMachinesWithSameAttributesOnOwnerSubclassTest < Test::Unit::TestCase
2889
- def setup
2890
- @klass = Class.new
2891
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
2892
- @second_machine = EnumStateMachine::Machine.new(@klass, :public_state, :initial => :idling, :attribute => :state)
2893
-
2894
- @subclass = Class.new(@klass)
2895
- @object = @subclass.new
2896
- end
2897
-
2898
- def test_should_not_copy_sibling_machines_to_subclass_after_initialization
2899
- @subclass.state_machine(:state) {}
2900
- assert_equal @klass.state_machine(:public_state), @subclass.state_machine(:public_state)
2901
- end
2902
-
2903
- def test_should_copy_sibling_machines_to_subclass_after_new_state
2904
- subclass_machine = @subclass.state_machine(:state) {}
2905
- subclass_machine.state :first_gear
2906
- assert_not_equal @klass.state_machine(:public_state), @subclass.state_machine(:public_state)
2907
- end
2908
-
2909
- def test_should_copy_new_states_to_sibling_machines
2910
- subclass_machine = @subclass.state_machine(:state) {}
2911
- @first_gear = subclass_machine.state :first_gear
2912
-
2913
- second_subclass_machine = @subclass.state_machine(:public_state)
2914
- assert_equal @first_gear, second_subclass_machine.state(:first_gear)
2915
- end
2916
- end
2917
-
2918
- class MachineWithNamespaceTest < Test::Unit::TestCase
2919
- def setup
2920
- @klass = Class.new
2921
- @machine = EnumStateMachine::Machine.new(@klass, :namespace => 'alarm', :initial => :active) do
2922
- event :enable do
2923
- transition :off => :active
2924
- end
2925
-
2926
- event :disable do
2927
- transition :active => :off
2928
- end
2929
- end
2930
- @object = @klass.new
2931
- end
2932
-
2933
- def test_should_namespace_state_predicates
2934
- [:alarm_active?, :alarm_off?].each do |name|
2935
- assert @object.respond_to?(name)
2936
- end
2937
- end
2938
-
2939
- def test_should_namespace_event_checks
2940
- [:can_enable_alarm?, :can_disable_alarm?].each do |name|
2941
- assert @object.respond_to?(name)
2942
- end
2943
- end
2944
-
2945
- def test_should_namespace_event_transition_readers
2946
- [:enable_alarm_transition, :disable_alarm_transition].each do |name|
2947
- assert @object.respond_to?(name)
2948
- end
2949
- end
2950
-
2951
- def test_should_namespace_events
2952
- [:enable_alarm, :disable_alarm].each do |name|
2953
- assert @object.respond_to?(name)
2954
- end
2955
- end
2956
-
2957
- def test_should_namespace_bang_events
2958
- [:enable_alarm!, :disable_alarm!].each do |name|
2959
- assert @object.respond_to?(name)
2960
- end
2961
- end
2962
- end
2963
-
2964
- class MachineWithCustomAttributeTest < Test::Unit::TestCase
2965
- def setup
2966
- EnumStateMachine::Integrations.const_set('Custom', Module.new do
2967
- include EnumStateMachine::Integrations::Base
2968
-
2969
- @defaults = {:action => :save, :use_transactions => false}
2970
-
2971
- def create_with_scope(name)
2972
- lambda {}
2973
- end
2974
-
2975
- def create_without_scope(name)
2976
- lambda {}
2977
- end
2978
- end)
2979
-
2980
- @klass = Class.new
2981
- @machine = EnumStateMachine::Machine.new(@klass, :state, :attribute => :state_id, :initial => :active, :integration => :custom) do
2982
- event :ignite do
2983
- transition :parked => :idling
2984
- end
2985
- end
2986
- @object = @klass.new
2987
- end
2988
-
2989
- def test_should_define_a_reader_attribute_for_the_attribute
2990
- assert @object.respond_to?(:state_id)
2991
- end
2992
-
2993
- def test_should_define_a_writer_attribute_for_the_attribute
2994
- assert @object.respond_to?(:state_id=)
2995
- end
2996
-
2997
- def test_should_define_a_predicate_for_the_attribute
2998
- assert @object.respond_to?(:state?)
2999
- end
3000
-
3001
- def test_should_define_a_name_reader_for_the_attribute
3002
- assert @object.respond_to?(:state_name)
3003
- end
3004
-
3005
- def test_should_define_a_human_name_reader_for_the_attribute
3006
- assert @object.respond_to?(:state_name)
3007
- end
3008
-
3009
- def test_should_define_an_event_reader_for_the_attribute
3010
- assert @object.respond_to?(:state_events)
3011
- end
3012
-
3013
- def test_should_define_a_transition_reader_for_the_attribute
3014
- assert @object.respond_to?(:state_transitions)
3015
- end
3016
-
3017
- def test_should_define_a_path_reader_for_the_attribute
3018
- assert @object.respond_to?(:state_paths)
3019
- end
3020
-
3021
- def test_should_define_an_event_runner_for_the_attribute
3022
- assert @object.respond_to?(:fire_state_event)
3023
- end
3024
-
3025
- def test_should_define_a_human_attribute_name_reader
3026
- assert @klass.respond_to?(:human_state_name)
3027
- end
3028
-
3029
- def test_should_define_a_human_event_name_reader
3030
- assert @klass.respond_to?(:human_state_event_name)
3031
- end
3032
-
3033
- def test_should_define_singular_with_scope
3034
- assert @klass.respond_to?(:with_state)
3035
- end
3036
-
3037
- def test_should_define_singular_without_scope
3038
- assert @klass.respond_to?(:without_state)
3039
- end
3040
-
3041
- def test_should_define_plural_with_scope
3042
- assert @klass.respond_to?(:with_states)
3043
- end
3044
-
3045
- def test_should_define_plural_without_scope
3046
- assert @klass.respond_to?(:without_states)
3047
- end
3048
-
3049
- def test_should_define_state_machines_reader
3050
- expected = {:state => @machine}
3051
- assert_equal expected, @klass.state_machines
3052
- end
3053
-
3054
- def teardown
3055
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
3056
- end
3057
- end
3058
-
3059
- class MachineFinderWithoutExistingMachineTest < Test::Unit::TestCase
3060
- def setup
3061
- @klass = Class.new
3062
- @machine = EnumStateMachine::Machine.find_or_create(@klass)
3063
- end
3064
-
3065
- def test_should_accept_a_block
3066
- called = false
3067
- EnumStateMachine::Machine.find_or_create(Class.new) do
3068
- called = respond_to?(:event)
3069
- end
3070
-
3071
- assert called
3072
- end
3073
-
3074
- def test_should_create_a_new_machine
3075
- assert_not_nil @machine
3076
- end
3077
-
3078
- def test_should_use_default_state
3079
- assert_equal :state, @machine.attribute
3080
- end
3081
- end
3082
-
3083
- class MachineFinderWithExistingOnSameClassTest < Test::Unit::TestCase
3084
- def setup
3085
- @klass = Class.new
3086
- @existing_machine = EnumStateMachine::Machine.new(@klass)
3087
- @machine = EnumStateMachine::Machine.find_or_create(@klass)
3088
- end
3089
-
3090
- def test_should_accept_a_block
3091
- called = false
3092
- EnumStateMachine::Machine.find_or_create(@klass) do
3093
- called = respond_to?(:event)
3094
- end
3095
-
3096
- assert called
3097
- end
3098
-
3099
- def test_should_not_create_a_new_machine
3100
- assert_same @machine, @existing_machine
3101
- end
3102
- end
3103
-
3104
- class MachineFinderWithExistingMachineOnSuperclassTest < Test::Unit::TestCase
3105
- def setup
3106
- integration = Module.new do
3107
- include EnumStateMachine::Integrations::Base
3108
-
3109
- def self.matches?(klass)
3110
- false
3111
- end
3112
- end
3113
- EnumStateMachine::Integrations.const_set('Custom', integration)
3114
-
3115
- @base_class = Class.new
3116
- @base_machine = EnumStateMachine::Machine.new(@base_class, :status, :action => :save, :integration => :custom)
3117
- @base_machine.event(:ignite) {}
3118
- @base_machine.before_transition(lambda {})
3119
- @base_machine.after_transition(lambda {})
3120
- @base_machine.around_transition(lambda {})
3121
-
3122
- @klass = Class.new(@base_class)
3123
- @machine = EnumStateMachine::Machine.find_or_create(@klass, :status) {}
3124
- end
3125
-
3126
- def test_should_accept_a_block
3127
- called = false
3128
- EnumStateMachine::Machine.find_or_create(Class.new(@base_class)) do
3129
- called = respond_to?(:event)
3130
- end
3131
-
3132
- assert called
3133
- end
3134
-
3135
- def test_should_not_create_a_new_machine_if_no_block_or_options
3136
- machine = EnumStateMachine::Machine.find_or_create(Class.new(@base_class), :status)
3137
-
3138
- assert_same machine, @base_machine
3139
- end
3140
-
3141
- def test_should_create_a_new_machine_if_given_options
3142
- machine = EnumStateMachine::Machine.find_or_create(@klass, :status, :initial => :parked)
3143
-
3144
- assert_not_nil machine
3145
- assert_not_same machine, @base_machine
3146
- end
3147
-
3148
- def test_should_create_a_new_machine_if_given_block
3149
- assert_not_nil @machine
3150
- assert_not_same @machine, @base_machine
3151
- end
3152
-
3153
- def test_should_copy_the_base_attribute
3154
- assert_equal :status, @machine.attribute
3155
- end
3156
-
3157
- def test_should_copy_the_base_configuration
3158
- assert_equal :save, @machine.action
3159
- end
3160
-
3161
- def test_should_copy_events
3162
- # Can't assert equal arrays since their machines change
3163
- assert_equal 1, @machine.events.length
3164
- end
3165
-
3166
- def test_should_copy_before_callbacks
3167
- assert_equal @base_machine.callbacks[:before], @machine.callbacks[:before]
3168
- end
3169
-
3170
- def test_should_copy_after_transitions
3171
- assert_equal @base_machine.callbacks[:after], @machine.callbacks[:after]
3172
- end
3173
-
3174
- def test_should_use_the_same_integration
3175
- assert((class << @machine; ancestors; end).include?(EnumStateMachine::Integrations::Custom))
3176
- end
3177
-
3178
- def teardown
3179
- EnumStateMachine::Integrations.send(:remove_const, 'Custom')
3180
- end
3181
- end
3182
-
3183
- class MachineFinderCustomOptionsTest < Test::Unit::TestCase
3184
- def setup
3185
- @klass = Class.new
3186
- @machine = EnumStateMachine::Machine.find_or_create(@klass, :status, :initial => :parked)
3187
- @object = @klass.new
3188
- end
3189
-
3190
- def test_should_use_custom_attribute
3191
- assert_equal :status, @machine.attribute
3192
- end
3193
-
3194
- def test_should_set_custom_initial_state
3195
- assert_equal :parked, @machine.initial_state(@object).name
3196
- end
3197
- end
3198
-
3199
- begin
3200
- # Load library
3201
- require 'graphviz'
3202
-
3203
- class MachineDrawingTest < Test::Unit::TestCase
3204
- def setup
3205
- @klass = Class.new do
3206
- def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3207
- end
3208
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
3209
- @machine.event :ignite do
3210
- transition :parked => :idling
3211
- end
3212
- end
3213
-
3214
- def test_should_raise_exception_if_invalid_option_specified
3215
- assert_raise(ArgumentError) {@machine.draw(:invalid => true)}
3216
- end
3217
-
3218
- def test_should_save_file_with_class_name_by_default
3219
- @machine.draw
3220
- assert File.exists?("./#{@klass.name}_state.png")
3221
- end
3222
-
3223
- def test_should_allow_base_name_to_be_customized
3224
- name = "machine_#{rand(1000000)}"
3225
- @machine.draw(:name => name)
3226
- @path = "./#{name}.png"
3227
- assert File.exists?(@path)
3228
- end
3229
-
3230
- def test_should_allow_format_to_be_customized
3231
- @machine.draw(:format => 'jpg')
3232
- @path = "./#{@klass.name}_state.jpg"
3233
- assert File.exists?(@path)
3234
- end
3235
-
3236
- def test_should_allow_path_to_be_customized
3237
- @machine.draw(:path => "#{File.dirname(__FILE__)}/")
3238
- @path = "#{File.dirname(__FILE__)}/#{@klass.name}_state.png"
3239
- assert File.exists?(@path)
3240
- end
3241
-
3242
- def test_should_allow_orientation_to_be_landscape
3243
- graph = @machine.draw(:orientation => 'landscape')
3244
- assert_equal 'LR', graph['rankdir'].to_s.gsub('"', '')
3245
- end
3246
-
3247
- def test_should_allow_orientation_to_be_portrait
3248
- graph = @machine.draw(:orientation => 'portrait')
3249
- assert_equal 'TB', graph['rankdir'].to_s.gsub('"', '')
3250
- end
3251
-
3252
- if Constants::RGV_VERSION != '0.9.0'
3253
- def test_should_allow_human_names_to_be_displayed
3254
- @machine.event :ignite, :human_name => 'Ignite'
3255
- @machine.state :parked, :human_name => 'Parked'
3256
- @machine.state :idling, :human_name => 'Idling'
3257
- graph = @machine.draw(:human_names => true)
3258
-
3259
- parked_node = graph.get_node('parked')
3260
- assert_equal 'Parked', parked_node['label'].to_s.gsub('"', '')
3261
-
3262
- idling_node = graph.get_node('idling')
3263
- assert_equal 'Idling', idling_node['label'].to_s.gsub('"', '')
3264
- end
3265
- end
3266
-
3267
- def teardown
3268
- FileUtils.rm Dir[@path || "./#{@klass.name}_state.png"]
3269
- end
3270
- end
3271
-
3272
- class MachineDrawingWithIntegerStatesTest < Test::Unit::TestCase
3273
- def setup
3274
- @klass = Class.new do
3275
- def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3276
- end
3277
- @machine = EnumStateMachine::Machine.new(@klass, :state_id, :initial => :parked)
3278
- @machine.event :ignite do
3279
- transition :parked => :idling
3280
- end
3281
- @machine.state :parked, :value => 1
3282
- @machine.state :idling, :value => 2
3283
- @graph = @machine.draw
3284
- end
3285
-
3286
- def test_should_draw_all_states
3287
- assert_equal 3, @graph.node_count
3288
- end
3289
-
3290
- def test_should_draw_all_events
3291
- assert_equal 2, @graph.edge_count
3292
- end
3293
-
3294
- def test_should_draw_machine
3295
- assert File.exist?("./#{@klass.name}_state_id.png")
3296
- end
3297
-
3298
- def teardown
3299
- FileUtils.rm Dir["./#{@klass.name}_state_id.png"]
3300
- end
3301
- end
3302
-
3303
- class MachineDrawingWithNilStatesTest < Test::Unit::TestCase
3304
- def setup
3305
- @klass = Class.new do
3306
- def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3307
- end
3308
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
3309
- @machine.event :ignite do
3310
- transition :parked => :idling
3311
- end
3312
- @machine.state :parked, :value => nil
3313
- @graph = @machine.draw
3314
- end
3315
-
3316
- def test_should_draw_all_states
3317
- assert_equal 3, @graph.node_count
3318
- end
3319
-
3320
- def test_should_draw_all_events
3321
- assert_equal 2, @graph.edge_count
3322
- end
3323
-
3324
- def test_should_draw_machine
3325
- assert File.exist?("./#{@klass.name}_state.png")
3326
- end
3327
-
3328
- def teardown
3329
- FileUtils.rm Dir["./#{@klass.name}_state.png"]
3330
- end
3331
- end
3332
-
3333
- class MachineDrawingWithDynamicStatesTest < Test::Unit::TestCase
3334
- def setup
3335
- @klass = Class.new do
3336
- def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3337
- end
3338
- @machine = EnumStateMachine::Machine.new(@klass, :initial => :parked)
3339
- @machine.event :activate do
3340
- transition :parked => :idling
3341
- end
3342
- @machine.state :idling, :value => lambda {Time.now}
3343
- @graph = @machine.draw
3344
- end
3345
-
3346
- def test_should_draw_all_states
3347
- assert_equal 3, @graph.node_count
3348
- end
3349
-
3350
- def test_should_draw_all_events
3351
- assert_equal 2, @graph.edge_count
3352
- end
3353
-
3354
- def test_should_draw_machine
3355
- assert File.exist?("./#{@klass.name}_state.png")
3356
- end
3357
-
3358
- def teardown
3359
- FileUtils.rm Dir["./#{@klass.name}_state.png"]
3360
- end
3361
- end
3362
-
3363
- class MachineClassDrawingTest < Test::Unit::TestCase
3364
- def setup
3365
- @klass = Class.new do
3366
- def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end
3367
- end
3368
- @machine = EnumStateMachine::Machine.new(@klass)
3369
- @machine.event :ignite do
3370
- transition :parked => :idling
3371
- end
3372
- end
3373
-
3374
- def test_should_raise_exception_if_no_class_names_specified
3375
- exception = assert_raise(ArgumentError) {EnumStateMachine::Machine.draw(nil)}
3376
- assert_equal 'At least one class must be specified', exception.message
3377
- end
3378
-
3379
- def test_should_load_files
3380
- EnumStateMachine::Machine.draw('Switch', :file => File.expand_path("#{File.dirname(__FILE__)}/../files/switch.rb"))
3381
- assert defined?(::Switch)
3382
- end
3383
-
3384
- def test_should_allow_path_and_format_to_be_customized
3385
- EnumStateMachine::Machine.draw('Switch', :file => File.expand_path("#{File.dirname(__FILE__)}/../files/switch.rb"), :path => "#{File.dirname(__FILE__)}/", :format => 'jpg')
3386
- assert File.exist?("#{File.dirname(__FILE__)}/#{Switch.name}_state.jpg")
3387
- end
3388
-
3389
- def teardown
3390
- FileUtils.rm Dir["{.,#{File.dirname(__FILE__)}}/#{Switch.name}_state.{jpg,png}"]
3391
- end
3392
- end
3393
- rescue LoadError
3394
- $stderr.puts 'Skipping GraphViz EnumStateMachine::Machine tests. `gem install ruby-graphviz` >= v0.9.17 and try again.'
3395
- end unless ENV['TRAVIS']