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,1245 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
-
3
- require 'active_model'
4
- if defined?(ActiveModel::VERSION) && ActiveModel::VERSION::MAJOR >= 4
5
- require 'rails/observers/active_model/active_model'
6
- require 'active_model/mass_assignment_security'
7
- else
8
- require 'active_model/observing'
9
- end
10
- require 'active_support/all'
11
-
12
- module ActiveModelTest
13
- class BaseTestCase < Test::Unit::TestCase
14
- def default_test
15
- end
16
-
17
- protected
18
- # Creates a new ActiveModel model (and the associated table)
19
- def new_model(&block)
20
- # Simple ActiveModel superclass
21
- parent = Class.new do
22
- def self.model_attribute(name)
23
- define_method(name) { instance_variable_defined?("@#{name}") ? instance_variable_get("@#{name}") : nil }
24
- define_method("#{name}=") do |value|
25
- send("#{name}_will_change!") if self.class <= ActiveModel::Dirty && value != send(name)
26
- instance_variable_set("@#{name}", value)
27
- end
28
- end
29
-
30
- def self.create
31
- object = new
32
- object.save
33
- object
34
- end
35
-
36
- def initialize(attrs = {})
37
- attrs.each {|attr, value| send("#{attr}=", value)}
38
- @changed_attributes = {}
39
- end
40
-
41
- def attributes
42
- @attributes ||= {}
43
- end
44
-
45
- def save
46
- @changed_attributes = {}
47
- true
48
- end
49
- end
50
-
51
- model = Class.new(parent) do
52
- def self.name
53
- 'ActiveModelTest::Foo'
54
- end
55
-
56
- model_attribute :state
57
- end
58
- model.class_eval(&block) if block_given?
59
- model
60
- end
61
-
62
- # Creates a new ActiveModel observer
63
- def new_observer(model, &block)
64
- observer = Class.new(ActiveModel::Observer) do
65
- attr_accessor :notifications
66
-
67
- def initialize
68
- super
69
- @notifications = []
70
- end
71
- end
72
- observer.observe(model)
73
- observer.class_eval(&block) if block_given?
74
- observer
75
- end
76
- end
77
-
78
- class IntegrationTest < BaseTestCase
79
- def test_should_have_an_integration_name
80
- assert_equal :active_model, EnumStateMachine::Integrations::ActiveModel.integration_name
81
- end
82
-
83
- def test_should_be_available
84
- assert EnumStateMachine::Integrations::ActiveModel.available?
85
- end
86
-
87
- def test_should_match_if_class_includes_observing_feature
88
- assert EnumStateMachine::Integrations::ActiveModel.matches?(new_model { include ActiveModel::Observing })
89
- end
90
-
91
- def test_should_match_if_class_includes_validations_feature
92
- assert EnumStateMachine::Integrations::ActiveModel.matches?(new_model { include ActiveModel::Validations })
93
- end
94
-
95
- def test_should_not_match_if_class_does_not_include_active_model_features
96
- assert !EnumStateMachine::Integrations::ActiveModel.matches?(new_model)
97
- end
98
-
99
- def test_should_have_no_defaults
100
- assert_equal({}, EnumStateMachine::Integrations::ActiveModel.defaults)
101
- end
102
-
103
- def test_should_have_a_locale_path
104
- assert_not_nil EnumStateMachine::Integrations::ActiveModel.locale_path
105
- end
106
- end
107
-
108
- class MachineByDefaultTest < BaseTestCase
109
- def setup
110
- @model = new_model
111
- @machine = EnumStateMachine::Machine.new(@model, :integration => :active_model)
112
- end
113
-
114
- def test_should_not_have_action
115
- assert_nil @machine.action
116
- end
117
-
118
- def test_should_use_transactions
119
- assert_equal true, @machine.use_transactions
120
- end
121
-
122
- def test_should_not_have_any_before_callbacks
123
- assert_equal 0, @machine.callbacks[:before].size
124
- end
125
-
126
- def test_should_not_have_any_after_callbacks
127
- assert_equal 0, @machine.callbacks[:after].size
128
- end
129
- end
130
-
131
- class MachineWithStatesTest < BaseTestCase
132
- def setup
133
- @model = new_model
134
- @machine = EnumStateMachine::Machine.new(@model)
135
- @machine.state :first_gear
136
- end
137
-
138
- def test_should_humanize_name
139
- assert_equal 'first gear', @machine.state(:first_gear).human_name
140
- end
141
- end
142
-
143
- class MachineWithStaticInitialStateTest < BaseTestCase
144
- def setup
145
- @model = new_model
146
- @machine = EnumStateMachine::Machine.new(@model, :initial => :parked, :integration => :active_model)
147
- end
148
-
149
- def test_should_set_initial_state_on_created_object
150
- record = @model.new
151
- assert_equal 'parked', record.state
152
- end
153
- end
154
-
155
- class MachineWithDynamicInitialStateTest < BaseTestCase
156
- def setup
157
- @model = new_model
158
- @machine = EnumStateMachine::Machine.new(@model, :initial => lambda {|object| :parked}, :integration => :active_model)
159
- @machine.state :parked
160
- end
161
-
162
- def test_should_set_initial_state_on_created_object
163
- record = @model.new
164
- assert_equal 'parked', record.state
165
- end
166
- end
167
-
168
- class MachineWithEventsTest < BaseTestCase
169
- def setup
170
- @model = new_model
171
- @machine = EnumStateMachine::Machine.new(@model)
172
- @machine.event :shift_up
173
- end
174
-
175
- def test_should_humanize_name
176
- assert_equal 'shift up', @machine.event(:shift_up).human_name
177
- end
178
- end
179
-
180
- class MachineWithModelStateAttributeTest < BaseTestCase
181
- def setup
182
- @model = new_model
183
- @machine = EnumStateMachine::Machine.new(@model, :initial => :parked, :integration => :active_model)
184
- @machine.other_states(:idling)
185
-
186
- @record = @model.new
187
- end
188
-
189
- def test_should_have_an_attribute_predicate
190
- assert @record.respond_to?(:state?)
191
- end
192
-
193
- def test_should_raise_exception_for_predicate_without_parameters
194
- assert_raise(ArgumentError) { @record.state? }
195
- end
196
-
197
- def test_should_return_false_for_predicate_if_does_not_match_current_value
198
- assert !@record.state?(:idling)
199
- end
200
-
201
- def test_should_return_true_for_predicate_if_matches_current_value
202
- assert @record.state?(:parked)
203
- end
204
-
205
- def test_should_raise_exception_for_predicate_if_invalid_state_specified
206
- assert_raise(IndexError) { @record.state?(:invalid) }
207
- end
208
- end
209
-
210
- class MachineWithNonModelStateAttributeUndefinedTest < BaseTestCase
211
- def setup
212
- @model = new_model do
213
- def initialize
214
- end
215
- end
216
-
217
- @machine = EnumStateMachine::Machine.new(@model, :status, :initial => :parked, :integration => :active_model)
218
- @machine.other_states(:idling)
219
- @record = @model.new
220
- end
221
-
222
- def test_should_not_define_a_reader_attribute_for_the_attribute
223
- assert !@record.respond_to?(:status)
224
- end
225
-
226
- def test_should_not_define_a_writer_attribute_for_the_attribute
227
- assert !@record.respond_to?(:status=)
228
- end
229
-
230
- def test_should_define_an_attribute_predicate
231
- assert @record.respond_to?(:status?)
232
- end
233
- end
234
-
235
- class MachineWithInitializedStateTest < BaseTestCase
236
- def setup
237
- @model = new_model
238
- @machine = EnumStateMachine::Machine.new(@model, :initial => :parked, :integration => :active_model)
239
- @machine.state :idling
240
- end
241
-
242
- def test_should_allow_nil_initial_state_when_static
243
- @machine.state nil
244
-
245
- record = @model.new(:state => nil)
246
- assert_nil record.state
247
- end
248
-
249
- def test_should_allow_nil_initial_state_when_dynamic
250
- @machine.state nil
251
-
252
- @machine.initial_state = lambda {:parked}
253
- record = @model.new(:state => nil)
254
- assert_nil record.state
255
- end
256
-
257
- def test_should_allow_different_initial_state_when_static
258
- record = @model.new(:state => 'idling')
259
- assert_equal 'idling', record.state
260
- end
261
-
262
- def test_should_allow_different_initial_state_when_dynamic
263
- @machine.initial_state = lambda {:parked}
264
- record = @model.new(:state => 'idling')
265
- assert_equal 'idling', record.state
266
- end
267
-
268
- def test_should_use_default_state_if_protected
269
- @model.class_eval do
270
- include ActiveModel::MassAssignmentSecurity
271
- attr_protected :state
272
-
273
- def initialize(attrs = {})
274
- initialize_state_machines do
275
- sanitize_for_mass_assignment(attrs).each {|attr, value| send("#{attr}=", value)} if attrs
276
- @changed_attributes = {}
277
- end
278
- end
279
- end
280
-
281
- record = @model.new(:state => 'idling')
282
- assert_equal 'parked', record.state
283
-
284
- record = @model.new(nil)
285
- assert_equal 'parked', record.state
286
- end
287
- end
288
-
289
- class MachineMultipleTest < BaseTestCase
290
- def setup
291
- @model = new_model do
292
- model_attribute :status
293
- end
294
-
295
- @state_machine = EnumStateMachine::Machine.new(@model, :initial => :parked, :integration => :active_model)
296
- @status_machine = EnumStateMachine::Machine.new(@model, :status, :initial => :idling, :integration => :active_model)
297
- end
298
-
299
- def test_should_should_initialize_each_state
300
- record = @model.new
301
- assert_equal 'parked', record.state
302
- assert_equal 'idling', record.status
303
- end
304
- end
305
-
306
- class MachineWithDirtyAttributesTest < BaseTestCase
307
- def setup
308
- @model = new_model do
309
- include ActiveModel::Dirty
310
- define_attribute_methods [:state]
311
- end
312
- @machine = EnumStateMachine::Machine.new(@model, :initial => :parked)
313
- @machine.event :ignite
314
- @machine.state :idling
315
-
316
- @record = @model.create
317
-
318
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
319
- @transition.perform
320
- end
321
-
322
- def test_should_include_state_in_changed_attributes
323
- assert_equal %w(state), @record.changed
324
- end
325
-
326
- def test_should_track_attribute_change
327
- assert_equal %w(parked idling), @record.changes['state']
328
- end
329
-
330
- def test_should_not_reset_changes_on_multiple_transitions
331
- transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
332
- transition.perform
333
-
334
- assert_equal %w(parked idling), @record.changes['state']
335
- end
336
- end
337
-
338
- class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
339
- def setup
340
- @model = new_model do
341
- include ActiveModel::Dirty
342
- define_attribute_methods [:state]
343
- end
344
- @machine = EnumStateMachine::Machine.new(@model, :initial => :parked)
345
- @machine.event :park
346
-
347
- @record = @model.create
348
-
349
- @transition = EnumStateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
350
- @transition.perform
351
- end
352
-
353
- def test_should_not_include_state_in_changed_attributes
354
- assert_equal [], @record.changed
355
- end
356
-
357
- def test_should_not_track_attribute_changes
358
- assert_equal nil, @record.changes['state']
359
- end
360
- end
361
-
362
- class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
363
- def setup
364
- @model = new_model do
365
- include ActiveModel::Dirty
366
- model_attribute :status
367
- define_attribute_methods [:status]
368
- end
369
- @machine = EnumStateMachine::Machine.new(@model, :status, :initial => :parked)
370
- @machine.event :ignite
371
- @machine.state :idling
372
-
373
- @record = @model.create
374
-
375
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
376
- @transition.perform
377
- end
378
-
379
- def test_should_include_state_in_changed_attributes
380
- assert_equal %w(status), @record.changed
381
- end
382
-
383
- def test_should_track_attribute_change
384
- assert_equal %w(parked idling), @record.changes['status']
385
- end
386
-
387
- def test_should_not_reset_changes_on_multiple_transitions
388
- transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
389
- transition.perform
390
-
391
- assert_equal %w(parked idling), @record.changes['status']
392
- end
393
- end
394
-
395
- class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
396
- def setup
397
- @model = new_model do
398
- include ActiveModel::Dirty
399
- model_attribute :status
400
- define_attribute_methods [:status]
401
- end
402
- @machine = EnumStateMachine::Machine.new(@model, :status, :initial => :parked)
403
- @machine.event :park
404
-
405
- @record = @model.create
406
-
407
- @transition = EnumStateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
408
- @transition.perform
409
- end
410
-
411
- def test_should_not_include_state_in_changed_attributes
412
- assert_equal [], @record.changed
413
- end
414
-
415
- def test_should_not_track_attribute_changes
416
- assert_equal nil, @record.changes['status']
417
- end
418
- end
419
-
420
- class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
421
- def setup
422
- @model = new_model do
423
- include ActiveModel::Dirty
424
- define_attribute_methods [:state]
425
- end
426
- @machine = EnumStateMachine::Machine.new(@model, :action => :save, :initial => :parked)
427
- @machine.event :ignite
428
-
429
- @record = @model.create
430
- @record.state_event = 'ignite'
431
- end
432
-
433
- def test_should_not_include_state_in_changed_attributes
434
- assert_equal [], @record.changed
435
- end
436
-
437
- def test_should_not_track_attribute_change
438
- assert_equal nil, @record.changes['state']
439
- end
440
- end
441
-
442
- class MachineWithCallbacksTest < BaseTestCase
443
- def setup
444
- @model = new_model
445
- @machine = EnumStateMachine::Machine.new(@model, :initial => :parked, :integration => :active_model)
446
- @machine.other_states :idling
447
- @machine.event :ignite
448
-
449
- @record = @model.new(:state => 'parked')
450
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
451
- end
452
-
453
- def test_should_run_before_callbacks
454
- called = false
455
- @machine.before_transition {called = true}
456
-
457
- @transition.perform
458
- assert called
459
- end
460
-
461
- def test_should_pass_record_to_before_callbacks_with_one_argument
462
- record = nil
463
- @machine.before_transition {|arg| record = arg}
464
-
465
- @transition.perform
466
- assert_equal @record, record
467
- end
468
-
469
- def test_should_pass_record_and_transition_to_before_callbacks_with_multiple_arguments
470
- callback_args = nil
471
- @machine.before_transition {|*args| callback_args = args}
472
-
473
- @transition.perform
474
- assert_equal [@record, @transition], callback_args
475
- end
476
-
477
- def test_should_run_before_callbacks_outside_the_context_of_the_record
478
- context = nil
479
- @machine.before_transition {context = self}
480
-
481
- @transition.perform
482
- assert_equal self, context
483
- end
484
-
485
- def test_should_run_after_callbacks
486
- called = false
487
- @machine.after_transition {called = true}
488
-
489
- @transition.perform
490
- assert called
491
- end
492
-
493
- def test_should_pass_record_to_after_callbacks_with_one_argument
494
- record = nil
495
- @machine.after_transition {|arg| record = arg}
496
-
497
- @transition.perform
498
- assert_equal @record, record
499
- end
500
-
501
- def test_should_pass_record_and_transition_to_after_callbacks_with_multiple_arguments
502
- callback_args = nil
503
- @machine.after_transition {|*args| callback_args = args}
504
-
505
- @transition.perform
506
- assert_equal [@record, @transition], callback_args
507
- end
508
-
509
- def test_should_run_after_callbacks_outside_the_context_of_the_record
510
- context = nil
511
- @machine.after_transition {context = self}
512
-
513
- @transition.perform
514
- assert_equal self, context
515
- end
516
-
517
- def test_should_run_around_callbacks
518
- before_called = false
519
- after_called = false
520
- ensure_called = 0
521
- @machine.around_transition do |block|
522
- before_called = true
523
- begin
524
- block.call
525
- ensure
526
- ensure_called += 1
527
- end
528
- after_called = true
529
- end
530
-
531
- @transition.perform
532
- assert before_called
533
- assert after_called
534
- assert_equal ensure_called, 1
535
- end
536
-
537
- def test_should_include_transition_states_in_known_states
538
- @machine.before_transition :to => :first_gear, :do => lambda {}
539
-
540
- assert_equal [:parked, :idling, :first_gear], @machine.states.map {|state| state.name}
541
- end
542
-
543
- def test_should_allow_symbolic_callbacks
544
- callback_args = nil
545
-
546
- klass = class << @record; self; end
547
- klass.send(:define_method, :after_ignite) do |*args|
548
- callback_args = args
549
- end
550
-
551
- @machine.before_transition(:after_ignite)
552
-
553
- @transition.perform
554
- assert_equal [@transition], callback_args
555
- end
556
-
557
- def test_should_allow_string_callbacks
558
- class << @record
559
- attr_reader :callback_result
560
- end
561
-
562
- @machine.before_transition('@callback_result = [1, 2, 3]')
563
- @transition.perform
564
-
565
- assert_equal [1, 2, 3], @record.callback_result
566
- end
567
- end
568
-
569
- class MachineWithFailedBeforeCallbacksTest < BaseTestCase
570
- def setup
571
- @callbacks = []
572
-
573
- @model = new_model
574
- @machine = EnumStateMachine::Machine.new(@model, :integration => :active_model)
575
- @machine.state :parked, :idling
576
- @machine.event :ignite
577
- @machine.before_transition {@callbacks << :before_1; false}
578
- @machine.before_transition {@callbacks << :before_2}
579
- @machine.after_transition {@callbacks << :after}
580
- @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
581
-
582
- @record = @model.new(:state => 'parked')
583
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
584
- @result = @transition.perform
585
- end
586
-
587
- def test_should_not_be_successful
588
- assert !@result
589
- end
590
-
591
- def test_should_not_change_current_state
592
- assert_equal 'parked', @record.state
593
- end
594
-
595
- def test_should_not_run_further_callbacks
596
- assert_equal [:before_1], @callbacks
597
- end
598
- end
599
-
600
- class MachineWithFailedAfterCallbacksTest < BaseTestCase
601
- def setup
602
- @callbacks = []
603
-
604
- @model = new_model
605
- @machine = EnumStateMachine::Machine.new(@model, :integration => :active_model)
606
- @machine.state :parked, :idling
607
- @machine.event :ignite
608
- @machine.after_transition {@callbacks << :after_1; false}
609
- @machine.after_transition {@callbacks << :after_2}
610
- @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
611
-
612
- @record = @model.new(:state => 'parked')
613
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
614
- @result = @transition.perform
615
- end
616
-
617
- def test_should_be_successful
618
- assert @result
619
- end
620
-
621
- def test_should_change_current_state
622
- assert_equal 'idling', @record.state
623
- end
624
-
625
- def test_should_not_run_further_after_callbacks
626
- assert_equal [:around_before, :around_after, :after_1], @callbacks
627
- end
628
- end
629
-
630
- class MachineWithValidationsTest < BaseTestCase
631
- def setup
632
- @model = new_model { include ActiveModel::Validations }
633
- @machine = EnumStateMachine::Machine.new(@model, :action => :save)
634
- @machine.state :parked
635
-
636
- @record = @model.new
637
- end
638
-
639
- def test_should_invalidate_using_errors
640
- I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:I18n)
641
- @record.state = 'parked'
642
-
643
- @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
644
- assert_equal ['State cannot transition via "park"'], @record.errors.full_messages
645
- end
646
-
647
- def test_should_auto_prefix_custom_attributes_on_invalidation
648
- @machine.invalidate(@record, :event, :invalid)
649
-
650
- assert_equal ['State event is invalid'], @record.errors.full_messages
651
- end
652
-
653
- def test_should_clear_errors_on_reset
654
- @record.state = 'parked'
655
- @record.errors.add(:state, 'is invalid')
656
-
657
- @machine.reset(@record)
658
- assert_equal [], @record.errors.full_messages
659
- end
660
-
661
- def test_should_be_valid_if_state_is_known
662
- @record.state = 'parked'
663
-
664
- assert @record.valid?
665
- end
666
-
667
- def test_should_not_be_valid_if_state_is_unknown
668
- @record.state = 'invalid'
669
-
670
- assert !@record.valid?
671
- assert_equal ['State is invalid'], @record.errors.full_messages
672
- end
673
- end
674
-
675
- class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
676
- def setup
677
- @model = new_model { include ActiveModel::Validations }
678
-
679
- @machine = EnumStateMachine::Machine.new(@model, :status, :attribute => :state)
680
- @machine.state :parked
681
-
682
- @record = @model.new
683
- end
684
-
685
- def test_should_add_validation_errors_to_custom_attribute
686
- @record.state = 'invalid'
687
-
688
- assert !@record.valid?
689
- assert_equal ['State is invalid'], @record.errors.full_messages
690
-
691
- @record.state = 'parked'
692
- assert @record.valid?
693
- end
694
- end
695
-
696
- class MachineErrorsTest < BaseTestCase
697
- def setup
698
- @model = new_model { include ActiveModel::Validations }
699
- @machine = EnumStateMachine::Machine.new(@model)
700
- @record = @model.new
701
- end
702
-
703
- def test_should_be_able_to_describe_current_errors
704
- @record.errors.add(:id, 'cannot be blank')
705
- @record.errors.add(:state, 'is invalid')
706
- assert_equal ['Id cannot be blank', 'State is invalid'], @machine.errors_for(@record).split(', ').sort
707
- end
708
-
709
- def test_should_describe_as_halted_with_no_errors
710
- assert_equal 'Transition halted', @machine.errors_for(@record)
711
- end
712
- end
713
-
714
- class MachineWithStateDrivenValidationsTest < BaseTestCase
715
- def setup
716
- @model = new_model do
717
- include ActiveModel::Validations
718
- attr_accessor :seatbelt
719
- end
720
-
721
- @machine = EnumStateMachine::Machine.new(@model)
722
- @machine.state :first_gear, :second_gear do
723
- validates_presence_of :seatbelt
724
- end
725
- @machine.other_states :parked
726
- end
727
-
728
- def test_should_be_valid_if_validation_fails_outside_state_scope
729
- record = @model.new(:state => 'parked', :seatbelt => nil)
730
- assert record.valid?
731
- end
732
-
733
- def test_should_be_invalid_if_validation_fails_within_state_scope
734
- record = @model.new(:state => 'first_gear', :seatbelt => nil)
735
- assert !record.valid?
736
- end
737
-
738
- def test_should_be_valid_if_validation_succeeds_within_state_scope
739
- record = @model.new(:state => 'second_gear', :seatbelt => true)
740
- assert record.valid?
741
- end
742
- end
743
-
744
- class ObserverUpdateTest < BaseTestCase
745
- def setup
746
- @model = new_model { include ActiveModel::Observing }
747
- @machine = EnumStateMachine::Machine.new(@model)
748
- @machine.state :parked, :idling
749
- @machine.event :ignite
750
-
751
- @record = @model.new(:state => 'parked')
752
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
753
-
754
- @observer_update = EnumStateMachine::Integrations::ActiveModel::ObserverUpdate.new(:before_transition, @record, @transition)
755
- end
756
-
757
- def test_should_have_method
758
- assert_equal :before_transition, @observer_update.method
759
- end
760
-
761
- def test_should_have_object
762
- assert_equal @record, @observer_update.object
763
- end
764
-
765
- def test_should_have_transition
766
- assert_equal @transition, @observer_update.transition
767
- end
768
-
769
- def test_should_include_object_and_transition_in_args
770
- assert_equal [@record, @transition], @observer_update.args
771
- end
772
-
773
- def test_should_use_record_class_as_class
774
- assert_equal @model, @observer_update.class
775
- end
776
- end
777
-
778
- class MachineWithObserversTest < BaseTestCase
779
- def setup
780
- @model = new_model { include ActiveModel::Observing }
781
- @machine = EnumStateMachine::Machine.new(@model)
782
- @machine.state :parked, :idling
783
- @machine.event :ignite
784
- @record = @model.new(:state => 'parked')
785
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
786
- end
787
-
788
- def test_should_call_all_transition_callback_permutations
789
- callbacks = [
790
- :before_ignite_from_parked_to_idling,
791
- :before_ignite_from_parked,
792
- :before_ignite_to_idling,
793
- :before_ignite,
794
- :before_transition_state_from_parked_to_idling,
795
- :before_transition_state_from_parked,
796
- :before_transition_state_to_idling,
797
- :before_transition_state,
798
- :before_transition
799
- ]
800
-
801
- observer = new_observer(@model) do
802
- callbacks.each do |callback|
803
- define_method(callback) do |*args|
804
- notifications << callback
805
- end
806
- end
807
- end
808
-
809
- instance = observer.instance
810
-
811
- @transition.perform
812
- assert_equal callbacks, instance.notifications
813
- end
814
-
815
- def test_should_call_no_transition_callbacks_when_observers_disabled
816
- return unless ActiveModel::VERSION::MAJOR >= 3 && ActiveModel::VERSION::MINOR >= 1
817
-
818
- callbacks = [
819
- :before_ignite,
820
- :before_transition
821
- ]
822
-
823
- observer = new_observer(@model) do
824
- callbacks.each do |callback|
825
- define_method(callback) do |*args|
826
- notifications << callback
827
- end
828
- end
829
- end
830
-
831
- instance = observer.instance
832
-
833
- @model.observers.disable(observer) do
834
- @transition.perform
835
- end
836
-
837
- assert_equal [], instance.notifications
838
- end
839
-
840
- def test_should_pass_record_and_transition_to_before_callbacks
841
- observer = new_observer(@model) do
842
- def before_transition(*args)
843
- notifications << args
844
- end
845
- end
846
- instance = observer.instance
847
-
848
- @transition.perform
849
- assert_equal [[@record, @transition]], instance.notifications
850
- end
851
-
852
- def test_should_pass_record_and_transition_to_after_callbacks
853
- observer = new_observer(@model) do
854
- def after_transition(*args)
855
- notifications << args
856
- end
857
- end
858
- instance = observer.instance
859
-
860
- @transition.perform
861
- assert_equal [[@record, @transition]], instance.notifications
862
- end
863
-
864
- def test_should_call_methods_outside_the_context_of_the_record
865
- observer = new_observer(@model) do
866
- def before_ignite(*args)
867
- notifications << self
868
- end
869
- end
870
- instance = observer.instance
871
-
872
- @transition.perform
873
- assert_equal [instance], instance.notifications
874
- end
875
-
876
- def test_should_support_nil_from_states
877
- callbacks = [
878
- :before_ignite_from_nil_to_idling,
879
- :before_ignite_from_nil,
880
- :before_transition_state_from_nil_to_idling,
881
- :before_transition_state_from_nil
882
- ]
883
-
884
- observer = new_observer(@model) do
885
- callbacks.each do |callback|
886
- define_method(callback) do |*args|
887
- notifications << callback
888
- end
889
- end
890
- end
891
-
892
- instance = observer.instance
893
-
894
- transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, nil, :idling)
895
- transition.perform
896
- assert_equal callbacks, instance.notifications
897
- end
898
-
899
- def test_should_support_nil_to_states
900
- callbacks = [
901
- :before_ignite_from_parked_to_nil,
902
- :before_ignite_to_nil,
903
- :before_transition_state_from_parked_to_nil,
904
- :before_transition_state_to_nil
905
- ]
906
-
907
- observer = new_observer(@model) do
908
- callbacks.each do |callback|
909
- define_method(callback) do |*args|
910
- notifications << callback
911
- end
912
- end
913
- end
914
-
915
- instance = observer.instance
916
-
917
- transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, nil)
918
- transition.perform
919
- assert_equal callbacks, instance.notifications
920
- end
921
- end
922
-
923
- class MachineWithNamespacedObserversTest < BaseTestCase
924
- def setup
925
- @model = new_model { include ActiveModel::Observing }
926
- @machine = EnumStateMachine::Machine.new(@model, :state, :namespace => 'alarm')
927
- @machine.state :active, :off
928
- @machine.event :enable
929
- @record = @model.new(:state => 'off')
930
- @transition = EnumStateMachine::Transition.new(@record, @machine, :enable, :off, :active)
931
- end
932
-
933
- def test_should_call_namespaced_before_event_method
934
- observer = new_observer(@model) do
935
- def before_enable_alarm(*args)
936
- notifications << args
937
- end
938
- end
939
- instance = observer.instance
940
-
941
- @transition.perform
942
- assert_equal [[@record, @transition]], instance.notifications
943
- end
944
-
945
- def test_should_call_namespaced_after_event_method
946
- observer = new_observer(@model) do
947
- def after_enable_alarm(*args)
948
- notifications << args
949
- end
950
- end
951
- instance = observer.instance
952
-
953
- @transition.perform
954
- assert_equal [[@record, @transition]], instance.notifications
955
- end
956
- end
957
-
958
- class MachineWithFailureCallbacksTest < BaseTestCase
959
- def setup
960
- @model = new_model { include ActiveModel::Observing }
961
- @machine = EnumStateMachine::Machine.new(@model)
962
- @machine.state :parked, :idling
963
- @machine.event :ignite
964
- @record = @model.new(:state => 'parked')
965
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
966
-
967
- @notifications = []
968
-
969
- # Create callbacks
970
- @machine.before_transition {false}
971
- @machine.after_failure {@notifications << :callback_after_failure}
972
-
973
- # Create observer callbacks
974
- observer = new_observer(@model) do
975
- def after_failure_to_ignite(*args)
976
- notifications << :observer_after_failure_ignite
977
- end
978
-
979
- def after_failure_to_transition(*args)
980
- notifications << :observer_after_failure_transition
981
- end
982
- end
983
- instance = observer.instance
984
- instance.notifications = @notifications
985
-
986
- @transition.perform
987
- end
988
-
989
- def test_should_invoke_callbacks_in_specific_order
990
- expected = [
991
- :callback_after_failure,
992
- :observer_after_failure_ignite,
993
- :observer_after_failure_transition
994
- ]
995
-
996
- assert_equal expected, @notifications
997
- end
998
- end
999
-
1000
- class MachineWithMixedCallbacksTest < BaseTestCase
1001
- def setup
1002
- @model = new_model { include ActiveModel::Observing }
1003
- @machine = EnumStateMachine::Machine.new(@model)
1004
- @machine.state :parked, :idling
1005
- @machine.event :ignite
1006
- @record = @model.new(:state => 'parked')
1007
- @transition = EnumStateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1008
-
1009
- @notifications = []
1010
-
1011
- # Create callbacks
1012
- @machine.before_transition {@notifications << :callback_before_transition}
1013
- @machine.after_transition {@notifications << :callback_after_transition}
1014
- @machine.around_transition {|block| @notifications << :callback_around_before_transition; block.call; @notifications << :callback_around_after_transition}
1015
-
1016
- # Create observer callbacks
1017
- observer = new_observer(@model) do
1018
- def before_ignite(*args)
1019
- notifications << :observer_before_ignite
1020
- end
1021
-
1022
- def before_transition(*args)
1023
- notifications << :observer_before_transition
1024
- end
1025
-
1026
- def after_ignite(*args)
1027
- notifications << :observer_after_ignite
1028
- end
1029
-
1030
- def after_transition(*args)
1031
- notifications << :observer_after_transition
1032
- end
1033
- end
1034
- instance = observer.instance
1035
- instance.notifications = @notifications
1036
-
1037
- @transition.perform
1038
- end
1039
-
1040
- def test_should_invoke_callbacks_in_specific_order
1041
- expected = [
1042
- :callback_before_transition,
1043
- :callback_around_before_transition,
1044
- :observer_before_ignite,
1045
- :observer_before_transition,
1046
- :callback_around_after_transition,
1047
- :callback_after_transition,
1048
- :observer_after_ignite,
1049
- :observer_after_transition
1050
- ]
1051
-
1052
- assert_equal expected, @notifications
1053
- end
1054
- end
1055
-
1056
- class MachineWithInternationalizationTest < BaseTestCase
1057
- def setup
1058
- I18n.backend = I18n::Backend::Simple.new
1059
-
1060
- # Initialize the backend
1061
- I18n.backend.translate(:en, 'activemodel.errors.messages.invalid_transition', :event => 'ignite', :value => 'idling')
1062
-
1063
- @model = new_model { include ActiveModel::Validations }
1064
- end
1065
-
1066
- def test_should_use_defaults
1067
- I18n.backend.store_translations(:en, {
1068
- :activemodel => {:errors => {:messages => {:invalid_transition => 'cannot %{event}'}}}
1069
- })
1070
-
1071
- machine = EnumStateMachine::Machine.new(@model, :action => :save)
1072
- machine.state :parked, :idling
1073
- machine.event :ignite
1074
-
1075
- record = @model.new(:state => 'idling')
1076
-
1077
- machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1078
- assert_equal ['State cannot ignite'], record.errors.full_messages
1079
- end
1080
-
1081
- def test_should_allow_customized_error_key
1082
- I18n.backend.store_translations(:en, {
1083
- :activemodel => {:errors => {:messages => {:bad_transition => 'cannot %{event}'}}}
1084
- })
1085
-
1086
- machine = EnumStateMachine::Machine.new(@model, :action => :save, :messages => {:invalid_transition => :bad_transition})
1087
- machine.state :parked, :idling
1088
-
1089
- record = @model.new
1090
- record.state = 'idling'
1091
-
1092
- machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1093
- assert_equal ['State cannot ignite'], record.errors.full_messages
1094
- end
1095
-
1096
- def test_should_allow_customized_error_string
1097
- machine = EnumStateMachine::Machine.new(@model, :action => :save, :messages => {:invalid_transition => 'cannot %{event}'})
1098
- machine.state :parked, :idling
1099
-
1100
- record = @model.new(:state => 'idling')
1101
-
1102
- machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1103
- assert_equal ['State cannot ignite'], record.errors.full_messages
1104
- end
1105
-
1106
- def test_should_allow_customized_state_key_scoped_to_class_and_machine
1107
- I18n.backend.store_translations(:en, {
1108
- :activemodel => {:state_machines => {:'active_model_test/foo' => {:state => {:states => {:parked => 'shutdown'}}}}}
1109
- })
1110
-
1111
- machine = EnumStateMachine::Machine.new(@model)
1112
- machine.state :parked
1113
-
1114
- assert_equal 'shutdown', machine.state(:parked).human_name
1115
- end
1116
-
1117
- def test_should_allow_customized_state_key_scoped_to_class
1118
- I18n.backend.store_translations(:en, {
1119
- :activemodel => {:state_machines => {:'active_model_test/foo' => {:states => {:parked => 'shutdown'}}}}
1120
- })
1121
-
1122
- machine = EnumStateMachine::Machine.new(@model)
1123
- machine.state :parked
1124
-
1125
- assert_equal 'shutdown', machine.state(:parked).human_name
1126
- end
1127
-
1128
- def test_should_allow_customized_state_key_scoped_to_machine
1129
- I18n.backend.store_translations(:en, {
1130
- :activemodel => {:state_machines => {:state => {:states => {:parked => 'shutdown'}}}}
1131
- })
1132
-
1133
- machine = EnumStateMachine::Machine.new(@model)
1134
- machine.state :parked
1135
-
1136
- assert_equal 'shutdown', machine.state(:parked).human_name
1137
- end
1138
-
1139
- def test_should_allow_customized_state_key_unscoped
1140
- I18n.backend.store_translations(:en, {
1141
- :activemodel => {:state_machines => {:states => {:parked => 'shutdown'}}}
1142
- })
1143
-
1144
- machine = EnumStateMachine::Machine.new(@model)
1145
- machine.state :parked
1146
-
1147
- assert_equal 'shutdown', machine.state(:parked).human_name
1148
- end
1149
-
1150
- def test_should_support_nil_state_key
1151
- I18n.backend.store_translations(:en, {
1152
- :activemodel => {:state_machines => {:states => {:nil => 'empty'}}}
1153
- })
1154
-
1155
- machine = EnumStateMachine::Machine.new(@model)
1156
-
1157
- assert_equal 'empty', machine.state(nil).human_name
1158
- end
1159
-
1160
- def test_should_allow_customized_event_key_scoped_to_class_and_machine
1161
- I18n.backend.store_translations(:en, {
1162
- :activemodel => {:state_machines => {:'active_model_test/foo' => {:state => {:events => {:park => 'stop'}}}}}
1163
- })
1164
-
1165
- machine = EnumStateMachine::Machine.new(@model)
1166
- machine.event :park
1167
-
1168
- assert_equal 'stop', machine.event(:park).human_name
1169
- end
1170
-
1171
- def test_should_allow_customized_event_key_scoped_to_class
1172
- I18n.backend.store_translations(:en, {
1173
- :activemodel => {:state_machines => {:'active_model_test/foo' => {:events => {:park => 'stop'}}}}
1174
- })
1175
-
1176
- machine = EnumStateMachine::Machine.new(@model)
1177
- machine.event :park
1178
-
1179
- assert_equal 'stop', machine.event(:park).human_name
1180
- end
1181
-
1182
- def test_should_allow_customized_event_key_scoped_to_machine
1183
- I18n.backend.store_translations(:en, {
1184
- :activemodel => {:state_machines => {:state => {:events => {:park => 'stop'}}}}
1185
- })
1186
-
1187
- machine = EnumStateMachine::Machine.new(@model)
1188
- machine.event :park
1189
-
1190
- assert_equal 'stop', machine.event(:park).human_name
1191
- end
1192
-
1193
- def test_should_allow_customized_event_key_unscoped
1194
- I18n.backend.store_translations(:en, {
1195
- :activemodel => {:state_machines => {:events => {:park => 'stop'}}}
1196
- })
1197
-
1198
- machine = EnumStateMachine::Machine.new(@model)
1199
- machine.event :park
1200
-
1201
- assert_equal 'stop', machine.event(:park).human_name
1202
- end
1203
-
1204
- def test_should_only_add_locale_once_in_load_path
1205
- assert_equal 1, I18n.load_path.select {|path| path =~ %r{active_model/locale\.rb$}}.length
1206
-
1207
- # Create another ActiveModel model that will triger the i18n feature
1208
- new_model
1209
-
1210
- assert_equal 1, I18n.load_path.select {|path| path =~ %r{active_model/locale\.rb$}}.length
1211
- end
1212
-
1213
- def test_should_add_locale_to_beginning_of_load_path
1214
- @original_load_path = I18n.load_path
1215
- I18n.backend = I18n::Backend::Simple.new
1216
-
1217
- app_locale = File.dirname(__FILE__) + '/../../files/en.yml'
1218
- default_locale = File.dirname(__FILE__) + '/../../../lib/state_machine/integrations/active_model/locale.rb'
1219
- I18n.load_path = [app_locale]
1220
-
1221
- EnumStateMachine::Machine.new(@model)
1222
-
1223
- assert_equal [default_locale, app_locale].map {|path| File.expand_path(path)}, I18n.load_path.map {|path| File.expand_path(path)}
1224
- ensure
1225
- I18n.load_path = @original_load_path
1226
- end
1227
-
1228
- def test_should_prefer_other_locales_first
1229
- @original_load_path = I18n.load_path
1230
- I18n.backend = I18n::Backend::Simple.new
1231
- I18n.load_path = [File.dirname(__FILE__) + '/../../files/en.yml']
1232
-
1233
- machine = EnumStateMachine::Machine.new(@model)
1234
- machine.state :parked, :idling
1235
- machine.event :ignite
1236
-
1237
- record = @model.new(:state => 'idling')
1238
-
1239
- machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1240
- assert_equal ['State cannot ignite'], record.errors.full_messages
1241
- ensure
1242
- I18n.load_path = @original_load_path
1243
- end
1244
- end
1245
- end