pluginaweek-state_machine 0.7.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +21 -1
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/lib/state_machine.rb +24 -65
- data/lib/state_machine/callback.rb +1 -1
- data/lib/state_machine/event.rb +10 -9
- data/lib/state_machine/event_collection.rb +21 -10
- data/lib/state_machine/extensions.rb +2 -11
- data/lib/state_machine/guard.rb +12 -1
- data/lib/state_machine/integrations/active_record.rb +51 -13
- data/lib/state_machine/integrations/active_record/locale.rb +1 -0
- data/lib/state_machine/integrations/data_mapper.rb +22 -10
- data/lib/state_machine/integrations/data_mapper/observer.rb +5 -5
- data/lib/state_machine/integrations/sequel.rb +36 -7
- data/lib/state_machine/machine.rb +91 -55
- data/lib/state_machine/machine_collection.rb +15 -13
- data/lib/state_machine/state.rb +4 -4
- data/lib/state_machine/transition.rb +41 -14
- data/test/unit/assertions_test.rb +3 -3
- data/test/unit/eval_helpers_test.rb +13 -22
- data/test/unit/event_collection_test.rb +26 -2
- data/test/unit/event_test.rb +94 -0
- data/test/unit/guard_test.rb +46 -0
- data/test/unit/integrations/active_record_test.rb +294 -11
- data/test/unit/integrations/data_mapper_test.rb +214 -1
- data/test/unit/integrations/sequel_test.rb +321 -7
- data/test/unit/machine_collection_test.rb +42 -19
- data/test/unit/machine_test.rb +104 -10
- data/test/unit/state_test.rb +1 -1
- data/test/unit/transition_test.rb +108 -9
- metadata +4 -3
|
@@ -25,7 +25,7 @@ begin
|
|
|
25
25
|
storage_names[:default] = 'foo'
|
|
26
26
|
def self.name; 'DataMapperTest::Foo'; end
|
|
27
27
|
|
|
28
|
-
property :id,
|
|
28
|
+
property :id, DataMapper::Types::Serial
|
|
29
29
|
property :state, String
|
|
30
30
|
|
|
31
31
|
auto_migrate! if auto_migrate
|
|
@@ -232,6 +232,57 @@ begin
|
|
|
232
232
|
end
|
|
233
233
|
end
|
|
234
234
|
|
|
235
|
+
class MachineWithOwnerSubclassTest < BaseTestCase
|
|
236
|
+
def setup
|
|
237
|
+
@resource = new_resource
|
|
238
|
+
@machine = StateMachine::Machine.new(@resource, :state)
|
|
239
|
+
|
|
240
|
+
@subclass = Class.new(@resource)
|
|
241
|
+
@subclass_machine = @subclass.state_machine(:state) {}
|
|
242
|
+
@subclass_machine.state :parked, :idling, :first_gear
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def test_should_only_include_records_with_subclass_states_in_with_scope
|
|
246
|
+
parked = @subclass.create :state => 'parked'
|
|
247
|
+
idling = @subclass.create :state => 'idling'
|
|
248
|
+
|
|
249
|
+
assert_equal [parked, idling], @subclass.with_states(:parked, :idling)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def test_should_only_include_records_without_subclass_states_in_without_scope
|
|
253
|
+
parked = @subclass.create :state => 'parked'
|
|
254
|
+
idling = @subclass.create :state => 'idling'
|
|
255
|
+
first_gear = @subclass.create :state => 'first_gear'
|
|
256
|
+
|
|
257
|
+
assert_equal [parked, idling], @subclass.without_states(:first_gear)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
class MachineWithTransactionsTest < BaseTestCase
|
|
262
|
+
def setup
|
|
263
|
+
@resource = new_resource
|
|
264
|
+
@machine = StateMachine::Machine.new(@resource, :use_transactions => true)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def test_should_rollback_transaction_if_false
|
|
268
|
+
@machine.within_transaction(@resource.new) do
|
|
269
|
+
@resource.create
|
|
270
|
+
false
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
assert_equal 0, @resource.all.size
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def test_should_not_rollback_transaction_if_true
|
|
277
|
+
@machine.within_transaction(@resource.new) do
|
|
278
|
+
@resource.create
|
|
279
|
+
true
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
assert_equal 1, @resource.all.size
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
235
286
|
class MachineWithCallbacksTest < BaseTestCase
|
|
236
287
|
def setup
|
|
237
288
|
@resource = new_resource
|
|
@@ -324,6 +375,45 @@ begin
|
|
|
324
375
|
end
|
|
325
376
|
end
|
|
326
377
|
|
|
378
|
+
class MachineWithLoopbackTest < BaseTestCase
|
|
379
|
+
def setup
|
|
380
|
+
dirty_attributes = nil
|
|
381
|
+
|
|
382
|
+
@resource = new_resource do
|
|
383
|
+
property :updated_at, DateTime
|
|
384
|
+
auto_migrate!
|
|
385
|
+
|
|
386
|
+
# Simulate dm-timestamps
|
|
387
|
+
before :update do
|
|
388
|
+
dirty_attributes = self.dirty_attributes.dup
|
|
389
|
+
|
|
390
|
+
return unless dirty?
|
|
391
|
+
self.updated_at = DateTime.now
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
@machine = StateMachine::Machine.new(@resource, :initial => :parked)
|
|
396
|
+
@machine.event :park
|
|
397
|
+
|
|
398
|
+
@record = @resource.create(:updated_at => Time.now - 1)
|
|
399
|
+
@timestamp = @record.updated_at
|
|
400
|
+
|
|
401
|
+
@transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
|
|
402
|
+
@transition.perform
|
|
403
|
+
|
|
404
|
+
@dirty_attributes = dirty_attributes
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def test_should_include_state_in_dirty_attributes
|
|
408
|
+
expected = {@resource.properties[:state] => 'parked'}
|
|
409
|
+
assert_equal expected, @dirty_attributes
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def test_should_update_record
|
|
413
|
+
assert_not_equal @timestamp, @record.updated_at
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
327
417
|
begin
|
|
328
418
|
gem 'dm-observer', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.4'
|
|
329
419
|
require 'dm-observer'
|
|
@@ -572,6 +662,26 @@ begin
|
|
|
572
662
|
end
|
|
573
663
|
end
|
|
574
664
|
|
|
665
|
+
class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
|
|
666
|
+
def setup
|
|
667
|
+
@resource = new_resource
|
|
668
|
+
@machine = StateMachine::Machine.new(@resource, :status, :attribute => :state)
|
|
669
|
+
@machine.state :parked
|
|
670
|
+
|
|
671
|
+
@record = @resource.new
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
def test_should_add_validation_errors_to_custom_attribute
|
|
675
|
+
@record.state = 'invalid'
|
|
676
|
+
|
|
677
|
+
assert !@record.valid?
|
|
678
|
+
assert_equal ['is invalid'], @record.errors.on(:state)
|
|
679
|
+
|
|
680
|
+
@record.state = 'parked'
|
|
681
|
+
assert @record.valid?
|
|
682
|
+
end
|
|
683
|
+
end
|
|
684
|
+
|
|
575
685
|
class MachineWithStateDrivenValidationsTest < BaseTestCase
|
|
576
686
|
def setup
|
|
577
687
|
@resource = new_resource do
|
|
@@ -650,6 +760,109 @@ begin
|
|
|
650
760
|
@record.valid?
|
|
651
761
|
assert !ran_callback
|
|
652
762
|
end
|
|
763
|
+
|
|
764
|
+
def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
|
|
765
|
+
@resource.class_eval do
|
|
766
|
+
attr_accessor :seatbelt
|
|
767
|
+
validates_present :seatbelt
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
ran_callback = false
|
|
771
|
+
@machine.after_transition { ran_callback = true }
|
|
772
|
+
|
|
773
|
+
@record.valid?
|
|
774
|
+
assert !ran_callback
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
|
|
778
|
+
@resource.class_eval do
|
|
779
|
+
attr_accessor :seatbelt
|
|
780
|
+
validates_present :seatbelt
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
ran_callback = false
|
|
784
|
+
@machine.after_transition(:include_failures => true) { ran_callback = true }
|
|
785
|
+
|
|
786
|
+
@record.valid?
|
|
787
|
+
assert ran_callback
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
class MachineWithEventAttributesOnSaveTest < BaseTestCase
|
|
792
|
+
def setup
|
|
793
|
+
@resource = new_resource
|
|
794
|
+
@machine = StateMachine::Machine.new(@resource)
|
|
795
|
+
@machine.event :ignite do
|
|
796
|
+
transition :parked => :idling
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
@record = @resource.new
|
|
800
|
+
@record.state = 'parked'
|
|
801
|
+
@record.state_event = 'ignite'
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
def test_should_fail_if_event_is_invalid
|
|
805
|
+
@record.state_event = 'invalid'
|
|
806
|
+
assert !@record.save
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
def test_should_fail_if_event_has_no_transition
|
|
810
|
+
@record.state = 'idling'
|
|
811
|
+
assert !@record.save
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
def test_should_be_successful_if_event_has_transition
|
|
815
|
+
assert_equal true, @record.save
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def test_should_run_before_callbacks
|
|
819
|
+
ran_callback = false
|
|
820
|
+
@machine.before_transition { ran_callback = true }
|
|
821
|
+
|
|
822
|
+
@record.save
|
|
823
|
+
assert ran_callback
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
def test_should_run_before_callbacks_once
|
|
827
|
+
before_count = 0
|
|
828
|
+
@machine.before_transition { before_count += 1 }
|
|
829
|
+
|
|
830
|
+
@record.save
|
|
831
|
+
assert_equal 1, before_count
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
def test_should_persist_new_state
|
|
835
|
+
@record.save
|
|
836
|
+
assert_equal 'idling', @record.state
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
def test_should_run_after_callbacks
|
|
840
|
+
ran_callback = false
|
|
841
|
+
@machine.after_transition { ran_callback = true }
|
|
842
|
+
|
|
843
|
+
@record.save
|
|
844
|
+
assert ran_callback
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
|
|
848
|
+
@resource.before(:create) { throw :halt }
|
|
849
|
+
|
|
850
|
+
ran_callback = false
|
|
851
|
+
@machine.after_transition { ran_callback = true }
|
|
852
|
+
|
|
853
|
+
@record.save
|
|
854
|
+
assert !ran_callback
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
def test_should_run_after_callbacks_with_failures_enabled_if_fails
|
|
858
|
+
@resource.before(:create) { throw :halt }
|
|
859
|
+
|
|
860
|
+
ran_callback = false
|
|
861
|
+
@machine.after_transition(:include_failures => true) { ran_callback = true }
|
|
862
|
+
|
|
863
|
+
@record.save
|
|
864
|
+
assert ran_callback
|
|
865
|
+
end
|
|
653
866
|
end
|
|
654
867
|
|
|
655
868
|
class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
|
|
@@ -25,10 +25,10 @@ begin
|
|
|
25
25
|
end if auto_migrate
|
|
26
26
|
model = Class.new(Sequel::Model(:foo)) do
|
|
27
27
|
self.raise_on_save_failure = false
|
|
28
|
-
plugin :validation_class_methods if respond_to?(:plugin)
|
|
29
|
-
|
|
30
28
|
def self.name; 'SequelTest::Foo'; end
|
|
31
29
|
end
|
|
30
|
+
model.plugin(:validation_class_methods) if model.respond_to?(:plugin)
|
|
31
|
+
model.plugin(:hook_class_methods) if model.respond_to?(:plugin)
|
|
32
32
|
model.class_eval(&block) if block_given?
|
|
33
33
|
model
|
|
34
34
|
end
|
|
@@ -185,15 +185,136 @@ begin
|
|
|
185
185
|
end
|
|
186
186
|
end
|
|
187
187
|
|
|
188
|
-
class
|
|
188
|
+
class MachineWithStaticInitialStateTest < BaseTestCase
|
|
189
189
|
def setup
|
|
190
|
-
@model = new_model
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
@model = new_model do
|
|
191
|
+
attr_accessor :value
|
|
192
|
+
end
|
|
193
|
+
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
|
193
194
|
end
|
|
194
195
|
|
|
195
196
|
def test_should_set_initial_state_on_created_object
|
|
196
|
-
|
|
197
|
+
record = @model.new
|
|
198
|
+
assert_equal 'parked', record.state
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def test_should_still_set_attributes
|
|
202
|
+
record = @model.new(:value => 1)
|
|
203
|
+
assert_equal 1, record.value
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def test_should_still_allow_initialize_blocks
|
|
207
|
+
block_args = nil
|
|
208
|
+
record = @model.new do |*args|
|
|
209
|
+
block_args = args
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
assert_equal [record], block_args
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def test_should_not_have_any_changed_columns
|
|
216
|
+
record = @model.new
|
|
217
|
+
assert record.changed_columns.empty?
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def test_should_set_attributes_prior_to_after_initialize_hook
|
|
221
|
+
state = nil
|
|
222
|
+
@model.class_eval do
|
|
223
|
+
define_method(:after_initialize) do
|
|
224
|
+
state = self.state
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
@model.new
|
|
228
|
+
assert_equal 'parked', state
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def test_should_set_initial_state_before_setting_attributes
|
|
232
|
+
@model.class_eval do
|
|
233
|
+
attr_accessor :state_during_setter
|
|
234
|
+
|
|
235
|
+
define_method(:value=) do |value|
|
|
236
|
+
self.state_during_setter = state
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
record = @model.new(:value => 1)
|
|
241
|
+
assert_equal 'parked', record.state_during_setter
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def test_should_not_set_initial_state_after_already_initialized
|
|
245
|
+
record = @model.new(:value => 1)
|
|
246
|
+
assert_equal 'parked', record.state
|
|
247
|
+
|
|
248
|
+
record.state = 'idling'
|
|
249
|
+
record.set({})
|
|
250
|
+
assert_equal 'idling', record.state
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
class MachineWithDynamicInitialStateTest < BaseTestCase
|
|
255
|
+
def setup
|
|
256
|
+
@model = new_model do
|
|
257
|
+
attr_accessor :value
|
|
258
|
+
end
|
|
259
|
+
@machine = StateMachine::Machine.new(@model, :initial => lambda {|object| :parked})
|
|
260
|
+
@machine.state :parked
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def test_should_set_initial_state_on_created_object
|
|
264
|
+
record = @model.new
|
|
265
|
+
assert_equal 'parked', record.state
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def test_should_still_set_attributes
|
|
269
|
+
record = @model.new(:value => 1)
|
|
270
|
+
assert_equal 1, record.value
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def test_should_still_allow_initialize_blocks
|
|
274
|
+
block_args = nil
|
|
275
|
+
record = @model.new do |*args|
|
|
276
|
+
block_args = args
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
assert_equal [record], block_args
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def test_should_not_have_any_changed_columns
|
|
283
|
+
record = @model.new
|
|
284
|
+
assert record.changed_columns.empty?
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def test_should_set_attributes_prior_to_after_initialize_hook
|
|
288
|
+
state = nil
|
|
289
|
+
@model.class_eval do
|
|
290
|
+
define_method(:after_initialize) do
|
|
291
|
+
state = self.state
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
@model.new
|
|
295
|
+
assert_equal 'parked', state
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def test_should_set_initial_state_after_setting_attributes
|
|
299
|
+
@model.class_eval do
|
|
300
|
+
attr_accessor :state_during_setter
|
|
301
|
+
|
|
302
|
+
define_method(:value=) do |value|
|
|
303
|
+
self.state_during_setter = state || 'nil'
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
record = @model.new(:value => 1)
|
|
308
|
+
assert_equal 'nil', record.state_during_setter
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def test_should_not_set_initial_state_after_already_initialized
|
|
312
|
+
record = @model.new(:value => 1)
|
|
313
|
+
assert_equal 'parked', record.state
|
|
314
|
+
|
|
315
|
+
record.state = 'idling'
|
|
316
|
+
record.set({})
|
|
317
|
+
assert_equal 'idling', record.state
|
|
197
318
|
end
|
|
198
319
|
end
|
|
199
320
|
|
|
@@ -252,6 +373,56 @@ begin
|
|
|
252
373
|
end
|
|
253
374
|
end
|
|
254
375
|
|
|
376
|
+
class MachineWithOwnerSubclassTest < BaseTestCase
|
|
377
|
+
def setup
|
|
378
|
+
@model = new_model
|
|
379
|
+
@machine = StateMachine::Machine.new(@model, :state)
|
|
380
|
+
|
|
381
|
+
@subclass = Class.new(@model)
|
|
382
|
+
@subclass_machine = @subclass.state_machine(:state) {}
|
|
383
|
+
@subclass_machine.state :parked, :idling, :first_gear
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def test_should_only_include_records_with_subclass_states_in_with_scope
|
|
387
|
+
parked = @subclass.create :state => 'parked'
|
|
388
|
+
idling = @subclass.create :state => 'idling'
|
|
389
|
+
|
|
390
|
+
assert_equal [parked, idling], @subclass.with_states(:parked, :idling).all
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def test_should_only_include_records_without_subclass_states_in_without_scope
|
|
394
|
+
parked = @subclass.create :state => 'parked'
|
|
395
|
+
idling = @subclass.create :state => 'idling'
|
|
396
|
+
first_gear = @subclass.create :state => 'first_gear'
|
|
397
|
+
|
|
398
|
+
assert_equal [parked, idling], @subclass.without_states(:first_gear).all
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
class MachineWithCustomAttributeTest < BaseTestCase
|
|
403
|
+
def setup
|
|
404
|
+
@model = new_model do
|
|
405
|
+
alias_method :vehicle_status, :state
|
|
406
|
+
alias_method :vehicle_status=, :state=
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
@machine = StateMachine::Machine.new(@model, :status, :attribute => :vehicle_status)
|
|
410
|
+
@machine.state :parked
|
|
411
|
+
|
|
412
|
+
@record = @model.new
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def test_should_add_validation_errors_to_custom_attribute
|
|
416
|
+
@record.vehicle_status = 'invalid'
|
|
417
|
+
|
|
418
|
+
assert !@record.valid?
|
|
419
|
+
assert_equal ['is invalid'], @record.errors.on(:vehicle_status)
|
|
420
|
+
|
|
421
|
+
@record.vehicle_status = 'parked'
|
|
422
|
+
assert @record.valid?
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
255
426
|
class MachineWithCallbacksTest < BaseTestCase
|
|
256
427
|
def setup
|
|
257
428
|
@model = new_model
|
|
@@ -344,6 +515,46 @@ begin
|
|
|
344
515
|
end
|
|
345
516
|
end
|
|
346
517
|
|
|
518
|
+
class MachineWithLoopbackTest < BaseTestCase
|
|
519
|
+
def setup
|
|
520
|
+
changed_columns = nil
|
|
521
|
+
|
|
522
|
+
@model = new_model do
|
|
523
|
+
# Simulate timestamps plugin
|
|
524
|
+
define_method(:before_update) do
|
|
525
|
+
changed_columns = self.changed_columns.dup
|
|
526
|
+
|
|
527
|
+
super()
|
|
528
|
+
self.updated_at = Time.now if changed_columns.any?
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
DB.alter_table :foo do
|
|
533
|
+
add_column :updated_at, :datetime
|
|
534
|
+
end
|
|
535
|
+
@model.class_eval { get_db_schema(true) }
|
|
536
|
+
|
|
537
|
+
@machine = StateMachine::Machine.new(@model, :initial => :parked)
|
|
538
|
+
@machine.event :park
|
|
539
|
+
|
|
540
|
+
@record = @model.create(:updated_at => Time.now - 1)
|
|
541
|
+
@timestamp = @record.updated_at
|
|
542
|
+
|
|
543
|
+
@transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
|
|
544
|
+
@transition.perform
|
|
545
|
+
|
|
546
|
+
@changed_columns = changed_columns
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def test_should_include_state_in_changed_columns
|
|
550
|
+
assert_equal [:state], @changed_columns
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def test_should_update_record
|
|
554
|
+
assert_not_equal @timestamp, @record.updated_at
|
|
555
|
+
end
|
|
556
|
+
end
|
|
557
|
+
|
|
347
558
|
class MachineWithValidationsTest < BaseTestCase
|
|
348
559
|
def setup
|
|
349
560
|
@model = new_model
|
|
@@ -445,6 +656,109 @@ begin
|
|
|
445
656
|
@record.valid?
|
|
446
657
|
assert !ran_callback
|
|
447
658
|
end
|
|
659
|
+
|
|
660
|
+
def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
|
|
661
|
+
@model.class_eval do
|
|
662
|
+
attr_accessor :seatbelt
|
|
663
|
+
validates_presence_of :seatbelt
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
ran_callback = false
|
|
667
|
+
@machine.after_transition { ran_callback = true }
|
|
668
|
+
|
|
669
|
+
@record.valid?
|
|
670
|
+
assert !ran_callback
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
|
|
674
|
+
@model.class_eval do
|
|
675
|
+
attr_accessor :seatbelt
|
|
676
|
+
validates_presence_of :seatbelt
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
ran_callback = false
|
|
680
|
+
@machine.after_transition(:include_failures => true) { ran_callback = true }
|
|
681
|
+
|
|
682
|
+
@record.valid?
|
|
683
|
+
assert ran_callback
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
class MachineWithEventAttributesOnSaveTest < BaseTestCase
|
|
688
|
+
def setup
|
|
689
|
+
@model = new_model
|
|
690
|
+
@machine = StateMachine::Machine.new(@model)
|
|
691
|
+
@machine.event :ignite do
|
|
692
|
+
transition :parked => :idling
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
@record = @model.new
|
|
696
|
+
@record.state = 'parked'
|
|
697
|
+
@record.state_event = 'ignite'
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
def test_should_fail_if_event_is_invalid
|
|
701
|
+
@record.state_event = 'invalid'
|
|
702
|
+
assert !@record.save
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
def test_should_fail_if_event_has_no_transition
|
|
706
|
+
@record.state = 'idling'
|
|
707
|
+
assert !@record.save
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
def test_should_be_successful_if_event_has_transition
|
|
711
|
+
assert @record.save
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
def test_should_run_before_callbacks
|
|
715
|
+
ran_callback = false
|
|
716
|
+
@machine.before_transition { ran_callback = true }
|
|
717
|
+
|
|
718
|
+
@record.save
|
|
719
|
+
assert ran_callback
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
def test_should_run_before_callbacks_once
|
|
723
|
+
before_count = 0
|
|
724
|
+
@machine.before_transition { before_count += 1 }
|
|
725
|
+
|
|
726
|
+
@record.save
|
|
727
|
+
assert_equal 1, before_count
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
def test_should_persist_new_state
|
|
731
|
+
@record.save
|
|
732
|
+
assert_equal 'idling', @record.state
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
def test_should_run_after_callbacks
|
|
736
|
+
ran_callback = false
|
|
737
|
+
@machine.after_transition { ran_callback = true }
|
|
738
|
+
|
|
739
|
+
@record.save
|
|
740
|
+
assert ran_callback
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
|
|
744
|
+
@model.before_create {|record| false}
|
|
745
|
+
|
|
746
|
+
ran_callback = false
|
|
747
|
+
@machine.after_transition { ran_callback = true }
|
|
748
|
+
|
|
749
|
+
@record.save
|
|
750
|
+
assert !ran_callback
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
def test_should_run_after_callbacks_with_failures_enabled_if_fails
|
|
754
|
+
@model.before_create {|record| false}
|
|
755
|
+
|
|
756
|
+
ran_callback = false
|
|
757
|
+
@machine.after_transition(:include_failures => true) { ran_callback = true }
|
|
758
|
+
|
|
759
|
+
@record.save
|
|
760
|
+
assert ran_callback
|
|
761
|
+
end
|
|
448
762
|
end
|
|
449
763
|
|
|
450
764
|
class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
|