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.
- data/CHANGELOG.rdoc +17 -0
- data/LICENSE +1 -1
- data/README.rdoc +162 -23
- data/Rakefile +3 -18
- data/lib/state_machine.rb +3 -4
- data/lib/state_machine/callback.rb +65 -13
- data/lib/state_machine/eval_helpers.rb +20 -4
- data/lib/state_machine/initializers.rb +4 -0
- data/lib/state_machine/initializers/merb.rb +1 -0
- data/lib/state_machine/initializers/rails.rb +7 -0
- data/lib/state_machine/integrations.rb +21 -6
- data/lib/state_machine/integrations/active_model.rb +414 -0
- data/lib/state_machine/integrations/active_model/locale.rb +11 -0
- data/lib/state_machine/integrations/{active_record → active_model}/observer.rb +7 -7
- data/lib/state_machine/integrations/active_record.rb +65 -129
- data/lib/state_machine/integrations/active_record/locale.rb +4 -11
- data/lib/state_machine/integrations/data_mapper.rb +24 -6
- data/lib/state_machine/integrations/data_mapper/observer.rb +36 -0
- data/lib/state_machine/integrations/mongo_mapper.rb +295 -0
- data/lib/state_machine/integrations/sequel.rb +33 -7
- data/lib/state_machine/machine.rb +121 -23
- data/lib/state_machine/machine_collection.rb +12 -103
- data/lib/state_machine/transition.rb +125 -164
- data/lib/state_machine/transition_collection.rb +244 -0
- data/lib/tasks/state_machine.rb +12 -15
- data/test/functional/state_machine_test.rb +11 -1
- data/test/unit/callback_test.rb +305 -32
- data/test/unit/eval_helpers_test.rb +103 -1
- data/test/unit/event_test.rb +2 -1
- data/test/unit/guard_test.rb +2 -1
- data/test/unit/integrations/active_model_test.rb +909 -0
- data/test/unit/integrations/active_record_test.rb +1542 -1292
- data/test/unit/integrations/data_mapper_test.rb +1369 -1041
- data/test/unit/integrations/mongo_mapper_test.rb +1349 -0
- data/test/unit/integrations/sequel_test.rb +1214 -985
- data/test/unit/integrations_test.rb +8 -0
- data/test/unit/machine_collection_test.rb +140 -513
- data/test/unit/machine_test.rb +212 -10
- data/test/unit/state_test.rb +2 -1
- data/test/unit/transition_collection_test.rb +2098 -0
- data/test/unit/transition_test.rb +704 -552
- metadata +16 -3
@@ -1,579 +1,622 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
61
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
149
|
-
|
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
|
-
|
165
|
-
|
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
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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
|
-
|
216
|
-
|
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
|
-
|
226
|
-
|
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
|
-
|
236
|
-
|
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
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
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
|
-
|
253
|
-
assert @record.state?
|
254
|
-
end
|
217
|
+
assert_nil block_args
|
255
218
|
end
|
256
219
|
|
257
|
-
|
258
|
-
|
259
|
-
|
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
|
-
|
264
|
-
|
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
|
-
|
281
|
-
|
282
|
-
|
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
|
-
|
285
|
-
|
286
|
-
|
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
|
-
|
289
|
-
|
290
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
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
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
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
|
-
|
312
|
-
|
313
|
-
|
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
|
-
|
316
|
-
|
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
|
-
|
320
|
-
|
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
|
-
|
324
|
-
|
325
|
-
|
366
|
+
@machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
|
367
|
+
@machine.other_states(:idling)
|
368
|
+
@record = @resource.new
|
326
369
|
end
|
327
370
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
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
|
-
|
335
|
-
@machine.other_states(:idling)
|
336
|
-
@record = @resource.new
|
423
|
+
assert_raise(ArgumentError) { @resource.new(:state => 'idling') }
|
337
424
|
end
|
338
|
-
|
339
|
-
|
340
|
-
|
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
|
-
|
344
|
-
|
345
|
-
end
|
441
|
+
@machine = StateMachine::Machine.new(@resource, :initial => :parked)
|
442
|
+
@machine.event :park
|
346
443
|
|
347
|
-
|
348
|
-
|
349
|
-
end
|
444
|
+
@record = @resource.create(:updated_at => Time.now - 1)
|
445
|
+
@transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
|
350
446
|
|
351
|
-
|
352
|
-
|
353
|
-
end
|
447
|
+
@timestamp = @record.updated_at
|
448
|
+
@transition.perform
|
354
449
|
end
|
355
450
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
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
|
-
|
375
|
-
record = @resource.new(:state => 'idling')
|
376
|
-
assert_equal 'idling', record.state
|
377
|
-
end
|
463
|
+
@record = @resource.create
|
378
464
|
|
379
|
-
|
380
|
-
|
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
|
-
|
397
|
-
|
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
|
-
|
425
|
-
|
426
|
-
@resource
|
427
|
-
|
428
|
-
@
|
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
|
-
|
450
|
-
|
451
|
-
|
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
|
-
|
462
|
-
|
463
|
-
|
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
|
-
|
474
|
-
assert_equal e = {@resource.properties[:state] => 'parked'}, @record.dirty_attributes
|
475
|
-
end
|
504
|
+
@record = @resource.create
|
476
505
|
|
477
|
-
|
478
|
-
|
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
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
@
|
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
|
-
|
503
|
-
|
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
|
-
|
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
|
-
|
515
|
-
|
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
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
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
|
-
|
542
|
-
assert_equal e = {@resource.properties[:status] => 'parked'}, @record.
|
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
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
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
|
-
|
555
|
-
|
556
|
-
@resource
|
557
|
-
|
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
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
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
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
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
|
-
|
605
|
-
|
606
|
-
|
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
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
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
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
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
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
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
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
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
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
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
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
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
|
-
|
664
|
-
|
665
|
-
|
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
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
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
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
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
|
-
|
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
|
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
|
-
@
|
715
|
-
@after_count = after_count
|
889
|
+
@record = @resource.new
|
716
890
|
end
|
717
891
|
|
718
|
-
def
|
719
|
-
|
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
|
723
|
-
|
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
|
727
|
-
|
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
|
731
|
-
|
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
|
735
|
-
|
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
|
927
|
+
class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
|
740
928
|
def setup
|
741
|
-
@resource = new_resource
|
742
|
-
|
743
|
-
|
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
|
-
@
|
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
|
786
|
-
|
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
|
791
|
-
|
792
|
-
|
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 :
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
@
|
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
|
813
|
-
|
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
|
817
|
-
|
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
|
821
|
-
|
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
|
-
|
826
|
-
|
827
|
-
|
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.
|
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
|
839
|
-
@record.
|
840
|
-
|
841
|
-
|
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
|
846
|
-
@
|
847
|
-
|
848
|
-
assert_equal ['
|
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
|
852
|
-
@record.
|
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
|
860
|
-
|
1011
|
+
def test_should_run_before_callbacks
|
1012
|
+
ran_callback = false
|
1013
|
+
@machine.before_transition { ran_callback = true }
|
861
1014
|
|
862
|
-
|
1015
|
+
@record.valid?
|
1016
|
+
assert ran_callback
|
863
1017
|
end
|
864
1018
|
|
865
|
-
def
|
866
|
-
|
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
|
-
|
869
|
-
|
1023
|
+
@record.valid?
|
1024
|
+
assert ran_callback
|
870
1025
|
end
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
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
|
1036
|
+
@record.valid?
|
1037
|
+
assert !ran_callback
|
880
1038
|
end
|
881
1039
|
|
882
|
-
def
|
883
|
-
@
|
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
|
-
|
886
|
-
|
1050
|
+
ran_callback = false
|
1051
|
+
@machine.after_transition { ran_callback = true }
|
887
1052
|
|
888
|
-
@record.
|
889
|
-
assert
|
1053
|
+
@record.valid?
|
1054
|
+
assert !ran_callback
|
890
1055
|
end
|
891
|
-
|
892
|
-
|
893
|
-
|
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
|
-
|
900
|
-
@machine.
|
901
|
-
|
902
|
-
|
903
|
-
|
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
|
907
|
-
|
908
|
-
|
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
|
912
|
-
|
913
|
-
|
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
|
917
|
-
|
918
|
-
|
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
|
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.
|
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.
|
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
|
-
|
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.
|
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.
|
1184
|
+
@record.save
|
961
1185
|
assert_equal 'idling', @record.state
|
962
1186
|
end
|
963
1187
|
|
964
|
-
def
|
1188
|
+
def test_should_run_after_callbacks
|
965
1189
|
ran_callback = false
|
966
1190
|
@machine.after_transition { ran_callback = true }
|
967
1191
|
|
968
|
-
@record.
|
969
|
-
assert
|
1192
|
+
@record.save
|
1193
|
+
assert ran_callback
|
970
1194
|
end
|
971
1195
|
|
972
|
-
def
|
973
|
-
@resource.
|
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.
|
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
|
986
|
-
@
|
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
|
-
|
992
|
-
@
|
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.
|
995
|
-
|
1261
|
+
assert_equal false, @record.save
|
1262
|
+
assert_equal 1, @resource.all.size
|
996
1263
|
end
|
997
1264
|
end
|
998
|
-
|
999
|
-
|
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
|
-
|
1048
|
-
|
1049
|
-
|
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
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
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
|
-
|
1068
|
-
|
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
|
-
|
1117
|
-
|
1118
|
-
|
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
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
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
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
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
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
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
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
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
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
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
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
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
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
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
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
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
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
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
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
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
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
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
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
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
|
-
|
1555
|
+
before_transition :status, :from => :parked do
|
1556
|
+
called_status = true
|
1557
|
+
end
|
1299
1558
|
end
|
1300
1559
|
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
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
|
1589
|
+
class MachineWithMixedCallbacksTest < BaseTestCase
|
1317
1590
|
def setup
|
1318
1591
|
@resource = new_resource
|
1319
1592
|
@machine = StateMachine::Machine.new(@resource)
|
1320
|
-
@machine.state :parked, :
|
1321
|
-
@machine.
|
1322
|
-
|
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
|
-
|
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
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
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
|
1351
|
-
|
1352
|
-
|
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
|
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
|
-
|
1358
|
-
|
1359
|
-
|
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
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
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
|
-
|
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
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
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
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
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
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
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
|
-
|
1404
|
-
|
1405
|
-
|
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
|
-
|
1410
|
-
|
1411
|
-
|
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
|
-
|
1414
|
-
|
1415
|
-
|
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
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
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
|
-
|
1440
|
-
|
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
|
-
|
1444
|
-
|
1445
|
-
|
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
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
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
|