state_machine 0.3.1 → 0.4.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 +26 -0
- data/README.rdoc +254 -46
- data/Rakefile +29 -3
- data/examples/AutoShop_state.png +0 -0
- data/examples/Car_state.jpg +0 -0
- data/examples/Vehicle_state.png +0 -0
- data/lib/state_machine.rb +161 -116
- data/lib/state_machine/assertions.rb +21 -0
- data/lib/state_machine/callback.rb +168 -0
- data/lib/state_machine/eval_helpers.rb +67 -0
- data/lib/state_machine/event.rb +135 -101
- data/lib/state_machine/extensions.rb +83 -0
- data/lib/state_machine/guard.rb +115 -0
- data/lib/state_machine/integrations/active_record.rb +242 -0
- data/lib/state_machine/integrations/data_mapper.rb +198 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +153 -0
- data/lib/state_machine/integrations/sequel.rb +169 -0
- data/lib/state_machine/machine.rb +746 -352
- data/lib/state_machine/transition.rb +104 -212
- data/test/active_record.log +34865 -0
- data/test/classes/switch.rb +11 -0
- data/test/data_mapper.log +14015 -0
- data/test/functional/state_machine_test.rb +249 -15
- data/test/sequel.log +3835 -0
- data/test/test_helper.rb +3 -12
- data/test/unit/assertions_test.rb +13 -0
- data/test/unit/callback_test.rb +189 -0
- data/test/unit/eval_helpers_test.rb +92 -0
- data/test/unit/event_test.rb +247 -113
- data/test/unit/guard_test.rb +420 -0
- data/test/unit/integrations/active_record_test.rb +515 -0
- data/test/unit/integrations/data_mapper_test.rb +407 -0
- data/test/unit/integrations/sequel_test.rb +244 -0
- data/test/unit/invalid_transition_test.rb +1 -1
- data/test/unit/machine_test.rb +1056 -98
- data/test/unit/state_machine_test.rb +14 -113
- data/test/unit/transition_test.rb +269 -495
- metadata +44 -30
- data/test/app_root/app/models/auto_shop.rb +0 -34
- data/test/app_root/app/models/car.rb +0 -19
- data/test/app_root/app/models/highway.rb +0 -3
- data/test/app_root/app/models/motorcycle.rb +0 -3
- data/test/app_root/app/models/switch.rb +0 -23
- data/test/app_root/app/models/switch_observer.rb +0 -20
- data/test/app_root/app/models/toggle_switch.rb +0 -2
- data/test/app_root/app/models/vehicle.rb +0 -78
- data/test/app_root/config/environment.rb +0 -7
- data/test/app_root/db/migrate/001_create_switches.rb +0 -12
- data/test/app_root/db/migrate/002_create_auto_shops.rb +0 -13
- data/test/app_root/db/migrate/003_create_highways.rb +0 -11
- data/test/app_root/db/migrate/004_create_vehicles.rb +0 -16
- data/test/factory.rb +0 -77
@@ -1,130 +1,31 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
2
|
|
3
|
-
class
|
4
|
-
def test_should_track_all_state_machines
|
5
|
-
@machine = Switch.state_machine(:state)
|
6
|
-
assert_equal @machine, Switch.state_machines['state']
|
7
|
-
end
|
8
|
-
|
9
|
-
def test_should_allow_multiple_state_machines
|
10
|
-
@machine = Switch.state_machine(:state)
|
11
|
-
@second_machine = Switch.state_machine(:kind)
|
12
|
-
assert_equal 2, Switch.state_machines.size
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_should_evaluate_block_within_event_context
|
16
|
-
responded = false
|
17
|
-
Switch.state_machine(:state) do
|
18
|
-
responded = respond_to?(:event)
|
19
|
-
end
|
20
|
-
|
21
|
-
assert responded
|
22
|
-
end
|
23
|
-
|
24
|
-
def teardown
|
25
|
-
Switch.write_inheritable_attribute(:state_machines, {})
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class StateMachineAfterInitializedTest < Test::Unit::TestCase
|
3
|
+
class StateMachineByDefaultTest < Test::Unit::TestCase
|
30
4
|
def setup
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def test_should_set_the_initial_state
|
35
|
-
assert_equal 'off', Switch.new.state
|
5
|
+
@klass = Class.new
|
6
|
+
@machine = @klass.state_machine
|
36
7
|
end
|
37
8
|
|
38
|
-
def
|
39
|
-
assert_equal '
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_should_not_set_the_initial_state_if_specified_as_string
|
43
|
-
assert_equal 'on', Switch.new('state' => 'on').state
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_should_allow_evaluation_block_during_initialization
|
47
|
-
evaluated = false
|
48
|
-
Switch.new do
|
49
|
-
evaluated = true
|
50
|
-
end
|
51
|
-
|
52
|
-
assert evaluated
|
53
|
-
end
|
54
|
-
|
55
|
-
def teardown
|
56
|
-
Switch.write_inheritable_attribute(:state_machines, {})
|
9
|
+
def test_should_use_state_attribute
|
10
|
+
assert_equal 'state', @machine.attribute
|
57
11
|
end
|
58
12
|
end
|
59
13
|
|
60
|
-
class
|
14
|
+
class StateMachineTest < Test::Unit::TestCase
|
61
15
|
def setup
|
62
|
-
|
16
|
+
@klass = Class.new
|
63
17
|
end
|
64
18
|
|
65
|
-
def
|
66
|
-
|
67
|
-
assert_equal 'on', Switch.new(:initial_state => 'on').state
|
19
|
+
def test_should_allow_state_machines_on_any_class
|
20
|
+
assert @klass.respond_to?(:state_machine)
|
68
21
|
end
|
69
22
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
class StateMachineWithSubclassTest < Test::Unit::TestCase
|
76
|
-
def setup
|
77
|
-
@machine = Switch.state_machine(:state, :initial => 'on') do
|
78
|
-
event :turn_on do
|
79
|
-
transition :to => 'on', :from => 'off'
|
80
|
-
end
|
23
|
+
def test_should_evaluate_block_within_machine_context
|
24
|
+
responded = false
|
25
|
+
@klass.state_machine(:state) do
|
26
|
+
responded = respond_to?(:event)
|
81
27
|
end
|
82
28
|
|
83
|
-
|
84
|
-
# class
|
85
|
-
ToggleSwitch.write_inheritable_attribute :state_machines, {'state' => @machine}
|
86
|
-
|
87
|
-
@new_machine = ToggleSwitch.state_machine(:state, :initial => 'off') do
|
88
|
-
event :turn_on do
|
89
|
-
transition :to => 'off', :from => 'on'
|
90
|
-
end
|
91
|
-
|
92
|
-
event :replace do
|
93
|
-
transition :to => 'under_repair', :from => 'off'
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def test_should_not_have_the_same_machine_as_the_superclass
|
99
|
-
assert_not_same @machine, @new_machine
|
100
|
-
end
|
101
|
-
|
102
|
-
def test_should_use_new_initial_state
|
103
|
-
assert_equal 'off', @new_machine.initial_state(new_switch)
|
104
|
-
end
|
105
|
-
|
106
|
-
def test_should_not_change_original_initial_state
|
107
|
-
assert_equal 'on', @machine.initial_state(new_switch)
|
108
|
-
end
|
109
|
-
|
110
|
-
def test_should_define_new_events_on_subclass
|
111
|
-
assert new_toggle_switch.respond_to?(:replace)
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_should_not_define_new_events_on_superclass
|
115
|
-
assert !new_switch.respond_to?(:replace)
|
116
|
-
end
|
117
|
-
|
118
|
-
def test_should_define_new_transitions_on_subclass
|
119
|
-
assert_equal 2, @new_machine.events['turn_on'].transitions.length
|
120
|
-
end
|
121
|
-
|
122
|
-
def test_should_not_define_new_transitions_on_superclass
|
123
|
-
assert_equal 1, @machine.events['turn_on'].transitions.length
|
124
|
-
end
|
125
|
-
|
126
|
-
def teardown
|
127
|
-
Switch.write_inheritable_attribute(:state_machines, {})
|
128
|
-
ToggleSwitch.write_inheritable_attribute(:state_machines, {})
|
29
|
+
assert responded
|
129
30
|
end
|
130
31
|
end
|
@@ -2,632 +2,406 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
2
|
|
3
3
|
class TransitionTest < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
@
|
6
|
-
@
|
7
|
-
@
|
5
|
+
@klass = Class.new
|
6
|
+
@machine = StateMachine::Machine.new(@klass)
|
7
|
+
@object = @klass.new
|
8
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
8
9
|
end
|
9
10
|
|
10
|
-
def
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_should_have_options
|
15
|
-
assert_not_nil @transition.options
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_should_match_any_from_state
|
19
|
-
assert @transition.matches?('off')
|
20
|
-
assert @transition.matches?('on')
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_should_match_empty_query
|
24
|
-
assert @transition.matches?('off', {})
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_should_match_if_from_state_included
|
28
|
-
assert @transition.matches?('off', :from => 'off')
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_should_not_match_if_from_state_not_included
|
32
|
-
assert !@transition.matches?('off', :from => 'on')
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_should_allow_matching_of_multiple_from_states
|
36
|
-
assert @transition.matches?('off', :from => %w(on off))
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_should_match_if_except_from_state_not_included
|
40
|
-
assert @transition.matches?('off', :except_from => 'on')
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_should_not_match_if_except_from_state_included
|
44
|
-
assert !@transition.matches?('off', :except_from => 'off')
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_should_allow_matching_of_multiple_except_from_states
|
48
|
-
assert @transition.matches?('off', :except_from => %w(on maybe))
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_should_match_if_to_state_included
|
52
|
-
assert @transition.matches?('off', :to => 'on')
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_should_not_match_if_to_state_not_included
|
56
|
-
assert !@transition.matches?('off', :to => 'off')
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_should_allow_matching_of_multiple_to_states
|
60
|
-
assert @transition.matches?('off', :to => %w(on off))
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_should_match_if_except_to_state_not_included
|
64
|
-
assert @transition.matches?('off', :except_to => 'off')
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_should_not_match_if_except_to_state_included
|
68
|
-
assert !@transition.matches?('off', :except_to => 'on')
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_should_allow_matching_of_multiple_except_to_states
|
72
|
-
assert @transition.matches?('off', :except_to => %w(off maybe))
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_should_match_if_on_event_included
|
76
|
-
assert @transition.matches?('off', :on => 'turn_on')
|
77
|
-
end
|
78
|
-
|
79
|
-
def test_should_not_match_if_on_event_not_included
|
80
|
-
assert !@transition.matches?('off', :on => 'turn_off')
|
81
|
-
end
|
82
|
-
|
83
|
-
def test_should_allow_matching_of_multiple_on_events
|
84
|
-
assert @transition.matches?('off', :on => %w(turn_off turn_on))
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_should_match_if_except_on_event_not_included
|
88
|
-
assert @transition.matches?('off', :except_on => 'turn_off')
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_should_not_match_if_except_on_event_included
|
92
|
-
assert !@transition.matches?('off', :except_on => 'turn_on')
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_should_allow_matching_of_multiple_except_on_events
|
96
|
-
assert @transition.matches?('off', :except_on => %w(turn_off not_sure))
|
97
|
-
end
|
98
|
-
|
99
|
-
def test_should_match_if_from_state_and_to_state_match
|
100
|
-
assert @transition.matches?('off', :from => 'off', :to => 'on')
|
101
|
-
end
|
102
|
-
|
103
|
-
def test_should_not_match_if_from_state_matches_but_not_to_state
|
104
|
-
assert !@transition.matches?('off', :from => 'off', :to => 'off')
|
105
|
-
end
|
106
|
-
|
107
|
-
def test_should_not_match_if_to_state_matches_but_not_from_state
|
108
|
-
assert !@transition.matches?('off', :from => 'on', :to => 'on')
|
109
|
-
end
|
110
|
-
|
111
|
-
def test_should_match_if_from_state_to_state_and_on_event_match
|
112
|
-
assert @transition.matches?('off', :from => 'off', :to => 'on', :on => 'turn_on')
|
113
|
-
end
|
114
|
-
|
115
|
-
def test_should_not_match_if_from_state_and_to_state_match_but_not_on_event
|
116
|
-
assert !@transition.matches?('off', :from => 'off', :to => 'on', :on => 'turn_off')
|
117
|
-
end
|
118
|
-
|
119
|
-
def test_should_be_able_to_perform_on_all_states
|
120
|
-
record = new_switch(:state => 'off')
|
121
|
-
assert @transition.can_perform?(record)
|
122
|
-
|
123
|
-
record = new_switch(:state => 'on')
|
124
|
-
assert @transition.can_perform?(record)
|
125
|
-
end
|
126
|
-
|
127
|
-
def test_should_perform_for_all_states
|
128
|
-
record = new_switch(:state => 'off')
|
129
|
-
assert @transition.perform(record)
|
130
|
-
|
131
|
-
record = new_switch(:state => 'on')
|
132
|
-
assert @transition.perform(record)
|
133
|
-
end
|
134
|
-
|
135
|
-
def test_should_not_raise_exception_if_not_valid_during_perform
|
136
|
-
record = new_switch(:state => 'off')
|
137
|
-
record.fail_validation = true
|
138
|
-
|
139
|
-
assert !@transition.perform(record)
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_should_raise_exception_if_not_valid_during_perform!
|
143
|
-
record = new_switch(:state => 'off')
|
144
|
-
record.fail_validation = true
|
145
|
-
|
146
|
-
assert_raise(ActiveRecord::RecordInvalid) {@transition.perform!(record)}
|
147
|
-
end
|
148
|
-
|
149
|
-
def test_should_not_raise_exception_if_not_saved_during_perform
|
150
|
-
record = new_switch(:state => 'off')
|
151
|
-
record.fail_save = true
|
152
|
-
|
153
|
-
assert !@transition.perform(record)
|
154
|
-
end
|
155
|
-
|
156
|
-
def test_should_raise_exception_if_not_saved_during_perform!
|
157
|
-
record = new_switch(:state => 'off')
|
158
|
-
record.fail_save = true
|
159
|
-
|
160
|
-
assert_raise(ActiveRecord::RecordNotSaved) {@transition.perform!(record)}
|
161
|
-
end
|
162
|
-
|
163
|
-
def test_should_raise_exception_if_invalid_option_specified
|
164
|
-
assert_raise(ArgumentError) {PluginAWeek::StateMachine::Transition.new(@event, :invalid => true)}
|
165
|
-
end
|
166
|
-
|
167
|
-
def test_should_raise_exception_if_to_option_not_specified
|
168
|
-
assert_raise(ArgumentError) {PluginAWeek::StateMachine::Transition.new(@event, :from => 'off')}
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
class TransitionWithConditionalTest < Test::Unit::TestCase
|
173
|
-
def setup
|
174
|
-
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
|
175
|
-
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
176
|
-
@switch = create_switch(:state => 'off')
|
177
|
-
end
|
178
|
-
|
179
|
-
def test_should_be_able_to_perform_if_if_is_true
|
180
|
-
transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => lambda {true})
|
181
|
-
assert transition.can_perform?(@switch)
|
11
|
+
def test_should_have_an_object
|
12
|
+
assert_equal @object, @transition.object
|
182
13
|
end
|
183
14
|
|
184
|
-
def
|
185
|
-
|
186
|
-
assert !transition.can_perform?(@switch)
|
15
|
+
def test_should_have_a_machine
|
16
|
+
assert_equal @machine, @transition.machine
|
187
17
|
end
|
188
18
|
|
189
|
-
def
|
190
|
-
|
191
|
-
assert transition.can_perform?(@switch)
|
19
|
+
def test_should_have_an_event
|
20
|
+
assert_equal 'turn_on', @transition.event
|
192
21
|
end
|
193
22
|
|
194
|
-
def
|
195
|
-
|
196
|
-
assert !transition.can_perform?(@switch)
|
23
|
+
def test_should_have_a_from_state
|
24
|
+
assert_equal 'off', @transition.from
|
197
25
|
end
|
198
26
|
|
199
|
-
def
|
200
|
-
|
201
|
-
assert transition.can_perform?(@switch)
|
27
|
+
def test_should_have_a_to_state
|
28
|
+
assert_equal 'on', @transition.to
|
202
29
|
end
|
203
30
|
|
204
|
-
def
|
205
|
-
@
|
206
|
-
transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => :data)
|
207
|
-
assert transition.can_perform?(@switch)
|
31
|
+
def test_should_have_an_attribute
|
32
|
+
assert_equal 'state', @transition.attribute
|
208
33
|
end
|
209
34
|
|
210
|
-
def
|
211
|
-
|
212
|
-
|
213
|
-
assert !transition.can_perform?(@switch)
|
35
|
+
def test_should_generate_attributes
|
36
|
+
expected = {:object => @object, :attribute => 'state', :event => 'turn_on', :from => 'off', :to => 'on'}
|
37
|
+
assert_equal expected, @transition.attributes
|
214
38
|
end
|
215
39
|
end
|
216
40
|
|
217
|
-
class
|
41
|
+
class TransitionWithSymbolicValuesTest < Test::Unit::TestCase
|
218
42
|
def setup
|
219
|
-
@
|
220
|
-
@
|
221
|
-
@
|
43
|
+
@klass = Class.new
|
44
|
+
@machine = StateMachine::Machine.new(@klass)
|
45
|
+
@object = @klass.new
|
46
|
+
@transition = StateMachine::Transition.new(@object, @machine, :turn_on, :off, :on)
|
222
47
|
end
|
223
48
|
|
224
|
-
def
|
225
|
-
|
226
|
-
assert @transition.can_perform?(record)
|
49
|
+
def test_should_not_stringify_event
|
50
|
+
assert_equal :turn_on, @transition.event
|
227
51
|
end
|
228
52
|
|
229
|
-
def
|
230
|
-
|
231
|
-
assert @transition.perform(record)
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
class TransitionWithFromStateTest < Test::Unit::TestCase
|
236
|
-
def setup
|
237
|
-
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
|
238
|
-
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
239
|
-
@transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
|
53
|
+
def test_should_not_stringify_from_state
|
54
|
+
assert_equal :off, @transition.from
|
240
55
|
end
|
241
56
|
|
242
|
-
def
|
243
|
-
|
244
|
-
assert !@transition.can_perform?(record)
|
245
|
-
end
|
246
|
-
|
247
|
-
def test_should_be_able_to_perform_if_record_state_is_from_state
|
248
|
-
record = new_switch(:state => 'off')
|
249
|
-
assert @transition.can_perform?(record)
|
250
|
-
end
|
251
|
-
|
252
|
-
def test_should_perform_for_valid_from_state
|
253
|
-
record = new_switch(:state => 'off')
|
254
|
-
assert @transition.perform(record)
|
57
|
+
def test_should_not_stringify_to_state
|
58
|
+
assert_equal :on, @transition.to
|
255
59
|
end
|
256
60
|
end
|
257
61
|
|
258
|
-
class
|
62
|
+
class TransitionAfterBeingPerformedTest < Test::Unit::TestCase
|
259
63
|
def setup
|
260
|
-
@
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
def test_should_be_able_to_perform_if_record_state_is_any_from_state
|
271
|
-
record = new_switch(:state => 'off')
|
272
|
-
assert @transition.can_perform?(record)
|
273
|
-
|
274
|
-
record = new_switch(:state => 'on')
|
275
|
-
assert @transition.can_perform?(record)
|
276
|
-
end
|
277
|
-
|
278
|
-
def test_should_perform_for_any_valid_from_state
|
279
|
-
record = new_switch(:state => 'off')
|
280
|
-
assert @transition.perform(record)
|
64
|
+
@klass = Class.new do
|
65
|
+
attr_reader :saved, :save_state
|
66
|
+
|
67
|
+
def save
|
68
|
+
@save_state = state
|
69
|
+
@saved = true
|
70
|
+
end
|
71
|
+
end
|
281
72
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
class TransitionWithMismatchedFromStatesRequiredTest < Test::Unit::TestCase
|
288
|
-
def setup
|
289
|
-
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
|
290
|
-
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
291
|
-
@transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :except_from => 'on')
|
73
|
+
@machine = StateMachine::Machine.new(@klass, :action => :save)
|
74
|
+
@object = @klass.new
|
75
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
76
|
+
@result = @transition.perform
|
292
77
|
end
|
293
78
|
|
294
|
-
def
|
295
|
-
|
296
|
-
assert @transition.can_perform?(record)
|
79
|
+
def test_should_be_successful
|
80
|
+
assert_equal true, @result
|
297
81
|
end
|
298
82
|
|
299
|
-
def
|
300
|
-
|
301
|
-
assert !@transition.can_perform?(record)
|
83
|
+
def test_should_the_current_state
|
84
|
+
assert_equal 'on', @object.state
|
302
85
|
end
|
303
86
|
|
304
|
-
def
|
305
|
-
|
306
|
-
assert @transition.perform(record)
|
87
|
+
def test_should_run_the_action
|
88
|
+
assert @object.saved
|
307
89
|
end
|
308
90
|
|
309
|
-
def
|
310
|
-
|
311
|
-
assert !@transition.can_perform?(record)
|
91
|
+
def test_should_run_the_action_after_saving_the_state
|
92
|
+
assert_equal 'on', @object.save_state
|
312
93
|
end
|
313
94
|
end
|
314
95
|
|
315
|
-
class
|
96
|
+
class TransitionWithoutRunningActionTest < Test::Unit::TestCase
|
316
97
|
def setup
|
317
|
-
@
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
end
|
325
|
-
|
326
|
-
def test_should_update_the_state_to_the_to_state
|
327
|
-
assert_equal 'on', @record.state
|
328
|
-
end
|
329
|
-
|
330
|
-
def test_should_no_longer_be_able_to_perform_on_the_record
|
331
|
-
assert !@transition.can_perform?(@record)
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
class TransitionWithLoopbackAfterBeingPerformedTest < Test::Unit::TestCase
|
336
|
-
def setup
|
337
|
-
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
|
338
|
-
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
339
|
-
@transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'on')
|
98
|
+
@klass = Class.new do
|
99
|
+
attr_reader :saved
|
100
|
+
|
101
|
+
def save
|
102
|
+
@saved = true
|
103
|
+
end
|
104
|
+
end
|
340
105
|
|
341
|
-
@
|
342
|
-
@
|
343
|
-
@transition.
|
344
|
-
@
|
106
|
+
@machine = StateMachine::Machine.new(@klass)
|
107
|
+
@object = @klass.new
|
108
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
109
|
+
@result = @transition.perform(false)
|
345
110
|
end
|
346
111
|
|
347
|
-
def
|
348
|
-
assert_equal
|
112
|
+
def test_should_be_successful
|
113
|
+
assert_equal true, @result
|
349
114
|
end
|
350
115
|
|
351
|
-
def
|
352
|
-
assert_equal '
|
116
|
+
def test_should_the_current_state
|
117
|
+
assert_equal 'on', @object.state
|
353
118
|
end
|
354
119
|
|
355
|
-
def
|
356
|
-
assert
|
120
|
+
def test_should_not_run_the_action
|
121
|
+
assert !@object.saved
|
357
122
|
end
|
358
123
|
end
|
359
124
|
|
360
125
|
class TransitionWithCallbacksTest < Test::Unit::TestCase
|
361
126
|
def setup
|
362
|
-
@
|
363
|
-
|
364
|
-
|
365
|
-
|
127
|
+
@klass = Class.new do
|
128
|
+
attr_reader :saved, :save_state
|
129
|
+
|
130
|
+
def save
|
131
|
+
@save_state = state
|
132
|
+
@saved = true
|
133
|
+
end
|
134
|
+
end
|
366
135
|
|
367
|
-
|
136
|
+
@machine = StateMachine::Machine.new(@klass)
|
137
|
+
@object = @klass.new
|
138
|
+
@object.state = 'off'
|
139
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
368
140
|
end
|
369
141
|
|
370
|
-
def
|
371
|
-
|
142
|
+
def test_should_run_before_callbacks_before_changing_the_state
|
143
|
+
@machine.before_transition(lambda {|object| @state = object.state})
|
144
|
+
@transition.perform
|
372
145
|
|
373
|
-
|
146
|
+
assert_equal 'off', @state
|
374
147
|
end
|
375
148
|
|
376
|
-
def
|
377
|
-
|
378
|
-
|
149
|
+
def test_should_run_after_callbacks_after_running_the_action
|
150
|
+
@machine.after_transition(lambda {|object| @state = object.state})
|
151
|
+
@transition.perform
|
379
152
|
|
380
|
-
|
381
|
-
assert_equal [], @record.callbacks
|
153
|
+
assert_equal 'on', @state
|
382
154
|
end
|
383
155
|
|
384
|
-
def
|
385
|
-
|
156
|
+
def test_should_run_before_callbacks_in_the_order_they_were_defined
|
157
|
+
@callbacks = []
|
158
|
+
@machine.before_transition(lambda {@callbacks << 1})
|
159
|
+
@machine.before_transition(lambda {@callbacks << 2})
|
160
|
+
@transition.perform
|
386
161
|
|
387
|
-
|
162
|
+
assert_equal [1, 2], @callbacks
|
388
163
|
end
|
389
164
|
|
390
|
-
def
|
391
|
-
|
392
|
-
|
165
|
+
def test_should_run_after_callbacks_in_the_order_they_were_defined
|
166
|
+
@callbacks = []
|
167
|
+
@machine.after_transition(lambda {@callbacks << 1})
|
168
|
+
@machine.after_transition(lambda {@callbacks << 2})
|
169
|
+
@transition.perform
|
393
170
|
|
394
|
-
|
395
|
-
assert_equal %w(before), @record.callbacks
|
171
|
+
assert_equal [1, 2], @callbacks
|
396
172
|
end
|
397
173
|
|
398
|
-
def
|
399
|
-
|
400
|
-
|
174
|
+
def test_should_only_run_before_callbacks_that_match_transition_context
|
175
|
+
@count = 0
|
176
|
+
callback = lambda {@count += 1}
|
401
177
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
Switch.after_transition_state lambda {|record| record.callbacks << 'after'; true}
|
178
|
+
@machine.before_transition :from => 'off', :to => 'on', :on => 'turn_off', :do => callback
|
179
|
+
@machine.before_transition :from => 'off', :to => 'off', :on => 'turn_off', :do => callback
|
180
|
+
@machine.before_transition :from => 'off', :to => 'on', :on => 'turn_on', :do => callback
|
181
|
+
@machine.before_transition :from => 'on', :to => 'on', :on => 'turn_off', :do => callback
|
182
|
+
@transition.perform
|
408
183
|
|
409
|
-
|
410
|
-
assert_equal %w(before after), @record.callbacks
|
184
|
+
assert_equal 1, @count
|
411
185
|
end
|
412
186
|
|
413
|
-
def
|
414
|
-
|
415
|
-
|
187
|
+
def test_should_only_run_after_callbacks_that_match_transition_context
|
188
|
+
@count = 0
|
189
|
+
callback = lambda {@count += 1}
|
416
190
|
|
417
|
-
|
418
|
-
|
191
|
+
@machine.after_transition :from => 'off', :to => 'on', :on => 'turn_off', :do => callback
|
192
|
+
@machine.after_transition :from => 'off', :to => 'off', :on => 'turn_off', :do => callback
|
193
|
+
@machine.after_transition :from => 'off', :to => 'on', :on => 'turn_on', :do => callback
|
194
|
+
@machine.after_transition :from => 'on', :to => 'on', :on => 'turn_off', :do => callback
|
195
|
+
@transition.perform
|
196
|
+
|
197
|
+
assert_equal 1, @count
|
419
198
|
end
|
420
199
|
|
421
|
-
def
|
422
|
-
|
423
|
-
|
200
|
+
def test_should_pass_transition_to_before_callbacks
|
201
|
+
@machine.before_transition(lambda {|*args| @args = args})
|
202
|
+
@transition.perform
|
424
203
|
|
425
|
-
|
426
|
-
assert_equal [], @record.callbacks
|
204
|
+
assert_equal [@object, @transition], @args
|
427
205
|
end
|
428
206
|
|
429
|
-
def
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
207
|
+
def test_should_pass_transition_and_action_result_to_after_callbacks
|
208
|
+
@machine.after_transition(lambda {|*args| @args = args})
|
209
|
+
@transition.perform
|
210
|
+
|
211
|
+
assert_equal [@object, @transition, true], @args
|
434
212
|
end
|
435
213
|
end
|
436
214
|
|
437
|
-
class
|
215
|
+
class TransitionHaltedDuringBeforeCallbacksTest < Test::Unit::TestCase
|
438
216
|
def setup
|
439
|
-
@
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
217
|
+
@klass = Class.new do
|
218
|
+
class << self; attr_accessor :cancelled_transaction; end
|
219
|
+
attr_reader :saved
|
220
|
+
|
221
|
+
def save
|
222
|
+
@saved = true
|
223
|
+
end
|
224
|
+
end
|
225
|
+
@before_count = 0
|
226
|
+
@after_count = 0
|
444
227
|
|
445
|
-
|
228
|
+
@machine = StateMachine::Machine.new(@klass, :action => :save)
|
229
|
+
class << @machine
|
230
|
+
def within_transaction(object)
|
231
|
+
owner_class.cancelled_transaction = yield == false
|
232
|
+
end
|
233
|
+
end
|
234
|
+
@machine.before_transition lambda {@before_count += 1; throw :halt}
|
235
|
+
@machine.before_transition lambda {@before_count += 1}
|
236
|
+
@machine.after_transition lambda {@after_count += 1}
|
237
|
+
@object = @klass.new
|
238
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
239
|
+
@result = @transition.perform
|
446
240
|
end
|
447
241
|
|
448
|
-
def
|
449
|
-
|
450
|
-
@transition.perform(@record)
|
451
|
-
assert @invoked
|
242
|
+
def test_should_not_be_successful
|
243
|
+
assert !@result
|
452
244
|
end
|
453
245
|
|
454
|
-
def
|
455
|
-
|
456
|
-
@transition.perform(@record)
|
457
|
-
assert !@invoked
|
246
|
+
def test_should_not_change_current_state
|
247
|
+
assert_nil @object.state
|
458
248
|
end
|
459
249
|
|
460
|
-
def
|
461
|
-
|
462
|
-
@transition.perform(@record)
|
463
|
-
assert @invoked
|
250
|
+
def test_should_not_run_action
|
251
|
+
assert !@object.saved
|
464
252
|
end
|
465
253
|
|
466
|
-
def
|
467
|
-
|
468
|
-
@transition.perform(@record)
|
469
|
-
assert !@invoked
|
254
|
+
def test_should_not_run_further_before_callbacks
|
255
|
+
assert_equal 1, @before_count
|
470
256
|
end
|
471
257
|
|
472
|
-
def
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
258
|
+
def test_should_not_run_after_callbacks
|
259
|
+
assert_equal 0, @after_count
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_should_cancel_the_transaction
|
263
|
+
assert @klass.cancelled_transaction
|
477
264
|
end
|
478
265
|
end
|
479
266
|
|
480
|
-
class
|
267
|
+
class TransitionHaltedDuringActionTest < Test::Unit::TestCase
|
481
268
|
def setup
|
482
|
-
@
|
483
|
-
|
484
|
-
|
485
|
-
|
269
|
+
@klass = Class.new do
|
270
|
+
class << self; attr_accessor :cancelled_transaction; end
|
271
|
+
attr_reader :saved
|
272
|
+
|
273
|
+
def save
|
274
|
+
throw :halt
|
275
|
+
end
|
276
|
+
end
|
277
|
+
@before_count = 0
|
278
|
+
@after_count = 0
|
486
279
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
@transition.perform(@record)
|
499
|
-
assert !@invoked
|
500
|
-
end
|
501
|
-
|
502
|
-
def test_should_invoke_callback_if_except_from_state_not_included
|
503
|
-
Switch.before_transition_state lambda {|record| @invoked = true}, :except_from => 'on'
|
504
|
-
@transition.perform(@record)
|
505
|
-
assert @invoked
|
280
|
+
@machine = StateMachine::Machine.new(@klass, :action => :save)
|
281
|
+
class << @machine
|
282
|
+
def within_transaction(object)
|
283
|
+
owner_class.cancelled_transaction = yield == false
|
284
|
+
end
|
285
|
+
end
|
286
|
+
@machine.before_transition lambda {@before_count += 1}
|
287
|
+
@machine.after_transition lambda {@after_count += 1}
|
288
|
+
@object = @klass.new
|
289
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
290
|
+
@result = @transition.perform
|
506
291
|
end
|
507
292
|
|
508
|
-
def
|
509
|
-
|
510
|
-
@transition.perform(@record)
|
511
|
-
assert !@invoked
|
293
|
+
def test_should_not_be_successful
|
294
|
+
assert !@result
|
512
295
|
end
|
513
296
|
|
514
|
-
def
|
515
|
-
|
516
|
-
@transition.perform(@record)
|
517
|
-
assert @invoked
|
297
|
+
def test_should_change_current_state
|
298
|
+
assert_equal 'on', @object.state
|
518
299
|
end
|
519
300
|
|
520
|
-
def
|
521
|
-
|
522
|
-
@transition.perform(@record)
|
523
|
-
assert !@invoked
|
301
|
+
def test_should_run_before_callbacks
|
302
|
+
assert_equal 1, @before_count
|
524
303
|
end
|
525
304
|
|
526
|
-
def
|
527
|
-
|
528
|
-
@transition.perform(@record)
|
529
|
-
assert @invoked
|
305
|
+
def test_should_not_run_after_callbacks
|
306
|
+
assert_equal 0, @after_count
|
530
307
|
end
|
531
308
|
|
532
|
-
def
|
533
|
-
|
534
|
-
@transition.perform(@record)
|
535
|
-
assert !@invoked
|
309
|
+
def test_should_cancel_the_transaction
|
310
|
+
assert @klass.cancelled_transaction
|
536
311
|
end
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
312
|
+
end
|
313
|
+
|
314
|
+
class TransitionHaltedAfterCallbackTest < Test::Unit::TestCase
|
315
|
+
def setup
|
316
|
+
@klass = Class.new do
|
317
|
+
class << self; attr_accessor :cancelled_transaction; end
|
318
|
+
attr_reader :saved
|
319
|
+
|
320
|
+
def save
|
321
|
+
@saved = true
|
322
|
+
end
|
323
|
+
end
|
324
|
+
@before_count = 0
|
325
|
+
@after_count = 0
|
326
|
+
|
327
|
+
@machine = StateMachine::Machine.new(@klass, :action => :save)
|
328
|
+
class << @machine
|
329
|
+
def within_transaction(object)
|
330
|
+
owner_class.cancelled_transaction = yield == false
|
331
|
+
end
|
332
|
+
end
|
333
|
+
@machine.before_transition lambda {@before_count += 1}
|
334
|
+
@machine.after_transition lambda {@after_count += 1; throw :halt}
|
335
|
+
@machine.after_transition lambda {@after_count += 1}
|
336
|
+
@object = @klass.new
|
337
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
338
|
+
@result = @transition.perform
|
542
339
|
end
|
543
340
|
|
544
|
-
def
|
545
|
-
|
546
|
-
@transition.perform(@record)
|
547
|
-
assert !@invoked
|
341
|
+
def test_should_be_successful
|
342
|
+
assert @result
|
548
343
|
end
|
549
344
|
|
550
|
-
def
|
551
|
-
|
552
|
-
@transition.perform(@record)
|
553
|
-
assert @invoked
|
345
|
+
def test_should_change_current_state
|
346
|
+
assert_equal 'on', @object.state
|
554
347
|
end
|
555
348
|
|
556
|
-
def
|
557
|
-
|
558
|
-
@transition.perform(@record)
|
559
|
-
assert !@invoked
|
349
|
+
def test_should_run_before_callbacks
|
350
|
+
assert_equal 1, @before_count
|
560
351
|
end
|
561
352
|
|
562
|
-
def
|
563
|
-
|
564
|
-
Switch.before_transition_state lambda {|record| @invoked = true}, :from => 'off'
|
565
|
-
@transition.perform(@record)
|
566
|
-
assert @invoked
|
353
|
+
def test_should_not_run_further_after_callbacks
|
354
|
+
assert_equal 1, @after_count
|
567
355
|
end
|
568
356
|
|
569
|
-
def
|
570
|
-
|
571
|
-
@before_transition_state_callbacks = nil
|
572
|
-
@after_transition_state_callbacks = nil
|
573
|
-
end
|
357
|
+
def test_should_not_cancel_the_transaction
|
358
|
+
assert !@klass.cancelled_transaction
|
574
359
|
end
|
575
360
|
end
|
576
361
|
|
577
|
-
class
|
362
|
+
class TransitionWithFailedActionTest < Test::Unit::TestCase
|
578
363
|
def setup
|
579
|
-
@
|
580
|
-
|
581
|
-
|
582
|
-
|
364
|
+
@klass = Class.new do
|
365
|
+
class << self; attr_accessor :cancelled_transaction; end
|
366
|
+
attr_reader :saved
|
367
|
+
|
368
|
+
def save
|
369
|
+
false
|
370
|
+
end
|
371
|
+
end
|
372
|
+
@before_count = 0
|
373
|
+
@after_count = 0
|
583
374
|
|
584
|
-
|
585
|
-
|
375
|
+
@machine = StateMachine::Machine.new(@klass, :action => :save)
|
376
|
+
class << @machine
|
377
|
+
def within_transaction(object)
|
378
|
+
owner_class.cancelled_transaction = yield == false
|
379
|
+
end
|
380
|
+
end
|
381
|
+
@machine.before_transition lambda {@before_count += 1}
|
382
|
+
@machine.after_transition lambda {@after_count += 1}
|
383
|
+
@object = @klass.new
|
384
|
+
@transition = StateMachine::Transition.new(@object, @machine, 'turn_on', 'off', 'on')
|
385
|
+
@result = @transition.perform
|
586
386
|
end
|
587
387
|
|
588
|
-
def
|
589
|
-
|
590
|
-
|
591
|
-
expected = [
|
592
|
-
['before_turn_on', @record, 'off', 'on'],
|
593
|
-
['before_transition', @record, 'state', 'turn_on', 'off', 'on'],
|
594
|
-
['after_turn_on', @record, 'off', 'on'],
|
595
|
-
['after_transition', @record, 'state', 'turn_on', 'off', 'on']
|
596
|
-
]
|
597
|
-
|
598
|
-
assert_equal expected, SwitchObserver.notifications
|
388
|
+
def test_should_not_be_successful
|
389
|
+
assert !@result
|
599
390
|
end
|
600
391
|
|
601
|
-
def
|
602
|
-
|
603
|
-
@transition.perform(@record)
|
604
|
-
|
605
|
-
expected = [
|
606
|
-
['before_turn_on', @record, 'off', 'on'],
|
607
|
-
['before_transition', @record, 'state', 'turn_on', 'off', 'on']
|
608
|
-
]
|
609
|
-
|
610
|
-
assert_equal expected, SwitchObserver.notifications
|
392
|
+
def test_should_change_current_state
|
393
|
+
assert_equal 'on', @object.state
|
611
394
|
end
|
612
395
|
|
613
|
-
def
|
614
|
-
|
615
|
-
@transition.perform(@record)
|
616
|
-
|
617
|
-
expected = [
|
618
|
-
['before_turn_on', @record, 'off', 'on'],
|
619
|
-
['before_transition', @record, 'state', 'turn_on', 'off', 'on'],
|
620
|
-
['after_turn_on', @record, 'off', 'on'],
|
621
|
-
['after_transition', @record, 'state', 'turn_on', 'off', 'on']
|
622
|
-
]
|
623
|
-
|
624
|
-
assert_equal expected, SwitchObserver.notifications
|
396
|
+
def test_should_run_before_callbacks
|
397
|
+
assert_equal 1, @before_count
|
625
398
|
end
|
626
399
|
|
627
|
-
def
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
400
|
+
def test_should_run_after_callbacks
|
401
|
+
assert_equal 1, @after_count
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_should_cancel_the_transaction
|
405
|
+
assert @klass.cancelled_transaction
|
632
406
|
end
|
633
407
|
end
|