branston 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/lib/branston/app/controllers/scenarios_controller.rb +6 -5
  2. data/lib/branston/app/controllers/stories_controller.rb +101 -89
  3. data/lib/branston/app/models/story.rb +30 -1
  4. data/lib/branston/app/models/user.rb +4 -0
  5. data/lib/branston/app/views/iterations/index.html.erb +1 -1
  6. data/lib/branston/app/views/layouts/_header.html.erb +1 -2
  7. data/lib/branston/app/views/scenarios/_scenario.html.erb +6 -3
  8. data/lib/branston/app/views/scenarios/_scenarios.html.erb +4 -2
  9. data/lib/branston/app/views/stories/_form.html.erb +15 -4
  10. data/lib/branston/app/views/stories/_story.html.erb +26 -6
  11. data/lib/branston/app/views/stories/edit.html.erb +3 -3
  12. data/lib/branston/app/views/stories/index.html.erb +22 -3
  13. data/lib/branston/app/views/stories/new.html.erb +2 -2
  14. data/lib/branston/app/views/stories/show.html.erb +3 -3
  15. data/lib/branston/config/routes.rb +7 -4
  16. data/lib/branston/coverage/app-controllers-application_controller_rb.html +1 -1
  17. data/lib/branston/coverage/app-controllers-iterations_controller_rb.html +1 -1
  18. data/lib/branston/coverage/app-controllers-outcomes_controller_rb.html +1 -1
  19. data/lib/branston/coverage/app-controllers-preconditions_controller_rb.html +1 -1
  20. data/lib/branston/coverage/app-controllers-releases_controller_rb.html +1 -1
  21. data/lib/branston/coverage/app-controllers-scenarios_controller_rb.html +18 -12
  22. data/lib/branston/coverage/app-controllers-sessions_controller_rb.html +1 -1
  23. data/lib/branston/coverage/app-controllers-stories_controller_rb.html +193 -121
  24. data/lib/branston/coverage/app-controllers-user_roles_controller_rb.html +1 -1
  25. data/lib/branston/coverage/app-controllers-users_controller_rb.html +1 -1
  26. data/lib/branston/coverage/app-helpers-application_helper_rb.html +1 -1
  27. data/lib/branston/coverage/app-helpers-iterations_helper_rb.html +1 -1
  28. data/lib/branston/coverage/app-helpers-outcomes_helper_rb.html +1 -1
  29. data/lib/branston/coverage/app-helpers-preconditions_helper_rb.html +1 -1
  30. data/lib/branston/coverage/app-helpers-releases_helper_rb.html +1 -1
  31. data/lib/branston/coverage/app-helpers-sessions_helper_rb.html +1 -1
  32. data/lib/branston/coverage/app-helpers-stories_helper_rb.html +1 -1
  33. data/lib/branston/coverage/app-helpers-user_roles_helper_rb.html +1 -1
  34. data/lib/branston/coverage/app-models-iteration_rb.html +1 -1
  35. data/lib/branston/coverage/app-models-outcome_rb.html +1 -1
  36. data/lib/branston/coverage/app-models-participation_rb.html +1 -1
  37. data/lib/branston/coverage/app-models-precondition_rb.html +1 -1
  38. data/lib/branston/coverage/app-models-release_rb.html +1 -1
  39. data/lib/branston/coverage/app-models-scenario_rb.html +1 -1
  40. data/lib/branston/coverage/app-models-story_rb.html +192 -18
  41. data/lib/branston/coverage/app-models-user_rb.html +33 -9
  42. data/lib/branston/coverage/app-models-user_role_rb.html +1 -1
  43. data/lib/branston/coverage/index.html +13 -13
  44. data/lib/branston/coverage/lib-client_rb.html +1 -1
  45. data/lib/branston/coverage/lib-faker_extras_rb.html +1 -1
  46. data/lib/branston/coverage/lib-story_generator_rb.html +1 -1
  47. data/lib/branston/db/development.sqlite3 +0 -0
  48. data/lib/branston/db/migrate/20091223100903_add_status_to_story.rb +11 -0
  49. data/lib/branston/db/pristine.sqlite3 +0 -0
  50. data/lib/branston/db/schema.rb +5 -3
  51. data/lib/branston/db/test.sqlite3 +0 -0
  52. data/lib/branston/lib/branston.rb +4 -2
  53. data/lib/branston/log/development.log +4970 -0
  54. data/lib/branston/log/test.log +88225 -0
  55. data/lib/branston/test/blueprints.rb +10 -7
  56. data/lib/branston/test/functional/scenarios_controller_test.rb +22 -15
  57. data/lib/branston/test/functional/stories_controller_test.rb +51 -30
  58. data/lib/branston/test/unit/story_test.rb +47 -7
  59. data/lib/branston/test/unit/user_test.rb +4 -0
  60. data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_flat.txt +3 -2
  61. data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_graph.html +2041 -1307
  62. data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_tree.txt +7922 -7922
  63. data/lib/branston/vendor/plugins/state_machine/CHANGELOG.rdoc +298 -0
  64. data/lib/branston/vendor/plugins/state_machine/LICENSE +20 -0
  65. data/lib/branston/vendor/plugins/state_machine/README.rdoc +466 -0
  66. data/lib/branston/vendor/plugins/state_machine/Rakefile +98 -0
  67. data/lib/branston/vendor/plugins/state_machine/examples/AutoShop_state.png +0 -0
  68. data/lib/branston/vendor/plugins/state_machine/examples/Car_state.png +0 -0
  69. data/lib/branston/vendor/plugins/state_machine/examples/TrafficLight_state.png +0 -0
  70. data/lib/branston/vendor/plugins/state_machine/examples/Vehicle_state.png +0 -0
  71. data/lib/branston/vendor/plugins/state_machine/examples/auto_shop.rb +11 -0
  72. data/lib/branston/vendor/plugins/state_machine/examples/car.rb +19 -0
  73. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/controller.rb +51 -0
  74. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/model.rb +28 -0
  75. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_edit.html.erb +24 -0
  76. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_index.html.erb +23 -0
  77. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_new.html.erb +13 -0
  78. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_show.html.erb +17 -0
  79. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/controller.rb +43 -0
  80. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/migration.rb +11 -0
  81. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/model.rb +23 -0
  82. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_edit.html.erb +25 -0
  83. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_index.html.erb +23 -0
  84. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_new.html.erb +14 -0
  85. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_show.html.erb +17 -0
  86. data/lib/branston/vendor/plugins/state_machine/examples/traffic_light.rb +7 -0
  87. data/lib/branston/vendor/plugins/state_machine/examples/vehicle.rb +31 -0
  88. data/lib/branston/vendor/plugins/state_machine/init.rb +1 -0
  89. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/assertions.rb +36 -0
  90. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/callback.rb +189 -0
  91. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/condition_proxy.rb +94 -0
  92. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/eval_helpers.rb +67 -0
  93. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/event.rb +252 -0
  94. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/event_collection.rb +122 -0
  95. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/extensions.rb +149 -0
  96. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/guard.rb +230 -0
  97. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record/locale.rb +11 -0
  98. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record/observer.rb +41 -0
  99. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record.rb +492 -0
  100. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/data_mapper/observer.rb +139 -0
  101. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/data_mapper.rb +351 -0
  102. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/sequel.rb +322 -0
  103. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations.rb +68 -0
  104. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/machine.rb +1467 -0
  105. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/machine_collection.rb +155 -0
  106. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/matcher.rb +123 -0
  107. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/matcher_helpers.rb +54 -0
  108. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/node_collection.rb +152 -0
  109. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/state.rb +249 -0
  110. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/state_collection.rb +112 -0
  111. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/transition.rb +394 -0
  112. data/lib/branston/vendor/plugins/state_machine/lib/state_machine.rb +388 -0
  113. data/lib/branston/vendor/plugins/state_machine/state_machine.gemspec +30 -0
  114. data/lib/branston/vendor/plugins/state_machine/tasks/state_machine.rake +1 -0
  115. data/lib/branston/vendor/plugins/state_machine/tasks/state_machine.rb +30 -0
  116. data/lib/branston/vendor/plugins/state_machine/test/classes/switch.rb +11 -0
  117. data/lib/branston/vendor/plugins/state_machine/test/functional/state_machine_test.rb +941 -0
  118. data/lib/branston/vendor/plugins/state_machine/test/test_helper.rb +4 -0
  119. data/lib/branston/vendor/plugins/state_machine/test/unit/assertions_test.rb +40 -0
  120. data/lib/branston/vendor/plugins/state_machine/test/unit/callback_test.rb +455 -0
  121. data/lib/branston/vendor/plugins/state_machine/test/unit/condition_proxy_test.rb +328 -0
  122. data/lib/branston/vendor/plugins/state_machine/test/unit/eval_helpers_test.rb +120 -0
  123. data/lib/branston/vendor/plugins/state_machine/test/unit/event_collection_test.rb +326 -0
  124. data/lib/branston/vendor/plugins/state_machine/test/unit/event_test.rb +743 -0
  125. data/lib/branston/vendor/plugins/state_machine/test/unit/guard_test.rb +908 -0
  126. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/active_record_test.rb +1367 -0
  127. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/data_mapper_test.rb +962 -0
  128. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/sequel_test.rb +859 -0
  129. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations_test.rb +42 -0
  130. data/lib/branston/vendor/plugins/state_machine/test/unit/invalid_event_test.rb +7 -0
  131. data/lib/branston/vendor/plugins/state_machine/test/unit/invalid_transition_test.rb +7 -0
  132. data/lib/branston/vendor/plugins/state_machine/test/unit/machine_collection_test.rb +938 -0
  133. data/lib/branston/vendor/plugins/state_machine/test/unit/machine_test.rb +2004 -0
  134. data/lib/branston/vendor/plugins/state_machine/test/unit/matcher_helpers_test.rb +37 -0
  135. data/lib/branston/vendor/plugins/state_machine/test/unit/matcher_test.rb +155 -0
  136. data/lib/branston/vendor/plugins/state_machine/test/unit/node_collection_test.rb +207 -0
  137. data/lib/branston/vendor/plugins/state_machine/test/unit/state_collection_test.rb +280 -0
  138. data/lib/branston/vendor/plugins/state_machine/test/unit/state_machine_test.rb +31 -0
  139. data/lib/branston/vendor/plugins/state_machine/test/unit/state_test.rb +795 -0
  140. data/lib/branston/vendor/plugins/state_machine/test/unit/transition_test.rb +1212 -0
  141. metadata +81 -2
@@ -0,0 +1,859 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ begin
4
+ # Load library
5
+ require 'rubygems'
6
+
7
+ gem 'sequel', ENV['SEQUEL_VERSION'] ? "=#{ENV['SEQUEL_VERSION']}" : '>=2.8.0'
8
+ require 'sequel'
9
+ require 'logger'
10
+
11
+ # Establish database connection
12
+ DB = Sequel.connect('sqlite:///', :loggers => [Logger.new("#{File.dirname(__FILE__)}/../../sequel.log")])
13
+
14
+ module SequelTest
15
+ class BaseTestCase < Test::Unit::TestCase
16
+ def default_test
17
+ end
18
+
19
+ protected
20
+ # Creates a new Sequel model (and the associated table)
21
+ def new_model(auto_migrate = true, &block)
22
+ DB.create_table! :foo do
23
+ primary_key :id
24
+ column :state, :string
25
+ end if auto_migrate
26
+ model = Class.new(Sequel::Model(:foo)) do
27
+ self.raise_on_save_failure = false
28
+ def self.name; 'SequelTest::Foo'; end
29
+ end
30
+ model.plugin(:validation_class_methods) if model.respond_to?(:plugin)
31
+ model.plugin(:hook_class_methods) if model.respond_to?(:plugin)
32
+ model.class_eval(&block) if block_given?
33
+ model
34
+ end
35
+ end
36
+
37
+ class IntegrationTest < BaseTestCase
38
+ def test_should_match_if_class_inherits_from_sequel
39
+ assert StateMachine::Integrations::Sequel.matches?(new_model)
40
+ end
41
+
42
+ def test_should_not_match_if_class_does_not_inherit_from_sequel
43
+ assert !StateMachine::Integrations::Sequel.matches?(Class.new)
44
+ end
45
+ end
46
+
47
+ class MachineByDefaultTest < BaseTestCase
48
+ def setup
49
+ @model = new_model
50
+ @machine = StateMachine::Machine.new(@model)
51
+ end
52
+
53
+ def test_should_use_save_as_action
54
+ assert_equal :save, @machine.action
55
+ end
56
+
57
+ def test_should_use_transactions
58
+ assert_equal true, @machine.use_transactions
59
+ end
60
+ end
61
+
62
+ class MachineTest < BaseTestCase
63
+ def setup
64
+ @model = new_model
65
+ @machine = StateMachine::Machine.new(@model)
66
+ @machine.state :parked, :first_gear
67
+ @machine.state :idling, :value => lambda {'idling'}
68
+ end
69
+
70
+ def test_should_create_singular_with_scope
71
+ assert @model.respond_to?(:with_state)
72
+ end
73
+
74
+ def test_should_only_include_records_with_state_in_singular_with_scope
75
+ parked = @model.create :state => 'parked'
76
+ idling = @model.create :state => 'idling'
77
+
78
+ assert_equal [parked], @model.with_state(:parked).all
79
+ end
80
+
81
+ def test_should_create_plural_with_scope
82
+ assert @model.respond_to?(:with_states)
83
+ end
84
+
85
+ def test_should_only_include_records_with_states_in_plural_with_scope
86
+ parked = @model.create :state => 'parked'
87
+ idling = @model.create :state => 'idling'
88
+
89
+ assert_equal [parked, idling], @model.with_states(:parked, :idling).all
90
+ end
91
+
92
+ def test_should_create_singular_without_scope
93
+ assert @model.respond_to?(:without_state)
94
+ end
95
+
96
+ def test_should_only_include_records_without_state_in_singular_without_scope
97
+ parked = @model.create :state => 'parked'
98
+ idling = @model.create :state => 'idling'
99
+
100
+ assert_equal [parked], @model.without_state(:idling).all
101
+ end
102
+
103
+ def test_should_create_plural_without_scope
104
+ assert @model.respond_to?(:without_states)
105
+ end
106
+
107
+ def test_should_only_include_records_without_states_in_plural_without_scope
108
+ parked = @model.create :state => 'parked'
109
+ idling = @model.create :state => 'idling'
110
+ first_gear = @model.create :state => 'first_gear'
111
+
112
+ assert_equal [parked, idling], @model.without_states(:first_gear).all
113
+ end
114
+
115
+ def test_should_allow_chaining_scopes_and_fitlers
116
+ parked = @model.create :state => 'parked'
117
+ idling = @model.create :state => 'idling'
118
+
119
+ assert_equal [idling], @model.without_state(:parked).filter(:state => 'idling').all
120
+ end
121
+
122
+ def test_should_rollback_transaction_if_false
123
+ @machine.within_transaction(@model.new) do
124
+ @model.create
125
+ false
126
+ end
127
+
128
+ assert_equal 0, @model.count
129
+ end
130
+
131
+ def test_should_not_rollback_transaction_if_true
132
+ @machine.within_transaction(@model.new) do
133
+ @model.create
134
+ true
135
+ end
136
+
137
+ assert_equal 1, @model.count
138
+ end
139
+
140
+ def test_should_invalidate_using_errors
141
+ record = @model.new
142
+ record.state = 'parked'
143
+
144
+ @machine.invalidate(record, :state, :invalid_transition, [[:event, :park]])
145
+
146
+ assert_equal ['cannot transition via "park"'], record.errors.on(:state)
147
+ end
148
+
149
+ def test_should_auto_prefix_custom_attributes_on_invalidation
150
+ record = @model.new
151
+ @machine.invalidate(record, :event, :invalid)
152
+
153
+ assert_equal ['is invalid'], record.errors.on(:state_event)
154
+ end
155
+
156
+ def test_should_clear_errors_on_reset
157
+ record = @model.new
158
+ record.state = 'parked'
159
+ record.errors.add(:state, 'is invalid')
160
+
161
+ @machine.reset(record)
162
+ assert_nil record.errors.on(:id)
163
+ end
164
+
165
+ def test_should_not_override_the_column_reader
166
+ record = @model.new
167
+ record[:state] = 'parked'
168
+ assert_equal 'parked', record.state
169
+ end
170
+
171
+ def test_should_not_override_the_column_writer
172
+ record = @model.new
173
+ record.state = 'parked'
174
+ assert_equal 'parked', record[:state]
175
+ end
176
+ end
177
+
178
+ class MachineUnmigratedTest < BaseTestCase
179
+ def setup
180
+ @model = new_model(false)
181
+ end
182
+
183
+ def test_should_allow_machine_creation
184
+ assert_nothing_raised { StateMachine::Machine.new(@model) }
185
+ end
186
+ end
187
+
188
+ class MachineWithStaticInitialStateTest < BaseTestCase
189
+ def setup
190
+ @model = new_model do
191
+ attr_accessor :value
192
+ end
193
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
194
+ end
195
+
196
+ def test_should_set_initial_state_on_created_object
197
+ record = @model.new
198
+ assert_equal 'parked', record.state
199
+ end
200
+
201
+ def test_should_still_set_attributes
202
+ record = @model.new(:value => 1)
203
+ assert_equal 1, record.value
204
+ end
205
+
206
+ def test_should_still_allow_initialize_blocks
207
+ block_args = nil
208
+ record = @model.new do |*args|
209
+ block_args = args
210
+ end
211
+
212
+ assert_equal [record], block_args
213
+ end
214
+
215
+ def test_should_not_have_any_changed_columns
216
+ record = @model.new
217
+ assert record.changed_columns.empty?
218
+ end
219
+
220
+ def test_should_set_attributes_prior_to_after_initialize_hook
221
+ state = nil
222
+ @model.class_eval do
223
+ define_method(:after_initialize) do
224
+ state = self.state
225
+ end
226
+ end
227
+ @model.new
228
+ assert_equal 'parked', state
229
+ end
230
+
231
+ def test_should_set_initial_state_before_setting_attributes
232
+ @model.class_eval do
233
+ attr_accessor :state_during_setter
234
+
235
+ define_method(:value=) do |value|
236
+ self.state_during_setter = state
237
+ end
238
+ end
239
+
240
+ record = @model.new(:value => 1)
241
+ assert_equal 'parked', record.state_during_setter
242
+ end
243
+
244
+ def test_should_not_set_initial_state_after_already_initialized
245
+ record = @model.new(:value => 1)
246
+ assert_equal 'parked', record.state
247
+
248
+ record.state = 'idling'
249
+ record.set({})
250
+ assert_equal 'idling', record.state
251
+ end
252
+ end
253
+
254
+ class MachineWithDynamicInitialStateTest < BaseTestCase
255
+ def setup
256
+ @model = new_model do
257
+ attr_accessor :value
258
+ end
259
+ @machine = StateMachine::Machine.new(@model, :initial => lambda {|object| :parked})
260
+ @machine.state :parked
261
+ end
262
+
263
+ def test_should_set_initial_state_on_created_object
264
+ record = @model.new
265
+ assert_equal 'parked', record.state
266
+ end
267
+
268
+ def test_should_still_set_attributes
269
+ record = @model.new(:value => 1)
270
+ assert_equal 1, record.value
271
+ end
272
+
273
+ def test_should_still_allow_initialize_blocks
274
+ block_args = nil
275
+ record = @model.new do |*args|
276
+ block_args = args
277
+ end
278
+
279
+ assert_equal [record], block_args
280
+ end
281
+
282
+ def test_should_not_have_any_changed_columns
283
+ record = @model.new
284
+ assert record.changed_columns.empty?
285
+ end
286
+
287
+ def test_should_set_attributes_prior_to_after_initialize_hook
288
+ state = nil
289
+ @model.class_eval do
290
+ define_method(:after_initialize) do
291
+ state = self.state
292
+ end
293
+ end
294
+ @model.new
295
+ assert_equal 'parked', state
296
+ end
297
+
298
+ def test_should_set_initial_state_after_setting_attributes
299
+ @model.class_eval do
300
+ attr_accessor :state_during_setter
301
+
302
+ define_method(:value=) do |value|
303
+ self.state_during_setter = state || 'nil'
304
+ end
305
+ end
306
+
307
+ record = @model.new(:value => 1)
308
+ assert_equal 'nil', record.state_during_setter
309
+ end
310
+
311
+ def test_should_not_set_initial_state_after_already_initialized
312
+ record = @model.new(:value => 1)
313
+ assert_equal 'parked', record.state
314
+
315
+ record.state = 'idling'
316
+ record.set({})
317
+ assert_equal 'idling', record.state
318
+ end
319
+ end
320
+
321
+ class MachineWithColumnDefaultTest < BaseTestCase
322
+ def setup
323
+ @model = new_model
324
+ DB.alter_table :foo do
325
+ add_column :status, :string, :default => 'idling'
326
+ end
327
+ @model.class_eval { get_db_schema(true) }
328
+
329
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
330
+ @record = @model.new
331
+ end
332
+
333
+ def test_should_use_machine_default
334
+ assert_equal 'parked', @record.status
335
+ end
336
+ end
337
+
338
+ class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
339
+ def setup
340
+ @model = new_model do
341
+ def initialize
342
+ # Skip attribute initialization
343
+ @initialized_state_machines = true
344
+ super
345
+ end
346
+ end
347
+
348
+ @machine = StateMachine::Machine.new(@model, :status, :initial => 'parked')
349
+ @record = @model.new
350
+ end
351
+
352
+ def test_should_not_define_a_reader_attribute_for_the_attribute
353
+ assert !@record.respond_to?(:status)
354
+ end
355
+
356
+ def test_should_not_define_a_writer_attribute_for_the_attribute
357
+ assert !@record.respond_to?(:status=)
358
+ end
359
+
360
+ def test_should_define_an_attribute_predicate
361
+ assert @record.respond_to?(:status?)
362
+ end
363
+ end
364
+
365
+ class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
366
+ def setup
367
+ @model = new_model do
368
+ attr_accessor :status
369
+ end
370
+
371
+ @machine = StateMachine::Machine.new(@model, :status, :initial => 'parked')
372
+ @record = @model.new
373
+ end
374
+
375
+ def test_should_set_initial_state_on_created_object
376
+ assert_equal 'parked', @record.status
377
+ end
378
+ end
379
+
380
+ class MachineWithComplexPluralizationTest < BaseTestCase
381
+ def setup
382
+ @model = new_model
383
+ @machine = StateMachine::Machine.new(@model, :status)
384
+ end
385
+
386
+ def test_should_create_singular_with_scope
387
+ assert @model.respond_to?(:with_status)
388
+ end
389
+
390
+ def test_should_create_plural_with_scope
391
+ assert @model.respond_to?(:with_statuses)
392
+ end
393
+ end
394
+
395
+ class MachineWithOwnerSubclassTest < BaseTestCase
396
+ def setup
397
+ @model = new_model
398
+ @machine = StateMachine::Machine.new(@model, :state)
399
+
400
+ @subclass = Class.new(@model)
401
+ @subclass_machine = @subclass.state_machine(:state) {}
402
+ @subclass_machine.state :parked, :idling, :first_gear
403
+ end
404
+
405
+ def test_should_only_include_records_with_subclass_states_in_with_scope
406
+ parked = @subclass.create :state => 'parked'
407
+ idling = @subclass.create :state => 'idling'
408
+
409
+ assert_equal [parked, idling], @subclass.with_states(:parked, :idling).all
410
+ end
411
+
412
+ def test_should_only_include_records_without_subclass_states_in_without_scope
413
+ parked = @subclass.create :state => 'parked'
414
+ idling = @subclass.create :state => 'idling'
415
+ first_gear = @subclass.create :state => 'first_gear'
416
+
417
+ assert_equal [parked, idling], @subclass.without_states(:first_gear).all
418
+ end
419
+ end
420
+
421
+ class MachineWithCustomAttributeTest < BaseTestCase
422
+ def setup
423
+ @model = new_model do
424
+ alias_method :vehicle_status, :state
425
+ alias_method :vehicle_status=, :state=
426
+ end
427
+
428
+ @machine = StateMachine::Machine.new(@model, :status, :attribute => :vehicle_status)
429
+ @machine.state :parked
430
+
431
+ @record = @model.new
432
+ end
433
+
434
+ def test_should_add_validation_errors_to_custom_attribute
435
+ @record.vehicle_status = 'invalid'
436
+
437
+ assert !@record.valid?
438
+ assert_equal ['is invalid'], @record.errors.on(:vehicle_status)
439
+
440
+ @record.vehicle_status = 'parked'
441
+ assert @record.valid?
442
+ end
443
+ end
444
+
445
+ class MachineWithInitializedStateTest < BaseTestCase
446
+ def setup
447
+ @model = new_model
448
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
449
+ @machine.state nil, :idling
450
+ end
451
+
452
+ def test_should_allow_nil_initial_state_when_static
453
+ record = @model.new(:state => nil)
454
+ assert_nil record.state
455
+ end
456
+
457
+ def test_should_allow_nil_initial_state_when_dynamic
458
+ @machine.initial_state = lambda {:parked}
459
+ record = @model.new(:state => nil)
460
+ assert_nil record.state
461
+ end
462
+
463
+ def test_should_allow_different_initial_state_when_static
464
+ record = @model.new(:state => 'idling')
465
+ assert_equal 'idling', record.state
466
+ end
467
+
468
+ def test_should_allow_different_initial_state_when_dynamic
469
+ @machine.initial_state = lambda {:parked}
470
+ record = @model.new(:state => 'idling')
471
+ assert_equal 'idling', record.state
472
+ end
473
+
474
+ def test_should_use_default_state_if_protected
475
+ @model.class_eval do
476
+ self.strict_param_setting = false
477
+ set_restricted_columns :state
478
+ end
479
+
480
+ record = @model.new(:state => 'idling')
481
+ assert_equal 'parked', record.state
482
+ end
483
+ end
484
+
485
+ class MachineWithCallbacksTest < BaseTestCase
486
+ def setup
487
+ @model = new_model
488
+ @machine = StateMachine::Machine.new(@model)
489
+ @machine.state :parked, :idling
490
+ @machine.event :ignite
491
+ @record = @model.new(:state => 'parked')
492
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
493
+ end
494
+
495
+ def test_should_run_before_callbacks
496
+ called = false
497
+ @machine.before_transition(lambda {called = true})
498
+
499
+ @transition.perform
500
+ assert called
501
+ end
502
+
503
+ def test_should_pass_transition_to_before_callbacks_with_one_argument
504
+ transition = nil
505
+ @machine.before_transition(lambda {|arg| transition = arg})
506
+
507
+ @transition.perform
508
+ assert_equal @transition, transition
509
+ end
510
+
511
+ def test_should_pass_transition_to_before_callbacks_with_multiple_arguments
512
+ callback_args = nil
513
+ @machine.before_transition(lambda {|*args| callback_args = args})
514
+
515
+ @transition.perform
516
+ assert_equal [@transition], callback_args
517
+ end
518
+
519
+ def test_should_run_before_callbacks_within_the_context_of_the_record
520
+ context = nil
521
+ @machine.before_transition(lambda {context = self})
522
+
523
+ @transition.perform
524
+ assert_equal @record, context
525
+ end
526
+
527
+ def test_should_run_after_callbacks
528
+ called = false
529
+ @machine.after_transition(lambda {called = true})
530
+
531
+ @transition.perform
532
+ assert called
533
+ end
534
+
535
+ def test_should_pass_transition_to_after_callbacks_with_multiple_arguments
536
+ callback_args = nil
537
+ @machine.after_transition(lambda {|*args| callback_args = args})
538
+
539
+ @transition.perform
540
+ assert_equal [@transition], callback_args
541
+ end
542
+
543
+ def test_should_run_after_callbacks_with_the_context_of_the_record
544
+ context = nil
545
+ @machine.after_transition(lambda {context = self})
546
+
547
+ @transition.perform
548
+ assert_equal @record, context
549
+ end
550
+
551
+ def test_should_allow_symbolic_callbacks
552
+ callback_args = nil
553
+
554
+ klass = class << @record; self; end
555
+ klass.send(:define_method, :after_ignite) do |*args|
556
+ callback_args = args
557
+ end
558
+
559
+ @machine.before_transition(:after_ignite)
560
+
561
+ @transition.perform
562
+ assert_equal [@transition], callback_args
563
+ end
564
+
565
+ def test_should_allow_string_callbacks
566
+ class << @record
567
+ attr_reader :callback_result
568
+ end
569
+
570
+ @machine.before_transition('@callback_result = [1, 2, 3]')
571
+ @transition.perform
572
+
573
+ assert_equal [1, 2, 3], @record.callback_result
574
+ end
575
+ end
576
+
577
+ class MachineWithLoopbackTest < BaseTestCase
578
+ def setup
579
+ changed_columns = nil
580
+
581
+ @model = new_model do
582
+ # Simulate timestamps plugin
583
+ define_method(:before_update) do
584
+ changed_columns = self.changed_columns.dup
585
+
586
+ super()
587
+ self.updated_at = Time.now if changed_columns.any?
588
+ end
589
+ end
590
+
591
+ DB.alter_table :foo do
592
+ add_column :updated_at, :datetime
593
+ end
594
+ @model.class_eval { get_db_schema(true) }
595
+
596
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
597
+ @machine.event :park
598
+
599
+ @record = @model.create(:updated_at => Time.now - 1)
600
+ @timestamp = @record.updated_at
601
+
602
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
603
+ @transition.perform
604
+
605
+ @changed_columns = changed_columns
606
+ end
607
+
608
+ def test_should_include_state_in_changed_columns
609
+ assert_equal [:state], @changed_columns
610
+ end
611
+
612
+ def test_should_update_record
613
+ assert_not_equal @timestamp, @record.updated_at
614
+ end
615
+ end
616
+
617
+ class MachineWithValidationsTest < BaseTestCase
618
+ def setup
619
+ @model = new_model
620
+ @machine = StateMachine::Machine.new(@model)
621
+ @machine.state :parked
622
+
623
+ @record = @model.new
624
+ end
625
+
626
+ def test_should_be_valid_if_state_is_known
627
+ @record.state = 'parked'
628
+
629
+ assert @record.valid?
630
+ end
631
+
632
+ def test_should_not_be_valid_if_state_is_unknown
633
+ @record.state = 'invalid'
634
+
635
+ assert !@record.valid?
636
+ assert_equal ['state is invalid'], @record.errors.full_messages
637
+ end
638
+ end
639
+
640
+ class MachineWithStateDrivenValidationsTest < BaseTestCase
641
+ def setup
642
+ @model = new_model do
643
+ attr_accessor :seatbelt
644
+ end
645
+
646
+ @machine = StateMachine::Machine.new(@model)
647
+ @machine.state :first_gear do
648
+ validates_presence_of :seatbelt
649
+ end
650
+ @machine.other_states :parked
651
+ end
652
+
653
+ def test_should_be_valid_if_validation_fails_outside_state_scope
654
+ record = @model.new(:state => 'parked', :seatbelt => nil)
655
+ assert record.valid?
656
+ end
657
+
658
+ def test_should_be_invalid_if_validation_fails_within_state_scope
659
+ record = @model.new(:state => 'first_gear', :seatbelt => nil)
660
+ assert !record.valid?
661
+ end
662
+
663
+ def test_should_be_valid_if_validation_succeeds_within_state_scope
664
+ record = @model.new(:state => 'first_gear', :seatbelt => true)
665
+ assert record.valid?
666
+ end
667
+ end
668
+
669
+ class MachineWithEventAttributesOnValidationTest < BaseTestCase
670
+ def setup
671
+ @model = new_model
672
+ @machine = StateMachine::Machine.new(@model)
673
+ @machine.event :ignite do
674
+ transition :parked => :idling
675
+ end
676
+
677
+ @record = @model.new
678
+ @record.state = 'parked'
679
+ @record.state_event = 'ignite'
680
+ end
681
+
682
+ def test_should_fail_if_event_is_invalid
683
+ @record.state_event = 'invalid'
684
+ assert !@record.valid?
685
+ assert_equal ['state_event is invalid'], @record.errors.full_messages
686
+ end
687
+
688
+ def test_should_fail_if_event_has_no_transition
689
+ @record.state = 'idling'
690
+ assert !@record.valid?
691
+ assert_equal ['state_event cannot transition when idling'], @record.errors.full_messages
692
+ end
693
+
694
+ def test_should_be_successful_if_event_has_transition
695
+ assert @record.valid?
696
+ end
697
+
698
+ def test_should_run_before_callbacks
699
+ ran_callback = false
700
+ @machine.before_transition { ran_callback = true }
701
+
702
+ @record.valid?
703
+ assert ran_callback
704
+ end
705
+
706
+ def test_should_persist_new_state
707
+ @record.valid?
708
+ assert_equal 'idling', @record.state
709
+ end
710
+
711
+ def test_should_not_run_after_callbacks
712
+ ran_callback = false
713
+ @machine.after_transition { ran_callback = true }
714
+
715
+ @record.valid?
716
+ assert !ran_callback
717
+ end
718
+
719
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
720
+ @model.class_eval do
721
+ attr_accessor :seatbelt
722
+ validates_presence_of :seatbelt
723
+ end
724
+
725
+ ran_callback = false
726
+ @machine.after_transition { ran_callback = true }
727
+
728
+ @record.valid?
729
+ assert !ran_callback
730
+ end
731
+
732
+ def test_should_run_after_callbacks_with_failures_enabled_if_validation_fails
733
+ @model.class_eval do
734
+ attr_accessor :seatbelt
735
+ validates_presence_of :seatbelt
736
+ end
737
+
738
+ ran_callback = false
739
+ @machine.after_transition(:include_failures => true) { ran_callback = true }
740
+
741
+ @record.valid?
742
+ assert ran_callback
743
+ end
744
+ end
745
+
746
+ class MachineWithEventAttributesOnSaveTest < BaseTestCase
747
+ def setup
748
+ @model = new_model
749
+ @machine = StateMachine::Machine.new(@model)
750
+ @machine.event :ignite do
751
+ transition :parked => :idling
752
+ end
753
+
754
+ @record = @model.new
755
+ @record.state = 'parked'
756
+ @record.state_event = 'ignite'
757
+ end
758
+
759
+ def test_should_fail_if_event_is_invalid
760
+ @record.state_event = 'invalid'
761
+ assert !@record.save
762
+ end
763
+
764
+ def test_should_fail_if_event_has_no_transition
765
+ @record.state = 'idling'
766
+ assert !@record.save
767
+ end
768
+
769
+ def test_should_be_successful_if_event_has_transition
770
+ assert @record.save
771
+ end
772
+
773
+ def test_should_run_before_callbacks
774
+ ran_callback = false
775
+ @machine.before_transition { ran_callback = true }
776
+
777
+ @record.save
778
+ assert ran_callback
779
+ end
780
+
781
+ def test_should_run_before_callbacks_once
782
+ before_count = 0
783
+ @machine.before_transition { before_count += 1 }
784
+
785
+ @record.save
786
+ assert_equal 1, before_count
787
+ end
788
+
789
+ def test_should_persist_new_state
790
+ @record.save
791
+ assert_equal 'idling', @record.state
792
+ end
793
+
794
+ def test_should_run_after_callbacks
795
+ ran_callback = false
796
+ @machine.after_transition { ran_callback = true }
797
+
798
+ @record.save
799
+ assert ran_callback
800
+ end
801
+
802
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
803
+ @model.before_create {|record| false}
804
+
805
+ ran_callback = false
806
+ @machine.after_transition { ran_callback = true }
807
+
808
+ @record.save
809
+ assert !ran_callback
810
+ end
811
+
812
+ def test_should_run_after_callbacks_with_failures_enabled_if_fails
813
+ @model.before_create {|record| false}
814
+
815
+ ran_callback = false
816
+ @machine.after_transition(:include_failures => true) { ran_callback = true }
817
+
818
+ @record.save
819
+ assert ran_callback
820
+ end
821
+ end
822
+
823
+ class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
824
+ def setup
825
+ @superclass = new_model do
826
+ def persist
827
+ save
828
+ end
829
+ end
830
+ @model = Class.new(@superclass)
831
+ @machine = StateMachine::Machine.new(@model, :action => :persist)
832
+ @machine.event :ignite do
833
+ transition :parked => :idling
834
+ end
835
+
836
+ @record = @model.new
837
+ @record.state = 'parked'
838
+ @record.state_event = 'ignite'
839
+ end
840
+
841
+ def test_should_not_transition_on_valid?
842
+ @record.valid?
843
+ assert_equal 'parked', @record.state
844
+ end
845
+
846
+ def test_should_not_transition_on_save
847
+ @record.save
848
+ assert_equal 'parked', @record.state
849
+ end
850
+
851
+ def test_should_transition_on_custom_action
852
+ @record.persist
853
+ assert_equal 'idling', @record.state
854
+ end
855
+ end
856
+ end
857
+ rescue LoadError
858
+ $stderr.puts "Skipping Sequel tests. `gem install sequel#{" -v #{ENV['SEQUEL_VERSION']}" if ENV['SEQUEL_VERSION']}` and try again."
859
+ end