state_machine 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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