state_machine 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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