state_machine 0.9.4 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGELOG.rdoc +20 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +74 -4
  4. data/Rakefile +3 -3
  5. data/lib/state_machine.rb +51 -24
  6. data/lib/state_machine/{guard.rb → branch.rb} +34 -40
  7. data/lib/state_machine/callback.rb +13 -18
  8. data/lib/state_machine/error.rb +13 -0
  9. data/lib/state_machine/eval_helpers.rb +3 -0
  10. data/lib/state_machine/event.rb +67 -30
  11. data/lib/state_machine/event_collection.rb +20 -3
  12. data/lib/state_machine/extensions.rb +3 -3
  13. data/lib/state_machine/integrations.rb +7 -0
  14. data/lib/state_machine/integrations/active_model.rb +149 -59
  15. data/lib/state_machine/integrations/active_model/versions.rb +30 -0
  16. data/lib/state_machine/integrations/active_record.rb +74 -148
  17. data/lib/state_machine/integrations/active_record/locale.rb +0 -7
  18. data/lib/state_machine/integrations/active_record/versions.rb +149 -0
  19. data/lib/state_machine/integrations/base.rb +64 -0
  20. data/lib/state_machine/integrations/data_mapper.rb +50 -39
  21. data/lib/state_machine/integrations/data_mapper/observer.rb +47 -12
  22. data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
  23. data/lib/state_machine/integrations/mongo_mapper.rb +37 -64
  24. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  25. data/lib/state_machine/integrations/mongo_mapper/versions.rb +102 -0
  26. data/lib/state_machine/integrations/mongoid.rb +297 -0
  27. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  28. data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
  29. data/lib/state_machine/integrations/sequel.rb +99 -55
  30. data/lib/state_machine/integrations/sequel/versions.rb +40 -0
  31. data/lib/state_machine/machine.rb +273 -136
  32. data/lib/state_machine/machine_collection.rb +21 -13
  33. data/lib/state_machine/node_collection.rb +6 -1
  34. data/lib/state_machine/path.rb +120 -0
  35. data/lib/state_machine/path_collection.rb +90 -0
  36. data/lib/state_machine/state.rb +28 -9
  37. data/lib/state_machine/state_collection.rb +1 -1
  38. data/lib/state_machine/transition.rb +65 -6
  39. data/lib/state_machine/transition_collection.rb +1 -1
  40. data/test/files/en.yml +8 -0
  41. data/test/functional/state_machine_test.rb +15 -2
  42. data/test/unit/branch_test.rb +890 -0
  43. data/test/unit/callback_test.rb +9 -36
  44. data/test/unit/error_test.rb +43 -0
  45. data/test/unit/event_collection_test.rb +67 -33
  46. data/test/unit/event_test.rb +165 -38
  47. data/test/unit/integrations/active_model_test.rb +103 -3
  48. data/test/unit/integrations/active_record_test.rb +90 -43
  49. data/test/unit/integrations/base_test.rb +87 -0
  50. data/test/unit/integrations/data_mapper_test.rb +105 -44
  51. data/test/unit/integrations/mongo_mapper_test.rb +261 -64
  52. data/test/unit/integrations/mongoid_test.rb +1529 -0
  53. data/test/unit/integrations/sequel_test.rb +33 -49
  54. data/test/unit/integrations_test.rb +4 -0
  55. data/test/unit/invalid_event_test.rb +15 -2
  56. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  57. data/test/unit/invalid_transition_test.rb +72 -2
  58. data/test/unit/machine_collection_test.rb +55 -61
  59. data/test/unit/machine_test.rb +388 -26
  60. data/test/unit/node_collection_test.rb +14 -4
  61. data/test/unit/path_collection_test.rb +266 -0
  62. data/test/unit/path_test.rb +485 -0
  63. data/test/unit/state_collection_test.rb +30 -0
  64. data/test/unit/state_test.rb +82 -35
  65. data/test/unit/transition_collection_test.rb +48 -44
  66. data/test/unit/transition_test.rb +198 -41
  67. metadata +111 -74
  68. data/test/unit/guard_test.rb +0 -909
@@ -26,12 +26,16 @@ module DataMapperTest
26
26
  def new_resource(create_table = :foo, &block)
27
27
  table_name = create_table || :foo
28
28
 
29
- resource = Class.new
29
+ resource = Class.new do
30
+ (class << self; self; end).class_eval do
31
+ define_method(:name) { "DataMapperTest::#{table_name.to_s.capitalize}" }
32
+ end
33
+ end
34
+
30
35
  resource.class_eval do
31
36
  include DataMapper::Resource
32
37
 
33
38
  storage_names[:default] = table_name.to_s
34
- def self.name; "DataMapperTest::#{storage_names[:default].capitalize}"; end
35
39
 
36
40
  property :id, resource.class_eval('Serial')
37
41
  property :state, String
@@ -516,7 +520,7 @@ module DataMapperTest
516
520
 
517
521
  def test_should_have_changes_when_loaded_from_database
518
522
  record = @resource.get(@record.id)
519
- assert record.dirty_attributes.blank?
523
+ assert record.dirty_attributes.empty?
520
524
  end
521
525
  end
522
526
 
@@ -617,6 +621,50 @@ module DataMapperTest
617
621
  end
618
622
  end
619
623
 
624
+ class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
625
+ def setup
626
+ @resource = new_resource
627
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
628
+ @machine.event :ignite
629
+
630
+ @record = @resource.create
631
+ @record.state_event = 'ignite'
632
+ end
633
+
634
+ def test_should_include_state_in_changed_attributes
635
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.dirty_attributes
636
+ end
637
+
638
+ def test_should_track_attribute_change
639
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
640
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
641
+ elsif Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
642
+ assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
643
+ else
644
+ assert_equal e = {:state => 'parked-ignored'}, @record.original_values
645
+ end
646
+ end
647
+
648
+ def test_should_not_reset_changes_on_multiple_changes
649
+ @record.state_event = 'ignite'
650
+
651
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
652
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
653
+ elsif Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
654
+ assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
655
+ else
656
+ assert_equal e = {:state => 'parked-ignored'}, @record.original_values
657
+ end
658
+ end
659
+
660
+ def test_should_not_include_state_in_changed_attributes_if_nil
661
+ @record = @resource.create
662
+ @record.state_event = nil
663
+
664
+ assert_equal e = {}, @record.dirty_attributes
665
+ end
666
+ end
667
+
620
668
  class MachineWithoutTransactionsTest < BaseTestCase
621
669
  def setup
622
670
  @resource = new_resource
@@ -837,13 +885,8 @@ module DataMapperTest
837
885
  callbacks = []
838
886
  @machine.before_transition {callbacks << :before}
839
887
  @machine.after_transition {callbacks << :after}
840
- @machine.after_transition(:include_failures => true) {callbacks << :after_failure}
888
+ @machine.after_failure {callbacks << :after_failure}
841
889
  @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
842
- @machine.around_transition(:include_failures => true) do |block|
843
- callbacks << :around_before_failure
844
- block.call
845
- callbacks << :around_after_failure
846
- end
847
890
 
848
891
  @record = @resource.new(:state => 'parked')
849
892
  @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
@@ -865,7 +908,7 @@ module DataMapperTest
865
908
  end
866
909
 
867
910
  def test_should_run_before_callbacks_and_after_callbacks_with_failures
868
- assert_equal [:before, :around_before, :around_before_failure, :around_after_failure, :after_failure], @callbacks
911
+ assert_equal [:before, :around_before, :after_failure], @callbacks
869
912
  end
870
913
  end
871
914
 
@@ -1083,7 +1126,7 @@ module DataMapperTest
1083
1126
  assert !ran_callback
1084
1127
  end
1085
1128
 
1086
- def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
1129
+ def test_should_run_failure_callbacks_if_validation_fails
1087
1130
  @resource.class_eval do
1088
1131
  attr_accessor :seatbelt
1089
1132
  if respond_to?(:validates_presence_of)
@@ -1094,7 +1137,7 @@ module DataMapperTest
1094
1137
  end
1095
1138
 
1096
1139
  ran_callback = false
1097
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1140
+ @machine.after_failure { ran_callback = true }
1098
1141
 
1099
1142
  @record.valid?
1100
1143
  assert ran_callback
@@ -1125,23 +1168,6 @@ module DataMapperTest
1125
1168
  assert !ran_callback[0]
1126
1169
  end
1127
1170
 
1128
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_validation_fails
1129
- @resource.class_eval do
1130
- attr_accessor :seatbelt
1131
- if respond_to?(:validates_presence_of)
1132
- validates_presence_of :seatbelt
1133
- else
1134
- validates_present :seatbelt
1135
- end
1136
- end
1137
-
1138
- ran_callback = [false]
1139
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback[0] = true }
1140
-
1141
- @record.valid?
1142
- assert ran_callback[0]
1143
- end
1144
-
1145
1171
  def test_should_not_run_before_transitions_within_transaction
1146
1172
  @machine.before_transition { self.class.create; throw :halt }
1147
1173
 
@@ -1232,11 +1258,11 @@ module DataMapperTest
1232
1258
  assert !ran_callback
1233
1259
  end
1234
1260
 
1235
- def test_should_run_after_callbacks_with_failures_enabled_if_fails
1261
+ def test_should_run_failure_callbacks_if_fails
1236
1262
  @resource.before(:create) { throw :halt }
1237
1263
 
1238
1264
  ran_callback = false
1239
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1265
+ @machine.after_failure { ran_callback = true }
1240
1266
 
1241
1267
  @record.save
1242
1268
  assert ran_callback
@@ -1260,16 +1286,6 @@ module DataMapperTest
1260
1286
  assert ran_callback[0]
1261
1287
  end
1262
1288
 
1263
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_fails
1264
- @resource.before(:create) { throw :halt }
1265
-
1266
- ran_callback = [false]
1267
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback[0] = true }
1268
-
1269
- @record.save
1270
- assert ran_callback[0]
1271
- end
1272
-
1273
1289
  def test_should_not_run_before_transitions_within_transaction
1274
1290
  @machine.before_transition { self.class.create; throw :halt }
1275
1291
 
@@ -1545,7 +1561,7 @@ module DataMapperTest
1545
1561
  assert !called
1546
1562
  end
1547
1563
 
1548
- def test_should_pass_transition_to_after_callbacks
1564
+ def test_should_pass_transition_to_around_callbacks
1549
1565
  callback_args = nil
1550
1566
 
1551
1567
  observer = new_observer(@resource) do
@@ -1560,6 +1576,51 @@ module DataMapperTest
1560
1576
  assert_equal [@transition], callback_args
1561
1577
  end
1562
1578
 
1579
+ def test_should_call_failure_callback_if_requirements_match
1580
+ @resource.before(:create) { throw :halt }
1581
+
1582
+ called = false
1583
+
1584
+ observer = new_observer(@resource) do
1585
+ after_transition_failure :on => :ignite do
1586
+ called = true
1587
+ end
1588
+ end
1589
+
1590
+ @transition.perform
1591
+ assert called
1592
+ end
1593
+
1594
+ def test_should_not_call_failure_callback_if_requirements_do_not_match
1595
+ @resource.before(:create) { throw :halt }
1596
+
1597
+ called = false
1598
+
1599
+ observer = new_observer(@resource) do
1600
+ after_transition_failure :on => :park do
1601
+ called = true
1602
+ end
1603
+ end
1604
+
1605
+ @transition.perform
1606
+ assert !called
1607
+ end
1608
+
1609
+ def test_should_pass_transition_to_failure_callbacks
1610
+ @resource.before(:create) { throw :halt }
1611
+
1612
+ callback_args = nil
1613
+
1614
+ observer = new_observer(@resource) do
1615
+ after_transition_failure do |*args|
1616
+ callback_args = args
1617
+ end
1618
+ end
1619
+
1620
+ @transition.perform
1621
+ assert_equal [@transition], callback_args
1622
+ end
1623
+
1563
1624
  def test_should_raise_exception_if_targeting_invalid_machine
1564
1625
  assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) do
1565
1626
  new_observer(@resource) do
@@ -1570,7 +1631,7 @@ module DataMapperTest
1570
1631
  end
1571
1632
 
1572
1633
  def test_should_allow_targeting_specific_machine
1573
- @second_machine = StateMachine::Machine.new(@resource, :status)
1634
+ @second_machine = StateMachine::Machine.new(@resource, :status, :namespace => 'alarm')
1574
1635
  @resource.auto_migrate!
1575
1636
 
1576
1637
  called_state = false
@@ -1593,7 +1654,7 @@ module DataMapperTest
1593
1654
  end
1594
1655
 
1595
1656
  def test_should_allow_targeting_multiple_specific_machines
1596
- @second_machine = StateMachine::Machine.new(@resource, :status)
1657
+ @second_machine = StateMachine::Machine.new(@resource, :status, :namespace => 'alarm')
1597
1658
  @second_machine.state :parked, :idling
1598
1659
  @second_machine.event :ignite
1599
1660
  @resource.auto_migrate!
@@ -3,16 +3,21 @@ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
3
3
  # Load library
4
4
  require 'rubygems'
5
5
 
6
- if ENV['VERSION'] && Gem::Version.new(ENV['VERSION']) <= Gem::Version.new('0.7.0') || !Gem.available?('>=0.7.0')
7
- gem 'activesupport', '~>2.3'
8
- require 'active_support'
6
+ if ENV['VERSION']
7
+ if Gem::Version.new(ENV['VERSION']) >= Gem::Version.new('0.9.0')
8
+ gem 'activesupport', '~>3.0'
9
+ require 'active_support'
10
+ elsif Gem::Version.new(ENV['VERSION']) <= Gem::Version.new('0.7.0') || !Gem.available?('>=0.7.0')
11
+ gem 'activesupport', '~>2.3'
12
+ require 'active_support'
13
+ end
9
14
  end
10
15
 
11
16
  gem 'mongo_mapper', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.5.5'
12
17
  require 'mongo_mapper'
13
18
 
14
19
  # Establish database connection
15
- MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new("#{File.dirname(__FILE__)}/../../mongo_mapper.log")})
20
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new("#{File.dirname(__FILE__)}/../../mongo_mapper.log"), :slave_ok => true})
16
21
  MongoMapper.database = 'test'
17
22
 
18
23
  module MongoMapperTest
@@ -25,12 +30,16 @@ module MongoMapperTest
25
30
  def new_model(table_name = :foo, &block)
26
31
 
27
32
  model = Class.new do
33
+ (class << self; self; end).class_eval do
34
+ define_method(:name) { "MongoMapperTest::#{table_name.to_s.capitalize}" }
35
+ define_method(:to_s) { name }
36
+ end
37
+ end
38
+
39
+ model.class_eval do
28
40
  include MongoMapper::Document
29
41
  set_collection_name(table_name)
30
42
 
31
- def self.name; "MongoMapperTest::#{collection_name}"; end
32
- def self.to_s; "MongoMapperTest::#{collection_name}"; end
33
-
34
43
  key :state, String
35
44
  end
36
45
  model.class_eval(&block) if block_given?
@@ -335,7 +344,7 @@ module MongoMapperTest
335
344
  end
336
345
 
337
346
  def test_should_define_a_new_key_for_the_attribute
338
- assert_not_nil @model.keys[:status]
347
+ assert_not_nil @model.keys['status']
339
348
  end
340
349
 
341
350
  def test_should_define_a_reader_attribute_for_the_attribute
@@ -575,6 +584,37 @@ module MongoMapperTest
575
584
  end
576
585
  end
577
586
 
587
+ class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
588
+ def setup
589
+ @model = new_model
590
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
591
+ @machine.event :ignite
592
+
593
+ @record = @model.create
594
+ @record.state_event = 'ignite'
595
+ end
596
+
597
+ def test_should_include_state_in_changed_attributes
598
+ assert_equal %w(state), @record.changed
599
+ end
600
+
601
+ def test_should_track_attribute_change
602
+ assert_equal %w(parked parked), @record.changes['state']
603
+ end
604
+
605
+ def test_should_not_reset_changes_on_multiple_changes
606
+ @record.state_event = 'ignite'
607
+ assert_equal %w(parked parked), @record.changes['state']
608
+ end
609
+
610
+ def test_should_not_include_state_in_changed_attributes_if_nil
611
+ @record = @model.create
612
+ @record.state_event = nil
613
+
614
+ assert_equal [], @record.changed
615
+ end
616
+ end
617
+
578
618
  class MachineWithCallbacksTest < BaseTestCase
579
619
  def setup
580
620
  @model = new_model
@@ -710,27 +750,45 @@ module MongoMapperTest
710
750
  @result = @transition.perform
711
751
  end
712
752
 
713
- def test_should_be_successful
714
- assert @result
715
- end
716
-
717
- def test_should_change_current_state
718
- assert_equal 'idling', @record.state
719
- end
720
-
721
- def test_should_run_action
722
- assert !@record.new_record?
723
- end
724
-
725
- def test_should_run_further_callbacks
726
- assert_equal [:before_1, :before_2, :around_before, :around_after, :after], @callbacks
753
+ if defined?(MongoMapper::Version) && MongoMapper::Version >= '0.9.0'
754
+ def test_should_not_be_successful
755
+ assert !@result
756
+ end
757
+
758
+ def test_should_not_change_current_state
759
+ assert_equal 'parked', @record.state
760
+ end
761
+
762
+ def test_should_not_run_action
763
+ assert @record.new_record?
764
+ end
765
+
766
+ def test_should_not_run_further_callbacks
767
+ assert_equal [:before_1], @callbacks
768
+ end
769
+ else
770
+ def test_should_be_successful
771
+ assert @result
772
+ end
773
+
774
+ def test_should_change_current_state
775
+ assert_equal 'idling', @record.state
776
+ end
777
+
778
+ def test_should_run_action
779
+ assert !@record.new_record?
780
+ end
781
+
782
+ def test_should_run_further_callbacks
783
+ assert_equal [:before_1, :before_2, :around_before, :around_after, :after], @callbacks
784
+ end
727
785
  end
728
786
  end
729
787
 
730
788
  class MachineWithFailedActionTest < BaseTestCase
731
789
  def setup
732
790
  @model = new_model do
733
- validates_inclusion_of :state, :within => %w(first_gear)
791
+ validates_numericality_of :state
734
792
  end
735
793
 
736
794
  @machine = StateMachine::Machine.new(@model)
@@ -740,13 +798,8 @@ module MongoMapperTest
740
798
  @callbacks = []
741
799
  @machine.before_transition {@callbacks << :before}
742
800
  @machine.after_transition {@callbacks << :after}
743
- @machine.after_transition(:include_failures => true) {@callbacks << :after_failure}
801
+ @machine.after_failure {@callbacks << :after_failure}
744
802
  @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
745
- @machine.around_transition(:include_failures => true) do |block|
746
- @callbacks << :around_before_failure
747
- block.call
748
- @callbacks << :around_after_failure
749
- end
750
803
 
751
804
  @record = @model.new(:state => 'parked')
752
805
  @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
@@ -766,7 +819,7 @@ module MongoMapperTest
766
819
  end
767
820
 
768
821
  def test_should_run_before_callbacks_and_after_callbacks_with_failures
769
- assert_equal [:before, :around_before, :around_before_failure, :around_after_failure, :after_failure], @callbacks
822
+ assert_equal [:before, :around_before, :after_failure], @callbacks
770
823
  end
771
824
  end
772
825
 
@@ -799,8 +852,14 @@ module MongoMapperTest
799
852
  assert !@record.new_record?
800
853
  end
801
854
 
802
- def test_should_still_run_further_after_callbacks
803
- assert_equal [:around_before, :around_after, :after_1, :after_2], @callbacks
855
+ if defined?(MongoMapper::Version) && MongoMapper::Version >= '0.9.0'
856
+ def test_should_not_run_further_after_callbacks
857
+ assert_equal [:around_before, :around_after, :after_1], @callbacks
858
+ end
859
+ else
860
+ def test_should_still_run_further_after_callbacks
861
+ assert_equal [:around_before, :around_after, :after_1, :after_2], @callbacks
862
+ end
804
863
  end
805
864
  end
806
865
 
@@ -814,6 +873,7 @@ module MongoMapperTest
814
873
  end
815
874
 
816
875
  def test_should_invalidate_using_errors
876
+ I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:ActiveModel)
817
877
  @record.state = 'parked'
818
878
 
819
879
  @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
@@ -995,27 +1055,14 @@ module MongoMapperTest
995
1055
  assert !ran_callback
996
1056
  end
997
1057
 
998
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_validation_fails
1058
+ def test_should_run_failure_callbacks_if_validation_fails
999
1059
  @model.class_eval do
1000
1060
  attr_accessor :seatbelt
1001
1061
  validates_presence_of :seatbelt
1002
1062
  end
1003
1063
 
1004
1064
  ran_callback = false
1005
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback = true }
1006
-
1007
- @record.valid?
1008
- assert ran_callback
1009
- end
1010
-
1011
- def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
1012
- @model.class_eval do
1013
- attr_accessor :seatbelt
1014
- validates_presence_of :seatbelt
1015
- end
1016
-
1017
- ran_callback = false
1018
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1065
+ @machine.after_failure { ran_callback = true }
1019
1066
 
1020
1067
  @record.valid?
1021
1068
  assert ran_callback
@@ -1096,7 +1143,7 @@ module MongoMapperTest
1096
1143
 
1097
1144
  def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
1098
1145
  @model.class_eval do
1099
- validates_inclusion_of :state, :within => %w(first_gear)
1146
+ validates_numericality_of :state
1100
1147
  end
1101
1148
 
1102
1149
  ran_callback = false
@@ -1106,13 +1153,13 @@ module MongoMapperTest
1106
1153
  assert !ran_callback
1107
1154
  end
1108
1155
 
1109
- def test_should_run_after_callbacks_with_failures_enabled_if_fails
1156
+ def test_should_run_failure_callbacks__if_fails
1110
1157
  @model.class_eval do
1111
- validates_inclusion_of :state, :within => %w(first_gear)
1158
+ validates_numericality_of :state
1112
1159
  end
1113
1160
 
1114
1161
  ran_callback = false
1115
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1162
+ @machine.after_failure { ran_callback = true }
1116
1163
 
1117
1164
  begin; @record.save; rescue; end
1118
1165
  assert ran_callback
@@ -1120,7 +1167,7 @@ module MongoMapperTest
1120
1167
 
1121
1168
  def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
1122
1169
  @model.class_eval do
1123
- validates_inclusion_of :state, :within => %w(first_gear)
1170
+ validates_numericality_of :state
1124
1171
  end
1125
1172
 
1126
1173
  ran_callback = false
@@ -1137,18 +1184,6 @@ module MongoMapperTest
1137
1184
  @record.save
1138
1185
  assert ran_callback
1139
1186
  end
1140
-
1141
- def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_fails
1142
- @model.class_eval do
1143
- validates_inclusion_of :state, :within => %w(first_gear)
1144
- end
1145
-
1146
- ran_callback = false
1147
- @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback = true }
1148
-
1149
- begin; @record.save; rescue; end
1150
- assert ran_callback
1151
- end
1152
1187
  end
1153
1188
 
1154
1189
  class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
@@ -1379,4 +1414,166 @@ module MongoMapperTest
1379
1414
  assert @model.respond_to?(:with_statuses)
1380
1415
  end
1381
1416
  end
1417
+
1418
+ if defined?(ActiveModel)
1419
+ class MachineWithInternationalizationTest < BaseTestCase
1420
+ def setup
1421
+ I18n.backend = I18n::Backend::Simple.new
1422
+
1423
+ # Initialize the backend
1424
+ StateMachine::Machine.new(new_model)
1425
+ I18n.backend.translate(:en, 'mongo_mapper.errors.messages.invalid_transition', :event => 'ignite', :value => 'idling')
1426
+
1427
+ @model = new_model
1428
+ end
1429
+
1430
+ def test_should_use_defaults
1431
+ I18n.backend.store_translations(:en, {
1432
+ :mongo_mapper => {:errors => {:messages => {:invalid_transition => 'cannot %{event}'}}}
1433
+ })
1434
+
1435
+ machine = StateMachine::Machine.new(@model)
1436
+ machine.state :parked, :idling
1437
+ machine.event :ignite
1438
+
1439
+ record = @model.new(:state => 'idling')
1440
+
1441
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1442
+ assert_equal ['State cannot ignite'], record.errors.full_messages
1443
+ end
1444
+
1445
+ def test_should_allow_customized_error_key
1446
+ I18n.backend.store_translations(:en, {
1447
+ :mongo_mapper => {:errors => {:messages => {:bad_transition => 'cannot %{event}'}}}
1448
+ })
1449
+
1450
+ machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => :bad_transition})
1451
+ machine.state :parked, :idling
1452
+
1453
+ record = @model.new(:state => 'idling')
1454
+
1455
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1456
+ assert_equal ['State cannot ignite'], record.errors.full_messages
1457
+ end
1458
+
1459
+ def test_should_allow_customized_error_string
1460
+ machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => 'cannot %{event}'})
1461
+ machine.state :parked, :idling
1462
+
1463
+ record = @model.new(:state => 'idling')
1464
+
1465
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1466
+ assert_equal ['State cannot ignite'], record.errors.full_messages
1467
+ end
1468
+
1469
+ def test_should_allow_customized_state_key_scoped_to_class_and_machine
1470
+ I18n.backend.store_translations(:en, {
1471
+ :mongo_mapper => {:state_machines => {:'mongo_mapper_test/foo' => {:state => {:states => {:parked => 'shutdown'}}}}}
1472
+ })
1473
+
1474
+ machine = StateMachine::Machine.new(@model)
1475
+ machine.state :parked
1476
+
1477
+ assert_equal 'shutdown', machine.state(:parked).human_name
1478
+ end
1479
+
1480
+ def test_should_allow_customized_state_key_scoped_to_machine
1481
+ I18n.backend.store_translations(:en, {
1482
+ :mongo_mapper => {:state_machines => {:state => {:states => {:parked => 'shutdown'}}}}
1483
+ })
1484
+
1485
+ machine = StateMachine::Machine.new(@model)
1486
+ machine.state :parked
1487
+
1488
+ assert_equal 'shutdown', machine.state(:parked).human_name
1489
+ end
1490
+
1491
+ def test_should_allow_customized_state_key_unscoped
1492
+ I18n.backend.store_translations(:en, {
1493
+ :mongo_mapper => {:state_machines => {:states => {:parked => 'shutdown'}}}
1494
+ })
1495
+
1496
+ machine = StateMachine::Machine.new(@model)
1497
+ machine.state :parked
1498
+
1499
+ assert_equal 'shutdown', machine.state(:parked).human_name
1500
+ end
1501
+
1502
+ def test_should_allow_customized_event_key_scoped_to_class_and_machine
1503
+ I18n.backend.store_translations(:en, {
1504
+ :mongo_mapper => {:state_machines => {:'mongo_mapper_test/foo' => {:state => {:events => {:park => 'stop'}}}}}
1505
+ })
1506
+
1507
+ machine = StateMachine::Machine.new(@model)
1508
+ machine.event :park
1509
+
1510
+ assert_equal 'stop', machine.event(:park).human_name
1511
+ end
1512
+
1513
+ def test_should_allow_customized_event_key_scoped_to_machine
1514
+ I18n.backend.store_translations(:en, {
1515
+ :mongo_mapper => {:state_machines => {:state => {:events => {:park => 'stop'}}}}
1516
+ })
1517
+
1518
+ machine = StateMachine::Machine.new(@model)
1519
+ machine.event :park
1520
+
1521
+ assert_equal 'stop', machine.event(:park).human_name
1522
+ end
1523
+
1524
+ def test_should_allow_customized_event_key_unscoped
1525
+ I18n.backend.store_translations(:en, {
1526
+ :mongo_mapper => {:state_machines => {:events => {:park => 'stop'}}}
1527
+ })
1528
+
1529
+ machine = StateMachine::Machine.new(@model)
1530
+ machine.event :park
1531
+
1532
+ assert_equal 'stop', machine.event(:park).human_name
1533
+ end
1534
+
1535
+ def test_should_only_add_locale_once_in_load_path
1536
+ assert_equal 1, I18n.load_path.select {|path| path =~ %r{mongo_mapper/locale\.rb$}}.length
1537
+
1538
+ # Create another MongoMapper model that will triger the i18n feature
1539
+ new_model
1540
+
1541
+ assert_equal 1, I18n.load_path.select {|path| path =~ %r{mongo_mapper/locale\.rb$}}.length
1542
+ end
1543
+
1544
+ def test_should_add_locale_to_beginning_of_load_path
1545
+ @original_load_path = I18n.load_path
1546
+ I18n.backend = I18n::Backend::Simple.new
1547
+
1548
+ app_locale = File.dirname(__FILE__) + '/../../files/en.yml'
1549
+ default_locale = File.dirname(__FILE__) + '/../../../lib/state_machine/integrations/mongo_mapper/locale.rb'
1550
+ I18n.load_path = [app_locale]
1551
+
1552
+ StateMachine::Machine.new(@model)
1553
+
1554
+ assert_equal [default_locale, app_locale].map {|path| File.expand_path(path)}, I18n.load_path.map {|path| File.expand_path(path)}
1555
+ ensure
1556
+ I18n.load_path = @original_load_path
1557
+ end
1558
+
1559
+ def test_should_prefer_other_locales_first
1560
+ @original_load_path = I18n.load_path
1561
+ I18n.backend = I18n::Backend::Simple.new
1562
+ I18n.load_path = [File.dirname(__FILE__) + '/../../files/en.yml']
1563
+
1564
+ machine = StateMachine::Machine.new(@model)
1565
+ machine.state :parked, :idling
1566
+ machine.event :ignite
1567
+
1568
+ record = @model.new(:state => 'idling')
1569
+
1570
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
1571
+ assert_equal ['State cannot transition'], record.errors.full_messages
1572
+ ensure
1573
+ I18n.load_path = @original_load_path
1574
+ end
1575
+ end
1576
+ else
1577
+ $stderr.puts 'Skipping MongoMapper I18n tests. `gem install mongo_mapper` >= v0.9.0 and try again.'
1578
+ end
1382
1579
  end