state_machine 0.9.4 → 0.10.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 +20 -0
- data/LICENSE +1 -1
- data/README.rdoc +74 -4
- data/Rakefile +3 -3
- data/lib/state_machine.rb +51 -24
- data/lib/state_machine/{guard.rb → branch.rb} +34 -40
- data/lib/state_machine/callback.rb +13 -18
- data/lib/state_machine/error.rb +13 -0
- data/lib/state_machine/eval_helpers.rb +3 -0
- data/lib/state_machine/event.rb +67 -30
- data/lib/state_machine/event_collection.rb +20 -3
- data/lib/state_machine/extensions.rb +3 -3
- data/lib/state_machine/integrations.rb +7 -0
- data/lib/state_machine/integrations/active_model.rb +149 -59
- data/lib/state_machine/integrations/active_model/versions.rb +30 -0
- data/lib/state_machine/integrations/active_record.rb +74 -148
- data/lib/state_machine/integrations/active_record/locale.rb +0 -7
- data/lib/state_machine/integrations/active_record/versions.rb +149 -0
- data/lib/state_machine/integrations/base.rb +64 -0
- data/lib/state_machine/integrations/data_mapper.rb +50 -39
- data/lib/state_machine/integrations/data_mapper/observer.rb +47 -12
- data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
- data/lib/state_machine/integrations/mongo_mapper.rb +37 -64
- data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
- data/lib/state_machine/integrations/mongo_mapper/versions.rb +102 -0
- data/lib/state_machine/integrations/mongoid.rb +297 -0
- data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
- data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
- data/lib/state_machine/integrations/sequel.rb +99 -55
- data/lib/state_machine/integrations/sequel/versions.rb +40 -0
- data/lib/state_machine/machine.rb +273 -136
- data/lib/state_machine/machine_collection.rb +21 -13
- data/lib/state_machine/node_collection.rb +6 -1
- data/lib/state_machine/path.rb +120 -0
- data/lib/state_machine/path_collection.rb +90 -0
- data/lib/state_machine/state.rb +28 -9
- data/lib/state_machine/state_collection.rb +1 -1
- data/lib/state_machine/transition.rb +65 -6
- data/lib/state_machine/transition_collection.rb +1 -1
- data/test/files/en.yml +8 -0
- data/test/functional/state_machine_test.rb +15 -2
- data/test/unit/branch_test.rb +890 -0
- data/test/unit/callback_test.rb +9 -36
- data/test/unit/error_test.rb +43 -0
- data/test/unit/event_collection_test.rb +67 -33
- data/test/unit/event_test.rb +165 -38
- data/test/unit/integrations/active_model_test.rb +103 -3
- data/test/unit/integrations/active_record_test.rb +90 -43
- data/test/unit/integrations/base_test.rb +87 -0
- data/test/unit/integrations/data_mapper_test.rb +105 -44
- data/test/unit/integrations/mongo_mapper_test.rb +261 -64
- data/test/unit/integrations/mongoid_test.rb +1529 -0
- data/test/unit/integrations/sequel_test.rb +33 -49
- data/test/unit/integrations_test.rb +4 -0
- data/test/unit/invalid_event_test.rb +15 -2
- data/test/unit/invalid_parallel_transition_test.rb +18 -0
- data/test/unit/invalid_transition_test.rb +72 -2
- data/test/unit/machine_collection_test.rb +55 -61
- data/test/unit/machine_test.rb +388 -26
- data/test/unit/node_collection_test.rb +14 -4
- data/test/unit/path_collection_test.rb +266 -0
- data/test/unit/path_test.rb +485 -0
- data/test/unit/state_collection_test.rb +30 -0
- data/test/unit/state_test.rb +82 -35
- data/test/unit/transition_collection_test.rb +48 -44
- data/test/unit/transition_test.rb +198 -41
- metadata +111 -74
- data/test/unit/guard_test.rb +0 -909
data/test/unit/callback_test.rb
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
3
3
|
class CallbackTest < Test::Unit::TestCase
|
4
4
|
def test_should_raise_exception_if_invalid_type_specified
|
5
5
|
exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:invalid) {} }
|
6
|
-
assert_equal 'Type must be :before, :after, or :
|
6
|
+
assert_equal 'Type must be :before, :after, :around, or :failure', exception.message
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_should_not_raise_exception_if_using_before_type
|
@@ -18,6 +18,10 @@ class CallbackTest < Test::Unit::TestCase
|
|
18
18
|
assert_nothing_raised { StateMachine::Callback.new(:around) {} }
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_should_not_raise_exception_if_using_failure_type
|
22
|
+
assert_nothing_raised { StateMachine::Callback.new(:failure) {} }
|
23
|
+
end
|
24
|
+
|
21
25
|
def test_should_raise_exception_if_no_methods_specified
|
22
26
|
exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:before) }
|
23
27
|
assert_equal 'Method(s) for callback must be specified', exception.message
|
@@ -61,10 +65,10 @@ class CallbackByDefaultTest < Test::Unit::TestCase
|
|
61
65
|
assert_nil @callback.terminator
|
62
66
|
end
|
63
67
|
|
64
|
-
def
|
65
|
-
assert_equal StateMachine::AllMatcher.instance, @callback.
|
66
|
-
assert_equal StateMachine::AllMatcher.instance, @callback.
|
67
|
-
assert_equal StateMachine::AllMatcher.instance, @callback.
|
68
|
+
def test_should_have_a_branch_with_all_matcher_requirements
|
69
|
+
assert_equal StateMachine::AllMatcher.instance, @callback.branch.event_requirement
|
70
|
+
assert_equal StateMachine::AllMatcher.instance, @callback.branch.state_requirements.first[:from]
|
71
|
+
assert_equal StateMachine::AllMatcher.instance, @callback.branch.state_requirements.first[:to]
|
68
72
|
end
|
69
73
|
|
70
74
|
def test_should_not_have_any_known_states
|
@@ -695,34 +699,3 @@ class CallbackWithAroundTypeAndBoundMethodTest < Test::Unit::TestCase
|
|
695
699
|
assert_equal [1, 2, 3], context
|
696
700
|
end
|
697
701
|
end
|
698
|
-
|
699
|
-
class CallbackSuccessMatcherTest < Test::Unit::TestCase
|
700
|
-
def setup
|
701
|
-
@object = Object.new
|
702
|
-
end
|
703
|
-
|
704
|
-
def test_should_match_if_not_specified
|
705
|
-
callback = StateMachine::Callback.new(:before) {}
|
706
|
-
assert callback.matches_success?(true)
|
707
|
-
end
|
708
|
-
|
709
|
-
def test_should_match_if_true_and_not_including_failures
|
710
|
-
callback = StateMachine::Callback.new(:before, :include_failures => false) {}
|
711
|
-
assert callback.matches_success?(true)
|
712
|
-
end
|
713
|
-
|
714
|
-
def test_should_match_if_true_and_including_failures
|
715
|
-
callback = StateMachine::Callback.new(:before, :include_failures => true) {}
|
716
|
-
assert callback.matches_success?(true)
|
717
|
-
end
|
718
|
-
|
719
|
-
def test_should_not_match_if_false_and_not_including_failures
|
720
|
-
callback = StateMachine::Callback.new(:before, :include_failures => false) {}
|
721
|
-
assert !callback.matches_success?(false)
|
722
|
-
end
|
723
|
-
|
724
|
-
def test_Should_match_if_false_and_including_failures
|
725
|
-
callback = StateMachine::Callback.new(:before, :include_failures => true) {}
|
726
|
-
assert callback.matches_success?(false)
|
727
|
-
end
|
728
|
-
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class ErrorByDefaultTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@machine = StateMachine::Machine.new(Class.new)
|
6
|
+
@collection = StateMachine::NodeCollection.new(@machine)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_not_have_any_nodes
|
10
|
+
assert_equal 0, @collection.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_have_a_machine
|
14
|
+
assert_equal @machine, @collection.machine
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_index_by_name
|
18
|
+
@collection << object = Struct.new(:name).new(:parked)
|
19
|
+
assert_equal object, @collection[:parked]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ErrorWithMessageTest < Test::Unit::TestCase
|
24
|
+
def setup
|
25
|
+
@machine = StateMachine::Machine.new(Class.new)
|
26
|
+
@collection = StateMachine::NodeCollection.new(@machine)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_raise_exception_if_invalid_option_specified
|
30
|
+
exception = assert_raise(ArgumentError) { StateMachine::NodeCollection.new(@machine, :invalid => true) }
|
31
|
+
assert_equal 'Invalid key(s): invalid', exception.message
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_should_raise_exception_on_lookup_if_invalid_index_specified
|
35
|
+
exception = assert_raise(ArgumentError) { @collection[:something, :invalid] }
|
36
|
+
assert_equal 'Invalid index: :invalid', exception.message
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_should_raise_exception_on_fetch_if_invalid_index_specified
|
40
|
+
exception = assert_raise(ArgumentError) { @collection.fetch(:something, :invalid) }
|
41
|
+
assert_equal 'Invalid index: :invalid', exception.message
|
42
|
+
end
|
43
|
+
end
|
@@ -29,6 +29,7 @@ class EventCollectionTest < Test::Unit::TestCase
|
|
29
29
|
@events = StateMachine::EventCollection.new(machine)
|
30
30
|
|
31
31
|
@events << @open = StateMachine::Event.new(machine, :enable)
|
32
|
+
machine.events.concat(@events)
|
32
33
|
end
|
33
34
|
|
34
35
|
def test_should_index_by_name
|
@@ -50,42 +51,72 @@ class EventCollectionWithEventsWithTransitionsTest < Test::Unit::TestCase
|
|
50
51
|
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
51
52
|
@events = StateMachine::EventCollection.new(@machine)
|
52
53
|
|
53
|
-
@machine.state :idling, :
|
54
|
-
@machine.event :ignite
|
54
|
+
@machine.state :idling, :first_gear
|
55
55
|
|
56
56
|
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
57
57
|
@ignite.transition :parked => :idling
|
58
|
-
@ignite.transition :stalled => :idling
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_should_only_include_valid_events_for_an_object
|
62
|
-
object = @klass.new
|
63
|
-
object.state = 'parked'
|
64
|
-
assert_equal [@ignite], @events.valid_for(object)
|
65
58
|
|
66
|
-
|
67
|
-
|
59
|
+
@events << @park = StateMachine::Event.new(@machine, :park)
|
60
|
+
@park.transition :idling => :parked
|
68
61
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
def test_should_only_include_valid_transitions_for_an_object
|
74
|
-
object = @klass.new
|
75
|
-
object.state = 'parked'
|
76
|
-
assert_equal [{:object => object, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}], @events.transitions_for(object).map {|transition| transition.attributes}
|
62
|
+
@events << @shift_up = StateMachine::Event.new(@machine, :shift_up)
|
63
|
+
@shift_up.transition :parked => :first_gear
|
64
|
+
@shift_up.transition :idling => :first_gear, :if => lambda{false}
|
77
65
|
|
78
|
-
|
79
|
-
assert_equal [{:object => object, :attribute => :state, :event => :ignite, :from => 'stalled', :to => 'idling'}], @events.transitions_for(object).map {|transition| transition.attributes}
|
66
|
+
@machine.events.concat(@events)
|
80
67
|
|
81
|
-
object
|
82
|
-
assert_equal [], @events.transitions_for(object)
|
68
|
+
@object = @klass.new
|
83
69
|
end
|
84
70
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
71
|
+
def test_should_find_valid_events_based_on_current_state
|
72
|
+
assert_equal [@ignite, @shift_up], @events.valid_for(@object)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_filter_valid_events_by_from_state
|
76
|
+
assert_equal [@park], @events.valid_for(@object, :from => :idling)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_should_filter_valid_events_by_to_state
|
80
|
+
assert_equal [@shift_up], @events.valid_for(@object, :to => :first_gear)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_should_filter_valid_events_by_event
|
84
|
+
assert_equal [@ignite], @events.valid_for(@object, :on => :ignite)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_should_filter_valid_events_by_multiple_requirements
|
88
|
+
assert_equal [], @events.valid_for(@object, :from => :idling, :to => :first_gear)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_should_allow_finding_valid_events_without_guards
|
92
|
+
assert_equal [@shift_up], @events.valid_for(@object, :from => :idling, :to => :first_gear, :guard => false)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_should_find_valid_transitions_based_on_current_state
|
96
|
+
assert_equal [
|
97
|
+
StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling),
|
98
|
+
StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :first_gear)
|
99
|
+
], @events.transitions_for(@object)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_should_filter_valid_transitions_by_from_state
|
103
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :park, :idling, :parked)], @events.transitions_for(@object, :from => :idling)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_should_filter_valid_transitions_by_to_state
|
107
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :first_gear)], @events.transitions_for(@object, :to => :first_gear)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_should_filter_valid_transitions_by_event
|
111
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)], @events.transitions_for(@object, :on => :ignite)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_should_filter_valid_transitions_by_multiple_requirements
|
115
|
+
assert_equal [], @events.transitions_for(@object, :from => :idling, :to => :first_gear)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_should_allow_finding_valid_transitions_without_guards
|
119
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :shift_up, :idling, :first_gear)], @events.transitions_for(@object, :from => :idling, :to => :first_gear, :guard => false)
|
89
120
|
end
|
90
121
|
end
|
91
122
|
|
@@ -103,6 +134,8 @@ class EventCollectionWithMultipleEventsTest < Test::Unit::TestCase
|
|
103
134
|
|
104
135
|
@events << @shift_down = StateMachine::Event.new(@machine, :shift_down)
|
105
136
|
@shift_down.transition :first_gear => :parked
|
137
|
+
|
138
|
+
@machine.events.concat(@events)
|
106
139
|
end
|
107
140
|
|
108
141
|
def test_should_only_include_all_valid_events_for_an_object
|
@@ -117,9 +150,8 @@ class EventCollectionWithoutMachineActionTest < Test::Unit::TestCase
|
|
117
150
|
@klass = Class.new
|
118
151
|
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
119
152
|
@events = StateMachine::EventCollection.new(@machine)
|
120
|
-
|
121
|
-
@machine.event :ignite
|
122
153
|
@events << StateMachine::Event.new(@machine, :ignite)
|
154
|
+
@machine.events.concat(@events)
|
123
155
|
|
124
156
|
@object = @klass.new
|
125
157
|
end
|
@@ -139,9 +171,9 @@ class EventCollectionAttributeWithMachineActionTest < Test::Unit::TestCase
|
|
139
171
|
@machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
|
140
172
|
@events = StateMachine::EventCollection.new(@machine)
|
141
173
|
|
142
|
-
@machine.event :ignite
|
143
174
|
@machine.state :parked, :idling
|
144
175
|
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
176
|
+
@machine.events.concat(@events)
|
145
177
|
|
146
178
|
@object = @klass.new
|
147
179
|
end
|
@@ -200,9 +232,9 @@ class EventCollectionAttributeWithNamespacedMachineTest < Test::Unit::TestCase
|
|
200
232
|
@machine = StateMachine::Machine.new(@klass, :namespace => 'alarm', :initial => :active, :action => :save)
|
201
233
|
@events = StateMachine::EventCollection.new(@machine)
|
202
234
|
|
203
|
-
@machine.event :disable
|
204
235
|
@machine.state :active, :off
|
205
236
|
@events << @disable = StateMachine::Event.new(@machine, :disable)
|
237
|
+
@machine.events.concat(@events)
|
206
238
|
|
207
239
|
@object = @klass.new
|
208
240
|
end
|
@@ -228,6 +260,8 @@ end
|
|
228
260
|
class EventCollectionWithValidationsTest < Test::Unit::TestCase
|
229
261
|
def setup
|
230
262
|
StateMachine::Integrations.const_set('Custom', Module.new do
|
263
|
+
include StateMachine::Integrations::Base
|
264
|
+
|
231
265
|
def invalidate(object, attribute, message, values = [])
|
232
266
|
(object.errors ||= []) << generate_message(message, values)
|
233
267
|
end
|
@@ -249,9 +283,9 @@ class EventCollectionWithValidationsTest < Test::Unit::TestCase
|
|
249
283
|
@machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save, :integration => :custom)
|
250
284
|
@events = StateMachine::EventCollection.new(@machine)
|
251
285
|
|
252
|
-
@machine.event :ignite
|
253
286
|
@parked, @idling = @machine.state :parked, :idling
|
254
287
|
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
288
|
+
@machine.events.concat(@events)
|
255
289
|
|
256
290
|
@object = @klass.new
|
257
291
|
end
|
@@ -303,9 +337,9 @@ class EventCollectionWithCustomMachineAttributeTest < Test::Unit::TestCase
|
|
303
337
|
@machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id, :initial => :parked, :action => :save)
|
304
338
|
@events = StateMachine::EventCollection.new(@machine)
|
305
339
|
|
306
|
-
@machine.event :ignite
|
307
340
|
@machine.state :parked, :idling
|
308
341
|
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
342
|
+
@machine.events.concat(@events)
|
309
343
|
|
310
344
|
@object = @klass.new
|
311
345
|
end
|
data/test/unit/event_test.rb
CHANGED
@@ -4,7 +4,7 @@ class EventByDefaultTest < Test::Unit::TestCase
|
|
4
4
|
def setup
|
5
5
|
@klass = Class.new
|
6
6
|
@machine = StateMachine::Machine.new(@klass)
|
7
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
7
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
8
8
|
|
9
9
|
@object = @klass.new
|
10
10
|
end
|
@@ -25,8 +25,8 @@ class EventByDefaultTest < Test::Unit::TestCase
|
|
25
25
|
assert_equal 'ignite', @event.human_name
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
assert @event.
|
28
|
+
def test_should_not_have_any_branches
|
29
|
+
assert @event.branches.empty?
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_should_have_no_known_states
|
@@ -61,7 +61,7 @@ end
|
|
61
61
|
class EventTest < Test::Unit::TestCase
|
62
62
|
def setup
|
63
63
|
@machine = StateMachine::Machine.new(Class.new)
|
64
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
64
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
65
65
|
@event.transition :parked => :idling
|
66
66
|
end
|
67
67
|
|
@@ -95,7 +95,7 @@ class EventWithHumanNameTest < Test::Unit::TestCase
|
|
95
95
|
def setup
|
96
96
|
@klass = Class.new
|
97
97
|
@machine = StateMachine::Machine.new(@klass)
|
98
|
-
@event = StateMachine::Event.new(@machine, :ignite, :human_name => 'start')
|
98
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => 'start')
|
99
99
|
end
|
100
100
|
|
101
101
|
def test_should_use_custom_human_name
|
@@ -107,7 +107,7 @@ class EventWithDynamicHumanNameTest < Test::Unit::TestCase
|
|
107
107
|
def setup
|
108
108
|
@klass = Class.new
|
109
109
|
@machine = StateMachine::Machine.new(@klass)
|
110
|
-
@event = StateMachine::Event.new(@machine, :ignite, :human_name => lambda {|event, object| ['start', object]})
|
110
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => lambda {|event, object| ['start', object]})
|
111
111
|
end
|
112
112
|
|
113
113
|
def test_should_use_custom_human_name
|
@@ -147,7 +147,7 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
@machine = StateMachine::Machine.new(@klass)
|
150
|
-
@
|
150
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
151
151
|
@object = @klass.new
|
152
152
|
end
|
153
153
|
|
@@ -198,11 +198,58 @@ class EventWithConflictingHelpersTest < Test::Unit::TestCase
|
|
198
198
|
end
|
199
199
|
end
|
200
200
|
|
201
|
+
class EventWithConflictingMachineTest < Test::Unit::TestCase
|
202
|
+
def setup
|
203
|
+
require 'stringio'
|
204
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
205
|
+
|
206
|
+
@klass = Class.new
|
207
|
+
@state_machine = StateMachine::Machine.new(@klass, :state)
|
208
|
+
@state_machine.state :parked, :idling
|
209
|
+
@state_machine.events << @state_event = StateMachine::Event.new(@state_machine, :ignite)
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_should_not_overwrite_first_event
|
213
|
+
@status_machine = StateMachine::Machine.new(@klass, :status)
|
214
|
+
@status_machine.state :first_gear, :second_gear
|
215
|
+
@status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
|
216
|
+
|
217
|
+
@object = @klass.new
|
218
|
+
@object.state = 'parked'
|
219
|
+
@object.status = 'first_gear'
|
220
|
+
|
221
|
+
@state_event.transition(:parked => :idling)
|
222
|
+
@status_event.transition(:parked => :first_gear)
|
223
|
+
|
224
|
+
@object.ignite
|
225
|
+
assert_equal 'idling', @object.state
|
226
|
+
assert_equal 'first_gear', @object.status
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_should_output_warning
|
230
|
+
@status_machine = StateMachine::Machine.new(@klass, :status)
|
231
|
+
@status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
|
232
|
+
|
233
|
+
assert_equal "Event :ignite for :status is already defined in :state\n", $stderr.string
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_should_not_output_warning_if_using_different_namespace
|
237
|
+
@status_machine = StateMachine::Machine.new(@klass, :status, :namespace => 'alarm')
|
238
|
+
@status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
|
239
|
+
|
240
|
+
assert_equal '', $stderr.string
|
241
|
+
end
|
242
|
+
|
243
|
+
def teardown
|
244
|
+
$stderr = @original_stderr
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
201
248
|
class EventWithNamespaceTest < Test::Unit::TestCase
|
202
249
|
def setup
|
203
250
|
@klass = Class.new
|
204
251
|
@machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
|
205
|
-
@event = StateMachine::Event.new(@machine, :enable)
|
252
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :enable)
|
206
253
|
@object = @klass.new
|
207
254
|
end
|
208
255
|
|
@@ -234,7 +281,7 @@ end
|
|
234
281
|
class EventTransitionsTest < Test::Unit::TestCase
|
235
282
|
def setup
|
236
283
|
@machine = StateMachine::Machine.new(Class.new)
|
237
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
284
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
238
285
|
end
|
239
286
|
|
240
287
|
def test_should_not_raise_exception_if_implicit_option_specified
|
@@ -247,9 +294,9 @@ class EventTransitionsTest < Test::Unit::TestCase
|
|
247
294
|
end
|
248
295
|
|
249
296
|
def test_should_automatically_set_on_option
|
250
|
-
|
251
|
-
assert_instance_of StateMachine::WhitelistMatcher,
|
252
|
-
assert_equal [:ignite],
|
297
|
+
branch = @event.transition(:to => :idling)
|
298
|
+
assert_instance_of StateMachine::WhitelistMatcher, branch.event_requirement
|
299
|
+
assert_equal [:ignite], branch.event_requirement.values
|
253
300
|
end
|
254
301
|
|
255
302
|
def test_should_not_allow_except_to_option
|
@@ -283,20 +330,20 @@ class EventTransitionsTest < Test::Unit::TestCase
|
|
283
330
|
end
|
284
331
|
|
285
332
|
def test_should_have_transitions
|
286
|
-
|
287
|
-
assert_equal [
|
333
|
+
branch = @event.transition(:to => :idling)
|
334
|
+
assert_equal [branch], @event.branches
|
288
335
|
end
|
289
336
|
end
|
290
337
|
|
291
338
|
class EventAfterBeingCopiedTest < Test::Unit::TestCase
|
292
339
|
def setup
|
293
340
|
@machine = StateMachine::Machine.new(Class.new)
|
294
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
341
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
295
342
|
@copied_event = @event.dup
|
296
343
|
end
|
297
344
|
|
298
|
-
def
|
299
|
-
assert_not_same @event.
|
345
|
+
def test_should_not_have_the_same_collection_of_branches
|
346
|
+
assert_not_same @event.branches, @copied_event.branches
|
300
347
|
end
|
301
348
|
|
302
349
|
def test_should_not_have_the_same_collection_of_known_states
|
@@ -308,7 +355,7 @@ class EventWithoutTransitionsTest < Test::Unit::TestCase
|
|
308
355
|
def setup
|
309
356
|
@klass = Class.new
|
310
357
|
@machine = StateMachine::Machine.new(@klass)
|
311
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
358
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
312
359
|
@object = @klass.new
|
313
360
|
end
|
314
361
|
|
@@ -334,7 +381,7 @@ class EventWithTransitionsTest < Test::Unit::TestCase
|
|
334
381
|
def setup
|
335
382
|
@klass = Class.new
|
336
383
|
@machine = StateMachine::Machine.new(@klass)
|
337
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
384
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
338
385
|
@event.transition(:parked => :idling)
|
339
386
|
@event.transition(:first_gear => :idling)
|
340
387
|
end
|
@@ -361,7 +408,7 @@ class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
|
|
361
408
|
@machine = StateMachine::Machine.new(@klass)
|
362
409
|
@machine.state :parked, :idling
|
363
410
|
|
364
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
411
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
365
412
|
@event.transition(:parked => :idling)
|
366
413
|
|
367
414
|
@object = @klass.new
|
@@ -372,10 +419,18 @@ class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
|
|
372
419
|
assert !@event.can_fire?(@object)
|
373
420
|
end
|
374
421
|
|
422
|
+
def test_should_be_able_to_fire_with_custom_from_state
|
423
|
+
assert @event.can_fire?(@object, :from => :parked)
|
424
|
+
end
|
425
|
+
|
375
426
|
def test_should_not_have_a_transition
|
376
427
|
assert_nil @event.transition_for(@object)
|
377
428
|
end
|
378
429
|
|
430
|
+
def test_should_have_a_transition_with_custom_from_state
|
431
|
+
assert_not_nil @event.transition_for(@object, :from => :parked)
|
432
|
+
end
|
433
|
+
|
379
434
|
def test_should_not_fire
|
380
435
|
assert !@event.fire(@object)
|
381
436
|
end
|
@@ -389,6 +444,8 @@ end
|
|
389
444
|
class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
390
445
|
def setup
|
391
446
|
StateMachine::Integrations.const_set('Custom', Module.new do
|
447
|
+
include StateMachine::Integrations::Base
|
448
|
+
|
392
449
|
def invalidate(object, attribute, message, values = [])
|
393
450
|
(object.errors ||= []) << generate_message(message, values)
|
394
451
|
end
|
@@ -405,7 +462,7 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
|
405
462
|
@machine = StateMachine::Machine.new(@klass, :integration => :custom)
|
406
463
|
@machine.state :parked, :idling
|
407
464
|
|
408
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
465
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
409
466
|
@event.transition(:parked => :idling, :if => lambda {false})
|
410
467
|
|
411
468
|
@object = @klass.new
|
@@ -416,10 +473,18 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
|
416
473
|
assert !@event.can_fire?(@object)
|
417
474
|
end
|
418
475
|
|
476
|
+
def test_should_be_able_to_fire_with_disabled_guards
|
477
|
+
assert @event.can_fire?(@object, :guard => false)
|
478
|
+
end
|
479
|
+
|
419
480
|
def test_should_not_have_a_transition
|
420
481
|
assert_nil @event.transition_for(@object)
|
421
482
|
end
|
422
483
|
|
484
|
+
def test_should_have_a_transition_with_disabled_guards
|
485
|
+
assert_not_nil @event.transition_for(@object, :guard => false)
|
486
|
+
end
|
487
|
+
|
423
488
|
def test_should_not_fire
|
424
489
|
assert !@event.fire(@object)
|
425
490
|
end
|
@@ -447,6 +512,22 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
|
|
447
512
|
assert_equal ['cannot transition via "ignite"'], @object.errors
|
448
513
|
end
|
449
514
|
|
515
|
+
def test_should_run_failure_callbacks
|
516
|
+
callback_args = nil
|
517
|
+
@machine.after_failure {|*args| callback_args = args}
|
518
|
+
|
519
|
+
@event.fire(@object)
|
520
|
+
|
521
|
+
object, transition = callback_args
|
522
|
+
assert_equal @object, object
|
523
|
+
assert_not_nil transition
|
524
|
+
assert_equal @object, transition.object
|
525
|
+
assert_equal @machine, transition.machine
|
526
|
+
assert_equal :ignite, transition.event
|
527
|
+
assert_equal :parked, transition.from_name
|
528
|
+
assert_equal :parked, transition.to_name
|
529
|
+
end
|
530
|
+
|
450
531
|
def teardown
|
451
532
|
StateMachine::Integrations.send(:remove_const, 'Custom')
|
452
533
|
end
|
@@ -455,6 +536,8 @@ end
|
|
455
536
|
class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
|
456
537
|
def setup
|
457
538
|
StateMachine::Integrations.const_set('Custom', Module.new do
|
539
|
+
include StateMachine::Integrations::Base
|
540
|
+
|
458
541
|
def invalidate(object, attribute, message, values = [])
|
459
542
|
(object.errors ||= []) << generate_message(message, values)
|
460
543
|
end
|
@@ -470,9 +553,8 @@ class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
|
|
470
553
|
|
471
554
|
@machine = StateMachine::Machine.new(@klass, :integration => :custom)
|
472
555
|
@machine.state :parked, :idling
|
473
|
-
@machine.event :ignite
|
474
556
|
|
475
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
557
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
476
558
|
@event.transition(:parked => :idling)
|
477
559
|
|
478
560
|
@object = @klass.new
|
@@ -522,9 +604,8 @@ class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
|
|
522
604
|
@klass = Class.new
|
523
605
|
@machine = StateMachine::Machine.new(@klass)
|
524
606
|
@machine.state :parked
|
525
|
-
@machine.event :park
|
526
607
|
|
527
|
-
@event = StateMachine::Event.new(@machine, :park)
|
608
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :park)
|
528
609
|
@event.transition(:from => :parked)
|
529
610
|
|
530
611
|
@object = @klass.new
|
@@ -558,9 +639,8 @@ class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
|
|
558
639
|
@klass = Class.new
|
559
640
|
@machine = StateMachine::Machine.new(@klass)
|
560
641
|
@machine.state nil, :idling
|
561
|
-
@machine.event :park
|
562
642
|
|
563
|
-
@event = StateMachine::Event.new(@machine, :park)
|
643
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :park)
|
564
644
|
@event.transition(:idling => nil)
|
565
645
|
|
566
646
|
@object = @klass.new
|
@@ -594,9 +674,8 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
|
|
594
674
|
@klass = Class.new
|
595
675
|
@machine = StateMachine::Machine.new(@klass)
|
596
676
|
@machine.state :parked, :idling
|
597
|
-
@machine.event :ignite
|
598
677
|
|
599
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
678
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
600
679
|
@event.transition(:idling => :idling)
|
601
680
|
@event.transition(:parked => :idling) # This one should get used
|
602
681
|
@event.transition(:parked => :parked)
|
@@ -635,12 +714,9 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
|
|
635
714
|
assert_equal :ignite, transition.event
|
636
715
|
end
|
637
716
|
|
638
|
-
def
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
transition = @event.transition_for(@object, :on => :ignite)
|
643
|
-
assert_not_nil transition
|
717
|
+
def test_should_not_allow_specific_transition_selection_using_on
|
718
|
+
exception = assert_raise(ArgumentError) { @event.transition_for(@object, :on => :park) }
|
719
|
+
assert_equal 'Invalid key(s): on', exception.message
|
644
720
|
end
|
645
721
|
|
646
722
|
def test_should_fire
|
@@ -689,9 +765,8 @@ class EventWithInvalidCurrentStateTest < Test::Unit::TestCase
|
|
689
765
|
@klass = Class.new
|
690
766
|
@machine = StateMachine::Machine.new(@klass)
|
691
767
|
@machine.state :parked, :idling
|
692
|
-
@machine.event :ignite
|
693
768
|
|
694
|
-
@event = StateMachine::Event.new(@machine, :ignite)
|
769
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
695
770
|
@event.transition(:parked => :idling)
|
696
771
|
|
697
772
|
@object = @klass.new
|
@@ -714,6 +789,58 @@ class EventWithInvalidCurrentStateTest < Test::Unit::TestCase
|
|
714
789
|
end
|
715
790
|
end
|
716
791
|
|
792
|
+
class EventOnFailureTest < Test::Unit::TestCase
|
793
|
+
def setup
|
794
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
795
|
+
include StateMachine::Integrations::Base
|
796
|
+
|
797
|
+
def invalidate(object, attribute, message, values = [])
|
798
|
+
(object.errors ||= []) << generate_message(message, values)
|
799
|
+
end
|
800
|
+
|
801
|
+
def reset(object)
|
802
|
+
object.errors = []
|
803
|
+
end
|
804
|
+
end)
|
805
|
+
|
806
|
+
@klass = Class.new do
|
807
|
+
attr_accessor :errors
|
808
|
+
end
|
809
|
+
|
810
|
+
@machine = StateMachine::Machine.new(@klass, :integration => :custom)
|
811
|
+
@machine.state :parked
|
812
|
+
@machine.events << @event = StateMachine::Event.new(@machine, :ignite)
|
813
|
+
|
814
|
+
@object = @klass.new
|
815
|
+
@object.state = 'parked'
|
816
|
+
end
|
817
|
+
|
818
|
+
def test_should_invalidate_the_state
|
819
|
+
@event.fire(@object)
|
820
|
+
assert_equal ['cannot transition via "ignite"'], @object.errors
|
821
|
+
end
|
822
|
+
|
823
|
+
def test_should_run_failure_callbacks
|
824
|
+
callback_args = nil
|
825
|
+
@machine.after_failure {|*args| callback_args = args}
|
826
|
+
|
827
|
+
@event.fire(@object)
|
828
|
+
|
829
|
+
object, transition = callback_args
|
830
|
+
assert_equal @object, object
|
831
|
+
assert_not_nil transition
|
832
|
+
assert_equal @object, transition.object
|
833
|
+
assert_equal @machine, transition.machine
|
834
|
+
assert_equal :ignite, transition.event
|
835
|
+
assert_equal :parked, transition.from_name
|
836
|
+
assert_equal :parked, transition.to_name
|
837
|
+
end
|
838
|
+
|
839
|
+
def teardown
|
840
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
717
844
|
class EventWithMarshallingTest < Test::Unit::TestCase
|
718
845
|
def setup
|
719
846
|
@klass = Class.new do
|
@@ -774,7 +901,7 @@ begin
|
|
774
901
|
graph = GraphViz.new('G')
|
775
902
|
states.each {|state| graph.add_node(state.to_s)}
|
776
903
|
|
777
|
-
@event = StateMachine::Event.new(@machine , :park)
|
904
|
+
@machine.events << @event = StateMachine::Event.new(@machine , :park)
|
778
905
|
@event.transition :parked => :idling
|
779
906
|
@event.transition :first_gear => :parked
|
780
907
|
@event.transition :except_from => :parked, :to => :parked
|