state_machine 0.5.2 → 0.6.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.
@@ -10,9 +10,8 @@ class CallbackTest < Test::Unit::TestCase
10
10
  assert_nothing_raised { StateMachine::Callback.new(:do => :run) }
11
11
  end
12
12
 
13
- def test_should_raise_exception_if_invalid_option_specified
14
- exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:do => :run, :invalid => true) }
15
- assert_match 'Invalid key(s): invalid', exception.message
13
+ def test_should_not_raise_exception_if_implicit_option_specified
14
+ assert_nothing_raised { StateMachine::Callback.new(:do => :run, :invalid => true) }
16
15
  end
17
16
 
18
17
  def test_should_not_bind_to_objects
@@ -33,8 +32,8 @@ class CallbackByDefaultTest < Test::Unit::TestCase
33
32
 
34
33
  def test_should_have_a_guard_with_all_matcher_requirements
35
34
  assert_equal StateMachine::AllMatcher.instance, @callback.guard.event_requirement
36
- assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirement[:from]
37
- assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirement[:to]
35
+ assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:from]
36
+ assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:to]
38
37
  end
39
38
 
40
39
  def test_should_not_bind_to_the_object
@@ -57,7 +56,7 @@ class CallbackWithOnlyMethodTest < Test::Unit::TestCase
57
56
  end
58
57
  end
59
58
 
60
- class CallbackWithRequirementsTest < Test::Unit::TestCase
59
+ class CallbackWithExplicitRequirementsTest < Test::Unit::TestCase
61
60
  def setup
62
61
  @object = Object.new
63
62
  @callback = StateMachine::Callback.new(:from => :parked, :to => :idling, :on => :ignite, :do => lambda {true})
@@ -88,6 +87,37 @@ class CallbackWithRequirementsTest < Test::Unit::TestCase
88
87
  end
89
88
  end
90
89
 
90
+ class CallbackWithImplicitRequirementsTest < Test::Unit::TestCase
91
+ def setup
92
+ @object = Object.new
93
+ @callback = StateMachine::Callback.new(:parked => :idling, :on => :ignite, :do => lambda {true})
94
+ end
95
+
96
+ def test_should_call_with_empty_context
97
+ assert @callback.call(@object, {})
98
+ end
99
+
100
+ def test_should_not_call_if_from_not_included
101
+ assert !@callback.call(@object, :from => :idling)
102
+ end
103
+
104
+ def test_should_not_call_if_to_not_included
105
+ assert !@callback.call(@object, :to => :parked)
106
+ end
107
+
108
+ def test_should_not_call_if_on_not_included
109
+ assert !@callback.call(@object, :on => :park)
110
+ end
111
+
112
+ def test_should_call_if_all_requirements_met
113
+ assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
114
+ end
115
+
116
+ def test_should_include_in_known_states
117
+ assert_equal [:parked, :idling], @callback.known_states
118
+ end
119
+ end
120
+
91
121
  class CallbackWithIfConditionTest < Test::Unit::TestCase
92
122
  def setup
93
123
  @object = Object.new
@@ -0,0 +1,301 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class Validateable
4
+ class << self
5
+ def validate(*args, &block)
6
+ args << block if block_given?
7
+ args
8
+ end
9
+ end
10
+ end
11
+
12
+ class ConditionProxyTest < Test::Unit::TestCase
13
+ def test_should_call_class_with_same_arguments
14
+ options = {}
15
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {})
16
+ validation = condition_proxy.validate(:name, options)
17
+
18
+ assert_equal [:name, options], validation
19
+ end
20
+
21
+ def test_should_pass_block_through_to_class
22
+ options = {}
23
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {})
24
+
25
+ proxy_block = lambda {}
26
+ validation = condition_proxy.validate(:name, options, &proxy_block)
27
+
28
+ assert_equal [:name, options, proxy_block], validation
29
+ end
30
+
31
+ def test_should_pass_object_into_proxy_condition
32
+ condition_args = []
33
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {|*args| condition_args = args})
34
+ validation = condition_proxy.validate(:name)
35
+
36
+ object = Validateable.new
37
+ validation.last[:if].call(object)
38
+
39
+ assert_equal [object], condition_args
40
+ end
41
+
42
+ def test_should_evaluate_symbol_condition
43
+ klass = Class.new(Validateable) do
44
+ attr_accessor :callback_called
45
+
46
+ def callback
47
+ @callback_called = true
48
+ end
49
+ end
50
+
51
+ condition_proxy = StateMachine::ConditionProxy.new(klass, :callback)
52
+ validation = condition_proxy.validate(:name)
53
+
54
+ object = klass.new
55
+ validation.last[:if].call(object)
56
+
57
+ assert object.callback_called
58
+ end
59
+
60
+ def test_should_evaluate_string_condition
61
+ klass = Class.new(Validateable) do
62
+ attr_accessor :callback_called
63
+ end
64
+
65
+ condition_proxy = StateMachine::ConditionProxy.new(klass, '@callback_called = true')
66
+ validation = condition_proxy.validate(:name)
67
+
68
+ object = klass.new
69
+ validation.last[:if].call(object)
70
+
71
+ assert object.callback_called
72
+ end
73
+ end
74
+
75
+ class ConditionProxyWithoutConditionsTest < Test::Unit::TestCase
76
+ def setup
77
+ @proxy_result = nil
78
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {@proxy_result})
79
+
80
+ @object = Validateable.new
81
+ @validation = condition_proxy.validate(:name)
82
+ @options = @validation.last
83
+ end
84
+
85
+ def test_should_have_options_configuration
86
+ assert_instance_of Hash, @options
87
+ end
88
+
89
+ def test_should_have_if_option
90
+ assert_not_nil @options[:if]
91
+ end
92
+
93
+ def test_should_be_false_if_proxy_condition_is_false
94
+ @proxy_result = false
95
+ assert !@options[:if].call(@object)
96
+ end
97
+
98
+ def test_should_be_true_if_proxy_condition_is_true
99
+ @proxy_result = true
100
+ assert @options[:if].call(@object)
101
+ end
102
+
103
+ def test_should_be_true_if_proxy_condition_is_not_true
104
+ @proxy_result = 1
105
+ assert @options[:if].call(@object)
106
+ end
107
+ end
108
+
109
+ class ConditionProxyWithIfConditionTest < Test::Unit::TestCase
110
+ def setup
111
+ @proxy_result = nil
112
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {@proxy_result})
113
+
114
+ @object = Validateable.new
115
+
116
+ @condition_result = nil
117
+ @validation = condition_proxy.validate(:name, :if => lambda {@condition_result})
118
+ @options = @validation.pop
119
+ end
120
+
121
+ def test_should_have_if_option
122
+ assert_not_nil @options[:if]
123
+ end
124
+
125
+ def test_should_be_false_if_proxy_condition_is_false
126
+ @proxy_result = false
127
+ assert !@options[:if].call(@object)
128
+ end
129
+
130
+ def test_should_be_false_if_original_condition_is_false
131
+ @condition_result = false
132
+ assert !@options[:if].call(@object)
133
+ end
134
+
135
+ def test_should_be_true_if_proxy_and_original_condition_are_true
136
+ @proxy_result = true
137
+ @condition_result = true
138
+ assert @options[:if].call(@object)
139
+ end
140
+
141
+ def test_should_evaluate_symbol_condition
142
+ klass = Class.new(Validateable) do
143
+ attr_accessor :callback
144
+ end
145
+
146
+ condition_proxy = StateMachine::ConditionProxy.new(klass, lambda {true})
147
+ validation = condition_proxy.validate(:name, :if => :callback)
148
+ options = validation.last
149
+
150
+ object = klass.new
151
+ object.callback = false
152
+ assert !options[:if].call(object)
153
+
154
+ object.callback = true
155
+ assert options[:if].call(object)
156
+ end
157
+
158
+ def test_should_evaluate_string_condition
159
+ klass = Class.new(Validateable) do
160
+ attr_accessor :callback
161
+ end
162
+
163
+ condition_proxy = StateMachine::ConditionProxy.new(klass, lambda {true})
164
+ validation = condition_proxy.validate(:name, :if => '@callback')
165
+ options = validation.last
166
+
167
+ object = klass.new
168
+ object.callback = false
169
+ assert !options[:if].call(object)
170
+
171
+ object.callback = true
172
+ assert options[:if].call(object)
173
+ end
174
+ end
175
+
176
+ class ConditionProxyWithMultipleIfConditionsTest < Test::Unit::TestCase
177
+ def setup
178
+ @proxy_result = true
179
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {@proxy_result})
180
+
181
+ @object = Validateable.new
182
+
183
+ @first_condition_result = nil
184
+ @second_condition_result = nil
185
+ @validation = condition_proxy.validate(:name, :if => [lambda {@first_condition_result}, lambda {@second_condition_result}])
186
+ @options = @validation.pop
187
+ end
188
+
189
+ def test_should_be_true_if_all_conditions_are_true
190
+ @first_condition_result = true
191
+ @second_condition_result = true
192
+ assert @options[:if].call(@object)
193
+ end
194
+
195
+ def test_should_be_false_if_any_condition_is_false
196
+ @first_condition_result = true
197
+ @second_condition_result = false
198
+ assert !@options[:if].call(@object)
199
+
200
+ @first_condition_result = false
201
+ @second_condition_result = true
202
+ assert !@options[:if].call(@object)
203
+ end
204
+ end
205
+
206
+ class ConditionProxyWithUnlessConditionTest < Test::Unit::TestCase
207
+ def setup
208
+ @proxy_result = nil
209
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {@proxy_result})
210
+
211
+ @object = Validateable.new
212
+
213
+ @condition_result = nil
214
+ @validation = condition_proxy.validate(:name, :unless => lambda {@condition_result})
215
+ @options = @validation.pop
216
+ end
217
+
218
+ def test_should_have_if_option
219
+ assert_not_nil @options[:if]
220
+ end
221
+
222
+ def test_should_be_false_if_proxy_condition_is_false
223
+ @proxy_result = false
224
+ assert !@options[:if].call(@object)
225
+ end
226
+
227
+ def test_should_be_false_if_original_condition_is_true
228
+ @condition_result = true
229
+ assert !@options[:if].call(@object)
230
+ end
231
+
232
+ def test_should_be_true_if_proxy_is_true_and_original_condition_is_false
233
+ @proxy_result = true
234
+ @condition_result = false
235
+ assert @options[:if].call(@object)
236
+ end
237
+
238
+ def test_should_evaluate_symbol_condition
239
+ klass = Class.new(Validateable) do
240
+ attr_accessor :callback
241
+ end
242
+
243
+ condition_proxy = StateMachine::ConditionProxy.new(klass, lambda {true})
244
+ validation = condition_proxy.validate(:name, :unless => :callback)
245
+ options = validation.last
246
+
247
+ object = klass.new
248
+ object.callback = true
249
+ assert !options[:if].call(object)
250
+
251
+ object.callback = false
252
+ assert options[:if].call(object)
253
+ end
254
+
255
+ def test_should_evaluate_string_condition
256
+ klass = Class.new(Validateable) do
257
+ attr_accessor :callback
258
+ end
259
+
260
+ condition_proxy = StateMachine::ConditionProxy.new(klass, lambda {true})
261
+ validation = condition_proxy.validate(:name, :unless => '@callback')
262
+ options = validation.last
263
+
264
+ object = klass.new
265
+ object.callback = true
266
+ assert !options[:if].call(object)
267
+
268
+ object.callback = false
269
+ assert options[:if].call(object)
270
+ end
271
+ end
272
+
273
+ class ConditionProxyWithMultipleUnlessConditionsTest < Test::Unit::TestCase
274
+ def setup
275
+ @proxy_result = true
276
+ condition_proxy = StateMachine::ConditionProxy.new(Validateable, lambda {@proxy_result})
277
+
278
+ @object = Validateable.new
279
+
280
+ @first_condition_result = nil
281
+ @second_condition_result = nil
282
+ @validation = condition_proxy.validate(:name, :unless => [lambda {@first_condition_result}, lambda {@second_condition_result}])
283
+ @options = @validation.pop
284
+ end
285
+
286
+ def test_should_be_true_if_all_conditions_are_false
287
+ @first_condition_result = false
288
+ @second_condition_result = false
289
+ assert @options[:if].call(@object)
290
+ end
291
+
292
+ def test_should_be_false_if_any_condition_is_true
293
+ @first_condition_result = true
294
+ @second_condition_result = false
295
+ assert !@options[:if].call(@object)
296
+
297
+ @first_condition_result = false
298
+ @second_condition_result = true
299
+ assert !@options[:if].call(@object)
300
+ end
301
+ end
@@ -54,7 +54,7 @@ class EventTest < Test::Unit::TestCase
54
54
  def setup
55
55
  @machine = StateMachine::Machine.new(Class.new)
56
56
  @event = StateMachine::Event.new(@machine, :ignite)
57
- @event.transition :to => :idling, :from => :parked
57
+ @event.transition :parked => :idling
58
58
  end
59
59
 
60
60
  def test_should_allow_changing_machine
@@ -63,6 +63,16 @@ class EventTest < Test::Unit::TestCase
63
63
  assert_equal new_machine, @event.machine
64
64
  end
65
65
 
66
+ def test_should_provide_matcher_helpers_during_initialization
67
+ matchers = []
68
+
69
+ @event.instance_eval do
70
+ matchers = [all, any, same]
71
+ end
72
+
73
+ assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
74
+ end
75
+
66
76
  def test_should_use_pretty_inspect
67
77
  assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling]>", @event.inspect
68
78
  end
@@ -99,8 +109,8 @@ class EventTransitionsTest < Test::Unit::TestCase
99
109
  @event = StateMachine::Event.new(@machine, :ignite)
100
110
  end
101
111
 
102
- def test_should_raise_exception_if_invalid_option_specified
103
- assert_raise(ArgumentError) {@event.transition(:invalid => true)}
112
+ def test_should_not_raise_exception_if_implicit_option_specified
113
+ assert_nothing_raised {@event.transition(:invalid => true)}
104
114
  end
105
115
 
106
116
  def test_should_not_allow_on_option
@@ -131,11 +141,11 @@ class EventTransitionsTest < Test::Unit::TestCase
131
141
  end
132
142
 
133
143
  def test_should_allow_transitioning_from_a_single_state
134
- assert @event.transition(:to => :idling, :from => :parked)
144
+ assert @event.transition(:parked => :idling)
135
145
  end
136
146
 
137
147
  def test_should_allow_transitioning_from_multiple_states
138
- assert @event.transition(:to => :idling, :from => [:parked, :idling])
148
+ assert @event.transition([:parked, :idling] => :idling)
139
149
  end
140
150
 
141
151
  def test_should_have_transitions
@@ -196,8 +206,8 @@ class EventWithTransitionsTest < Test::Unit::TestCase
196
206
  @klass = Class.new
197
207
  @machine = StateMachine::Machine.new(@klass)
198
208
  @event = StateMachine::Event.new(@machine, :ignite)
199
- @event.transition(:to => :idling, :from => :parked)
200
- @event.transition(:to => :idling, :except_from => :first_gear)
209
+ @event.transition(:parked => :idling)
210
+ @event.transition(:first_gear => :idling)
201
211
  end
202
212
 
203
213
  def test_should_include_all_transition_states_in_known_states
@@ -206,10 +216,14 @@ class EventWithTransitionsTest < Test::Unit::TestCase
206
216
 
207
217
  def test_should_include_new_transition_states_after_calling_known_states
208
218
  @event.known_states
209
- @event.transition(:to => :idling, :from => :stalled)
219
+ @event.transition(:stalled => :idling)
210
220
 
211
221
  assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states
212
222
  end
223
+
224
+ def test_should_use_pretty_inspect
225
+ assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling, :first_gear => :idling]>", @event.inspect
226
+ end
213
227
  end
214
228
 
215
229
  class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
@@ -219,7 +233,7 @@ class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
219
233
  @machine.state :parked, :idling
220
234
 
221
235
  @event = StateMachine::Event.new(@machine, :ignite)
222
- @event.transition(:to => :idling, :from => :parked)
236
+ @event.transition(:parked => :idling)
223
237
 
224
238
  @object = @klass.new
225
239
  @object.state = 'idling'
@@ -255,7 +269,7 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
255
269
  @machine.state :parked, :idling
256
270
 
257
271
  @event = StateMachine::Event.new(@machine, :ignite)
258
- @event.transition(:to => :idling, :from => :parked, :if => lambda {false})
272
+ @event.transition(:parked => :idling, :if => lambda {false})
259
273
 
260
274
  @object = @klass.new
261
275
  @object.state = 'parked'
@@ -286,7 +300,7 @@ class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
286
300
  @machine.state :parked, :idling
287
301
 
288
302
  @event = StateMachine::Event.new(@machine, :ignite)
289
- @event.transition(:to => :idling, :from => :parked)
303
+ @event.transition(:parked => :idling)
290
304
 
291
305
  @object = @klass.new
292
306
  @object.state = 'parked'
@@ -353,11 +367,11 @@ class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
353
367
  def setup
354
368
  @klass = Class.new
355
369
  @machine = StateMachine::Machine.new(@klass)
356
- @machine.state :parked, :value => nil
370
+ @machine.state nil
357
371
  @machine.state :idling
358
372
 
359
373
  @event = StateMachine::Event.new(@machine, :park)
360
- @event.transition(:from => :idling, :to => :parked)
374
+ @event.transition(:idling => nil)
361
375
 
362
376
  @object = @klass.new
363
377
  @object.state = 'idling'
@@ -392,8 +406,8 @@ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
392
406
  @machine.state :parked, :idling
393
407
 
394
408
  @event = StateMachine::Event.new(@machine, :ignite)
395
- @event.transition(:to => :idling, :from => :idling)
396
- @event.transition(:to => :idling, :from => :parked) # This one should get used
409
+ @event.transition(:idling => :idling)
410
+ @event.transition(:parked => :idling) # This one should get used
397
411
 
398
412
  @object = @klass.new
399
413
  @object.state = 'parked'
@@ -437,8 +451,8 @@ begin
437
451
  states.each {|state| graph.add_node(state.to_s)}
438
452
 
439
453
  @event = StateMachine::Event.new(@machine , :park)
440
- @event.transition :from => :idling, :to => :parked
441
- @event.transition :from => :first_gear, :to => :parked
454
+ @event.transition :parked => :idling
455
+ @event.transition :first_gear => :parked
442
456
  @event.transition :except_from => :parked, :to => :parked
443
457
 
444
458
  @edges = @event.draw(graph)