spree-state_machine 2.0.0.beta1
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +12 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +502 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +1246 -0
- data/Rakefile +20 -0
- data/examples/AutoShop_state.png +0 -0
- data/examples/Car_state.png +0 -0
- data/examples/Gemfile +5 -0
- data/examples/Gemfile.lock +14 -0
- data/examples/TrafficLight_state.png +0 -0
- data/examples/Vehicle_state.png +0 -0
- data/examples/auto_shop.rb +13 -0
- data/examples/car.rb +21 -0
- data/examples/doc/AutoShop.html +2856 -0
- data/examples/doc/AutoShop_state.png +0 -0
- data/examples/doc/Car.html +919 -0
- data/examples/doc/Car_state.png +0 -0
- data/examples/doc/TrafficLight.html +2230 -0
- data/examples/doc/TrafficLight_state.png +0 -0
- data/examples/doc/Vehicle.html +7921 -0
- data/examples/doc/Vehicle_state.png +0 -0
- data/examples/doc/_index.html +136 -0
- data/examples/doc/class_list.html +47 -0
- data/examples/doc/css/common.css +1 -0
- data/examples/doc/css/full_list.css +55 -0
- data/examples/doc/css/style.css +322 -0
- data/examples/doc/file_list.html +46 -0
- data/examples/doc/frames.html +13 -0
- data/examples/doc/index.html +136 -0
- data/examples/doc/js/app.js +205 -0
- data/examples/doc/js/full_list.js +173 -0
- data/examples/doc/js/jquery.js +16 -0
- data/examples/doc/method_list.html +734 -0
- data/examples/doc/top-level-namespace.html +105 -0
- data/examples/merb-rest/controller.rb +51 -0
- data/examples/merb-rest/model.rb +28 -0
- data/examples/merb-rest/view_edit.html.erb +24 -0
- data/examples/merb-rest/view_index.html.erb +23 -0
- data/examples/merb-rest/view_new.html.erb +13 -0
- data/examples/merb-rest/view_show.html.erb +17 -0
- data/examples/rails-rest/controller.rb +43 -0
- data/examples/rails-rest/migration.rb +7 -0
- data/examples/rails-rest/model.rb +23 -0
- data/examples/rails-rest/view__form.html.erb +34 -0
- data/examples/rails-rest/view_edit.html.erb +6 -0
- data/examples/rails-rest/view_index.html.erb +25 -0
- data/examples/rails-rest/view_new.html.erb +5 -0
- data/examples/rails-rest/view_show.html.erb +19 -0
- data/examples/traffic_light.rb +9 -0
- data/examples/vehicle.rb +33 -0
- data/lib/state_machine/assertions.rb +36 -0
- data/lib/state_machine/branch.rb +225 -0
- data/lib/state_machine/callback.rb +236 -0
- data/lib/state_machine/core.rb +7 -0
- data/lib/state_machine/core_ext/class/state_machine.rb +5 -0
- data/lib/state_machine/core_ext.rb +2 -0
- data/lib/state_machine/error.rb +13 -0
- data/lib/state_machine/eval_helpers.rb +87 -0
- data/lib/state_machine/event.rb +257 -0
- data/lib/state_machine/event_collection.rb +141 -0
- data/lib/state_machine/extensions.rb +149 -0
- data/lib/state_machine/graph.rb +92 -0
- data/lib/state_machine/helper_module.rb +17 -0
- data/lib/state_machine/initializers/rails.rb +25 -0
- data/lib/state_machine/initializers.rb +4 -0
- data/lib/state_machine/integrations/active_model/locale.rb +11 -0
- data/lib/state_machine/integrations/active_model/observer.rb +33 -0
- data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
- data/lib/state_machine/integrations/active_model/versions.rb +31 -0
- data/lib/state_machine/integrations/active_model.rb +585 -0
- data/lib/state_machine/integrations/active_record/locale.rb +20 -0
- data/lib/state_machine/integrations/active_record/versions.rb +123 -0
- data/lib/state_machine/integrations/active_record.rb +525 -0
- data/lib/state_machine/integrations/base.rb +100 -0
- data/lib/state_machine/integrations.rb +121 -0
- data/lib/state_machine/machine.rb +2287 -0
- data/lib/state_machine/machine_collection.rb +74 -0
- data/lib/state_machine/macro_methods.rb +522 -0
- data/lib/state_machine/matcher.rb +123 -0
- data/lib/state_machine/matcher_helpers.rb +54 -0
- data/lib/state_machine/node_collection.rb +222 -0
- data/lib/state_machine/path.rb +120 -0
- data/lib/state_machine/path_collection.rb +90 -0
- data/lib/state_machine/state.rb +297 -0
- data/lib/state_machine/state_collection.rb +112 -0
- data/lib/state_machine/state_context.rb +138 -0
- data/lib/state_machine/transition.rb +470 -0
- data/lib/state_machine/transition_collection.rb +245 -0
- data/lib/state_machine/version.rb +3 -0
- data/lib/state_machine/yard/handlers/base.rb +32 -0
- data/lib/state_machine/yard/handlers/event.rb +25 -0
- data/lib/state_machine/yard/handlers/machine.rb +344 -0
- data/lib/state_machine/yard/handlers/state.rb +25 -0
- data/lib/state_machine/yard/handlers/transition.rb +47 -0
- data/lib/state_machine/yard/handlers.rb +12 -0
- data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
- data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
- data/lib/state_machine/yard/templates.rb +3 -0
- data/lib/state_machine/yard.rb +8 -0
- data/lib/state_machine.rb +8 -0
- data/lib/yard-state_machine.rb +2 -0
- data/state_machine.gemspec +22 -0
- data/test/files/en.yml +17 -0
- data/test/files/switch.rb +15 -0
- data/test/functional/state_machine_test.rb +1066 -0
- data/test/test_helper.rb +7 -0
- data/test/unit/assertions_test.rb +40 -0
- data/test/unit/branch_test.rb +969 -0
- data/test/unit/callback_test.rb +704 -0
- data/test/unit/error_test.rb +43 -0
- data/test/unit/eval_helpers_test.rb +270 -0
- data/test/unit/event_collection_test.rb +398 -0
- data/test/unit/event_test.rb +1196 -0
- data/test/unit/graph_test.rb +98 -0
- data/test/unit/helper_module_test.rb +17 -0
- data/test/unit/integrations/active_model_test.rb +1245 -0
- data/test/unit/integrations/active_record_test.rb +2551 -0
- data/test/unit/integrations/base_test.rb +104 -0
- data/test/unit/integrations_test.rb +71 -0
- data/test/unit/invalid_event_test.rb +20 -0
- data/test/unit/invalid_parallel_transition_test.rb +18 -0
- data/test/unit/invalid_transition_test.rb +115 -0
- data/test/unit/machine_collection_test.rb +603 -0
- data/test/unit/machine_test.rb +3395 -0
- data/test/unit/matcher_helpers_test.rb +37 -0
- data/test/unit/matcher_test.rb +155 -0
- data/test/unit/node_collection_test.rb +362 -0
- data/test/unit/path_collection_test.rb +266 -0
- data/test/unit/path_test.rb +485 -0
- data/test/unit/state_collection_test.rb +352 -0
- data/test/unit/state_context_test.rb +441 -0
- data/test/unit/state_machine_test.rb +31 -0
- data/test/unit/state_test.rb +1101 -0
- data/test/unit/transition_collection_test.rb +2168 -0
- data/test/unit/transition_test.rb +1558 -0
- metadata +264 -0
@@ -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
|
@@ -0,0 +1,270 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class EvalHelpersBaseTest < Test::Unit::TestCase
|
4
|
+
include StateMachine::EvalHelpers
|
5
|
+
|
6
|
+
def default_test
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class EvalHelpersTest < EvalHelpersBaseTest
|
11
|
+
def setup
|
12
|
+
@object = Object.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_should_raise_exception_if_method_is_not_symbol_string_or_proc
|
16
|
+
exception = assert_raise(ArgumentError) { evaluate_method(@object, 1) }
|
17
|
+
assert_match(/Methods must/, exception.message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class EvalHelpersSymbolTest < EvalHelpersBaseTest
|
22
|
+
def setup
|
23
|
+
class << (@object = Object.new)
|
24
|
+
def callback
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_call_method_on_object_with_no_arguments
|
31
|
+
assert_equal true, evaluate_method(@object, :callback, 1, 2, 3)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class EvalHelpersSymbolProtectedTest < EvalHelpersBaseTest
|
36
|
+
def setup
|
37
|
+
class << (@object = Object.new)
|
38
|
+
protected
|
39
|
+
def callback
|
40
|
+
true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_call_method_on_object_with_no_arguments
|
46
|
+
assert_equal true, evaluate_method(@object, :callback, 1, 2, 3)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class EvalHelpersSymbolPrivateTest < EvalHelpersBaseTest
|
51
|
+
def setup
|
52
|
+
class << (@object = Object.new)
|
53
|
+
private
|
54
|
+
def callback
|
55
|
+
true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_should_call_method_on_object_with_no_arguments
|
61
|
+
assert_equal true, evaluate_method(@object, :callback, 1, 2, 3)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class EvalHelpersSymbolWithArgumentsTest < EvalHelpersBaseTest
|
66
|
+
def setup
|
67
|
+
class << (@object = Object.new)
|
68
|
+
def callback(*args)
|
69
|
+
args
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_should_call_method_with_all_arguments
|
75
|
+
assert_equal [1, 2, 3], evaluate_method(@object, :callback, 1, 2, 3)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class EvalHelpersSymbolWithBlockTest < EvalHelpersBaseTest
|
80
|
+
def setup
|
81
|
+
class << (@object = Object.new)
|
82
|
+
def callback
|
83
|
+
yield
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_should_call_method_on_object_with_block
|
89
|
+
assert_equal true, evaluate_method(@object, :callback) { true }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class EvalHelpersSymbolWithArgumentsAndBlockTest < EvalHelpersBaseTest
|
94
|
+
def setup
|
95
|
+
class << (@object = Object.new)
|
96
|
+
def callback(*args)
|
97
|
+
args << yield
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_should_call_method_on_object_with_all_arguments_and_block
|
103
|
+
assert_equal [1, 2, 3, true], evaluate_method(@object, :callback, 1, 2, 3) { true }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class EvalHelpersSymbolTaintedMethodTest < EvalHelpersBaseTest
|
108
|
+
def setup
|
109
|
+
class << (@object = Object.new)
|
110
|
+
def callback
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
taint
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_should_not_raise_security_error
|
119
|
+
assert_nothing_raised { evaluate_method(@object, :callback, 1, 2, 3) }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class EvalHelpersSymbolMethodMissingTest < EvalHelpersBaseTest
|
124
|
+
def setup
|
125
|
+
class << (@object = Object.new)
|
126
|
+
def method_missing(symbol, *args)
|
127
|
+
send("method_missing_#{symbol}", *args)
|
128
|
+
end
|
129
|
+
|
130
|
+
def method_missing_callback(*args)
|
131
|
+
args
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_should_call_dynamic_method_with_all_arguments
|
137
|
+
assert_equal [1, 2, 3], evaluate_method(@object, :callback, 1, 2, 3)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class EvalHelpersStringTest < EvalHelpersBaseTest
|
142
|
+
def setup
|
143
|
+
@object = Object.new
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_should_evaluate_string
|
147
|
+
assert_equal 1, evaluate_method(@object, '1')
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_should_evaluate_string_within_object_context
|
151
|
+
@object.instance_variable_set('@value', 1)
|
152
|
+
assert_equal 1, evaluate_method(@object, '@value')
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_should_ignore_additional_arguments
|
156
|
+
assert_equal 1, evaluate_method(@object, '1', 2, 3, 4)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class EvalHelpersStringWithBlockTest < EvalHelpersBaseTest
|
161
|
+
def setup
|
162
|
+
@object = Object.new
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_should_call_method_on_object_with_block
|
166
|
+
assert_equal 1, evaluate_method(@object, 'yield') { 1 }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class EvalHelpersProcTest < EvalHelpersBaseTest
|
171
|
+
def setup
|
172
|
+
@object = Object.new
|
173
|
+
@proc = lambda {|obj| obj}
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_should_call_proc_with_object_as_argument
|
177
|
+
assert_equal @object, evaluate_method(@object, @proc, 1, 2, 3)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class EvalHelpersProcWithoutArgumentsTest < EvalHelpersBaseTest
|
182
|
+
def setup
|
183
|
+
@object = Object.new
|
184
|
+
@proc = lambda {|*args| args}
|
185
|
+
class << @proc
|
186
|
+
def arity
|
187
|
+
0
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_should_call_proc_with_no_arguments
|
193
|
+
assert_equal [], evaluate_method(@object, @proc, 1, 2, 3)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class EvalHelpersProcWithArgumentsTest < EvalHelpersBaseTest
|
198
|
+
def setup
|
199
|
+
@object = Object.new
|
200
|
+
@proc = lambda {|*args| args}
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_should_call_method_with_all_arguments
|
204
|
+
assert_equal [@object, 1, 2, 3], evaluate_method(@object, @proc, 1, 2, 3)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
class EvalHelpersProcWithBlockTest < EvalHelpersBaseTest
|
209
|
+
def setup
|
210
|
+
@object = Object.new
|
211
|
+
@proc = lambda {|obj, block| block.call}
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_should_call_method_on_object_with_block
|
215
|
+
assert_equal true, evaluate_method(@object, @proc, 1, 2, 3) { true }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class EvalHelpersProcWithBlockWithoutArgumentsTest < EvalHelpersBaseTest
|
220
|
+
def setup
|
221
|
+
@object = Object.new
|
222
|
+
@proc = lambda {|*args| args}
|
223
|
+
class << @proc
|
224
|
+
def arity
|
225
|
+
0
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_should_call_proc_without_arguments
|
231
|
+
block = lambda { true }
|
232
|
+
assert_equal [], evaluate_method(@object, @proc, 1, 2, 3, &block)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class EvalHelpersProcWithBlockWithoutObjectTest < EvalHelpersBaseTest
|
237
|
+
def setup
|
238
|
+
@object = Object.new
|
239
|
+
@proc = lambda {|block| [block]}
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_should_call_proc_with_block_only
|
243
|
+
block = lambda { true }
|
244
|
+
assert_equal [block], evaluate_method(@object, @proc, 1, 2, 3, &block)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
class EvalHelpersProcBlockAndImplicitArgumentsTest < EvalHelpersBaseTest
|
249
|
+
def setup
|
250
|
+
@object = Object.new
|
251
|
+
@proc = lambda {|*args| args}
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_should_call_method_on_object_with_all_arguments_and_block
|
255
|
+
block = lambda { true }
|
256
|
+
assert_equal [@object, 1, 2, 3, block], evaluate_method(@object, @proc, 1, 2, 3, &block)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class EvalHelpersProcBlockAndExplicitArgumentsTest < EvalHelpersBaseTest
|
261
|
+
def setup
|
262
|
+
@object = Object.new
|
263
|
+
@proc = lambda {|object, arg1, arg2, arg3, block| [object, arg1, arg2, arg3, block]}
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_should_call_method_on_object_with_all_arguments_and_block
|
267
|
+
block = lambda { true }
|
268
|
+
assert_equal [@object, 1, 2, 3, block], evaluate_method(@object, @proc, 1, 2, 3, &block)
|
269
|
+
end
|
270
|
+
end
|
@@ -0,0 +1,398 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class EventCollectionByDefaultTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@klass = Class.new
|
6
|
+
@machine = StateMachine::Machine.new(@klass)
|
7
|
+
@events = StateMachine::EventCollection.new(@machine)
|
8
|
+
@object = @klass.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_should_not_have_any_nodes
|
12
|
+
assert_equal 0, @events.length
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_should_have_a_machine
|
16
|
+
assert_equal @machine, @events.machine
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_not_have_any_valid_events_for_an_object
|
20
|
+
assert @events.valid_for(@object).empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_should_not_have_any_transitions_for_an_object
|
24
|
+
assert @events.transitions_for(@object).empty?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class EventCollectionTest < Test::Unit::TestCase
|
29
|
+
def setup
|
30
|
+
machine = StateMachine::Machine.new(Class.new, :namespace => 'alarm')
|
31
|
+
@events = StateMachine::EventCollection.new(machine)
|
32
|
+
|
33
|
+
@events << @open = StateMachine::Event.new(machine, :enable)
|
34
|
+
machine.events.concat(@events)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_index_by_name
|
38
|
+
assert_equal @open, @events[:enable, :name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_should_index_by_name_by_default
|
42
|
+
assert_equal @open, @events[:enable]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_index_by_string_name
|
46
|
+
assert_equal @open, @events['enable']
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_should_index_by_qualified_name
|
50
|
+
assert_equal @open, @events[:enable_alarm, :qualified_name]
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_index_by_string_qualified_name
|
54
|
+
assert_equal @open, @events['enable_alarm', :qualified_name]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class EventStringCollectionTest < Test::Unit::TestCase
|
59
|
+
def setup
|
60
|
+
machine = StateMachine::Machine.new(Class.new, :namespace => 'alarm')
|
61
|
+
@events = StateMachine::EventCollection.new(machine)
|
62
|
+
|
63
|
+
@events << @open = StateMachine::Event.new(machine, 'enable')
|
64
|
+
machine.events.concat(@events)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_should_index_by_name
|
68
|
+
assert_equal @open, @events['enable', :name]
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_should_index_by_name_by_default
|
72
|
+
assert_equal @open, @events['enable']
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_index_by_symbol_name
|
76
|
+
assert_equal @open, @events[:enable]
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_should_index_by_qualified_name
|
80
|
+
assert_equal @open, @events['enable_alarm', :qualified_name]
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_should_index_by_symbol_qualified_name
|
84
|
+
assert_equal @open, @events[:enable_alarm, :qualified_name]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class EventCollectionWithEventsWithTransitionsTest < Test::Unit::TestCase
|
89
|
+
def setup
|
90
|
+
@klass = Class.new
|
91
|
+
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
92
|
+
@events = StateMachine::EventCollection.new(@machine)
|
93
|
+
|
94
|
+
@machine.state :idling, :first_gear
|
95
|
+
|
96
|
+
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
97
|
+
@ignite.transition :parked => :idling
|
98
|
+
|
99
|
+
@events << @park = StateMachine::Event.new(@machine, :park)
|
100
|
+
@park.transition :idling => :parked
|
101
|
+
|
102
|
+
@events << @shift_up = StateMachine::Event.new(@machine, :shift_up)
|
103
|
+
@shift_up.transition :parked => :first_gear
|
104
|
+
@shift_up.transition :idling => :first_gear, :if => lambda{false}
|
105
|
+
|
106
|
+
@machine.events.concat(@events)
|
107
|
+
|
108
|
+
@object = @klass.new
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_should_find_valid_events_based_on_current_state
|
112
|
+
assert_equal [@ignite, @shift_up], @events.valid_for(@object)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_should_filter_valid_events_by_from_state
|
116
|
+
assert_equal [@park], @events.valid_for(@object, :from => :idling)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_should_filter_valid_events_by_to_state
|
120
|
+
assert_equal [@shift_up], @events.valid_for(@object, :to => :first_gear)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_should_filter_valid_events_by_event
|
124
|
+
assert_equal [@ignite], @events.valid_for(@object, :on => :ignite)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_should_filter_valid_events_by_multiple_requirements
|
128
|
+
assert_equal [], @events.valid_for(@object, :from => :idling, :to => :first_gear)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_should_allow_finding_valid_events_without_guards
|
132
|
+
assert_equal [@shift_up], @events.valid_for(@object, :from => :idling, :to => :first_gear, :guard => false)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_should_find_valid_transitions_based_on_current_state
|
136
|
+
assert_equal [
|
137
|
+
StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling),
|
138
|
+
StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :first_gear)
|
139
|
+
], @events.transitions_for(@object)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_should_filter_valid_transitions_by_from_state
|
143
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :park, :idling, :parked)], @events.transitions_for(@object, :from => :idling)
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_should_filter_valid_transitions_by_to_state
|
147
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :shift_up, :parked, :first_gear)], @events.transitions_for(@object, :to => :first_gear)
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_should_filter_valid_transitions_by_event
|
151
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)], @events.transitions_for(@object, :on => :ignite)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_should_filter_valid_transitions_by_multiple_requirements
|
155
|
+
assert_equal [], @events.transitions_for(@object, :from => :idling, :to => :first_gear)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_should_allow_finding_valid_transitions_without_guards
|
159
|
+
assert_equal [StateMachine::Transition.new(@object, @machine, :shift_up, :idling, :first_gear)], @events.transitions_for(@object, :from => :idling, :to => :first_gear, :guard => false)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class EventCollectionWithMultipleEventsTest < Test::Unit::TestCase
|
164
|
+
def setup
|
165
|
+
@klass = Class.new
|
166
|
+
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
167
|
+
@events = StateMachine::EventCollection.new(@machine)
|
168
|
+
|
169
|
+
@machine.state :first_gear
|
170
|
+
@park, @shift_down = @machine.event :park, :shift_down
|
171
|
+
|
172
|
+
@events << @park
|
173
|
+
@park.transition :first_gear => :parked
|
174
|
+
|
175
|
+
@events << @shift_down
|
176
|
+
@shift_down.transition :first_gear => :parked
|
177
|
+
|
178
|
+
@machine.events.concat(@events)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_should_only_include_all_valid_events_for_an_object
|
182
|
+
object = @klass.new
|
183
|
+
object.state = 'first_gear'
|
184
|
+
assert_equal [@park, @shift_down], @events.valid_for(object)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class EventCollectionWithoutMachineActionTest < Test::Unit::TestCase
|
189
|
+
def setup
|
190
|
+
@klass = Class.new
|
191
|
+
@machine = StateMachine::Machine.new(@klass, :initial => :parked)
|
192
|
+
@events = StateMachine::EventCollection.new(@machine)
|
193
|
+
@events << StateMachine::Event.new(@machine, :ignite)
|
194
|
+
@machine.events.concat(@events)
|
195
|
+
|
196
|
+
@object = @klass.new
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_should_not_have_an_attribute_transition
|
200
|
+
assert_nil @events.attribute_transition_for(@object)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class EventCollectionAttributeWithMachineActionTest < Test::Unit::TestCase
|
205
|
+
def setup
|
206
|
+
@klass = Class.new do
|
207
|
+
def save
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
@machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
|
212
|
+
@events = StateMachine::EventCollection.new(@machine)
|
213
|
+
|
214
|
+
@machine.state :parked, :idling
|
215
|
+
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
216
|
+
@machine.events.concat(@events)
|
217
|
+
|
218
|
+
@object = @klass.new
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_should_not_have_transition_if_nil
|
222
|
+
@object.state_event = nil
|
223
|
+
assert_nil @events.attribute_transition_for(@object)
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_should_not_have_transition_if_empty
|
227
|
+
@object.state_event = ''
|
228
|
+
assert_nil @events.attribute_transition_for(@object)
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_should_have_invalid_transition_if_invalid_event_specified
|
232
|
+
@object.state_event = 'invalid'
|
233
|
+
assert_equal false, @events.attribute_transition_for(@object)
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_should_have_invalid_transition_if_event_cannot_be_fired
|
237
|
+
@object.state_event = 'ignite'
|
238
|
+
assert_equal false, @events.attribute_transition_for(@object)
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_should_have_valid_transition_if_event_can_be_fired
|
242
|
+
@ignite.transition :parked => :idling
|
243
|
+
@object.state_event = 'ignite'
|
244
|
+
|
245
|
+
assert_instance_of StateMachine::Transition, @events.attribute_transition_for(@object)
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_should_have_valid_transition_if_already_defined_in_transition_cache
|
249
|
+
@ignite.transition :parked => :idling
|
250
|
+
@object.state_event = nil
|
251
|
+
@object.send(:state_event_transition=, transition = @ignite.transition_for(@object))
|
252
|
+
|
253
|
+
assert_equal transition, @events.attribute_transition_for(@object)
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_should_use_transition_cache_if_both_event_and_transition_are_present
|
257
|
+
@ignite.transition :parked => :idling
|
258
|
+
@object.state_event = 'ignite'
|
259
|
+
@object.send(:state_event_transition=, transition = @ignite.transition_for(@object))
|
260
|
+
|
261
|
+
assert_equal transition, @events.attribute_transition_for(@object)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class EventCollectionAttributeWithNamespacedMachineTest < Test::Unit::TestCase
|
266
|
+
def setup
|
267
|
+
@klass = Class.new do
|
268
|
+
def save
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
@machine = StateMachine::Machine.new(@klass, :namespace => 'alarm', :initial => :active, :action => :save)
|
273
|
+
@events = StateMachine::EventCollection.new(@machine)
|
274
|
+
|
275
|
+
@machine.state :active, :off
|
276
|
+
@events << @disable = StateMachine::Event.new(@machine, :disable)
|
277
|
+
@machine.events.concat(@events)
|
278
|
+
|
279
|
+
@object = @klass.new
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_should_not_have_transition_if_nil
|
283
|
+
@object.state_event = nil
|
284
|
+
assert_nil @events.attribute_transition_for(@object)
|
285
|
+
end
|
286
|
+
|
287
|
+
def test_should_have_invalid_transition_if_event_cannot_be_fired
|
288
|
+
@object.state_event = 'disable'
|
289
|
+
assert_equal false, @events.attribute_transition_for(@object)
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_should_have_valid_transition_if_event_can_be_fired
|
293
|
+
@disable.transition :active => :off
|
294
|
+
@object.state_event = 'disable'
|
295
|
+
|
296
|
+
assert_instance_of StateMachine::Transition, @events.attribute_transition_for(@object)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
class EventCollectionWithValidationsTest < Test::Unit::TestCase
|
301
|
+
def setup
|
302
|
+
StateMachine::Integrations.const_set('Custom', Module.new do
|
303
|
+
include StateMachine::Integrations::Base
|
304
|
+
|
305
|
+
def invalidate(object, attribute, message, values = [])
|
306
|
+
(object.errors ||= []) << generate_message(message, values)
|
307
|
+
end
|
308
|
+
|
309
|
+
def reset(object)
|
310
|
+
object.errors = []
|
311
|
+
end
|
312
|
+
end)
|
313
|
+
|
314
|
+
@klass = Class.new do
|
315
|
+
attr_accessor :errors
|
316
|
+
|
317
|
+
def initialize
|
318
|
+
@errors = []
|
319
|
+
super
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
@machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save, :integration => :custom)
|
324
|
+
@events = StateMachine::EventCollection.new(@machine)
|
325
|
+
|
326
|
+
@parked, @idling = @machine.state :parked, :idling
|
327
|
+
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
328
|
+
@machine.events.concat(@events)
|
329
|
+
|
330
|
+
@object = @klass.new
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_should_invalidate_if_invalid_event_specified
|
334
|
+
@object.state_event = 'invalid'
|
335
|
+
@events.attribute_transition_for(@object, true)
|
336
|
+
|
337
|
+
assert_equal ['is invalid'], @object.errors
|
338
|
+
end
|
339
|
+
|
340
|
+
def test_should_invalidate_if_event_cannot_be_fired
|
341
|
+
@object.state = 'idling'
|
342
|
+
@object.state_event = 'ignite'
|
343
|
+
@events.attribute_transition_for(@object, true)
|
344
|
+
|
345
|
+
assert_equal ['cannot transition when idling'], @object.errors
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_should_invalidate_with_human_name_if_invalid_event_specified
|
349
|
+
@idling.human_name = 'waiting'
|
350
|
+
@object.state = 'idling'
|
351
|
+
@object.state_event = 'ignite'
|
352
|
+
@events.attribute_transition_for(@object, true)
|
353
|
+
|
354
|
+
assert_equal ['cannot transition when waiting'], @object.errors
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_should_not_invalidate_event_can_be_fired
|
358
|
+
@ignite.transition :parked => :idling
|
359
|
+
@object.state_event = 'ignite'
|
360
|
+
@events.attribute_transition_for(@object, true)
|
361
|
+
|
362
|
+
assert_equal [], @object.errors
|
363
|
+
end
|
364
|
+
|
365
|
+
def teardown
|
366
|
+
StateMachine::Integrations.send(:remove_const, 'Custom')
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
class EventCollectionWithCustomMachineAttributeTest < Test::Unit::TestCase
|
371
|
+
def setup
|
372
|
+
@klass = Class.new do
|
373
|
+
def save
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
@machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id, :initial => :parked, :action => :save)
|
378
|
+
@events = StateMachine::EventCollection.new(@machine)
|
379
|
+
|
380
|
+
@machine.state :parked, :idling
|
381
|
+
@events << @ignite = StateMachine::Event.new(@machine, :ignite)
|
382
|
+
@machine.events.concat(@events)
|
383
|
+
|
384
|
+
@object = @klass.new
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_should_not_have_transition_if_nil
|
388
|
+
@object.state_event = nil
|
389
|
+
assert_nil @events.attribute_transition_for(@object)
|
390
|
+
end
|
391
|
+
|
392
|
+
def test_should_have_valid_transition_if_event_can_be_fired
|
393
|
+
@ignite.transition :parked => :idling
|
394
|
+
@object.state_event = 'ignite'
|
395
|
+
|
396
|
+
assert_instance_of StateMachine::Transition, @events.attribute_transition_for(@object)
|
397
|
+
end
|
398
|
+
end
|