state_machine 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/CHANGELOG.rdoc +17 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +162 -23
  4. data/Rakefile +3 -18
  5. data/lib/state_machine.rb +3 -4
  6. data/lib/state_machine/callback.rb +65 -13
  7. data/lib/state_machine/eval_helpers.rb +20 -4
  8. data/lib/state_machine/initializers.rb +4 -0
  9. data/lib/state_machine/initializers/merb.rb +1 -0
  10. data/lib/state_machine/initializers/rails.rb +7 -0
  11. data/lib/state_machine/integrations.rb +21 -6
  12. data/lib/state_machine/integrations/active_model.rb +414 -0
  13. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  14. data/lib/state_machine/integrations/{active_record → active_model}/observer.rb +7 -7
  15. data/lib/state_machine/integrations/active_record.rb +65 -129
  16. data/lib/state_machine/integrations/active_record/locale.rb +4 -11
  17. data/lib/state_machine/integrations/data_mapper.rb +24 -6
  18. data/lib/state_machine/integrations/data_mapper/observer.rb +36 -0
  19. data/lib/state_machine/integrations/mongo_mapper.rb +295 -0
  20. data/lib/state_machine/integrations/sequel.rb +33 -7
  21. data/lib/state_machine/machine.rb +121 -23
  22. data/lib/state_machine/machine_collection.rb +12 -103
  23. data/lib/state_machine/transition.rb +125 -164
  24. data/lib/state_machine/transition_collection.rb +244 -0
  25. data/lib/tasks/state_machine.rb +12 -15
  26. data/test/functional/state_machine_test.rb +11 -1
  27. data/test/unit/callback_test.rb +305 -32
  28. data/test/unit/eval_helpers_test.rb +103 -1
  29. data/test/unit/event_test.rb +2 -1
  30. data/test/unit/guard_test.rb +2 -1
  31. data/test/unit/integrations/active_model_test.rb +909 -0
  32. data/test/unit/integrations/active_record_test.rb +1542 -1292
  33. data/test/unit/integrations/data_mapper_test.rb +1369 -1041
  34. data/test/unit/integrations/mongo_mapper_test.rb +1349 -0
  35. data/test/unit/integrations/sequel_test.rb +1214 -985
  36. data/test/unit/integrations_test.rb +8 -0
  37. data/test/unit/machine_collection_test.rb +140 -513
  38. data/test/unit/machine_test.rb +212 -10
  39. data/test/unit/state_test.rb +2 -1
  40. data/test/unit/transition_collection_test.rb +2098 -0
  41. data/test/unit/transition_test.rb +704 -552
  42. metadata +16 -3
@@ -1,579 +1,622 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
2
 
3
- begin
4
- # Load library
5
- require 'rubygems'
6
-
7
- gem 'dm-core', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.4'
8
- require 'dm-core'
9
- require 'dm-core/version' unless defined?(::DataMapper::VERSION)
10
-
11
- # Establish database connection
12
- DataMapper.setup(:default, 'sqlite3::memory:')
13
- DataObjects::Sqlite3.logger = DataObjects::Logger.new("#{File.dirname(__FILE__)}/../../data_mapper.log", :info)
14
-
15
- module DataMapperTest
16
- class BaseTestCase < Test::Unit::TestCase
17
- def default_test
18
- end
19
-
20
- protected
21
- # Creates a new DataMapper resource (and the associated table)
22
- def new_resource(create_table = :foo, &block)
23
- table_name = create_table || :foo
24
-
25
- resource = Class.new do
26
- include DataMapper::Resource
27
-
28
- storage_names[:default] = table_name.to_s
29
- def self.name; "DataMapperTest::#{storage_names[:default].capitalize}"; end
30
-
31
- property :id, DataMapper::Types::Serial
32
- property :state, String
33
-
34
- auto_migrate! if create_table
35
- end
36
- resource.class_eval(&block) if block_given?
37
- resource
38
- end
39
-
40
- # Creates a new DataMapper observer
41
- def new_observer(resource, &block)
42
- observer = Class.new do
43
- include DataMapper::Observer
44
- end
45
- observer.observe(resource)
46
- observer.class_eval(&block) if block_given?
47
- observer
48
- end
3
+ # Load library
4
+ require 'rubygems'
5
+
6
+ gem 'dm-core', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.9.4'
7
+ require 'dm-core'
8
+ require 'dm-core/version' unless defined?(::DataMapper::VERSION)
9
+
10
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
11
+ gem 'dm-migrations', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.10.3'
12
+ require 'dm-migrations'
13
+ end
14
+
15
+ # Establish database connection
16
+ DataMapper.setup(:default, 'sqlite3::memory:')
17
+ DataObjects::Sqlite3.logger = DataObjects::Logger.new("#{File.dirname(__FILE__)}/../../data_mapper.log", :info)
18
+
19
+ module DataMapperTest
20
+ class BaseTestCase < Test::Unit::TestCase
21
+ def default_test
49
22
  end
50
23
 
51
- class IntegrationTest < BaseTestCase
52
- def test_should_match_if_class_inherits_from_active_record
53
- assert StateMachine::Integrations::DataMapper.matches?(new_resource)
54
- end
55
-
56
- def test_should_not_match_if_class_does_not_inherit_from_active_record
57
- assert !StateMachine::Integrations::DataMapper.matches?(Class.new)
24
+ protected
25
+ # Creates a new DataMapper resource (and the associated table)
26
+ def new_resource(create_table = :foo, &block)
27
+ table_name = create_table || :foo
28
+
29
+ resource = Class.new do
30
+ include DataMapper::Resource
31
+
32
+ storage_names[:default] = table_name.to_s
33
+ def self.name; "DataMapperTest::#{storage_names[:default].capitalize}"; end
34
+
35
+ property :id, DataMapper::Types::Serial
36
+ property :state, String
37
+
38
+ auto_migrate! if create_table
39
+ end
40
+ resource.class_eval(&block) if block_given?
41
+ resource
58
42
  end
59
43
 
60
- def test_should_have_defaults
61
- assert_equal e = {:action => :save, :use_transactions => false}, StateMachine::Integrations::DataMapper.defaults
44
+ # Creates a new DataMapper observer
45
+ def new_observer(resource, &block)
46
+ observer = Class.new do
47
+ include DataMapper::Observer
48
+ end
49
+ observer.observe(resource)
50
+ observer.class_eval(&block) if block_given?
51
+ observer
62
52
  end
53
+ end
54
+
55
+ class IntegrationTest < BaseTestCase
56
+ def test_should_match_if_class_includes_data_mapper
57
+ assert StateMachine::Integrations::DataMapper.matches?(new_resource)
63
58
  end
64
59
 
65
- class MachineWithoutDatabaseTest < BaseTestCase
66
- def setup
67
- @resource = new_resource(false) do
68
- # Simulate the database not being available entirely
69
- def self.repository
70
- raise DataObjects::SyntaxError
71
- end
60
+ def test_should_not_match_if_class_does_not_include_data_mapper
61
+ assert !StateMachine::Integrations::DataMapper.matches?(Class.new)
62
+ end
63
+
64
+ def test_should_have_defaults
65
+ assert_equal e = {:action => :save, :use_transactions => false}, StateMachine::Integrations::DataMapper.defaults
66
+ end
67
+ end
68
+
69
+ class MachineWithoutDatabaseTest < BaseTestCase
70
+ def setup
71
+ @resource = new_resource(false) do
72
+ # Simulate the database not being available entirely
73
+ def self.repository
74
+ raise DataObjects::SyntaxError
72
75
  end
73
76
  end
74
-
75
- def test_should_allow_machine_creation
76
- assert_nothing_raised { StateMachine::Machine.new(@resource) }
77
- end
78
77
  end
79
78
 
80
- class MachineUnmigratedTest < BaseTestCase
81
- def setup
82
- @resource = new_resource(false)
83
- end
84
-
85
- def test_should_allow_machine_creation
86
- assert_nothing_raised { StateMachine::Machine.new(@resource) }
87
- end
79
+ def test_should_allow_machine_creation
80
+ assert_nothing_raised { StateMachine::Machine.new(@resource) }
81
+ end
82
+ end
83
+
84
+ class MachineUnmigratedTest < BaseTestCase
85
+ def setup
86
+ @resource = new_resource(false)
88
87
  end
89
88
 
90
- class MachineByDefaultTest < BaseTestCase
91
- def setup
92
- @resource = new_resource
93
- @machine = StateMachine::Machine.new(@resource)
94
- end
95
-
96
- def test_should_use_save_as_action
97
- assert_equal :save, @machine.action
98
- end
99
-
100
- def test_should_not_use_transactions
101
- assert_equal false, @machine.use_transactions
102
- end
103
-
104
- def test_should_not_have_any_before_callbacks
105
- assert_equal 0, @machine.callbacks[:before].size
106
- end
107
-
108
- def test_should_not_have_any_after_callbacks
109
- assert_equal 0, @machine.callbacks[:after].size
110
- end
89
+ def test_should_allow_machine_creation
90
+ assert_nothing_raised { StateMachine::Machine.new(@resource) }
91
+ end
92
+ end
93
+
94
+ class MachineByDefaultTest < BaseTestCase
95
+ def setup
96
+ @resource = new_resource
97
+ @machine = StateMachine::Machine.new(@resource)
111
98
  end
112
99
 
113
- class MachineWithStaticInitialStateTest < BaseTestCase
114
- def setup
115
- @resource = new_resource do
116
- attr_accessor :value
117
- end
118
- @machine = StateMachine::Machine.new(@resource, :initial => :parked)
119
- end
120
-
121
- def test_should_set_initial_state_on_created_object
122
- record = @resource.new
123
- assert_equal 'parked', record.state
100
+ def test_should_use_save_as_action
101
+ assert_equal :save, @machine.action
102
+ end
103
+
104
+ def test_should_not_use_transactions
105
+ assert_equal false, @machine.use_transactions
106
+ end
107
+
108
+ def test_should_not_have_any_before_callbacks
109
+ assert_equal 0, @machine.callbacks[:before].size
110
+ end
111
+
112
+ def test_should_not_have_any_after_callbacks
113
+ assert_equal 0, @machine.callbacks[:after].size
114
+ end
115
+ end
116
+
117
+ class MachineWithStaticInitialStateTest < BaseTestCase
118
+ def setup
119
+ @resource = new_resource do
120
+ attr_accessor :value
124
121
  end
125
-
126
- def test_should_set_initial_state_with_nil_attributes
127
- @resource.class_eval do
128
- def attributes=(attributes)
129
- super(attributes || {})
130
- end
122
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
123
+ end
124
+
125
+ def test_should_set_initial_state_on_created_object
126
+ record = @resource.new
127
+ assert_equal 'parked', record.state
128
+ end
129
+
130
+ def test_should_set_initial_state_with_nil_attributes
131
+ @resource.class_eval do
132
+ def attributes=(attributes)
133
+ super(attributes || {})
131
134
  end
132
-
133
- record = @resource.new(nil)
134
- assert_equal 'parked', record.state
135
135
  end
136
136
 
137
- def test_should_still_set_attributes
138
- record = @resource.new(:value => 1)
139
- assert_equal 1, record.value
137
+ record = @resource.new(nil)
138
+ assert_equal 'parked', record.state
139
+ end
140
+
141
+ def test_should_still_set_attributes
142
+ record = @resource.new(:value => 1)
143
+ assert_equal 1, record.value
144
+ end
145
+
146
+ def test_should_not_allow_initialize_blocks
147
+ block_args = nil
148
+ record = @resource.new do |*args|
149
+ block_args = args
140
150
  end
141
151
 
142
- def test_should_not_allow_initialize_blocks
143
- block_args = nil
144
- record = @resource.new do |*args|
145
- block_args = args
146
- end
152
+ assert_nil block_args
153
+ end
154
+
155
+ def test_should_set_initial_state_before_setting_attributes
156
+ @resource.class_eval do
157
+ attr_accessor :state_during_setter
147
158
 
148
- assert_nil block_args
149
- end
150
-
151
- def test_should_set_initial_state_before_setting_attributes
152
- @resource.class_eval do
153
- attr_accessor :state_during_setter
154
-
155
- define_method(:value=) do |value|
156
- self.state_during_setter = state
157
- end
159
+ define_method(:value=) do |value|
160
+ self.state_during_setter = state
158
161
  end
159
-
160
- record = @resource.new(:value => 1)
161
- assert_equal 'parked', record.state_during_setter
162
162
  end
163
163
 
164
- def test_should_not_set_initial_state_after_already_initialized
165
- record = @resource.new(:value => 1)
166
- assert_equal 'parked', record.state
167
-
168
- record.state = 'idling'
169
- record.attributes = {}
170
- assert_equal 'idling', record.state
171
- end
164
+ record = @resource.new(:value => 1)
165
+ assert_equal 'parked', record.state_during_setter
172
166
  end
173
167
 
174
- class MachineWithDynamicInitialStateTest < BaseTestCase
175
- def setup
176
- @resource = new_resource do
177
- attr_accessor :value
178
- end
179
- @machine = StateMachine::Machine.new(@resource, :initial => lambda {|object| :parked})
180
- @machine.state :parked
181
- end
182
-
183
- def test_should_set_initial_state_on_created_object
184
- record = @resource.new
185
- assert_equal 'parked', record.state
186
- end
187
-
188
- def test_should_still_set_attributes
189
- record = @resource.new(:value => 1)
190
- assert_equal 1, record.value
191
- end
192
-
193
- def test_should_not_allow_initialize_blocks
194
- block_args = nil
195
- record = @resource.new do |*args|
196
- block_args = args
197
- end
198
-
199
- assert_nil block_args
200
- end
168
+ def test_should_not_set_initial_state_after_already_initialized
169
+ record = @resource.new(:value => 1)
170
+ assert_equal 'parked', record.state
201
171
 
202
- def test_should_set_initial_state_after_setting_attributes
203
- @resource.class_eval do
204
- attr_accessor :state_during_setter
205
-
206
- define_method(:value=) do |value|
207
- self.state_during_setter = state || 'nil'
208
- end
209
- end
210
-
211
- record = @resource.new(:value => 1)
212
- assert_equal 'nil', record.state_during_setter
213
- end
172
+ record.state = 'idling'
173
+ record.attributes = {}
174
+ assert_equal 'idling', record.state
175
+ end
176
+
177
+ def test_should_use_stored_values_when_loading_from_database
178
+ @machine.state :idling
214
179
 
215
- def test_should_not_set_initial_state_after_already_initialized
216
- record = @resource.new(:value => 1)
217
- assert_equal 'parked', record.state
218
-
219
- record.state = 'idling'
220
- record.attributes = {}
221
- assert_equal 'idling', record.state
222
- end
180
+ record = @resource.get(@resource.create(:state => 'idling').id)
181
+ assert_equal 'idling', record.state
223
182
  end
224
183
 
225
- class MachineWithColumnDefaultTest < BaseTestCase
226
- def setup
227
- @resource = new_resource do
228
- property :status, String, :default => 'idling'
229
- auto_migrate!
230
- end
231
- @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
232
- @record = @resource.new
233
- end
184
+ def test_should_use_stored_values_when_loading_from_database_with_nil_state
185
+ @machine.state nil
234
186
 
235
- def test_should_use_machine_default
236
- assert_equal 'parked', @record.status
187
+ record = @resource.get(@resource.create(:state => nil).id)
188
+ assert_nil record.state
189
+ end
190
+ end
191
+
192
+ class MachineWithDynamicInitialStateTest < BaseTestCase
193
+ def setup
194
+ @resource = new_resource do
195
+ attr_accessor :value
237
196
  end
197
+ @machine = StateMachine::Machine.new(@resource, :initial => lambda {|object| :parked})
198
+ @machine.state :parked
238
199
  end
239
200
 
240
- class MachineWithConflictingPredicateTest < BaseTestCase
241
- def setup
242
- @resource = new_resource do
243
- def state?(*args)
244
- true
245
- end
246
- end
247
-
248
- @machine = StateMachine::Machine.new(@resource)
249
- @record = @resource.new
201
+ def test_should_set_initial_state_on_created_object
202
+ record = @resource.new
203
+ assert_equal 'parked', record.state
204
+ end
205
+
206
+ def test_should_still_set_attributes
207
+ record = @resource.new(:value => 1)
208
+ assert_equal 1, record.value
209
+ end
210
+
211
+ def test_should_not_allow_initialize_blocks
212
+ block_args = nil
213
+ record = @resource.new do |*args|
214
+ block_args = args
250
215
  end
251
216
 
252
- def test_should_not_define_attribute_predicate
253
- assert @record.state?
254
- end
217
+ assert_nil block_args
255
218
  end
256
219
 
257
- class MachineWithColumnStateAttributeTest < BaseTestCase
258
- def setup
259
- @resource = new_resource
260
- @machine = StateMachine::Machine.new(@resource, :initial => :parked)
261
- @machine.other_states(:idling)
220
+ def test_should_set_initial_state_after_setting_attributes
221
+ @resource.class_eval do
222
+ attr_accessor :state_during_setter
262
223
 
263
- @record = @resource.new
264
- end
265
-
266
- def test_should_not_override_the_column_reader
267
- @record.attribute_set(:state, 'parked')
268
- assert_equal 'parked', @record.state
269
- end
270
-
271
- def test_should_not_override_the_column_writer
272
- @record.state = 'parked'
273
- assert_equal 'parked', @record.attribute_get(:state)
274
- end
275
-
276
- def test_should_have_an_attribute_predicate
277
- assert @record.respond_to?(:state?)
224
+ define_method(:value=) do |value|
225
+ self.state_during_setter = state || 'nil'
226
+ end
278
227
  end
279
228
 
280
- def test_should_raise_exception_for_predicate_without_parameters
281
- assert_raise(IndexError) { @record.state? }
282
- end
229
+ record = @resource.new(:value => 1)
230
+ assert_equal 'nil', record.state_during_setter
231
+ end
232
+
233
+ def test_should_not_set_initial_state_after_already_initialized
234
+ record = @resource.new(:value => 1)
235
+ assert_equal 'parked', record.state
283
236
 
284
- def test_should_return_false_for_predicate_if_does_not_match_current_value
285
- assert !@record.state?(:idling)
286
- end
237
+ record.state = 'idling'
238
+ record.attributes = {}
239
+ assert_equal 'idling', record.state
240
+ end
241
+
242
+ def test_should_use_stored_values_when_loading_from_database
243
+ @machine.state :idling
287
244
 
288
- def test_should_return_true_for_predicate_if_matches_current_value
289
- assert @record.state?(:parked)
290
- end
245
+ record = @resource.get(@resource.create(:state => 'idling').id)
246
+ assert_equal 'idling', record.state
247
+ end
248
+
249
+ def test_should_use_stored_values_when_loading_from_database_with_nil_state
250
+ @machine.state nil
291
251
 
292
- def test_should_raise_exception_for_predicate_if_invalid_state_specified
293
- assert_raise(IndexError) { @record.state?(:invalid) }
294
- end
252
+ record = @resource.get(@resource.create(:state => nil).id)
253
+ assert_nil record.state
254
+ end
255
+ end
256
+
257
+ class MachineWithColumnDefaultTest < BaseTestCase
258
+ def setup
259
+ @resource = new_resource do
260
+ property :status, String, :default => 'idling'
261
+ auto_migrate!
262
+ end
263
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
264
+ @record = @resource.new
295
265
  end
296
266
 
297
- class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
298
- def setup
299
- @resource = new_resource do
300
- def initialize
301
- # Skip attribute initialization
302
- @initialized_state_machines = true
303
- super
304
- end
267
+ def test_should_use_machine_default
268
+ assert_equal 'parked', @record.status
269
+ end
270
+ end
271
+
272
+ class MachineWithConflictingPredicateTest < BaseTestCase
273
+ def setup
274
+ @resource = new_resource do
275
+ def state?(*args)
276
+ true
305
277
  end
306
-
307
- @machine = StateMachine::Machine.new(@resource, :status, :initial => 'parked')
308
- @record = @resource.new
309
278
  end
310
279
 
311
- def test_should_define_a_new_property_for_the_attribute
312
- assert_not_nil @resource.properties[:status]
313
- end
280
+ @machine = StateMachine::Machine.new(@resource)
281
+ @record = @resource.new
282
+ end
283
+
284
+ def test_should_not_define_attribute_predicate
285
+ assert @record.state?
286
+ end
287
+ end
288
+
289
+ class MachineWithColumnStateAttributeTest < BaseTestCase
290
+ def setup
291
+ @resource = new_resource
292
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
293
+ @machine.other_states(:idling)
314
294
 
315
- def test_should_define_a_reader_attribute_for_the_attribute
316
- assert @record.respond_to?(:status)
295
+ @record = @resource.new
296
+ end
297
+
298
+ def test_should_not_override_the_column_reader
299
+ @record.attribute_set(:state, 'parked')
300
+ assert_equal 'parked', @record.state
301
+ end
302
+
303
+ def test_should_not_override_the_column_writer
304
+ @record.state = 'parked'
305
+ assert_equal 'parked', @record.attribute_get(:state)
306
+ end
307
+
308
+ def test_should_have_an_attribute_predicate
309
+ assert @record.respond_to?(:state?)
310
+ end
311
+
312
+ def test_should_raise_exception_for_predicate_without_parameters
313
+ assert_raise(IndexError) { @record.state? }
314
+ end
315
+
316
+ def test_should_return_false_for_predicate_if_does_not_match_current_value
317
+ assert !@record.state?(:idling)
318
+ end
319
+
320
+ def test_should_return_true_for_predicate_if_matches_current_value
321
+ assert @record.state?(:parked)
322
+ end
323
+
324
+ def test_should_raise_exception_for_predicate_if_invalid_state_specified
325
+ assert_raise(IndexError) { @record.state?(:invalid) }
326
+ end
327
+ end
328
+
329
+ class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
330
+ def setup
331
+ @resource = new_resource do
332
+ def initialize
333
+ # Skip attribute initialization
334
+ @initialized_state_machines = true
335
+ super
336
+ end
317
337
  end
318
338
 
319
- def test_should_define_a_writer_attribute_for_the_attribute
320
- assert @record.respond_to?(:status=)
339
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => 'parked')
340
+ @record = @resource.new
341
+ end
342
+
343
+ def test_should_define_a_new_property_for_the_attribute
344
+ assert_not_nil @resource.properties[:status]
345
+ end
346
+
347
+ def test_should_define_a_reader_attribute_for_the_attribute
348
+ assert @record.respond_to?(:status)
349
+ end
350
+
351
+ def test_should_define_a_writer_attribute_for_the_attribute
352
+ assert @record.respond_to?(:status=)
353
+ end
354
+
355
+ def test_should_define_an_attribute_predicate
356
+ assert @record.respond_to?(:status?)
357
+ end
358
+ end
359
+
360
+ class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
361
+ def setup
362
+ @resource = new_resource do
363
+ attr_accessor :status
321
364
  end
322
365
 
323
- def test_should_define_an_attribute_predicate
324
- assert @record.respond_to?(:status?)
325
- end
366
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
367
+ @machine.other_states(:idling)
368
+ @record = @resource.new
326
369
  end
327
370
 
328
- class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
329
- def setup
330
- @resource = new_resource do
331
- attr_accessor :status
371
+ def test_should_return_false_for_predicate_if_does_not_match_current_value
372
+ assert !@record.status?(:idling)
373
+ end
374
+
375
+ def test_should_return_true_for_predicate_if_matches_current_value
376
+ assert @record.status?(:parked)
377
+ end
378
+
379
+ def test_should_raise_exception_for_predicate_if_invalid_state_specified
380
+ assert_raise(IndexError) { @record.status?(:invalid) }
381
+ end
382
+
383
+ def test_should_set_initial_state_on_created_object
384
+ assert_equal 'parked', @record.status
385
+ end
386
+ end
387
+
388
+ class MachineWithInitializedStateTest < BaseTestCase
389
+ def setup
390
+ @resource = new_resource
391
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
392
+ @machine.state nil, :idling
393
+ end
394
+
395
+ def test_should_allow_nil_initial_state_when_static
396
+ record = @resource.new(:state => nil)
397
+ assert_nil record.state
398
+ end
399
+
400
+ def test_should_allow_nil_initial_state_when_dynamic
401
+ @machine.initial_state = lambda {:parked}
402
+ record = @resource.new(:state => nil)
403
+ assert_nil record.state
404
+ end
405
+
406
+ def test_should_allow_different_initial_state_when_static
407
+ record = @resource.new(:state => 'idling')
408
+ assert_equal 'idling', record.state
409
+ end
410
+
411
+ def test_should_allow_different_initial_state_when_dynamic
412
+ @machine.initial_state = lambda {:parked}
413
+ record = @resource.new(:state => 'idling')
414
+ assert_equal 'idling', record.state
415
+ end
416
+
417
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.9.8')
418
+ def test_should_raise_exception_if_protected
419
+ @resource.class_eval do
420
+ protected :state=
332
421
  end
333
422
 
334
- @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
335
- @machine.other_states(:idling)
336
- @record = @resource.new
423
+ assert_raise(ArgumentError) { @resource.new(:state => 'idling') }
337
424
  end
338
-
339
- def test_should_return_false_for_predicate_if_does_not_match_current_value
340
- assert !@record.status?(:idling)
425
+ end
426
+ end
427
+
428
+ class MachineWithLoopbackTest < BaseTestCase
429
+ def setup
430
+ @resource = new_resource do
431
+ property :updated_at, DateTime
432
+ auto_migrate!
433
+
434
+ # Simulate dm-timestamps
435
+ before :update do
436
+ return unless dirty?
437
+ self.updated_at = DateTime.now
438
+ end
341
439
  end
342
440
 
343
- def test_should_return_true_for_predicate_if_matches_current_value
344
- assert @record.status?(:parked)
345
- end
441
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
442
+ @machine.event :park
346
443
 
347
- def test_should_raise_exception_for_predicate_if_invalid_state_specified
348
- assert_raise(IndexError) { @record.status?(:invalid) }
349
- end
444
+ @record = @resource.create(:updated_at => Time.now - 1)
445
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
350
446
 
351
- def test_should_set_initial_state_on_created_object
352
- assert_equal 'parked', @record.status
353
- end
447
+ @timestamp = @record.updated_at
448
+ @transition.perform
354
449
  end
355
450
 
356
- class MachineWithInitializedStateTest < BaseTestCase
357
- def setup
358
- @resource = new_resource
359
- @machine = StateMachine::Machine.new(@resource, :initial => :parked)
360
- @machine.state nil, :idling
361
- end
362
-
363
- def test_should_allow_nil_initial_state_when_static
364
- record = @resource.new(:state => nil)
365
- assert_nil record.state
366
- end
367
-
368
- def test_should_allow_nil_initial_state_when_dynamic
369
- @machine.initial_state = lambda {:parked}
370
- record = @resource.new(:state => nil)
371
- assert_nil record.state
372
- end
451
+ def test_should_update_record
452
+ assert_not_equal @timestamp, @record.updated_at
453
+ end
454
+ end
455
+
456
+ class MachineWithDirtyAttributesTest < BaseTestCase
457
+ def setup
458
+ @resource = new_resource
459
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
460
+ @machine.event :ignite
461
+ @machine.state :idling
373
462
 
374
- def test_should_allow_different_initial_state_when_static
375
- record = @resource.new(:state => 'idling')
376
- assert_equal 'idling', record.state
377
- end
463
+ @record = @resource.create
378
464
 
379
- def test_should_allow_different_initial_state_when_dynamic
380
- @machine.initial_state = lambda {:parked}
381
- record = @resource.new(:state => 'idling')
382
- assert_equal 'idling', record.state
383
- end
384
-
385
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.9.8')
386
- def test_should_raise_exception_if_protected
387
- @resource.class_eval do
388
- protected :state=
389
- end
390
-
391
- assert_raise(ArgumentError) { @resource.new(:state => 'idling') }
392
- end
393
- end
465
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
466
+ @transition.perform(false)
394
467
  end
395
468
 
396
- class MachineWithLoopbackTest < BaseTestCase
397
- def setup
398
- @resource = new_resource do
399
- property :updated_at, DateTime
400
- auto_migrate!
401
-
402
- # Simulate dm-timestamps
403
- before :update do
404
- return unless dirty?
405
- self.updated_at = DateTime.now
406
- end
407
- end
408
-
409
- @machine = StateMachine::Machine.new(@resource, :initial => :parked)
410
- @machine.event :park
411
-
412
- @record = @resource.create(:updated_at => Time.now - 1)
413
- @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
414
-
415
- @timestamp = @record.updated_at
416
- @transition.perform
417
- end
418
-
419
- def test_should_update_record
420
- assert_not_equal @timestamp, @record.updated_at
421
- end
469
+ def test_should_include_state_in_changed_attributes
470
+ assert_equal e = {@resource.properties[:state] => 'idling'}, @record.dirty_attributes
422
471
  end
423
472
 
424
- class MachineWithDirtyAttributesTest < BaseTestCase
425
- def setup
426
- @resource = new_resource
427
- @machine = StateMachine::Machine.new(@resource, :initial => :parked)
428
- @machine.event :ignite
429
- @machine.state :idling
430
-
431
- @record = @resource.create
432
-
433
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
434
- @transition.perform(false)
435
- end
436
-
437
- def test_should_include_state_in_changed_attributes
438
- assert_equal e = {@resource.properties[:state] => 'idling'}, @record.dirty_attributes
439
- end
440
-
441
- def test_should_track_attribute_change
442
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
443
- assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
444
- else
445
- assert_equal e = {:state => 'parked'}, @record.original_values
446
- end
473
+ def test_should_track_attribute_change
474
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
475
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
476
+ else
477
+ assert_equal e = {:state => 'parked'}, @record.original_values
447
478
  end
479
+ end
480
+
481
+ def test_should_not_reset_changes_on_multiple_transitions
482
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
483
+ transition.perform(false)
448
484
 
449
- def test_should_not_reset_changes_on_multiple_transitions
450
- transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
451
- transition.perform(false)
452
-
453
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
454
- assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
455
- else
456
- assert_equal e = {:state => 'parked'}, @record.original_values
457
- end
485
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
486
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.original_attributes
487
+ else
488
+ assert_equal e = {:state => 'parked'}, @record.original_values
458
489
  end
459
490
  end
460
491
 
461
- class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
462
- def setup
463
- @resource = new_resource
464
- @machine = StateMachine::Machine.new(@resource, :initial => :parked)
465
- @machine.event :park
466
-
467
- @record = @resource.create
468
-
469
- @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
470
- @transition.perform(false)
492
+ def test_should_have_changes_when_loaded_from_database
493
+ record = @resource.get(@record.id)
494
+ assert record.dirty_attributes.blank?
471
495
  end
496
+ end
497
+
498
+ class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
499
+ def setup
500
+ @resource = new_resource
501
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
502
+ @machine.event :park
472
503
 
473
- def test_should_include_state_in_changed_attributes
474
- assert_equal e = {@resource.properties[:state] => 'parked'}, @record.dirty_attributes
475
- end
504
+ @record = @resource.create
476
505
 
477
- def test_should_track_attribute_change
478
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
479
- assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
480
- else
481
- assert_equal e = {:state => 'parked-ignored'}, @record.original_values
482
- end
483
- end
506
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
507
+ @transition.perform(false)
484
508
  end
485
509
 
486
- class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
487
- def setup
488
- @resource = new_resource do
489
- property :status, String, :default => 'idling'
490
- auto_migrate!
491
- end
492
- @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
493
- @machine.event :ignite
494
- @machine.state :idling
495
-
496
- @record = @resource.create
497
-
498
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
499
- @transition.perform(false)
510
+ def test_should_include_state_in_changed_attributes
511
+ assert_equal e = {@resource.properties[:state] => 'parked'}, @record.dirty_attributes
512
+ end
513
+
514
+ def test_should_track_attribute_change
515
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
516
+ assert_equal e = {@resource.properties[:state] => 'parked-ignored'}, @record.original_attributes
517
+ else
518
+ assert_equal e = {:state => 'parked-ignored'}, @record.original_values
500
519
  end
501
-
502
- def test_should_include_state_in_changed_attributes
503
- assert_equal e = {@resource.properties[:status] => 'idling'}, @record.dirty_attributes
520
+ end
521
+ end
522
+
523
+ class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
524
+ def setup
525
+ @resource = new_resource do
526
+ property :status, String, :default => 'idling'
527
+ auto_migrate!
504
528
  end
529
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
530
+ @machine.event :ignite
531
+ @machine.state :idling
505
532
 
506
- def test_should_track_attribute_change
507
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
508
- assert_equal e = {@resource.properties[:status] => 'parked'}, @record.original_attributes
509
- else
510
- assert_equal e = {:status => 'parked'}, @record.original_values
511
- end
512
- end
533
+ @record = @resource.create
513
534
 
514
- def test_should_not_reset_changes_on_multiple_transitions
515
- transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
516
- transition.perform(false)
517
-
518
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
519
- assert_equal e = {@resource.properties[:status] => 'parked'}, @record.original_attributes
520
- else
521
- assert_equal e = {:status => 'parked'}, @record.original_values
522
- end
523
- end
535
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
536
+ @transition.perform(false)
524
537
  end
525
538
 
526
- class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
527
- def setup
528
- @resource = new_resource do
529
- property :status, String, :default => 'idling'
530
- auto_migrate!
531
- end
532
- @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
533
- @machine.event :park
534
-
535
- @record = @resource.create
536
-
537
- @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
538
- @transition.perform(false)
539
+ def test_should_include_state_in_changed_attributes
540
+ assert_equal e = {@resource.properties[:status] => 'idling'}, @record.dirty_attributes
541
+ end
542
+
543
+ def test_should_track_attribute_change
544
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
545
+ assert_equal e = {@resource.properties[:status] => 'parked'}, @record.original_attributes
546
+ else
547
+ assert_equal e = {:status => 'parked'}, @record.original_values
539
548
  end
549
+ end
550
+
551
+ def test_should_not_reset_changes_on_multiple_transitions
552
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
553
+ transition.perform(false)
540
554
 
541
- def test_should_include_state_in_changed_attributes
542
- assert_equal e = {@resource.properties[:status] => 'parked'}, @record.dirty_attributes
555
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
556
+ assert_equal e = {@resource.properties[:status] => 'parked'}, @record.original_attributes
557
+ else
558
+ assert_equal e = {:status => 'parked'}, @record.original_values
559
+ end
560
+ end
561
+ end
562
+
563
+ class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
564
+ def setup
565
+ @resource = new_resource do
566
+ property :status, String, :default => 'idling'
567
+ auto_migrate!
543
568
  end
569
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
570
+ @machine.event :park
544
571
 
545
- def test_should_track_attribute_changes
546
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
547
- assert_equal e = {@resource.properties[:status] => 'parked-ignored'}, @record.original_attributes
548
- else
549
- assert_equal e = {:status => 'parked-ignored'}, @record.original_values
550
- end
572
+ @record = @resource.create
573
+
574
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
575
+ @transition.perform(false)
576
+ end
577
+
578
+ def test_should_include_state_in_changed_attributes
579
+ assert_equal e = {@resource.properties[:status] => 'parked'}, @record.dirty_attributes
580
+ end
581
+
582
+ def test_should_track_attribute_changes
583
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
584
+ assert_equal e = {@resource.properties[:status] => 'parked-ignored'}, @record.original_attributes
585
+ else
586
+ assert_equal e = {:status => 'parked-ignored'}, @record.original_values
551
587
  end
552
588
  end
589
+ end
590
+
591
+ class MachineWithoutTransactionsTest < BaseTestCase
592
+ def setup
593
+ @resource = new_resource
594
+ @machine = StateMachine::Machine.new(@resource, :use_transactions => false)
595
+ end
553
596
 
554
- class MachineWithoutTransactionsTest < BaseTestCase
555
- def setup
556
- @resource = new_resource
557
- @machine = StateMachine::Machine.new(@resource, :use_transactions => false)
597
+ def test_should_not_rollback_transaction_if_false
598
+ @machine.within_transaction(@resource.new) do
599
+ @resource.create
600
+ false
558
601
  end
559
602
 
560
- def test_should_not_rollback_transaction_if_false
561
- @machine.within_transaction(@resource.new) do
562
- @resource.create
563
- false
564
- end
565
-
566
- assert_equal 1, @resource.all.size
603
+ assert_equal 1, @resource.all.size
604
+ end
605
+
606
+ def test_should_not_rollback_transaction_if_true
607
+ @machine.within_transaction(@resource.new) do
608
+ @resource.create
609
+ true
567
610
  end
568
611
 
569
- def test_should_not_rollback_transaction_if_true
570
- @machine.within_transaction(@resource.new) do
571
- @resource.create
572
- true
573
- end
574
-
575
- assert_equal 1, @resource.all.size
576
- end
612
+ assert_equal 1, @resource.all.size
613
+ end
614
+ end
615
+
616
+ begin
617
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.3')
618
+ gem 'dm-transactions', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.10.3'
619
+ require 'dm-transactions'
577
620
  end
578
621
 
579
622
  class MachineWithTransactionsTest < BaseTestCase
@@ -600,326 +643,485 @@ begin
600
643
  assert_equal 1, @resource.all.size
601
644
  end
602
645
  end
646
+ rescue LoadError
647
+ $stderr.puts "Skipping DataMapper Transaction tests. `gem install dm-transactions#{" -v #{ENV['VERSION']}" if ENV['VERSION']}` and try again."
648
+ end
649
+
650
+ class MachineWithCallbacksTest < BaseTestCase
651
+ def setup
652
+ @resource = new_resource
653
+ @machine = StateMachine::Machine.new(@resource)
654
+ @machine.state :parked, :idling
655
+ @machine.event :ignite
656
+
657
+ @record = @resource.new(:state => 'parked')
658
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
659
+ end
603
660
 
604
- class MachineWithCallbacksTest < BaseTestCase
605
- def setup
606
- @resource = new_resource
607
- @machine = StateMachine::Machine.new(@resource)
608
- @machine.state :parked, :idling
609
- @machine.event :ignite
610
-
611
- @record = @resource.new(:state => 'parked')
612
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
613
- end
661
+ def test_should_run_before_callbacks
662
+ called = false
663
+ @machine.before_transition {called = true}
614
664
 
615
- def test_should_run_before_callbacks
616
- called = false
617
- @machine.before_transition(lambda {called = true})
618
-
619
- @transition.perform
620
- assert called
621
- end
665
+ @transition.perform
666
+ assert called
667
+ end
668
+
669
+ def test_should_pass_transition_to_before_callbacks_with_one_argument
670
+ transition = nil
671
+ @machine.before_transition {|arg| transition = arg}
622
672
 
623
- def test_should_pass_transition_to_before_callbacks_with_one_argument
624
- transition = nil
625
- @machine.before_transition(lambda {|arg| transition = arg})
626
-
627
- @transition.perform
628
- assert_equal @transition, transition
629
- end
673
+ @transition.perform
674
+ assert_equal @transition, transition
675
+ end
676
+
677
+ def test_should_pass_transition_to_before_callbacks_with_multiple_arguments
678
+ callback_args = nil
679
+ @machine.before_transition {|*args| callback_args = args}
630
680
 
631
- def test_should_pass_transition_to_before_callbacks_with_multiple_arguments
632
- callback_args = nil
633
- @machine.before_transition(lambda {|*args| callback_args = args})
634
-
635
- @transition.perform
636
- assert_equal [@transition], callback_args
637
- end
681
+ @transition.perform
682
+ assert_equal [@transition], callback_args
683
+ end
684
+
685
+ def test_should_run_before_callbacks_within_the_context_of_the_record
686
+ context = nil
687
+ @machine.before_transition {context = self}
638
688
 
639
- def test_should_run_before_callbacks_within_the_context_of_the_record
640
- context = nil
641
- @machine.before_transition(lambda {context = self})
642
-
643
- @transition.perform
644
- assert_equal @record, context
689
+ @transition.perform
690
+ assert_equal @record, context
691
+ end
692
+
693
+ def test_should_run_after_callbacks
694
+ called = false
695
+ @machine.after_transition {called = true}
696
+
697
+ @transition.perform
698
+ assert called
699
+ end
700
+
701
+ def test_should_pass_transition_to_after_callbacks_with_multiple_arguments
702
+ callback_args = nil
703
+ @machine.after_transition {|*args| callback_args = args}
704
+
705
+ @transition.perform
706
+ assert_equal [@transition], callback_args
707
+ end
708
+
709
+ def test_should_run_after_callbacks_with_the_context_of_the_record
710
+ context = nil
711
+ @machine.after_transition {context = self}
712
+
713
+ @transition.perform
714
+ assert_equal @record, context
715
+ end
716
+
717
+ def test_should_run_around_callbacks
718
+ before_called = false
719
+ after_called = [false]
720
+ @machine.around_transition {|block| before_called = true; block.call; after_called[0] = true}
721
+
722
+ @transition.perform
723
+ assert before_called
724
+ assert after_called[0]
725
+ end
726
+
727
+ def test_should_run_around_callbacks_with_the_context_of_the_record
728
+ context = nil
729
+ @machine.around_transition {|block| context = self; block.call}
730
+
731
+ @transition.perform
732
+ assert_equal @record, context
733
+ end
734
+
735
+ def test_should_allow_symbolic_callbacks
736
+ callback_args = nil
737
+
738
+ klass = class << @record; self; end
739
+ klass.send(:define_method, :after_ignite) do |*args|
740
+ callback_args = args
645
741
  end
646
742
 
647
- def test_should_run_after_callbacks
648
- called = false
649
- @machine.after_transition(lambda {called = true})
650
-
651
- @transition.perform
652
- assert called
743
+ @machine.before_transition(:after_ignite)
744
+
745
+ @transition.perform
746
+ assert_equal [@transition], callback_args
747
+ end
748
+
749
+ def test_should_allow_string_callbacks
750
+ class << @record
751
+ attr_reader :callback_result
653
752
  end
654
753
 
655
- def test_should_pass_transition_to_after_callbacks_with_multiple_arguments
656
- callback_args = nil
657
- @machine.after_transition(lambda {|*args| callback_args = args})
658
-
659
- @transition.perform
660
- assert_equal [@transition], callback_args
754
+ @machine.before_transition('@callback_result = [1, 2, 3]')
755
+ @transition.perform
756
+
757
+ assert_equal [1, 2, 3], @record.callback_result
758
+ end
759
+ end
760
+
761
+ class MachineWithFailedBeforeCallbacksTest < BaseTestCase
762
+ def setup
763
+ callbacks = []
764
+
765
+ @resource = new_resource
766
+ @machine = StateMachine::Machine.new(@resource)
767
+ @machine.state :parked, :idling
768
+ @machine.event :ignite
769
+ @machine.before_transition {callbacks << :before_1; throw :halt}
770
+ @machine.before_transition {callbacks << :before_2}
771
+ @machine.after_transition {callbacks << :after}
772
+ @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
773
+
774
+ @record = @resource.new(:state => 'parked')
775
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
776
+ @result = @transition.perform
777
+
778
+ @callbacks = callbacks
779
+ end
780
+
781
+ def test_should_not_be_successful
782
+ assert !@result
783
+ end
784
+
785
+ def test_should_not_change_current_state
786
+ assert_equal 'parked', @record.state
787
+ end
788
+
789
+ def test_should_not_run_action
790
+ assert @record.respond_to?(:new?) ? @record.new? : @record.new_record?
791
+ end
792
+
793
+ def test_should_not_run_further_callbacks
794
+ assert_equal [:before_1], @callbacks
795
+ end
796
+ end
797
+
798
+ class MachineWithFailedActionTest < BaseTestCase
799
+ def setup
800
+ @resource = new_resource do
801
+ before(:create) { throw :halt }
661
802
  end
662
803
 
663
- def test_should_run_after_callbacks_with_the_context_of_the_record
664
- context = nil
665
- @machine.after_transition(lambda {context = self})
666
-
667
- @transition.perform
668
- assert_equal @record, context
669
- end
804
+ @machine = StateMachine::Machine.new(@resource)
805
+ @machine.state :parked, :idling
806
+ @machine.event :ignite
670
807
 
671
- def test_should_allow_symbolic_callbacks
672
- callback_args = nil
673
-
674
- klass = class << @record; self; end
675
- klass.send(:define_method, :after_ignite) do |*args|
676
- callback_args = args
677
- end
678
-
679
- @machine.before_transition(:after_ignite)
680
-
681
- @transition.perform
682
- assert_equal [@transition], callback_args
808
+ callbacks = []
809
+ @machine.before_transition {callbacks << :before}
810
+ @machine.after_transition {callbacks << :after}
811
+ @machine.after_transition(:include_failures => true) {callbacks << :after_failure}
812
+ @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
813
+ @machine.around_transition(:include_failures => true) do |block|
814
+ callbacks << :around_before_failure
815
+ block.call
816
+ callbacks << :around_after_failure
683
817
  end
684
818
 
685
- def test_should_allow_string_callbacks
686
- class << @record
687
- attr_reader :callback_result
688
- end
689
-
690
- @machine.before_transition('@callback_result = [1, 2, 3]')
691
- @transition.perform
692
-
693
- assert_equal [1, 2, 3], @record.callback_result
694
- end
819
+ @record = @resource.new(:state => 'parked')
820
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
821
+ @result = @transition.perform
822
+
823
+ @callbacks = callbacks
824
+ end
825
+
826
+ def test_should_not_be_successful
827
+ assert !@result
828
+ end
829
+
830
+ def test_should_not_change_current_state
831
+ assert_equal 'parked', @record.state
832
+ end
833
+
834
+ def test_should_not_save_record
835
+ assert @record.respond_to?(:new?) ? @record.new? : @record.new_record?
836
+ end
837
+
838
+ def test_should_run_before_callbacks_and_after_callbacks_with_failures
839
+ assert_equal [:before, :around_before, :around_before_failure, :around_after_failure, :after_failure], @callbacks
840
+ end
841
+ end
842
+
843
+ class MachineWithFailedAfterCallbacksTest < BaseTestCase
844
+ def setup
845
+ callbacks = []
846
+
847
+ @resource = new_resource
848
+ @machine = StateMachine::Machine.new(@resource)
849
+ @machine.state :parked, :idling
850
+ @machine.event :ignite
851
+ @machine.after_transition {callbacks << :after_1; throw :halt}
852
+ @machine.after_transition {callbacks << :after_2}
853
+ @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
854
+
855
+ @record = @resource.new(:state => 'parked')
856
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
857
+ @result = @transition.perform
858
+
859
+ @callbacks = callbacks
860
+ end
861
+
862
+ def test_should_be_successful
863
+ assert @result
864
+ end
865
+
866
+ def test_should_change_current_state
867
+ assert_equal 'idling', @record.state
695
868
  end
696
869
 
697
- class MachineWithFailedBeforeCallbacksTest < BaseTestCase
870
+ def test_should_save_record
871
+ assert !(@record.respond_to?(:new?) ? @record.new? : @record.new_record?)
872
+ end
873
+
874
+ def test_should_not_run_further_after_callbacks
875
+ assert_equal [:around_before, :around_after, :after_1], @callbacks
876
+ end
877
+ end
878
+
879
+ begin
880
+ gem 'dm-validations', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.9.4'
881
+ require 'dm-validations'
882
+
883
+ class MachineWithValidationsTest < BaseTestCase
698
884
  def setup
699
- before_count = 0
700
- after_count = 0
701
-
702
885
  @resource = new_resource
703
886
  @machine = StateMachine::Machine.new(@resource)
704
- @machine.state :parked, :idling
705
- @machine.event :ignite
706
- @machine.before_transition(lambda {before_count += 1; throw :halt})
707
- @machine.before_transition(lambda {before_count += 1})
708
- @machine.after_transition(lambda {after_count += 1})
709
-
710
- @record = @resource.new(:state => 'parked')
711
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
712
- @result = @transition.perform
887
+ @machine.state :parked
713
888
 
714
- @before_count = before_count
715
- @after_count = after_count
889
+ @record = @resource.new
716
890
  end
717
891
 
718
- def test_should_not_be_successful
719
- assert !@result
892
+ def test_should_invalidate_using_errors
893
+ @record.state = 'parked'
894
+
895
+ @machine.invalidate(@record, :state, :invalid_transition, [[:event, :park]])
896
+ assert_equal ['cannot transition via "park"'], @record.errors.on(:state)
720
897
  end
721
898
 
722
- def test_should_not_change_current_state
723
- assert_equal 'parked', @record.state
899
+ def test_should_auto_prefix_custom_attributes_on_invalidation
900
+ @machine.invalidate(@record, :event, :invalid)
901
+
902
+ assert_equal ['is invalid'], @record.errors.on(:state_event)
724
903
  end
725
904
 
726
- def test_should_not_run_action
727
- assert @record.respond_to?(:new?) ? @record.new? : @record.new_record?
905
+ def test_should_clear_errors_on_reset
906
+ @record.state = 'parked'
907
+ @record.errors.add(:state, 'is invalid')
908
+
909
+ @machine.reset(@record)
910
+ assert_nil @record.errors.on(:id)
728
911
  end
729
912
 
730
- def test_should_not_run_further_before_callbacks
731
- assert_equal 1, @before_count
913
+ def test_should_be_valid_if_state_is_known
914
+ @record.state = 'parked'
915
+
916
+ assert @record.valid?
732
917
  end
733
918
 
734
- def test_should_not_run_after_callbacks
735
- assert_equal 0, @after_count
919
+ def test_should_not_be_valid_if_state_is_unknown
920
+ @record.state = 'invalid'
921
+
922
+ assert !@record.valid?
923
+ assert_equal ['is invalid'], @record.errors.on(:state)
736
924
  end
737
925
  end
738
926
 
739
- class MachineWithFailedActionTest < BaseTestCase
927
+ class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
740
928
  def setup
741
- @resource = new_resource do
742
- before(:create) { throw :halt }
743
- end
744
-
745
- @machine = StateMachine::Machine.new(@resource)
746
- @machine.state :parked, :idling
747
- @machine.event :ignite
748
-
749
- before_transition_called = false
750
- after_transition_called = false
751
- after_transition_with_failures_called = false
752
- @machine.before_transition(lambda {before_transition_called = true})
753
- @machine.after_transition(lambda {after_transition_called = true})
754
- @machine.after_transition(lambda {after_transition_with_failures_called = true}, :include_failures => true)
755
-
756
- @record = @resource.new(:state => 'parked')
757
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
758
- @result = @transition.perform
929
+ @resource = new_resource
930
+ @machine = StateMachine::Machine.new(@resource, :status, :attribute => :state)
931
+ @machine.state :parked
759
932
 
760
- @before_transition_called = before_transition_called
761
- @after_transition_called = after_transition_called
762
- @after_transition_with_failures_called = after_transition_with_failures_called
763
- end
764
-
765
- def test_should_not_be_successful
766
- assert !@result
767
- end
768
-
769
- def test_should_not_change_current_state
770
- assert_equal 'parked', @record.state
771
- end
772
-
773
- def test_should_not_save_record
774
- assert @record.respond_to?(:new?) ? @record.new? : @record.new_record?
775
- end
776
-
777
- def test_should_run_before_callback
778
- assert @before_transition_called
779
- end
780
-
781
- def test_should_not_run_after_callback_if_not_including_failures
782
- assert !@after_transition_called
933
+ @record = @resource.new
783
934
  end
784
935
 
785
- def test_should_run_after_callback_if_including_failures
786
- assert @after_transition_with_failures_called
936
+ def test_should_add_validation_errors_to_custom_attribute
937
+ @record.state = 'invalid'
938
+
939
+ assert !@record.valid?
940
+ assert_equal ['is invalid'], @record.errors.on(:state)
941
+
942
+ @record.state = 'parked'
943
+ assert @record.valid?
787
944
  end
788
945
  end
789
946
 
790
- class MachineWithFailedAfterCallbacksTest < BaseTestCase
791
- def setup
792
- after_count = 0
947
+ class MachineWithStateDrivenValidationsTest < BaseTestCase
948
+ def setup
949
+ @resource = resource = new_resource do
950
+ attr_accessor :seatbelt
951
+ end
793
952
 
794
- @resource = new_resource
795
953
  @machine = StateMachine::Machine.new(@resource)
796
- @machine.state :parked, :idling
797
- @machine.event :ignite
798
- @machine.after_transition(lambda {after_count += 1; throw :halt})
799
- @machine.after_transition(lambda {after_count += 1})
800
-
801
- @record = @resource.new(:state => 'parked')
802
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
803
- @result = @transition.perform
804
-
805
- @after_count = after_count
806
- end
807
-
808
- def test_should_be_successful
809
- assert @result
954
+ @machine.state :first_gear, :second_gear do
955
+ if resource.respond_to?(:validates_presence_of)
956
+ validates_presence_of :seatbelt
957
+ else
958
+ validates_present :seatbelt
959
+ end
960
+ end
961
+ @machine.other_states :parked
810
962
  end
811
963
 
812
- def test_should_change_current_state
813
- assert_equal 'idling', @record.state
964
+ def test_should_be_valid_if_validation_fails_outside_state_scope
965
+ record = @resource.new(:state => 'parked', :seatbelt => nil)
966
+ assert record.valid?
814
967
  end
815
968
 
816
- def test_should_save_record
817
- assert !(@record.respond_to?(:new?) ? @record.new? : @record.new_record?)
969
+ def test_should_be_invalid_if_validation_fails_within_state_scope
970
+ record = @resource.new(:state => 'first_gear', :seatbelt => nil)
971
+ assert !record.valid?
818
972
  end
819
973
 
820
- def test_should_not_run_further_after_callbacks
821
- assert_equal 1, @after_count
974
+ def test_should_be_valid_if_validation_succeeds_within_state_scope
975
+ record = @resource.new(:state => 'second_gear', :seatbelt => true)
976
+ assert record.valid?
822
977
  end
823
978
  end
824
979
 
825
- begin
826
- gem 'dm-validations', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.4'
827
- require 'dm-validations'
828
-
829
- class MachineWithValidationsTest < BaseTestCase
980
+ # See README caveats
981
+ if Gem::Version.new(::DataMapper::VERSION) > Gem::Version.new('0.9.6')
982
+ class MachineWithEventAttributesOnValidationTest < BaseTestCase
830
983
  def setup
831
984
  @resource = new_resource
832
985
  @machine = StateMachine::Machine.new(@resource)
833
- @machine.state :parked
986
+ @machine.event :ignite do
987
+ transition :parked => :idling
988
+ end
834
989
 
835
990
  @record = @resource.new
991
+ @record.state = 'parked'
992
+ @record.state_event = 'ignite'
836
993
  end
837
994
 
838
- def test_should_invalidate_using_errors
839
- @record.state = 'parked'
840
-
841
- @machine.invalidate(@record, :state, :invalid_transition, [[:event, :park]])
842
- assert_equal ['cannot transition via "park"'], @record.errors.on(:state)
995
+ def test_should_fail_if_event_is_invalid
996
+ @record.state_event = 'invalid'
997
+ assert !@record.valid?
998
+ assert_equal ['is invalid'], @record.errors.full_messages
843
999
  end
844
1000
 
845
- def test_should_auto_prefix_custom_attributes_on_invalidation
846
- @machine.invalidate(@record, :event, :invalid)
847
-
848
- assert_equal ['is invalid'], @record.errors.on(:state_event)
1001
+ def test_should_fail_if_event_has_no_transition
1002
+ @record.state = 'idling'
1003
+ assert !@record.valid?
1004
+ assert_equal ['cannot transition when idling'], @record.errors.full_messages
849
1005
  end
850
1006
 
851
- def test_should_clear_errors_on_reset
852
- @record.state = 'parked'
853
- @record.errors.add(:state, 'is invalid')
854
-
855
- @machine.reset(@record)
856
- assert_nil @record.errors.on(:id)
1007
+ def test_should_be_successful_if_event_has_transition
1008
+ assert @record.valid?
857
1009
  end
858
1010
 
859
- def test_should_be_valid_if_state_is_known
860
- @record.state = 'parked'
1011
+ def test_should_run_before_callbacks
1012
+ ran_callback = false
1013
+ @machine.before_transition { ran_callback = true }
861
1014
 
862
- assert @record.valid?
1015
+ @record.valid?
1016
+ assert ran_callback
863
1017
  end
864
1018
 
865
- def test_should_not_be_valid_if_state_is_unknown
866
- @record.state = 'invalid'
1019
+ def test_should_run_around_callbacks_before_yield
1020
+ ran_callback = false
1021
+ @machine.around_transition {|block| ran_callback = true; block.call }
867
1022
 
868
- assert !@record.valid?
869
- assert_equal ['is invalid'], @record.errors.on(:state)
1023
+ @record.valid?
1024
+ assert ran_callback
870
1025
  end
871
- end
872
-
873
- class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
874
- def setup
875
- @resource = new_resource
876
- @machine = StateMachine::Machine.new(@resource, :status, :attribute => :state)
877
- @machine.state :parked
1026
+
1027
+ def test_should_persist_new_state
1028
+ @record.valid?
1029
+ assert_equal 'idling', @record.state
1030
+ end
1031
+
1032
+ def test_should_not_run_after_callbacks
1033
+ ran_callback = false
1034
+ @machine.after_transition { ran_callback = true }
878
1035
 
879
- @record = @resource.new
1036
+ @record.valid?
1037
+ assert !ran_callback
880
1038
  end
881
1039
 
882
- def test_should_add_validation_errors_to_custom_attribute
883
- @record.state = 'invalid'
1040
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
1041
+ @resource.class_eval do
1042
+ attr_accessor :seatbelt
1043
+ if respond_to?(:validates_presence_of)
1044
+ validates_presence_of :seatbelt
1045
+ else
1046
+ validates_present :seatbelt
1047
+ end
1048
+ end
884
1049
 
885
- assert !@record.valid?
886
- assert_equal ['is invalid'], @record.errors.on(:state)
1050
+ ran_callback = false
1051
+ @machine.after_transition { ran_callback = true }
887
1052
 
888
- @record.state = 'parked'
889
- assert @record.valid?
1053
+ @record.valid?
1054
+ assert !ran_callback
890
1055
  end
891
- end
892
-
893
- class MachineWithStateDrivenValidationsTest < BaseTestCase
894
- def setup
895
- @resource = new_resource do
1056
+
1057
+ def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
1058
+ @resource.class_eval do
896
1059
  attr_accessor :seatbelt
1060
+ if respond_to?(:validates_presence_of)
1061
+ validates_presence_of :seatbelt
1062
+ else
1063
+ validates_present :seatbelt
1064
+ end
897
1065
  end
898
1066
 
899
- @machine = StateMachine::Machine.new(@resource)
900
- @machine.state :first_gear, :second_gear do
901
- validates_present :seatbelt
902
- end
903
- @machine.other_states :parked
1067
+ ran_callback = false
1068
+ @machine.after_transition(:include_failures => true) { ran_callback = true }
1069
+
1070
+ @record.valid?
1071
+ assert ran_callback
1072
+ end
1073
+
1074
+ def test_should_not_run_around_callbacks_after_yield
1075
+ ran_callback = [false]
1076
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1077
+
1078
+ @record.valid?
1079
+ assert !ran_callback[0]
904
1080
  end
905
1081
 
906
- def test_should_be_valid_if_validation_fails_outside_state_scope
907
- record = @resource.new(:state => 'parked', :seatbelt => nil)
908
- assert record.valid?
1082
+ def test_should_not_run_around_callbacks_after_yield_with_failures_disabled_if_validation_fails
1083
+ @resource.class_eval do
1084
+ attr_accessor :seatbelt
1085
+ if respond_to?(:validates_presence_of)
1086
+ validates_presence_of :seatbelt
1087
+ else
1088
+ validates_present :seatbelt
1089
+ end
1090
+ end
1091
+
1092
+ ran_callback = [false]
1093
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1094
+
1095
+ @record.valid?
1096
+ assert !ran_callback[0]
909
1097
  end
910
1098
 
911
- def test_should_be_invalid_if_validation_fails_within_state_scope
912
- record = @resource.new(:state => 'first_gear', :seatbelt => nil)
913
- assert !record.valid?
1099
+ def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_validation_fails
1100
+ @resource.class_eval do
1101
+ attr_accessor :seatbelt
1102
+ if respond_to?(:validates_presence_of)
1103
+ validates_presence_of :seatbelt
1104
+ else
1105
+ validates_present :seatbelt
1106
+ end
1107
+ end
1108
+
1109
+ ran_callback = [false]
1110
+ @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback[0] = true }
1111
+
1112
+ @record.valid?
1113
+ assert ran_callback[0]
914
1114
  end
915
1115
 
916
- def test_should_be_valid_if_validation_succeeds_within_state_scope
917
- record = @resource.new(:state => 'second_gear', :seatbelt => true)
918
- assert record.valid?
1116
+ def test_should_not_run_before_transitions_within_transaction
1117
+ @machine.before_transition { self.class.create; throw :halt }
1118
+
1119
+ assert !@record.valid?
1120
+ assert_equal 1, @resource.all.size
919
1121
  end
920
1122
  end
921
1123
 
922
- class MachineWithEventAttributesOnValidationTest < BaseTestCase
1124
+ class MachineWithEventAttributesOnSaveTest < BaseTestCase
923
1125
  def setup
924
1126
  @resource = new_resource
925
1127
  @machine = StateMachine::Machine.new(@resource)
@@ -934,69 +1136,136 @@ begin
934
1136
 
935
1137
  def test_should_fail_if_event_is_invalid
936
1138
  @record.state_event = 'invalid'
937
- assert !@record.valid?
938
- assert_equal ['is invalid'], @record.errors.full_messages
1139
+ assert !@record.save
939
1140
  end
940
1141
 
941
1142
  def test_should_fail_if_event_has_no_transition
942
1143
  @record.state = 'idling'
943
- assert !@record.valid?
944
- assert_equal ['cannot transition when idling'], @record.errors.full_messages
1144
+ assert !@record.save
945
1145
  end
946
1146
 
947
1147
  def test_should_be_successful_if_event_has_transition
948
- assert @record.valid?
1148
+ assert_equal true, @record.save
949
1149
  end
950
1150
 
951
1151
  def test_should_run_before_callbacks
952
1152
  ran_callback = false
953
1153
  @machine.before_transition { ran_callback = true }
954
1154
 
955
- @record.valid?
1155
+ @record.save
1156
+ assert ran_callback
1157
+ end
1158
+
1159
+ def test_should_run_before_callbacks_once
1160
+ before_count = 0
1161
+ @machine.before_transition { before_count += 1 }
1162
+
1163
+ @record.save
1164
+ assert_equal 1, before_count
1165
+ end
1166
+
1167
+ def test_should_run_around_callbacks_before_yield
1168
+ ran_callback = false
1169
+ @machine.around_transition {|block| ran_callback = true; block.call }
1170
+
1171
+ @record.save
956
1172
  assert ran_callback
957
1173
  end
958
1174
 
1175
+ def test_should_run_around_callbacks_before_yield_once
1176
+ around_before_count = 0
1177
+ @machine.around_transition {|block| around_before_count += 1; block.call }
1178
+
1179
+ @record.save
1180
+ assert_equal 1, around_before_count
1181
+ end
1182
+
959
1183
  def test_should_persist_new_state
960
- @record.valid?
1184
+ @record.save
961
1185
  assert_equal 'idling', @record.state
962
1186
  end
963
1187
 
964
- def test_should_not_run_after_callbacks
1188
+ def test_should_run_after_callbacks
965
1189
  ran_callback = false
966
1190
  @machine.after_transition { ran_callback = true }
967
1191
 
968
- @record.valid?
969
- assert !ran_callback
1192
+ @record.save
1193
+ assert ran_callback
970
1194
  end
971
1195
 
972
- def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
973
- @resource.class_eval do
974
- attr_accessor :seatbelt
975
- validates_present :seatbelt
976
- end
1196
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
1197
+ @resource.before(:create) { throw :halt }
977
1198
 
978
1199
  ran_callback = false
979
1200
  @machine.after_transition { ran_callback = true }
980
1201
 
981
- @record.valid?
982
- assert !ran_callback
1202
+ @record.save
1203
+ assert !ran_callback
1204
+ end
1205
+
1206
+ def test_should_run_after_callbacks_with_failures_enabled_if_fails
1207
+ @resource.before(:create) { throw :halt }
1208
+
1209
+ ran_callback = false
1210
+ @machine.after_transition(:include_failures => true) { ran_callback = true }
1211
+
1212
+ @record.save
1213
+ assert ran_callback
1214
+ end
1215
+
1216
+ def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
1217
+ @resource.before(:create) { throw :halt }
1218
+
1219
+ ran_callback = [false]
1220
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1221
+
1222
+ @record.save
1223
+ assert !ran_callback[0]
1224
+ end
1225
+
1226
+ def test_should_run_around_callbacks_after_yield
1227
+ ran_callback = [false]
1228
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1229
+
1230
+ @record.save
1231
+ assert ran_callback[0]
1232
+ end
1233
+
1234
+ def test_should_run_around_callbacks_after_yield_with_failures_enabled_if_fails
1235
+ @resource.before(:create) { throw :halt }
1236
+
1237
+ ran_callback = [false]
1238
+ @machine.around_transition(:include_failures => true) {|block| block.call; ran_callback[0] = true }
1239
+
1240
+ @record.save
1241
+ assert ran_callback[0]
1242
+ end
1243
+
1244
+ def test_should_not_run_before_transitions_within_transaction
1245
+ @machine.before_transition { self.class.create; throw :halt }
1246
+
1247
+ assert_equal false, @record.save
1248
+ assert_equal 1, @resource.all.size
983
1249
  end
984
1250
 
985
- def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
986
- @resource.class_eval do
987
- attr_accessor :seatbelt
988
- validates_present :seatbelt
989
- end
1251
+ def test_should_not_run_after_transitions_within_transaction
1252
+ @machine.before_transition { self.class.create; throw :halt }
990
1253
 
991
- ran_callback = false
992
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1254
+ assert_equal false, @record.save
1255
+ assert_equal 1, @resource.all.size
1256
+ end
1257
+
1258
+ def test_should_not_run_around_transition_within_transaction
1259
+ @machine.around_transition { self.class.create; throw :halt }
993
1260
 
994
- @record.valid?
995
- assert ran_callback
1261
+ assert_equal false, @record.save
1262
+ assert_equal 1, @resource.all.size
996
1263
  end
997
1264
  end
998
-
999
- class MachineWithEventAttributesOnSaveTest < BaseTestCase
1265
+ end
1266
+
1267
+ if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.10.0')
1268
+ class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
1000
1269
  def setup
1001
1270
  @resource = new_resource
1002
1271
  @machine = StateMachine::Machine.new(@resource)
@@ -1011,23 +1280,23 @@ begin
1011
1280
 
1012
1281
  def test_should_fail_if_event_is_invalid
1013
1282
  @record.state_event = 'invalid'
1014
- assert !@record.save
1283
+ assert !@record.save!
1015
1284
  end
1016
1285
 
1017
1286
  def test_should_fail_if_event_has_no_transition
1018
1287
  @record.state = 'idling'
1019
- assert !@record.save
1288
+ assert !@record.save!
1020
1289
  end
1021
1290
 
1022
1291
  def test_should_be_successful_if_event_has_transition
1023
- assert_equal true, @record.save
1292
+ assert_equal true, @record.save!
1024
1293
  end
1025
1294
 
1026
1295
  def test_should_run_before_callbacks
1027
1296
  ran_callback = false
1028
1297
  @machine.before_transition { ran_callback = true }
1029
1298
 
1030
- @record.save
1299
+ @record.save!
1031
1300
  assert ran_callback
1032
1301
  end
1033
1302
 
@@ -1035,47 +1304,50 @@ begin
1035
1304
  before_count = 0
1036
1305
  @machine.before_transition { before_count += 1 }
1037
1306
 
1038
- @record.save
1307
+ @record.save!
1039
1308
  assert_equal 1, before_count
1040
1309
  end
1041
1310
 
1311
+ def test_should_run_around_callbacks_before_yield
1312
+ ran_callback = false
1313
+ @machine.around_transition {|block| ran_callback = true; block.call }
1314
+
1315
+ @record.save!
1316
+ assert ran_callback
1317
+ end
1318
+
1319
+ def test_should_run_around_callbacks_before_yield_once
1320
+ around_before_count = 0
1321
+ @machine.around_transition {|block| around_before_count += 1; block.call }
1322
+
1323
+ @record.save!
1324
+ assert_equal 1, around_before_count
1325
+ end
1326
+
1042
1327
  def test_should_persist_new_state
1043
- @record.save
1328
+ @record.save!
1044
1329
  assert_equal 'idling', @record.state
1045
1330
  end
1046
1331
 
1047
- # See README caveats
1048
- if Gem::Version.new(::DataMapper::VERSION) >= Gem::Version.new('0.9.7')
1049
- def test_should_run_after_callbacks
1050
- ran_callback = false
1051
- @machine.after_transition { ran_callback = true }
1052
-
1053
- @record.save
1054
- assert ran_callback
1055
- end
1332
+ def test_should_run_after_callbacks
1333
+ ran_callback = false
1334
+ @machine.after_transition { ran_callback = true }
1056
1335
 
1057
- def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
1058
- @resource.before(:create) { throw :halt }
1059
-
1060
- ran_callback = false
1061
- @machine.after_transition { ran_callback = true }
1062
-
1063
- @record.save
1064
- assert !ran_callback
1065
- end
1336
+ @record.save!
1337
+ assert ran_callback
1338
+ end
1339
+
1340
+ def test_should_run_around_callbacks_after_yield
1341
+ ran_callback = [false]
1342
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1066
1343
 
1067
- def test_should_run_after_callbacks_with_failures_enabled_if_fails
1068
- @resource.before(:create) { throw :halt }
1069
-
1070
- ran_callback = false
1071
- @machine.after_transition(:include_failures => true) { ran_callback = true }
1072
-
1073
- @record.save
1074
- assert ran_callback
1075
- end
1344
+ @record.save!
1345
+ assert ran_callback[0]
1076
1346
  end
1077
1347
  end
1078
-
1348
+ end
1349
+
1350
+ if Gem::Version.new(::DataMapper::VERSION) > Gem::Version.new('0.9.6')
1079
1351
  class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
1080
1352
  def setup
1081
1353
  @superclass = new_resource do
@@ -1109,349 +1381,405 @@ begin
1109
1381
  assert_equal 'idling', @record.state
1110
1382
  end
1111
1383
  end
1112
- rescue LoadError
1113
- $stderr.puts "Skipping DataMapper Validation tests. `gem install dm-validations#{" -v #{ENV['DM_VERSION']}" if ENV['DM_VERSION']}` and try again."
1114
1384
  end
1385
+ rescue LoadError
1386
+ $stderr.puts "Skipping DataMapper Validation tests. `gem install dm-validations#{" -v #{ENV['VERSION']}" if ENV['VERSION']}` and try again."
1387
+ end
1388
+
1389
+ begin
1390
+ gem 'dm-observer', ENV['VERSION'] ? "=#{ENV['VERSION']}" : '>=0.9.4'
1391
+ require 'dm-observer'
1115
1392
 
1116
- begin
1117
- gem 'dm-observer', ENV['DM_VERSION'] ? "=#{ENV['DM_VERSION']}" : '>=0.9.4'
1118
- require 'dm-observer'
1393
+ class MachineWithObserversTest < BaseTestCase
1394
+ def setup
1395
+ @resource = new_resource
1396
+ @machine = StateMachine::Machine.new(@resource)
1397
+ @machine.state :parked, :idling
1398
+ @machine.event :ignite
1399
+ @record = @resource.new(:state => 'parked')
1400
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1401
+ end
1119
1402
 
1120
- class MachineWithObserversTest < BaseTestCase
1121
- def setup
1122
- @resource = new_resource
1123
- @machine = StateMachine::Machine.new(@resource)
1124
- @machine.state :parked, :idling
1125
- @machine.event :ignite
1126
- @record = @resource.new(:state => 'parked')
1127
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1403
+ def test_should_provide_matcher_helpers
1404
+ matchers = []
1405
+
1406
+ new_observer(@resource) do
1407
+ matchers = [all, any, same]
1128
1408
  end
1129
1409
 
1130
- def test_should_provide_matcher_helpers
1131
- matchers = []
1132
-
1133
- new_observer(@resource) do
1134
- matchers = [all, any, same]
1410
+ assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
1411
+ end
1412
+
1413
+ def test_should_call_before_transition_callback_if_requirements_match
1414
+ called = false
1415
+
1416
+ observer = new_observer(@resource) do
1417
+ before_transition :from => :parked do
1418
+ called = true
1135
1419
  end
1136
-
1137
- assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
1138
1420
  end
1139
1421
 
1140
- def test_should_call_before_transition_callback_if_requirements_match
1141
- called = false
1142
-
1143
- observer = new_observer(@resource) do
1144
- before_transition :from => :parked do
1145
- called = true
1146
- end
1422
+ @transition.perform
1423
+ assert called
1424
+ end
1425
+
1426
+ def test_should_not_call_before_transition_callback_if_requirements_do_not_match
1427
+ called = false
1428
+
1429
+ observer = new_observer(@resource) do
1430
+ before_transition :from => :idling do
1431
+ called = true
1147
1432
  end
1148
-
1149
- @transition.perform
1150
- assert called
1151
1433
  end
1152
1434
 
1153
- def test_should_not_call_before_transition_callback_if_requirements_do_not_match
1154
- called = false
1155
-
1156
- observer = new_observer(@resource) do
1157
- before_transition :from => :idling do
1158
- called = true
1159
- end
1435
+ @transition.perform
1436
+ assert !called
1437
+ end
1438
+
1439
+ def test_should_pass_transition_to_before_callbacks
1440
+ callback_args = nil
1441
+
1442
+ observer = new_observer(@resource) do
1443
+ before_transition do |*args|
1444
+ callback_args = args
1160
1445
  end
1161
-
1162
- @transition.perform
1163
- assert !called
1164
1446
  end
1165
1447
 
1166
- def test_should_pass_transition_to_before_callbacks
1167
- callback_args = nil
1168
-
1169
- observer = new_observer(@resource) do
1170
- before_transition do |*args|
1171
- callback_args = args
1172
- end
1448
+ @transition.perform
1449
+ assert_equal [@transition], callback_args
1450
+ end
1451
+
1452
+ def test_should_call_after_transition_callback_if_requirements_match
1453
+ called = false
1454
+
1455
+ observer = new_observer(@resource) do
1456
+ after_transition :from => :parked do
1457
+ called = true
1173
1458
  end
1174
-
1175
- @transition.perform
1176
- assert_equal [@transition], callback_args
1177
1459
  end
1178
1460
 
1179
- def test_should_call_after_transition_callback_if_requirements_match
1180
- called = false
1181
-
1182
- observer = new_observer(@resource) do
1183
- after_transition :from => :parked do
1184
- called = true
1185
- end
1461
+ @transition.perform
1462
+ assert called
1463
+ end
1464
+
1465
+ def test_should_not_call_after_transition_callback_if_requirements_do_not_match
1466
+ called = false
1467
+
1468
+ observer = new_observer(@resource) do
1469
+ after_transition :from => :idling do
1470
+ called = true
1186
1471
  end
1187
-
1188
- @transition.perform
1189
- assert called
1190
1472
  end
1191
1473
 
1192
- def test_should_not_call_after_transition_callback_if_requirements_do_not_match
1193
- called = false
1194
-
1195
- observer = new_observer(@resource) do
1196
- after_transition :from => :idling do
1197
- called = true
1198
- end
1474
+ @transition.perform
1475
+ assert !called
1476
+ end
1477
+
1478
+ def test_should_pass_transition_to_after_callbacks
1479
+ callback_args = nil
1480
+
1481
+ observer = new_observer(@resource) do
1482
+ after_transition do |*args|
1483
+ callback_args = args
1199
1484
  end
1200
-
1201
- @transition.perform
1202
- assert !called
1203
1485
  end
1204
1486
 
1205
- def test_should_pass_transition_to_after_callbacks
1206
- callback_args = nil
1207
-
1208
- observer = new_observer(@resource) do
1209
- after_transition do |*args|
1210
- callback_args = args
1211
- end
1487
+ @transition.perform
1488
+ assert_equal [@transition], callback_args
1489
+ end
1490
+
1491
+ def test_should_call_around_transition_callback_if_requirements_match
1492
+ called = false
1493
+
1494
+ observer = new_observer(@resource) do
1495
+ around_transition :from => :parked do |block|
1496
+ called = true
1497
+ block.call
1212
1498
  end
1213
-
1214
- @transition.perform
1215
- assert_equal [@transition], callback_args
1216
1499
  end
1217
1500
 
1218
- def test_should_raise_exception_if_targeting_invalid_machine
1219
- assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) do
1220
- new_observer(@resource) do
1221
- before_transition :invalid, :from => :parked do
1222
- end
1223
- end
1501
+ @transition.perform
1502
+ assert called
1503
+ end
1504
+
1505
+ def test_should_not_call_after_transition_callback_if_requirements_do_not_match
1506
+ called = false
1507
+
1508
+ observer = new_observer(@resource) do
1509
+ around_transition :from => :idling do |block|
1510
+ called = true
1511
+ block.call
1224
1512
  end
1225
1513
  end
1226
1514
 
1227
- def test_should_allow_targeting_specific_machine
1228
- @second_machine = StateMachine::Machine.new(@resource, :status)
1229
- @resource.auto_migrate!
1230
-
1231
- called_state = false
1232
- called_status = false
1233
-
1234
- observer = new_observer(@resource) do
1235
- before_transition :state, :from => :parked do
1236
- called_state = true
1237
- end
1238
-
1239
- before_transition :status, :from => :parked do
1240
- called_status = true
1241
- end
1515
+ @transition.perform
1516
+ assert !called
1517
+ end
1518
+
1519
+ def test_should_pass_transition_to_after_callbacks
1520
+ callback_args = nil
1521
+
1522
+ observer = new_observer(@resource) do
1523
+ around_transition do |*args|
1524
+ block = args.pop
1525
+ callback_args = args
1526
+ block.call
1242
1527
  end
1243
-
1244
- @transition.perform
1245
-
1246
- assert called_state
1247
- assert !called_status
1248
1528
  end
1249
1529
 
1250
- def test_should_allow_targeting_multiple_specific_machines
1251
- @second_machine = StateMachine::Machine.new(@resource, :status)
1252
- @second_machine.state :parked, :idling
1253
- @second_machine.event :ignite
1254
- @resource.auto_migrate!
1255
-
1256
- called_attribute = nil
1257
-
1258
- attributes = []
1259
- observer = new_observer(@resource) do
1260
- before_transition :state, :status, :from => :parked do |transition|
1261
- called_attribute = transition.attribute
1530
+ @transition.perform
1531
+ assert_equal [@transition], callback_args
1532
+ end
1533
+
1534
+ def test_should_raise_exception_if_targeting_invalid_machine
1535
+ assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) do
1536
+ new_observer(@resource) do
1537
+ before_transition :invalid, :from => :parked do
1262
1538
  end
1263
1539
  end
1264
-
1265
- @transition.perform
1266
- assert_equal :state, called_attribute
1267
-
1268
- StateMachine::Transition.new(@record, @second_machine, :ignite, :parked, :idling).perform
1269
- assert_equal :status, called_attribute
1270
1540
  end
1271
1541
  end
1272
1542
 
1273
- class MachineWithMixedCallbacksTest < BaseTestCase
1274
- def setup
1275
- @resource = new_resource
1276
- @machine = StateMachine::Machine.new(@resource)
1277
- @machine.state :parked, :idling
1278
- @machine.event :ignite
1279
- @record = @resource.new(:state => 'parked')
1280
- @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1281
-
1282
- @notifications = notifications = []
1283
-
1284
- # Create callbacks
1285
- @machine.before_transition(lambda {notifications << :callback_before_transition})
1286
- @machine.after_transition(lambda {notifications << :callback_after_transition})
1287
-
1288
- observer = new_observer(@resource) do
1289
- before_transition do
1290
- notifications << :observer_before_transition
1291
- end
1292
-
1293
- after_transition do
1294
- notifications << :observer_after_transition
1295
- end
1543
+ def test_should_allow_targeting_specific_machine
1544
+ @second_machine = StateMachine::Machine.new(@resource, :status)
1545
+ @resource.auto_migrate!
1546
+
1547
+ called_state = false
1548
+ called_status = false
1549
+
1550
+ observer = new_observer(@resource) do
1551
+ before_transition :state, :from => :parked do
1552
+ called_state = true
1296
1553
  end
1297
1554
 
1298
- @transition.perform
1555
+ before_transition :status, :from => :parked do
1556
+ called_status = true
1557
+ end
1299
1558
  end
1300
1559
 
1301
- def test_should_invoke_callbacks_in_specific_order
1302
- expected = [
1303
- :callback_before_transition,
1304
- :observer_before_transition,
1305
- :callback_after_transition,
1306
- :observer_after_transition
1307
- ]
1308
-
1309
- assert_equal expected, @notifications
1560
+ @transition.perform
1561
+
1562
+ assert called_state
1563
+ assert !called_status
1564
+ end
1565
+
1566
+ def test_should_allow_targeting_multiple_specific_machines
1567
+ @second_machine = StateMachine::Machine.new(@resource, :status)
1568
+ @second_machine.state :parked, :idling
1569
+ @second_machine.event :ignite
1570
+ @resource.auto_migrate!
1571
+
1572
+ called_attribute = nil
1573
+
1574
+ attributes = []
1575
+ observer = new_observer(@resource) do
1576
+ before_transition :state, :status, :from => :parked do |transition|
1577
+ called_attribute = transition.attribute
1578
+ end
1310
1579
  end
1580
+
1581
+ @transition.perform
1582
+ assert_equal :state, called_attribute
1583
+
1584
+ StateMachine::Transition.new(@record, @second_machine, :ignite, :parked, :idling).perform
1585
+ assert_equal :status, called_attribute
1311
1586
  end
1312
- rescue LoadError
1313
- $stderr.puts "Skipping DataMapper Observer tests. `gem install dm-observer#{" -v #{ENV['DM_VERSION']}" if ENV['DM_VERSION']}` and try again."
1314
1587
  end
1315
1588
 
1316
- class MachineWithScopesTest < BaseTestCase
1589
+ class MachineWithMixedCallbacksTest < BaseTestCase
1317
1590
  def setup
1318
1591
  @resource = new_resource
1319
1592
  @machine = StateMachine::Machine.new(@resource)
1320
- @machine.state :parked, :first_gear
1321
- @machine.state :idling, :value => lambda {'idling'}
1322
- end
1323
-
1324
- def test_should_create_singular_with_scope
1325
- assert @resource.respond_to?(:with_state)
1326
- end
1327
-
1328
- def test_should_only_include_records_with_state_in_singular_with_scope
1329
- parked = @resource.create :state => 'parked'
1330
- idling = @resource.create :state => 'idling'
1593
+ @machine.state :parked, :idling
1594
+ @machine.event :ignite
1595
+ @record = @resource.new(:state => 'parked')
1596
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1331
1597
 
1332
- assert_equal [parked], @resource.with_state(:parked)
1333
- end
1334
-
1335
- def test_should_create_plural_with_scope
1336
- assert @resource.respond_to?(:with_states)
1337
- end
1338
-
1339
- def test_should_only_include_records_with_states_in_plural_with_scope
1340
- parked = @resource.create :state => 'parked'
1341
- idling = @resource.create :state => 'idling'
1598
+ @notifications = notifications = []
1342
1599
 
1343
- assert_equal [parked, idling], @resource.with_states(:parked, :idling)
1344
- end
1345
-
1346
- def test_should_create_singular_without_scope
1347
- assert @resource.respond_to?(:without_state)
1600
+ # Create callbacks
1601
+ @machine.before_transition {notifications << :callback_before_transition}
1602
+ @machine.after_transition {notifications << :callback_after_transition}
1603
+ @machine.around_transition do |block|
1604
+ notifications << :callback_around_before_transition
1605
+ block.call
1606
+ notifications << :callback_around_after_transition
1607
+ end
1608
+
1609
+ observer = new_observer(@resource) do
1610
+ before_transition do
1611
+ notifications << :observer_before_transition
1612
+ end
1613
+
1614
+ after_transition do
1615
+ notifications << :observer_after_transition
1616
+ end
1617
+
1618
+ around_transition do |block|
1619
+ notifications << :observer_around_before_transition
1620
+ block.call
1621
+ notifications << :observer_around_after_transition
1622
+ end
1623
+ end
1624
+
1625
+ @transition.perform
1348
1626
  end
1349
1627
 
1350
- def test_should_only_include_records_without_state_in_singular_without_scope
1351
- parked = @resource.create :state => 'parked'
1352
- idling = @resource.create :state => 'idling'
1628
+ def test_should_invoke_callbacks_in_specific_order
1629
+ expected = [
1630
+ :callback_before_transition,
1631
+ :callback_around_before_transition,
1632
+ :observer_before_transition,
1633
+ :observer_around_before_transition,
1634
+ :observer_around_after_transition,
1635
+ :callback_around_after_transition,
1636
+ :callback_after_transition,
1637
+ :observer_after_transition
1638
+ ]
1353
1639
 
1354
- assert_equal [parked], @resource.without_state(:idling)
1640
+ assert_equal expected, @notifications
1355
1641
  end
1642
+ end
1643
+ rescue LoadError
1644
+ $stderr.puts "Skipping DataMapper Observer tests. `gem install dm-observer#{" -v #{ENV['VERSION']}" if ENV['VERSION']}` and try again."
1645
+ end
1646
+
1647
+ class MachineWithScopesTest < BaseTestCase
1648
+ def setup
1649
+ @resource = new_resource
1650
+ @machine = StateMachine::Machine.new(@resource)
1651
+ @machine.state :parked, :first_gear
1652
+ @machine.state :idling, :value => lambda {'idling'}
1653
+ end
1654
+
1655
+ def test_should_create_singular_with_scope
1656
+ assert @resource.respond_to?(:with_state)
1657
+ end
1658
+
1659
+ def test_should_only_include_records_with_state_in_singular_with_scope
1660
+ parked = @resource.create :state => 'parked'
1661
+ idling = @resource.create :state => 'idling'
1356
1662
 
1357
- def test_should_create_plural_without_scope
1358
- assert @resource.respond_to?(:without_states)
1359
- end
1663
+ assert_equal [parked], @resource.with_state(:parked)
1664
+ end
1665
+
1666
+ def test_should_create_plural_with_scope
1667
+ assert @resource.respond_to?(:with_states)
1668
+ end
1669
+
1670
+ def test_should_only_include_records_with_states_in_plural_with_scope
1671
+ parked = @resource.create :state => 'parked'
1672
+ idling = @resource.create :state => 'idling'
1360
1673
 
1361
- def test_should_only_include_records_without_states_in_plural_without_scope
1362
- parked = @resource.create :state => 'parked'
1363
- idling = @resource.create :state => 'idling'
1364
- first_gear = @resource.create :state => 'first_gear'
1365
-
1366
- assert_equal [parked, idling], @resource.without_states(:first_gear)
1367
- end
1674
+ assert_equal [parked, idling], @resource.with_states(:parked, :idling)
1675
+ end
1676
+
1677
+ def test_should_create_singular_without_scope
1678
+ assert @resource.respond_to?(:without_state)
1679
+ end
1680
+
1681
+ def test_should_only_include_records_without_state_in_singular_without_scope
1682
+ parked = @resource.create :state => 'parked'
1683
+ idling = @resource.create :state => 'idling'
1368
1684
 
1369
- def test_should_allow_chaining_scopes
1370
- parked = @resource.create :state => 'parked'
1371
- idling = @resource.create :state => 'idling'
1372
-
1373
- assert_equal [idling], @resource.without_state(:parked).with_state(:idling)
1374
- end
1685
+ assert_equal [parked], @resource.without_state(:idling)
1375
1686
  end
1376
1687
 
1377
- class MachineWithScopesAndOwnerSubclassTest < BaseTestCase
1378
- def setup
1379
- @resource = new_resource
1380
- @machine = StateMachine::Machine.new(@resource, :state)
1381
-
1382
- @subclass = Class.new(@resource)
1383
- @subclass_machine = @subclass.state_machine(:state) {}
1384
- @subclass_machine.state :parked, :idling, :first_gear
1385
- end
1688
+ def test_should_create_plural_without_scope
1689
+ assert @resource.respond_to?(:without_states)
1690
+ end
1691
+
1692
+ def test_should_only_include_records_without_states_in_plural_without_scope
1693
+ parked = @resource.create :state => 'parked'
1694
+ idling = @resource.create :state => 'idling'
1695
+ first_gear = @resource.create :state => 'first_gear'
1386
1696
 
1387
- def test_should_only_include_records_with_subclass_states_in_with_scope
1388
- parked = @subclass.create :state => 'parked'
1389
- idling = @subclass.create :state => 'idling'
1390
-
1391
- assert_equal [parked, idling], @subclass.with_states(:parked, :idling)
1392
- end
1697
+ assert_equal [parked, idling], @resource.without_states(:first_gear)
1698
+ end
1699
+
1700
+ def test_should_allow_chaining_scopes
1701
+ parked = @resource.create :state => 'parked'
1702
+ idling = @resource.create :state => 'idling'
1393
1703
 
1394
- def test_should_only_include_records_without_subclass_states_in_without_scope
1395
- parked = @subclass.create :state => 'parked'
1396
- idling = @subclass.create :state => 'idling'
1397
- first_gear = @subclass.create :state => 'first_gear'
1398
-
1399
- assert_equal [parked, idling], @subclass.without_states(:first_gear)
1400
- end
1704
+ assert_equal [idling], @resource.without_state(:parked).with_state(:idling)
1705
+ end
1706
+ end
1707
+
1708
+ class MachineWithScopesAndOwnerSubclassTest < BaseTestCase
1709
+ def setup
1710
+ @resource = new_resource
1711
+ @machine = StateMachine::Machine.new(@resource, :state)
1712
+
1713
+ @subclass = Class.new(@resource)
1714
+ @subclass_machine = @subclass.state_machine(:state) {}
1715
+ @subclass_machine.state :parked, :idling, :first_gear
1401
1716
  end
1402
1717
 
1403
- class MachineWithComplexPluralizationScopesTest < BaseTestCase
1404
- def setup
1405
- @resource = new_resource
1406
- @machine = StateMachine::Machine.new(@resource, :status)
1407
- end
1718
+ def test_should_only_include_records_with_subclass_states_in_with_scope
1719
+ parked = @subclass.create :state => 'parked'
1720
+ idling = @subclass.create :state => 'idling'
1408
1721
 
1409
- def test_should_create_singular_with_scope
1410
- assert @resource.respond_to?(:with_status)
1411
- end
1722
+ assert_equal [parked, idling], @subclass.with_states(:parked, :idling)
1723
+ end
1724
+
1725
+ def test_should_only_include_records_without_subclass_states_in_without_scope
1726
+ parked = @subclass.create :state => 'parked'
1727
+ idling = @subclass.create :state => 'idling'
1728
+ first_gear = @subclass.create :state => 'first_gear'
1412
1729
 
1413
- def test_should_create_plural_with_scope
1414
- assert @resource.respond_to?(:with_statuses)
1415
- end
1730
+ assert_equal [parked, idling], @subclass.without_states(:first_gear)
1731
+ end
1732
+ end
1733
+
1734
+ class MachineWithComplexPluralizationScopesTest < BaseTestCase
1735
+ def setup
1736
+ @resource = new_resource
1737
+ @machine = StateMachine::Machine.new(@resource, :status)
1416
1738
  end
1417
1739
 
1418
- class MachineWithScopesAndJoinsTest < BaseTestCase
1419
- def setup
1420
- @company = new_resource(:company)
1421
- DataMapperTest.const_set('Company', @company)
1422
-
1423
- @vehicle = new_resource(:vehicle) do
1424
- property :company_id, Integer
1425
- auto_migrate!
1426
-
1427
- belongs_to :company
1428
- end
1429
- DataMapperTest.const_set('Vehicle', @vehicle)
1430
-
1431
- @company_machine = StateMachine::Machine.new(@company, :initial => :active)
1432
- @vehicle_machine = StateMachine::Machine.new(@vehicle, :initial => :parked)
1433
- @vehicle_machine.state :idling
1434
-
1435
- @ford = @company.create
1436
- @mustang = @vehicle.create(:company => @ford)
1437
- end
1740
+ def test_should_create_singular_with_scope
1741
+ assert @resource.respond_to?(:with_status)
1742
+ end
1743
+
1744
+ def test_should_create_plural_with_scope
1745
+ assert @resource.respond_to?(:with_statuses)
1746
+ end
1747
+ end
1748
+
1749
+ class MachineWithScopesAndJoinsTest < BaseTestCase
1750
+ def setup
1751
+ @company = new_resource(:company)
1752
+ DataMapperTest.const_set('Company', @company)
1438
1753
 
1439
- def test_should_find_records_in_with_scope
1440
- assert_equal [@mustang], @vehicle.with_states(:parked).all(Vehicle.company.state => 'active')
1754
+ @vehicle = new_resource(:vehicle) do
1755
+ property :company_id, Integer
1756
+ auto_migrate!
1757
+
1758
+ belongs_to :company
1441
1759
  end
1760
+ DataMapperTest.const_set('Vehicle', @vehicle)
1442
1761
 
1443
- def test_should_find_records_in_without_scope
1444
- assert_equal [@mustang], @vehicle.without_states(:idling).all(Vehicle.company.state => 'active')
1445
- end
1762
+ @company_machine = StateMachine::Machine.new(@company, :initial => :active)
1763
+ @vehicle_machine = StateMachine::Machine.new(@vehicle, :initial => :parked)
1764
+ @vehicle_machine.state :idling
1446
1765
 
1447
- def teardown
1448
- DataMapperTest.class_eval do
1449
- remove_const('Vehicle')
1450
- remove_const('Company')
1451
- end
1766
+ @ford = @company.create
1767
+ @mustang = @vehicle.create(:company => @ford)
1768
+ end
1769
+
1770
+ def test_should_find_records_in_with_scope
1771
+ assert_equal [@mustang], @vehicle.with_states(:parked).all(Vehicle.company.state => 'active')
1772
+ end
1773
+
1774
+ def test_should_find_records_in_without_scope
1775
+ assert_equal [@mustang], @vehicle.without_states(:idling).all(Vehicle.company.state => 'active')
1776
+ end
1777
+
1778
+ def teardown
1779
+ DataMapperTest.class_eval do
1780
+ remove_const('Vehicle')
1781
+ remove_const('Company')
1452
1782
  end
1453
1783
  end
1454
1784
  end
1455
- rescue LoadError => ex
1456
- $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."
1457
1785
  end