state_machine 0.3.1 → 0.4.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 +26 -0
- data/README.rdoc +254 -46
- data/Rakefile +29 -3
- data/examples/AutoShop_state.png +0 -0
- data/examples/Car_state.jpg +0 -0
- data/examples/Vehicle_state.png +0 -0
- data/lib/state_machine.rb +161 -116
- data/lib/state_machine/assertions.rb +21 -0
- data/lib/state_machine/callback.rb +168 -0
- data/lib/state_machine/eval_helpers.rb +67 -0
- data/lib/state_machine/event.rb +135 -101
- data/lib/state_machine/extensions.rb +83 -0
- data/lib/state_machine/guard.rb +115 -0
- data/lib/state_machine/integrations/active_record.rb +242 -0
- data/lib/state_machine/integrations/data_mapper.rb +198 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +153 -0
- data/lib/state_machine/integrations/sequel.rb +169 -0
- data/lib/state_machine/machine.rb +746 -352
- data/lib/state_machine/transition.rb +104 -212
- data/test/active_record.log +34865 -0
- data/test/classes/switch.rb +11 -0
- data/test/data_mapper.log +14015 -0
- data/test/functional/state_machine_test.rb +249 -15
- data/test/sequel.log +3835 -0
- data/test/test_helper.rb +3 -12
- data/test/unit/assertions_test.rb +13 -0
- data/test/unit/callback_test.rb +189 -0
- data/test/unit/eval_helpers_test.rb +92 -0
- data/test/unit/event_test.rb +247 -113
- data/test/unit/guard_test.rb +420 -0
- data/test/unit/integrations/active_record_test.rb +515 -0
- data/test/unit/integrations/data_mapper_test.rb +407 -0
- data/test/unit/integrations/sequel_test.rb +244 -0
- data/test/unit/invalid_transition_test.rb +1 -1
- data/test/unit/machine_test.rb +1056 -98
- data/test/unit/state_machine_test.rb +14 -113
- data/test/unit/transition_test.rb +269 -495
- metadata +44 -30
- data/test/app_root/app/models/auto_shop.rb +0 -34
- data/test/app_root/app/models/car.rb +0 -19
- data/test/app_root/app/models/highway.rb +0 -3
- data/test/app_root/app/models/motorcycle.rb +0 -3
- data/test/app_root/app/models/switch.rb +0 -23
- data/test/app_root/app/models/switch_observer.rb +0 -20
- data/test/app_root/app/models/toggle_switch.rb +0 -2
- data/test/app_root/app/models/vehicle.rb +0 -78
- data/test/app_root/config/environment.rb +0 -7
- data/test/app_root/db/migrate/001_create_switches.rb +0 -12
- data/test/app_root/db/migrate/002_create_auto_shops.rb +0 -13
- data/test/app_root/db/migrate/003_create_highways.rb +0 -11
- data/test/app_root/db/migrate/004_create_vehicles.rb +0 -16
- data/test/factory.rb +0 -77
@@ -0,0 +1,407 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
|
2
|
+
|
3
|
+
begin
|
4
|
+
# Load library
|
5
|
+
require 'rubygems'
|
6
|
+
require 'dm-core'
|
7
|
+
require 'dm-observer'
|
8
|
+
require 'dm-aggregates'
|
9
|
+
|
10
|
+
# Establish database connection
|
11
|
+
DataMapper.setup(:default, 'sqlite3::memory:')
|
12
|
+
DataObjects::Sqlite3.logger = DataObjects::Logger.new("#{File.dirname(__FILE__)}/../../data_mapper.log", 0)
|
13
|
+
|
14
|
+
module DataMapperTest
|
15
|
+
class BaseTestCase < Test::Unit::TestCase
|
16
|
+
def default_test
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
# Creates a new DataMapper resource (and the associated table)
|
21
|
+
def new_resource(auto_migrate = true, &block)
|
22
|
+
resource = Class.new do
|
23
|
+
include DataMapper::Resource
|
24
|
+
|
25
|
+
storage_names[:default] = 'foo'
|
26
|
+
def self.name; 'DataMapperTest::Foo'; end
|
27
|
+
|
28
|
+
property :id, Integer, :serial => true
|
29
|
+
property :state, String
|
30
|
+
|
31
|
+
auto_migrate! if auto_migrate
|
32
|
+
end
|
33
|
+
resource.class_eval(&block) if block_given?
|
34
|
+
resource
|
35
|
+
end
|
36
|
+
|
37
|
+
# Creates a new DataMapper observer
|
38
|
+
def new_observer(resource, &block)
|
39
|
+
observer = Class.new do
|
40
|
+
include DataMapper::Observer
|
41
|
+
end
|
42
|
+
observer.observe(resource)
|
43
|
+
observer.class_eval(&block) if block_given?
|
44
|
+
observer
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class IntegrationTest < BaseTestCase
|
49
|
+
def test_should_match_if_class_inherits_from_active_record
|
50
|
+
assert StateMachine::Integrations::DataMapper.matches?(new_resource)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_not_match_if_class_does_not_inherit_from_active_record
|
54
|
+
assert !StateMachine::Integrations::DataMapper.matches?(Class.new)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class MachineByDefaultTest < BaseTestCase
|
59
|
+
def setup
|
60
|
+
@resource = new_resource
|
61
|
+
@machine = StateMachine::Machine.new(@resource)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_should_use_save_as_action
|
65
|
+
assert_equal :save, @machine.action
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class MachineTest < BaseTestCase
|
70
|
+
def setup
|
71
|
+
@resource = new_resource
|
72
|
+
@machine = StateMachine::Machine.new(@resource)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_create_singular_with_scope
|
76
|
+
assert @resource.respond_to?(:with_state)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_should_only_include_records_with_state_in_singular_with_scope
|
80
|
+
off = @resource.create :state => 'off'
|
81
|
+
on = @resource.create :state => 'on'
|
82
|
+
|
83
|
+
assert_equal [off], @resource.with_state('off')
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_should_create_plural_with_scope
|
87
|
+
assert @resource.respond_to?(:with_states)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_should_only_include_records_with_states_in_plural_with_scope
|
91
|
+
off = @resource.create :state => 'off'
|
92
|
+
on = @resource.create :state => 'on'
|
93
|
+
|
94
|
+
assert_equal [off, on], @resource.with_states('off', 'on')
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_should_create_singular_without_scope
|
98
|
+
assert @resource.respond_to?(:without_state)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_should_only_include_records_without_state_in_singular_without_scope
|
102
|
+
off = @resource.create :state => 'off'
|
103
|
+
on = @resource.create :state => 'on'
|
104
|
+
|
105
|
+
assert_equal [off], @resource.without_state('on')
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_should_create_plural_without_scope
|
109
|
+
assert @resource.respond_to?(:without_states)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_should_only_include_records_without_states_in_plural_without_scope
|
113
|
+
off = @resource.create :state => 'off'
|
114
|
+
on = @resource.create :state => 'on'
|
115
|
+
error = @resource.create :state => 'error'
|
116
|
+
|
117
|
+
assert_equal [off, on], @resource.without_states('error')
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_should_rollback_transaction_if_false
|
121
|
+
@machine.within_transaction(@resource.new) do
|
122
|
+
@resource.create
|
123
|
+
false
|
124
|
+
end
|
125
|
+
|
126
|
+
assert_equal 0, @resource.count
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_should_not_rollback_transaction_if_true
|
130
|
+
@machine.within_transaction(@resource.new) do
|
131
|
+
@resource.create
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
assert_equal 1, @resource.count
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_should_not_override_the_column_reader
|
139
|
+
record = @resource.new
|
140
|
+
record.attribute_set(:state, 'off')
|
141
|
+
assert_equal 'off', record.state
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_should_not_override_the_column_writer
|
145
|
+
record = @resource.new
|
146
|
+
record.state = 'off'
|
147
|
+
assert_equal 'off', record.attribute_get(:state)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class MachineUnmigratedTest < BaseTestCase
|
152
|
+
def setup
|
153
|
+
@resource = new_resource(false)
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_should_allow_machine_creation
|
157
|
+
assert_nothing_raised { StateMachine::Machine.new(@resource) }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class MachineWithInitialStateTest < BaseTestCase
|
162
|
+
def setup
|
163
|
+
@resource = new_resource
|
164
|
+
@machine = StateMachine::Machine.new(@resource, :initial => 'off')
|
165
|
+
@record = @resource.new
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_set_initial_state_on_created_object
|
169
|
+
assert_equal 'off', @record.state
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class MachineWithNonColumnStateAttributeTest < BaseTestCase
|
174
|
+
def setup
|
175
|
+
@resource = new_resource
|
176
|
+
@machine = StateMachine::Machine.new(@resource, :status, :initial => 'off')
|
177
|
+
@record = @resource.new
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_should_define_a_reader_attribute_for_the_attribute
|
181
|
+
assert @record.respond_to?(:status)
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_should_define_a_writer_attribute_for_the_attribute
|
185
|
+
assert @record.respond_to?(:status=)
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_should_set_initial_state_on_created_object
|
189
|
+
assert_equal 'off', @record.status
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
class MachineWithCallbacksTest < BaseTestCase
|
194
|
+
def setup
|
195
|
+
@resource = new_resource
|
196
|
+
@machine = StateMachine::Machine.new(@resource)
|
197
|
+
@record = @resource.new(:state => 'off')
|
198
|
+
@transition = StateMachine::Transition.new(@record, @machine, 'turn_on', 'off', 'on')
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_should_run_before_callbacks
|
202
|
+
called = false
|
203
|
+
@machine.before_transition(lambda {called = true})
|
204
|
+
|
205
|
+
@transition.perform
|
206
|
+
assert called
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_should_pass_transition_into_before_callbacks_with_one_argument
|
210
|
+
transition = nil
|
211
|
+
@machine.before_transition(lambda {|arg| transition = arg})
|
212
|
+
|
213
|
+
@transition.perform
|
214
|
+
assert_equal @transition, transition
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_should_pass_transition_into_before_callbacks_with_multiple_arguments
|
218
|
+
callback_args = nil
|
219
|
+
@machine.before_transition(lambda {|*args| callback_args = args})
|
220
|
+
|
221
|
+
@transition.perform
|
222
|
+
assert_equal [@transition], callback_args
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_should_run_before_callbacks_within_the_context_of_the_record
|
226
|
+
context = nil
|
227
|
+
@machine.before_transition(lambda {context = self})
|
228
|
+
|
229
|
+
@transition.perform
|
230
|
+
assert_equal @record, context
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_should_run_after_callbacks
|
234
|
+
called = false
|
235
|
+
@machine.after_transition(lambda {called = true})
|
236
|
+
|
237
|
+
@transition.perform
|
238
|
+
assert called
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_should_pass_transition_and_result_into_after_callbacks_with_multiple_arguments
|
242
|
+
callback_args = nil
|
243
|
+
@machine.after_transition(lambda {|*args| callback_args = args})
|
244
|
+
|
245
|
+
@transition.perform
|
246
|
+
assert_equal [@transition, true], callback_args
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_should_run_after_callbacks_with_the_context_of_the_record
|
250
|
+
context = nil
|
251
|
+
@machine.after_transition(lambda {context = self})
|
252
|
+
|
253
|
+
@transition.perform
|
254
|
+
assert_equal @record, context
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class MachineWithObserversTest < BaseTestCase
|
259
|
+
def setup
|
260
|
+
@resource = new_resource
|
261
|
+
@machine = StateMachine::Machine.new(@resource)
|
262
|
+
@record = @resource.new(:state => 'off')
|
263
|
+
@transition = StateMachine::Transition.new(@record, @machine, 'turn_on', 'off', 'on')
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_should_call_before_transition_callback_if_requirements_match
|
267
|
+
called = false
|
268
|
+
|
269
|
+
observer = new_observer(@resource) do
|
270
|
+
before_transition :from => 'off' do
|
271
|
+
called = true
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
@transition.perform
|
276
|
+
assert called
|
277
|
+
end
|
278
|
+
|
279
|
+
def test_should_not_call_before_transition_callback_if_requirements_do_not_match
|
280
|
+
called = false
|
281
|
+
|
282
|
+
observer = new_observer(@resource) do
|
283
|
+
before_transition :from => 'on' do
|
284
|
+
called = true
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
@transition.perform
|
289
|
+
assert !called
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_should_allow_targeting_specific_machine
|
293
|
+
@second_machine = StateMachine::Machine.new(@resource, :status)
|
294
|
+
|
295
|
+
called_state = false
|
296
|
+
called_status = false
|
297
|
+
|
298
|
+
observer = new_observer(@resource) do
|
299
|
+
before_transition :state, :from => 'off' do
|
300
|
+
called_state = true
|
301
|
+
end
|
302
|
+
|
303
|
+
before_transition :status, :from => 'off' do
|
304
|
+
called_status = true
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
@transition.perform
|
309
|
+
|
310
|
+
assert called_state
|
311
|
+
assert !called_status
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_should_pass_transition_to_before_callbacks
|
315
|
+
callback_args = nil
|
316
|
+
|
317
|
+
observer = new_observer(@resource) do
|
318
|
+
before_transition do |*args|
|
319
|
+
callback_args = args
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
@transition.perform
|
324
|
+
assert_equal [@transition], callback_args
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_should_call_after_transition_callback_if_requirements_match
|
328
|
+
called = false
|
329
|
+
|
330
|
+
observer = new_observer(@resource) do
|
331
|
+
after_transition :from => 'off' do
|
332
|
+
called = true
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
@transition.perform
|
337
|
+
assert called
|
338
|
+
end
|
339
|
+
|
340
|
+
def test_should_not_call_after_transition_callback_if_requirements_do_not_match
|
341
|
+
called = false
|
342
|
+
|
343
|
+
observer = new_observer(@resource) do
|
344
|
+
after_transition :from => 'on' do
|
345
|
+
called = true
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
@transition.perform
|
350
|
+
assert !called
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_should_pass_transition_and_result_to_before_callbacks
|
354
|
+
callback_args = nil
|
355
|
+
|
356
|
+
observer = new_observer(@resource) do
|
357
|
+
after_transition do |*args|
|
358
|
+
callback_args = args
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
@transition.perform
|
363
|
+
assert_equal [@transition, true], callback_args
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
class MachineWithMixedCallbacksTest < BaseTestCase
|
368
|
+
def setup
|
369
|
+
@resource = new_resource
|
370
|
+
@machine = StateMachine::Machine.new(@resource)
|
371
|
+
@record = @resource.new(:state => 'off')
|
372
|
+
@transition = StateMachine::Transition.new(@record, @machine, 'turn_on', 'off', 'on')
|
373
|
+
|
374
|
+
@notifications = notifications = []
|
375
|
+
|
376
|
+
# Create callbacks
|
377
|
+
@machine.before_transition(lambda {notifications << :callback_before_transition})
|
378
|
+
@machine.after_transition(lambda {notifications << :callback_after_transition})
|
379
|
+
|
380
|
+
observer = new_observer(@resource) do
|
381
|
+
before_transition do
|
382
|
+
notifications << :observer_before_transition
|
383
|
+
end
|
384
|
+
|
385
|
+
after_transition do
|
386
|
+
notifications << :observer_after_transition
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
@transition.perform
|
391
|
+
end
|
392
|
+
|
393
|
+
def test_should_invoke_callbacks_in_specific_order
|
394
|
+
expected = [
|
395
|
+
:callback_before_transition,
|
396
|
+
:observer_before_transition,
|
397
|
+
:callback_after_transition,
|
398
|
+
:observer_after_transition
|
399
|
+
]
|
400
|
+
|
401
|
+
assert_equal expected, @notifications
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
rescue LoadError
|
406
|
+
$stderr.puts 'Skipping DataMapper tests. `gem install dm-core dm-observer dm-aggregates` and try again.'
|
407
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
|
2
|
+
|
3
|
+
begin
|
4
|
+
# Load library
|
5
|
+
require 'rubygems'
|
6
|
+
require 'sequel'
|
7
|
+
require 'logger'
|
8
|
+
|
9
|
+
# Establish database connection
|
10
|
+
DB = Sequel.connect('sqlite:///', :loggers => [Logger.new("#{File.dirname(__FILE__)}/../../sequel.log")])
|
11
|
+
|
12
|
+
module SequelTest
|
13
|
+
class BaseTestCase < Test::Unit::TestCase
|
14
|
+
def default_test
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
# Creates a new Sequel model (and the associated table)
|
19
|
+
def new_model(auto_migrate = true, &block)
|
20
|
+
DB.create_table! :foo do
|
21
|
+
primary_key :id
|
22
|
+
column :state, :string
|
23
|
+
end if auto_migrate
|
24
|
+
model = Class.new(Sequel::Model(:foo)) do
|
25
|
+
def self.name; 'SequelTest::Foo'; end
|
26
|
+
end
|
27
|
+
model.class_eval(&block) if block_given?
|
28
|
+
model
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class IntegrationTest < BaseTestCase
|
33
|
+
def test_should_match_if_class_inherits_from_sequel
|
34
|
+
assert StateMachine::Integrations::Sequel.matches?(new_model)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_not_match_if_class_does_not_inherit_from_sequel
|
38
|
+
assert !StateMachine::Integrations::Sequel.matches?(Class.new)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class MachineByDefaultTest < BaseTestCase
|
43
|
+
def setup
|
44
|
+
@model = new_model
|
45
|
+
@machine = StateMachine::Machine.new(@model)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_should_use_save_as_action
|
49
|
+
assert_equal :save, @machine.action
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class MachineTest < BaseTestCase
|
54
|
+
def setup
|
55
|
+
@model = new_model
|
56
|
+
@machine = StateMachine::Machine.new(@model)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_should_create_singular_with_scope
|
60
|
+
assert @model.respond_to?(:with_state)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_should_only_include_records_with_state_in_singular_with_scope
|
64
|
+
off = @model.create :state => 'off'
|
65
|
+
on = @model.create :state => 'on'
|
66
|
+
|
67
|
+
assert_equal [off], @model.with_state('off').all
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_create_plural_with_scope
|
71
|
+
assert @model.respond_to?(:with_states)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_should_only_include_records_with_states_in_plural_with_scope
|
75
|
+
off = @model.create :state => 'off'
|
76
|
+
on = @model.create :state => 'on'
|
77
|
+
|
78
|
+
assert_equal [off, on], @model.with_states('off', 'on').all
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_should_create_singular_without_scope
|
82
|
+
assert @model.respond_to?(:without_state)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_should_only_include_records_without_state_in_singular_without_scope
|
86
|
+
off = @model.create :state => 'off'
|
87
|
+
on = @model.create :state => 'on'
|
88
|
+
|
89
|
+
assert_equal [off], @model.without_state('on').all
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_should_create_plural_without_scope
|
93
|
+
assert @model.respond_to?(:without_states)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_should_only_include_records_without_states_in_plural_without_scope
|
97
|
+
off = @model.create :state => 'off'
|
98
|
+
on = @model.create :state => 'on'
|
99
|
+
error = @model.create :state => 'error'
|
100
|
+
|
101
|
+
assert_equal [off, on], @model.without_states('error').all
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_should_rollback_transaction_if_false
|
105
|
+
@machine.within_transaction(@model.new) do
|
106
|
+
@model.create
|
107
|
+
false
|
108
|
+
end
|
109
|
+
|
110
|
+
assert_equal 0, @model.count
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_should_not_rollback_transaction_if_true
|
114
|
+
@machine.within_transaction(@model.new) do
|
115
|
+
@model.create
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
assert_equal 1, @model.count
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_should_not_override_the_column_reader
|
123
|
+
record = @model.new
|
124
|
+
record[:state] = 'off'
|
125
|
+
assert_equal 'off', record.state
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_should_not_override_the_column_writer
|
129
|
+
record = @model.new
|
130
|
+
record.state = 'off'
|
131
|
+
assert_equal 'off', record[:state]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class MachineUnmigratedTest < BaseTestCase
|
136
|
+
def setup
|
137
|
+
@model = new_model(false)
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_should_allow_machine_creation
|
141
|
+
assert_nothing_raised { StateMachine::Machine.new(@model) }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class MachineWithInitialStateTest < BaseTestCase
|
146
|
+
def setup
|
147
|
+
@model = new_model
|
148
|
+
@machine = StateMachine::Machine.new(@model, :initial => 'off')
|
149
|
+
@record = @model.new
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_should_set_initial_state_on_created_object
|
153
|
+
assert_equal 'off', @record.state
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class MachineWithNonColumnStateAttributeTest < BaseTestCase
|
158
|
+
def setup
|
159
|
+
@model = new_model
|
160
|
+
@machine = StateMachine::Machine.new(@model, :status, :initial => 'off')
|
161
|
+
@record = @model.new
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_should_define_a_reader_attribute_for_the_attribute
|
165
|
+
assert @record.respond_to?(:status)
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_define_a_writer_attribute_for_the_attribute
|
169
|
+
assert @record.respond_to?(:status=)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_should_set_initial_state_on_created_object
|
173
|
+
assert_equal 'off', @record.status
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class MachineWithCallbacksTest < BaseTestCase
|
178
|
+
def setup
|
179
|
+
@model = new_model
|
180
|
+
@machine = StateMachine::Machine.new(@model)
|
181
|
+
@record = @model.new(:state => 'off')
|
182
|
+
@transition = StateMachine::Transition.new(@record, @machine, 'turn_on', 'off', 'on')
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_should_run_before_callbacks
|
186
|
+
called = false
|
187
|
+
@machine.before_transition(lambda {called = true})
|
188
|
+
|
189
|
+
@transition.perform
|
190
|
+
assert called
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_should_pass_transition_into_before_callbacks_with_one_argument
|
194
|
+
transition = nil
|
195
|
+
@machine.before_transition(lambda {|arg| transition = arg})
|
196
|
+
|
197
|
+
@transition.perform
|
198
|
+
assert_equal @transition, transition
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_should_pass_transition_into_before_callbacks_with_multiple_arguments
|
202
|
+
callback_args = nil
|
203
|
+
@machine.before_transition(lambda {|*args| callback_args = args})
|
204
|
+
|
205
|
+
@transition.perform
|
206
|
+
assert_equal [@transition], callback_args
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_should_run_before_callbacks_within_the_context_of_the_record
|
210
|
+
context = nil
|
211
|
+
@machine.before_transition(lambda {context = self})
|
212
|
+
|
213
|
+
@transition.perform
|
214
|
+
assert_equal @record, context
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_should_run_after_callbacks
|
218
|
+
called = false
|
219
|
+
@machine.after_transition(lambda {called = true})
|
220
|
+
|
221
|
+
@transition.perform
|
222
|
+
assert called
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_should_pass_transition_and_result_into_after_callbacks_with_multiple_arguments
|
226
|
+
callback_args = nil
|
227
|
+
@machine.after_transition(lambda {|*args| callback_args = args})
|
228
|
+
|
229
|
+
@transition.perform
|
230
|
+
assert_equal [@transition, @record], callback_args
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_should_run_after_callbacks_with_the_context_of_the_record
|
234
|
+
context = nil
|
235
|
+
@machine.after_transition(lambda {context = self})
|
236
|
+
|
237
|
+
@transition.perform
|
238
|
+
assert_equal @record, context
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
rescue LoadError
|
243
|
+
$stderr.puts 'Skipping Sequel tests. `gem install sequel` and try again.'
|
244
|
+
end
|