state_machine 0.6.0 → 0.6.1

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.
@@ -264,8 +264,21 @@ end
264
264
 
265
265
  class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
266
266
  def setup
267
- @klass = Class.new
268
- @machine = StateMachine::Machine.new(@klass)
267
+ StateMachine::Integrations.const_set('Custom', Module.new do
268
+ def invalidate(object, event)
269
+ (object.errors ||= []) << invalid_message(object, event)
270
+ end
271
+
272
+ def reset(object)
273
+ object.errors = []
274
+ end
275
+ end)
276
+
277
+ @klass = Class.new do
278
+ attr_accessor :errors
279
+ end
280
+
281
+ @machine = StateMachine::Machine.new(@klass, :integration => :custom)
269
282
  @machine.state :parked, :idling
270
283
 
271
284
  @event = StateMachine::Event.new(@machine, :ignite)
@@ -291,12 +304,41 @@ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
291
304
  @event.fire(@object)
292
305
  assert_equal 'parked', @object.state
293
306
  end
307
+
308
+ def test_should_invalidate_the_state
309
+ @event.fire(@object)
310
+ assert_equal ['cannot be transitioned via :ignite from :parked'], @object.errors
311
+ end
312
+
313
+ def test_should_reset_existing_error
314
+ @object.errors = ['invalid']
315
+
316
+ @event.fire(@object)
317
+ assert_equal ['cannot be transitioned via :ignite from :parked'], @object.errors
318
+ end
319
+
320
+ def teardown
321
+ StateMachine::Integrations.send(:remove_const, 'Custom')
322
+ end
294
323
  end
295
324
 
296
325
  class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
297
326
  def setup
298
- @klass = Class.new
299
- @machine = StateMachine::Machine.new(@klass)
327
+ StateMachine::Integrations.const_set('Custom', Module.new do
328
+ def invalidate(object, event)
329
+ (object.errors ||= []) << invalid_message(object, event)
330
+ end
331
+
332
+ def reset(object)
333
+ object.errors = []
334
+ end
335
+ end)
336
+
337
+ @klass = Class.new do
338
+ attr_accessor :errors
339
+ end
340
+
341
+ @machine = StateMachine::Machine.new(@klass, :integration => :custom)
300
342
  @machine.state :parked, :idling
301
343
 
302
344
  @event = StateMachine::Event.new(@machine, :ignite)
@@ -326,6 +368,22 @@ class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
326
368
  @event.fire(@object)
327
369
  assert_equal 'idling', @object.state
328
370
  end
371
+
372
+ def test_should_reset_existing_error
373
+ @object.errors = ['invalid']
374
+
375
+ @event.fire(@object)
376
+ assert_equal [], @object.errors
377
+ end
378
+
379
+ def test_should_not_invalidate_the_state
380
+ @event.fire(@object)
381
+ assert_equal [], @object.errors
382
+ end
383
+
384
+ def teardown
385
+ StateMachine::Integrations.send(:remove_const, 'Custom')
386
+ end
329
387
  end
330
388
 
331
389
  class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
@@ -3,6 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
3
3
  begin
4
4
  # Load library
5
5
  require 'rubygems'
6
+
7
+ gem 'activerecord', ENV['AR_VERSION'] ? "=#{ENV['AR_VERSION']}" : '>=2.1.0'
6
8
  require 'active_record'
7
9
 
8
10
  FIXTURES_ROOT = File.dirname(__FILE__) + '/../../fixtures/'
@@ -160,6 +162,27 @@ begin
160
162
  assert_equal 1, @model.count
161
163
  end
162
164
 
165
+ def test_should_invalidate_using_errors
166
+ I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:I18n)
167
+
168
+ record = @model.new
169
+ record.state = 'parked'
170
+
171
+ @machine.invalidate(record, StateMachine::Event.new(@machine, :park))
172
+
173
+ assert record.errors.invalid?(:state)
174
+ assert_equal 'cannot be transitioned via :park from :parked', record.errors.on(:state)
175
+ end
176
+
177
+ def test_should_clear_errors_on_reset
178
+ record = @model.new
179
+ record.state = 'parked'
180
+ record.errors.add(:state, 'is invalid')
181
+
182
+ @machine.reset(record)
183
+ assert_nil record.errors.on(:id)
184
+ end
185
+
163
186
  def test_should_not_override_the_column_reader
164
187
  record = @model.new
165
188
  record[:state] = 'parked'
@@ -718,7 +741,75 @@ begin
718
741
  assert_equal expected, @notifications
719
742
  end
720
743
  end
744
+
745
+ if Object.const_defined?(:I18n)
746
+ class MachineWithInternationalizationTest < ActiveRecord::TestCase
747
+ def setup
748
+ I18n.backend = I18n::Backend::Simple.new
749
+
750
+ # Initialize the backend
751
+ I18n.backend.translate(:en, 'activerecord.errors.messages.invalid_transition', :event => 'ignite', :value => 'idling')
752
+
753
+ @model = new_model
754
+ end
755
+
756
+ def test_should_invalidate_using_i18n_default
757
+ I18n.backend.store_translations(:en, {
758
+ :activerecord => {
759
+ :errors => {
760
+ :messages => {
761
+ :invalid_transition => 'cannot {{event}} when {{value}}'
762
+ }
763
+ }
764
+ }
765
+ })
766
+
767
+ machine = StateMachine::Machine.new(@model)
768
+ machine.state :parked, :idling
769
+ event = StateMachine::Event.new(machine, :ignite)
770
+
771
+ record = @model.new(:state => 'idling')
772
+
773
+ machine.invalidate(record, event)
774
+ assert_equal 'cannot ignite when idling', record.errors.on(:state)
775
+ end
776
+
777
+ def test_should_invalidate_using_customized_i18n_key_if_specified
778
+ I18n.backend.store_translations(:en, {
779
+ :activerecord => {
780
+ :errors => {
781
+ :messages => {
782
+ :bad_transition => 'cannot {{event}} when {{value}}'
783
+ }
784
+ }
785
+ }
786
+ })
787
+
788
+ machine = StateMachine::Machine.new(@model, :invalid_message => :bad_transition)
789
+ machine.state :parked, :idling
790
+ event = StateMachine::Event.new(machine, :ignite)
791
+
792
+ record = @model.new(:state => 'idling')
793
+
794
+ machine.invalidate(record, event)
795
+ assert_equal 'cannot ignite when idling', record.errors.on(:state)
796
+ end
797
+ end
798
+
799
+ def test_should_invalidate_using_customized_i18n_string_if_specified
800
+ machine = StateMachine::Machine.new(@model, :invalid_message => 'cannot {{event}} when {{value}}')
801
+ machine.state :parked, :idling
802
+ event = StateMachine::Event.new(machine, :ignite)
803
+
804
+ record = @model.new(:state => 'idling')
805
+
806
+ machine.invalidate(record, event)
807
+ assert_equal 'cannot ignite when idling', record.errors.on(:state)
808
+ end
809
+ else
810
+ $stderr.puts 'Skipping ActiveRecord I18n tests. `gem install active_record` >= v2.2.0 and try again.'
811
+ end
721
812
  end
722
813
  rescue LoadError
723
- $stderr.puts 'Skipping ActiveRecord tests. `gem install active_record` and try again.'
814
+ $stderr.puts "Skipping ActiveRecord tests. `gem install activerecord#{" -v #{ENV['AR_VERSION']}" if ENV['AR_VERSION']}` and try again."
724
815
  end
@@ -3,6 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
3
3
  begin
4
4
  # Load library
5
5
  require 'rubygems'
6
+
7
+ gem 'dm-core', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.0'
6
8
  require 'dm-core'
7
9
 
8
10
  # Establish database connection
@@ -141,6 +143,24 @@ begin
141
143
  assert_equal 1, @resource.all.size
142
144
  end
143
145
 
146
+ def test_should_invalidate_using_errors
147
+ record = @resource.new
148
+ record.state = 'parked'
149
+
150
+ @machine.invalidate(record, StateMachine::Event.new(@machine, :park))
151
+
152
+ assert_equal ['cannot be transitioned via :park from :parked'], record.errors.on(:state)
153
+ end
154
+
155
+ def test_should_clear_errors_on_reset
156
+ record = @resource.new
157
+ record.state = 'parked'
158
+ record.errors.add(:state, 'is invalid')
159
+
160
+ @machine.reset(record)
161
+ assert_nil record.errors.on(:id)
162
+ end
163
+
144
164
  def test_should_not_override_the_column_reader
145
165
  record = @resource.new
146
166
  record.attribute_set(:state, 'parked')
@@ -323,6 +343,7 @@ begin
323
343
  end
324
344
 
325
345
  begin
346
+ gem 'dm-observer', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.0'
326
347
  require 'dm-observer'
327
348
 
328
349
  class MachineWithObserversTest < BaseTestCase
@@ -484,10 +505,11 @@ begin
484
505
  end
485
506
  end
486
507
  rescue LoadError
487
- $stderr.puts 'Skipping DataMapper Observer tests. `gem install dm-observer` and try again.'
508
+ $stderr.puts "Skipping DataMapper Observer tests. `gem install dm-observer#{" -v #{ENV['DM_VERSION']}" if ENV['DM_VERSION']}` and try again."
488
509
  end
489
510
 
490
511
  begin
512
+ gem 'dm-validations', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.0'
491
513
  require 'dm-validations'
492
514
 
493
515
  class MachineWithStateDrivenValidationsTest < BaseTestCase
@@ -519,9 +541,9 @@ begin
519
541
  end
520
542
  end
521
543
  rescue LoadError
522
- $stderr.puts 'Skipping DataMapper Validation tests. `gem install dm-validations` and try again.'
544
+ $stderr.puts "Skipping DataMapper Validation tests. `gem install dm-validations#{" -v #{ENV['DM_VERSION']}" if ENV['DM_VERSION']}` and try again."
523
545
  end
524
546
  end
525
547
  rescue LoadError
526
- $stderr.puts 'Skipping DataMapper tests. `gem install dm-core cucumber rspec hoe launchy do_sqlite3` and try again.'
548
+ $stderr.puts "Skipping DataMapper tests. `gem install dm-core#{" -v #{ENV['DM_VERSION']}" if ENV['DM_VERSION']}`, `gem install cucumber rspec hoe launchy do_sqlite3` and try again."
527
549
  end
@@ -3,6 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
3
3
  begin
4
4
  # Load library
5
5
  require 'rubygems'
6
+
7
+ gem 'sequel', ENV['SEQUEL_VERSION'] ? "=#{ENV['SEQUEL_VERSION']}" : '>=2.8.0'
6
8
  require 'sequel'
7
9
  require 'logger'
8
10
 
@@ -22,6 +24,8 @@ begin
22
24
  column :state, :string
23
25
  end if auto_migrate
24
26
  model = Class.new(Sequel::Model(:foo)) do
27
+ self.raise_on_save_failure = false
28
+
25
29
  def self.name; 'SequelTest::Foo'; end
26
30
  end
27
31
  model.class_eval(&block) if block_given?
@@ -127,6 +131,24 @@ begin
127
131
  assert_equal 1, @model.count
128
132
  end
129
133
 
134
+ def test_should_invalidate_using_errors
135
+ record = @model.new
136
+ record.state = 'parked'
137
+
138
+ @machine.invalidate(record, StateMachine::Event.new(@machine, :park))
139
+
140
+ assert_equal ['cannot be transitioned via :park from :parked'], record.errors.on(:state)
141
+ end
142
+
143
+ def test_should_clear_errors_on_reset
144
+ record = @model.new
145
+ record.state = 'parked'
146
+ record.errors.add(:state, 'is invalid')
147
+
148
+ @machine.reset(record)
149
+ assert_nil record.errors.on(:id)
150
+ end
151
+
130
152
  def test_should_not_override_the_column_reader
131
153
  record = @model.new
132
154
  record[:state] = 'parked'
@@ -271,7 +293,7 @@ begin
271
293
  @machine.after_transition(lambda {|*args| callback_args = args})
272
294
 
273
295
  @transition.perform
274
- assert_equal [@transition, @record], callback_args
296
+ assert_equal [@transition, true], callback_args
275
297
  end
276
298
 
277
299
  def test_should_run_after_callbacks_with_the_context_of_the_record
@@ -338,5 +360,5 @@ begin
338
360
  end
339
361
  end
340
362
  rescue LoadError
341
- $stderr.puts 'Skipping Sequel tests. `gem install sequel` and try again.'
363
+ $stderr.puts "Skipping Sequel tests. `gem install sequel#{" -v #{ENV['SEQUEL_VERSION']}" if ENV['SEQUEL_VERSION']}` and try again."
342
364
  end
@@ -250,6 +250,14 @@ class MachineWithoutIntegrationTest < Test::Unit::TestCase
250
250
 
251
251
  assert @yielded
252
252
  end
253
+
254
+ def test_invalidation_should_do_nothing
255
+ assert_nil @machine.invalidate(@object, StateMachine::Event.new(@machine, :park))
256
+ end
257
+
258
+ def test_reset_should_do_nothing
259
+ assert_nil @machine.reset(@object)
260
+ end
253
261
  end
254
262
 
255
263
  class MachineWithCustomIntegrationTest < Test::Unit::TestCase
@@ -328,7 +336,6 @@ class MachineWithCustomPluralTest < Test::Unit::TestCase
328
336
  def setup
329
337
  @integration = Module.new do
330
338
  class << self; attr_accessor :with_scopes, :without_scopes; end
331
- @initialized = false
332
339
  @with_scopes = []
333
340
  @without_scopes = []
334
341
 
@@ -360,11 +367,45 @@ class MachineWithCustomPluralTest < Test::Unit::TestCase
360
367
  end
361
368
  end
362
369
 
370
+ class MachineWithCustomInvalidationTest < Test::Unit::TestCase
371
+ def setup
372
+ @integration = Module.new do
373
+ def invalidate(object, event)
374
+ object.error = invalid_message(object, event)
375
+ end
376
+ end
377
+ StateMachine::Integrations.const_set('Custom', @integration)
378
+
379
+ @klass = Class.new do
380
+ attr_accessor :error
381
+ end
382
+
383
+ @machine = StateMachine::Machine.new(@klass, :integration => :custom, :invalid_message => 'cannot %s when %s')
384
+ @machine.state :parked
385
+
386
+ @object = @klass.new
387
+ @object.state = 'parked'
388
+ end
389
+
390
+ def test_use_custom_message
391
+ @machine.invalidate(@object, StateMachine::Event.new(@machine, :park))
392
+ assert_equal 'cannot park when parked', @object.error
393
+ end
394
+
395
+ def teardown
396
+ StateMachine::Integrations.send(:remove_const, 'Custom')
397
+ end
398
+ end
399
+
363
400
  class MachineTest < Test::Unit::TestCase
364
401
  def test_should_raise_exception_if_invalid_option_specified
365
402
  assert_raise(ArgumentError) {StateMachine::Machine.new(Class.new, :invalid => true)}
366
403
  end
367
404
 
405
+ def test_should_not_raise_exception_if_custom_invalid_message_specified
406
+ assert_nothing_raised {StateMachine::Machine.new(Class.new, :invalid_message => 'custom')}
407
+ end
408
+
368
409
  def test_should_evaluate_a_block_during_initialization
369
410
  called = true
370
411
  StateMachine::Machine.new(Class.new) do
@@ -969,8 +1010,8 @@ class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
969
1010
  @klass = Class.new
970
1011
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
971
1012
  @event = @machine.event(:ignite) do
972
- transition :to => :idling, :from => :parked
973
- transition :to => :idling, :from => :stalled
1013
+ transition :parked => :idling
1014
+ transition :stalled => :idling
974
1015
  end
975
1016
  end
976
1017
 
@@ -984,7 +1025,7 @@ class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
984
1025
 
985
1026
  def test_should_not_duplicate_states_defined_in_multiple_event_transitions
986
1027
  @machine.event :park do
987
- transition :to => :parked, :from => :idling
1028
+ transition :idling => :parked
988
1029
  end
989
1030
 
990
1031
  assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
@@ -992,7 +1033,7 @@ class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
992
1033
 
993
1034
  def test_should_track_state_from_new_events
994
1035
  @machine.event :shift_up do
995
- transition :to => :first_gear, :from => :idling
1036
+ transition :idling => :first_gear
996
1037
  end
997
1038
 
998
1039
  assert_equal [:parked, :idling, :stalled, :first_gear], @machine.states.map {|state| state.name}
@@ -1004,7 +1045,7 @@ class MachineWithMultipleEventsTest < Test::Unit::TestCase
1004
1045
  @klass = Class.new
1005
1046
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1006
1047
  @park, @shift_down = @machine.event(:park, :shift_down) do
1007
- transition :to => :parked, :from => :first_gear
1048
+ transition :first_gear => :parked
1008
1049
  end
1009
1050
  end
1010
1051
 
@@ -1037,7 +1078,7 @@ class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
1037
1078
 
1038
1079
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1039
1080
  @event = @machine.event :ignite do
1040
- transition :to => :idling, :from => :parked
1081
+ transition :parked => :idling
1041
1082
  end
1042
1083
 
1043
1084
  @object = @klass.new
@@ -1118,16 +1159,16 @@ class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
1118
1159
  end
1119
1160
 
1120
1161
  def test_should_track_states_defined_in_transition_callbacks
1121
- @machine.before_transition :from => :parked, :to => :idling, :do => lambda {}
1122
- @machine.after_transition :from => :first_gear, :to => :second_gear, :do => lambda {}
1162
+ @machine.before_transition :parked => :idling, :do => lambda {}
1163
+ @machine.after_transition :first_gear => :second_gear, :do => lambda {}
1123
1164
 
1124
1165
  assert_equal [:parked, :idling, :first_gear, :second_gear], @machine.states.map {|state| state.name}
1125
1166
  end
1126
1167
 
1127
1168
  def test_should_not_duplicate_states_defined_in_multiple_event_transitions
1128
- @machine.before_transition :from => :parked, :to => :idling, :do => lambda {}
1129
- @machine.after_transition :from => :first_gear, :to => :second_gear, :do => lambda {}
1130
- @machine.after_transition :from => :parked, :to => :idling, :do => lambda {}
1169
+ @machine.before_transition :parked => :idling, :do => lambda {}
1170
+ @machine.after_transition :first_gear => :second_gear, :do => lambda {}
1171
+ @machine.after_transition :parked => :idling, :do => lambda {}
1131
1172
 
1132
1173
  assert_equal [:parked, :idling, :first_gear, :second_gear], @machine.states.map {|state| state.name}
1133
1174
  end
@@ -1177,11 +1218,11 @@ class MachineWithNamespaceTest < Test::Unit::TestCase
1177
1218
  @klass = Class.new
1178
1219
  @machine = StateMachine::Machine.new(@klass, :namespace => 'car', :initial => :parked) do
1179
1220
  event :ignite do
1180
- transition :to => :idling, :from => :parked
1221
+ transition :parked => :idling
1181
1222
  end
1182
1223
 
1183
1224
  event :park do
1184
- transition :to => :parked, :from => :idling
1225
+ transition :idling => :parked
1185
1226
  end
1186
1227
  end
1187
1228
  @object = @klass.new
@@ -1354,7 +1395,7 @@ begin
1354
1395
  end
1355
1396
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1356
1397
  @machine.event :ignite do
1357
- transition :to => :idling, :from => :parked
1398
+ transition :parked => :idling
1358
1399
  end
1359
1400
  end
1360
1401
 
@@ -1398,7 +1439,7 @@ begin
1398
1439
  end
1399
1440
  @machine = StateMachine::Machine.new(@klass, :state_id, :initial => :parked)
1400
1441
  @machine.event :ignite do
1401
- transition :to => :idling, :from => :parked
1442
+ transition :parked => :idling
1402
1443
  end
1403
1444
  @machine.state :parked, :value => 1
1404
1445
  @machine.state :idling, :value => 2
@@ -1419,7 +1460,7 @@ begin
1419
1460
  end
1420
1461
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1421
1462
  @machine.event :ignite do
1422
- transition :to => :idling, :from => :parked
1463
+ transition :parked => :idling
1423
1464
  end
1424
1465
  @machine.state :parked, :value => nil
1425
1466
  @machine.draw
@@ -1439,7 +1480,7 @@ begin
1439
1480
  end
1440
1481
  @machine = StateMachine::Machine.new(@klass, :initial => :parked)
1441
1482
  @machine.event :activate do
1442
- transition :to => :idling, :from => :parked
1483
+ transition :parked => :idling
1443
1484
  end
1444
1485
  @machine.state :idling, :value => lambda {Time.now}
1445
1486
  @machine.draw
@@ -1459,7 +1500,7 @@ begin
1459
1500
  end
1460
1501
  @machine = StateMachine::Machine.new(@klass)
1461
1502
  @machine.event :ignite do
1462
- transition :to => :idling, :from => :parked
1503
+ transition :parked => :idling
1463
1504
  end
1464
1505
  end
1465
1506