state_machine_deuxito 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (310) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +8 -0
  4. data/.yardopts +5 -0
  5. data/Appraisals +12 -0
  6. data/CHANGELOG.md +502 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +20 -0
  9. data/README.md +8 -0
  10. data/Rakefile +41 -0
  11. data/TODO.md +2 -0
  12. data/examples/AutoShop_state.png +0 -0
  13. data/examples/Car_state.png +0 -0
  14. data/examples/Gemfile +5 -0
  15. data/examples/Gemfile.lock +14 -0
  16. data/examples/TrafficLight_state.png +0 -0
  17. data/examples/Vehicle_state.png +0 -0
  18. data/examples/auto_shop.rb +13 -0
  19. data/examples/car.rb +21 -0
  20. data/examples/doc/AutoShop.html +2856 -0
  21. data/examples/doc/AutoShop_state.png +0 -0
  22. data/examples/doc/Car.html +919 -0
  23. data/examples/doc/Car_state.png +0 -0
  24. data/examples/doc/TrafficLight.html +2230 -0
  25. data/examples/doc/TrafficLight_state.png +0 -0
  26. data/examples/doc/Vehicle.html +7921 -0
  27. data/examples/doc/Vehicle_state.png +0 -0
  28. data/examples/doc/_index.html +136 -0
  29. data/examples/doc/class_list.html +47 -0
  30. data/examples/doc/css/common.css +1 -0
  31. data/examples/doc/css/full_list.css +55 -0
  32. data/examples/doc/css/style.css +322 -0
  33. data/examples/doc/file_list.html +46 -0
  34. data/examples/doc/frames.html +13 -0
  35. data/examples/doc/index.html +136 -0
  36. data/examples/doc/js/app.js +205 -0
  37. data/examples/doc/js/full_list.js +173 -0
  38. data/examples/doc/js/jquery.js +16 -0
  39. data/examples/doc/method_list.html +734 -0
  40. data/examples/doc/top-level-namespace.html +105 -0
  41. data/examples/merb-rest/controller.rb +51 -0
  42. data/examples/merb-rest/model.rb +28 -0
  43. data/examples/merb-rest/view_edit.html.erb +24 -0
  44. data/examples/merb-rest/view_index.html.erb +23 -0
  45. data/examples/merb-rest/view_new.html.erb +13 -0
  46. data/examples/merb-rest/view_show.html.erb +17 -0
  47. data/examples/rails-rest/controller.rb +43 -0
  48. data/examples/rails-rest/migration.rb +7 -0
  49. data/examples/rails-rest/model.rb +23 -0
  50. data/examples/rails-rest/view__form.html.erb +34 -0
  51. data/examples/rails-rest/view_edit.html.erb +6 -0
  52. data/examples/rails-rest/view_index.html.erb +25 -0
  53. data/examples/rails-rest/view_new.html.erb +5 -0
  54. data/examples/rails-rest/view_show.html.erb +19 -0
  55. data/examples/traffic_light.rb +9 -0
  56. data/examples/vehicle.rb +33 -0
  57. data/gemfiles/4.2.11.1.gemfile +9 -0
  58. data/gemfiles/4.2.11.1.gemfile.lock +57 -0
  59. data/gemfiles/active_model_3.0.0.gemfile +7 -0
  60. data/gemfiles/active_model_3.0.0.gemfile.lock +35 -0
  61. data/gemfiles/active_model_3.0.5.gemfile +7 -0
  62. data/gemfiles/active_model_3.0.5.gemfile.lock +35 -0
  63. data/gemfiles/active_model_3.1.1.gemfile +7 -0
  64. data/gemfiles/active_model_3.1.1.gemfile.lock +36 -0
  65. data/gemfiles/active_model_3.2.1.gemfile +7 -0
  66. data/gemfiles/active_model_3.2.12.gemfile +7 -0
  67. data/gemfiles/active_model_3.2.12.gemfile.lock +36 -0
  68. data/gemfiles/active_model_3.2.13.rc1.gemfile +7 -0
  69. data/gemfiles/active_model_3.2.13.rc1.gemfile.lock +36 -0
  70. data/gemfiles/active_model_4.0.0.gemfile +9 -0
  71. data/gemfiles/active_model_4.0.0.gemfile.lock +78 -0
  72. data/gemfiles/active_record_2.0.0.gemfile +9 -0
  73. data/gemfiles/active_record_2.0.0.gemfile.lock +39 -0
  74. data/gemfiles/active_record_2.0.5.gemfile +9 -0
  75. data/gemfiles/active_record_2.0.5.gemfile.lock +39 -0
  76. data/gemfiles/active_record_2.1.0.gemfile +9 -0
  77. data/gemfiles/active_record_2.1.0.gemfile.lock +39 -0
  78. data/gemfiles/active_record_2.1.2.gemfile +9 -0
  79. data/gemfiles/active_record_2.1.2.gemfile.lock +39 -0
  80. data/gemfiles/active_record_2.2.3.gemfile +9 -0
  81. data/gemfiles/active_record_2.2.3.gemfile.lock +39 -0
  82. data/gemfiles/active_record_2.3.12.gemfile +9 -0
  83. data/gemfiles/active_record_2.3.12.gemfile.lock +39 -0
  84. data/gemfiles/active_record_2.3.5.gemfile +9 -0
  85. data/gemfiles/active_record_2.3.5.gemfile.lock +39 -0
  86. data/gemfiles/active_record_3.0.0.gemfile +9 -0
  87. data/gemfiles/active_record_3.0.0.gemfile.lock +51 -0
  88. data/gemfiles/active_record_3.0.5.gemfile +9 -0
  89. data/gemfiles/active_record_3.0.5.gemfile.lock +50 -0
  90. data/gemfiles/active_record_3.1.1.gemfile +9 -0
  91. data/gemfiles/active_record_3.1.1.gemfile.lock +51 -0
  92. data/gemfiles/active_record_3.2.12.gemfile +9 -0
  93. data/gemfiles/active_record_3.2.12.gemfile.lock +51 -0
  94. data/gemfiles/active_record_3.2.13.rc1.gemfile +9 -0
  95. data/gemfiles/active_record_3.2.13.rc1.gemfile.lock +51 -0
  96. data/gemfiles/active_record_4.0.0.gemfile +11 -0
  97. data/gemfiles/active_record_4.0.0.gemfile.lock +83 -0
  98. data/gemfiles/data_mapper_0.10.2.gemfile +13 -0
  99. data/gemfiles/data_mapper_0.10.2.gemfile.lock +56 -0
  100. data/gemfiles/data_mapper_0.9.11.gemfile +13 -0
  101. data/gemfiles/data_mapper_0.9.11.gemfile.lock +71 -0
  102. data/gemfiles/data_mapper_0.9.4.gemfile +12 -0
  103. data/gemfiles/data_mapper_0.9.4.gemfile.lock +70 -0
  104. data/gemfiles/data_mapper_0.9.7.gemfile +13 -0
  105. data/gemfiles/data_mapper_0.9.7.gemfile.lock +67 -0
  106. data/gemfiles/data_mapper_1.0.0.gemfile +12 -0
  107. data/gemfiles/data_mapper_1.0.0.gemfile.lock +63 -0
  108. data/gemfiles/data_mapper_1.0.1.gemfile +12 -0
  109. data/gemfiles/data_mapper_1.0.1.gemfile.lock +63 -0
  110. data/gemfiles/data_mapper_1.0.2.gemfile +12 -0
  111. data/gemfiles/data_mapper_1.0.2.gemfile.lock +63 -0
  112. data/gemfiles/data_mapper_1.1.0.gemfile +12 -0
  113. data/gemfiles/data_mapper_1.1.0.gemfile.lock +61 -0
  114. data/gemfiles/data_mapper_1.2.0.gemfile +12 -0
  115. data/gemfiles/data_mapper_1.2.0.gemfile.lock +61 -0
  116. data/gemfiles/default.gemfile +5 -0
  117. data/gemfiles/default.gemfile.lock +30 -0
  118. data/gemfiles/graphviz_0.9.17.gemfile +7 -0
  119. data/gemfiles/graphviz_0.9.17.gemfile.lock +29 -0
  120. data/gemfiles/graphviz_0.9.21.gemfile +7 -0
  121. data/gemfiles/graphviz_0.9.21.gemfile.lock +29 -0
  122. data/gemfiles/graphviz_1.0.0.gemfile +7 -0
  123. data/gemfiles/graphviz_1.0.0.gemfile.lock +29 -0
  124. data/gemfiles/graphviz_1.0.3.gemfile +7 -0
  125. data/gemfiles/graphviz_1.0.3.gemfile.lock +29 -0
  126. data/gemfiles/graphviz_1.0.8.gemfile +7 -0
  127. data/gemfiles/graphviz_1.0.8.gemfile.lock +29 -0
  128. data/gemfiles/mongo_mapper_0.10.0.gemfile +8 -0
  129. data/gemfiles/mongo_mapper_0.10.0.gemfile.lock +47 -0
  130. data/gemfiles/mongo_mapper_0.11.2.gemfile +9 -0
  131. data/gemfiles/mongo_mapper_0.11.2.gemfile.lock +48 -0
  132. data/gemfiles/mongo_mapper_0.12.0.gemfile +9 -0
  133. data/gemfiles/mongo_mapper_0.12.0.gemfile.lock +48 -0
  134. data/gemfiles/mongo_mapper_0.5.5.gemfile +8 -0
  135. data/gemfiles/mongo_mapper_0.5.5.gemfile.lock +36 -0
  136. data/gemfiles/mongo_mapper_0.5.8.gemfile +8 -0
  137. data/gemfiles/mongo_mapper_0.5.8.gemfile.lock +36 -0
  138. data/gemfiles/mongo_mapper_0.6.0.gemfile +8 -0
  139. data/gemfiles/mongo_mapper_0.6.0.gemfile.lock +36 -0
  140. data/gemfiles/mongo_mapper_0.6.10.gemfile +8 -0
  141. data/gemfiles/mongo_mapper_0.6.10.gemfile.lock +36 -0
  142. data/gemfiles/mongo_mapper_0.7.0.gemfile +8 -0
  143. data/gemfiles/mongo_mapper_0.7.0.gemfile.lock +36 -0
  144. data/gemfiles/mongo_mapper_0.7.5.gemfile +8 -0
  145. data/gemfiles/mongo_mapper_0.7.5.gemfile.lock +39 -0
  146. data/gemfiles/mongo_mapper_0.8.0.gemfile +10 -0
  147. data/gemfiles/mongo_mapper_0.8.0.gemfile.lock +43 -0
  148. data/gemfiles/mongo_mapper_0.8.3.gemfile +10 -0
  149. data/gemfiles/mongo_mapper_0.8.3.gemfile.lock +43 -0
  150. data/gemfiles/mongo_mapper_0.8.4.gemfile +8 -0
  151. data/gemfiles/mongo_mapper_0.8.4.gemfile.lock +42 -0
  152. data/gemfiles/mongo_mapper_0.8.6.gemfile +8 -0
  153. data/gemfiles/mongo_mapper_0.8.6.gemfile.lock +42 -0
  154. data/gemfiles/mongo_mapper_0.9.0.gemfile +7 -0
  155. data/gemfiles/mongo_mapper_0.9.0.gemfile.lock +45 -0
  156. data/gemfiles/mongoid_2.0.0.gemfile +9 -0
  157. data/gemfiles/mongoid_2.0.0.gemfile.lock +49 -0
  158. data/gemfiles/mongoid_2.1.4.gemfile +9 -0
  159. data/gemfiles/mongoid_2.1.4.gemfile.lock +47 -0
  160. data/gemfiles/mongoid_2.2.4.gemfile +9 -0
  161. data/gemfiles/mongoid_2.2.4.gemfile.lock +47 -0
  162. data/gemfiles/mongoid_2.3.3.gemfile +9 -0
  163. data/gemfiles/mongoid_2.3.3.gemfile.lock +47 -0
  164. data/gemfiles/mongoid_2.4.0.gemfile +9 -0
  165. data/gemfiles/mongoid_2.4.0.gemfile.lock +47 -0
  166. data/gemfiles/mongoid_2.4.10.gemfile +9 -0
  167. data/gemfiles/mongoid_2.4.10.gemfile.lock +47 -0
  168. data/gemfiles/mongoid_2.5.2.gemfile +9 -0
  169. data/gemfiles/mongoid_2.5.2.gemfile.lock +47 -0
  170. data/gemfiles/mongoid_2.6.0.gemfile +9 -0
  171. data/gemfiles/mongoid_2.6.0.gemfile.lock +47 -0
  172. data/gemfiles/mongoid_3.0.0.gemfile +8 -0
  173. data/gemfiles/mongoid_3.0.0.gemfile.lock +45 -0
  174. data/gemfiles/mongoid_3.0.22.gemfile +8 -0
  175. data/gemfiles/mongoid_3.0.22.gemfile.lock +45 -0
  176. data/gemfiles/mongoid_3.1.0.gemfile +8 -0
  177. data/gemfiles/mongoid_3.1.0.gemfile.lock +45 -0
  178. data/gemfiles/sequel_2.11.0.gemfile +9 -0
  179. data/gemfiles/sequel_2.11.0.gemfile.lock +33 -0
  180. data/gemfiles/sequel_2.12.0.gemfile +9 -0
  181. data/gemfiles/sequel_2.12.0.gemfile.lock +33 -0
  182. data/gemfiles/sequel_2.8.0.gemfile +9 -0
  183. data/gemfiles/sequel_2.8.0.gemfile.lock +33 -0
  184. data/gemfiles/sequel_3.0.0.gemfile +9 -0
  185. data/gemfiles/sequel_3.0.0.gemfile.lock +33 -0
  186. data/gemfiles/sequel_3.10.0.gemfile +9 -0
  187. data/gemfiles/sequel_3.10.0.gemfile.lock +33 -0
  188. data/gemfiles/sequel_3.13.0.gemfile +9 -0
  189. data/gemfiles/sequel_3.13.0.gemfile.lock +33 -0
  190. data/gemfiles/sequel_3.14.0.gemfile +9 -0
  191. data/gemfiles/sequel_3.14.0.gemfile.lock +33 -0
  192. data/gemfiles/sequel_3.23.0.gemfile +9 -0
  193. data/gemfiles/sequel_3.23.0.gemfile.lock +33 -0
  194. data/gemfiles/sequel_3.24.0.gemfile +9 -0
  195. data/gemfiles/sequel_3.24.0.gemfile.lock +33 -0
  196. data/gemfiles/sequel_3.29.0.gemfile +9 -0
  197. data/gemfiles/sequel_3.29.0.gemfile.lock +33 -0
  198. data/gemfiles/sequel_3.34.0.gemfile +9 -0
  199. data/gemfiles/sequel_3.34.0.gemfile.lock +33 -0
  200. data/gemfiles/sequel_3.35.0.gemfile +9 -0
  201. data/gemfiles/sequel_3.35.0.gemfile.lock +33 -0
  202. data/gemfiles/sequel_3.4.0.gemfile +9 -0
  203. data/gemfiles/sequel_3.4.0.gemfile.lock +33 -0
  204. data/gemfiles/sequel_3.44.0.gemfile +9 -0
  205. data/gemfiles/sequel_3.44.0.gemfile.lock +33 -0
  206. data/init.rb +1 -0
  207. data/lib/state_machine.rb +8 -0
  208. data/lib/state_machine/assertions.rb +36 -0
  209. data/lib/state_machine/branch.rb +225 -0
  210. data/lib/state_machine/callback.rb +236 -0
  211. data/lib/state_machine/core.rb +12 -0
  212. data/lib/state_machine/core_ext.rb +2 -0
  213. data/lib/state_machine/core_ext/class/state_machine.rb +5 -0
  214. data/lib/state_machine/error.rb +13 -0
  215. data/lib/state_machine/eval_helpers.rb +87 -0
  216. data/lib/state_machine/event.rb +257 -0
  217. data/lib/state_machine/event_collection.rb +141 -0
  218. data/lib/state_machine/extensions.rb +149 -0
  219. data/lib/state_machine/graph.rb +92 -0
  220. data/lib/state_machine/helper_module.rb +17 -0
  221. data/lib/state_machine/initializers.rb +4 -0
  222. data/lib/state_machine/initializers/merb.rb +1 -0
  223. data/lib/state_machine/initializers/rails.rb +25 -0
  224. data/lib/state_machine/integrations.rb +121 -0
  225. data/lib/state_machine/integrations/active_model.rb +585 -0
  226. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  227. data/lib/state_machine/integrations/active_model/observer.rb +33 -0
  228. data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
  229. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  230. data/lib/state_machine/integrations/active_record.rb +552 -0
  231. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  232. data/lib/state_machine/integrations/active_record/versions.rb +123 -0
  233. data/lib/state_machine/integrations/base.rb +100 -0
  234. data/lib/state_machine/integrations/data_mapper.rb +511 -0
  235. data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
  236. data/lib/state_machine/integrations/data_mapper/versions.rb +85 -0
  237. data/lib/state_machine/integrations/mongo_mapper.rb +389 -0
  238. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  239. data/lib/state_machine/integrations/mongo_mapper/versions.rb +89 -0
  240. data/lib/state_machine/integrations/mongoid.rb +465 -0
  241. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  242. data/lib/state_machine/integrations/mongoid/versions.rb +81 -0
  243. data/lib/state_machine/integrations/sequel.rb +486 -0
  244. data/lib/state_machine/integrations/sequel/versions.rb +95 -0
  245. data/lib/state_machine/machine.rb +2292 -0
  246. data/lib/state_machine/machine_collection.rb +86 -0
  247. data/lib/state_machine/macro_methods.rb +522 -0
  248. data/lib/state_machine/matcher.rb +123 -0
  249. data/lib/state_machine/matcher_helpers.rb +54 -0
  250. data/lib/state_machine/node_collection.rb +222 -0
  251. data/lib/state_machine/path.rb +120 -0
  252. data/lib/state_machine/path_collection.rb +90 -0
  253. data/lib/state_machine/state.rb +297 -0
  254. data/lib/state_machine/state_collection.rb +112 -0
  255. data/lib/state_machine/state_context.rb +138 -0
  256. data/lib/state_machine/transition.rb +470 -0
  257. data/lib/state_machine/transition_collection.rb +245 -0
  258. data/lib/state_machine/version.rb +3 -0
  259. data/lib/state_machine/yard.rb +8 -0
  260. data/lib/state_machine/yard/handlers.rb +12 -0
  261. data/lib/state_machine/yard/handlers/base.rb +32 -0
  262. data/lib/state_machine/yard/handlers/event.rb +25 -0
  263. data/lib/state_machine/yard/handlers/machine.rb +344 -0
  264. data/lib/state_machine/yard/handlers/state.rb +25 -0
  265. data/lib/state_machine/yard/handlers/transition.rb +47 -0
  266. data/lib/state_machine/yard/templates.rb +3 -0
  267. data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
  268. data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  269. data/lib/tasks/state_machine.rake +1 -0
  270. data/lib/tasks/state_machine.rb +30 -0
  271. data/lib/yard-state_machine.rb +2 -0
  272. data/state_machine.gemspec +21 -0
  273. data/test/files/en.yml +17 -0
  274. data/test/files/switch.rb +15 -0
  275. data/test/functional/state_machine_test.rb +1067 -0
  276. data/test/test_helper.rb +8 -0
  277. data/test/unit/assertions_test.rb +40 -0
  278. data/test/unit/branch_test.rb +969 -0
  279. data/test/unit/callback_test.rb +704 -0
  280. data/test/unit/error_test.rb +43 -0
  281. data/test/unit/eval_helpers_test.rb +270 -0
  282. data/test/unit/event_collection_test.rb +398 -0
  283. data/test/unit/event_test.rb +1196 -0
  284. data/test/unit/graph_test.rb +98 -0
  285. data/test/unit/helper_module_test.rb +17 -0
  286. data/test/unit/integrations/active_model_test.rb +1245 -0
  287. data/test/unit/integrations/active_record_test.rb +2551 -0
  288. data/test/unit/integrations/base_test.rb +104 -0
  289. data/test/unit/integrations/data_mapper_test.rb +2194 -0
  290. data/test/unit/integrations/mongo_mapper_test.rb +2026 -0
  291. data/test/unit/integrations/mongoid_test.rb +2309 -0
  292. data/test/unit/integrations/sequel_test.rb +1896 -0
  293. data/test/unit/integrations_test.rb +83 -0
  294. data/test/unit/invalid_event_test.rb +20 -0
  295. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  296. data/test/unit/invalid_transition_test.rb +115 -0
  297. data/test/unit/machine_collection_test.rb +603 -0
  298. data/test/unit/machine_test.rb +3431 -0
  299. data/test/unit/matcher_helpers_test.rb +37 -0
  300. data/test/unit/matcher_test.rb +155 -0
  301. data/test/unit/node_collection_test.rb +362 -0
  302. data/test/unit/path_collection_test.rb +266 -0
  303. data/test/unit/path_test.rb +485 -0
  304. data/test/unit/state_collection_test.rb +352 -0
  305. data/test/unit/state_context_test.rb +441 -0
  306. data/test/unit/state_machine_test.rb +31 -0
  307. data/test/unit/state_test.rb +1101 -0
  308. data/test/unit/transition_collection_test.rb +2168 -0
  309. data/test/unit/transition_test.rb +1558 -0
  310. metadata +451 -0
@@ -0,0 +1,104 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ # Load library
4
+ require 'rubygems'
5
+
6
+ module BaseTest
7
+ class IntegrationTest < Test::Unit::TestCase
8
+ def test_should_have_an_integration_name
9
+ assert_equal :base, StateMachine::Integrations::Base.integration_name
10
+ end
11
+
12
+ def test_should_not_be_available
13
+ assert !StateMachine::Integrations::Base.available?
14
+ end
15
+
16
+ def test_should_not_have_any_matching_ancestors
17
+ assert_equal [], StateMachine::Integrations::Base.matching_ancestors
18
+ end
19
+
20
+ def test_should_not_match_any_classes
21
+ assert !StateMachine::Integrations::Base.matches?(Class.new)
22
+ end
23
+
24
+ def test_should_not_have_a_locale_path
25
+ assert_nil StateMachine::Integrations::Base.locale_path
26
+ end
27
+ end
28
+
29
+ class IncludedTest < Test::Unit::TestCase
30
+ def setup
31
+ @integration = Module.new
32
+ StateMachine::Integrations.const_set('Custom', @integration)
33
+
34
+ @integration.class_eval do
35
+ include StateMachine::Integrations::Base
36
+ end
37
+ end
38
+
39
+ def test_should_not_have_any_defaults
40
+ assert_nil @integration.defaults
41
+ end
42
+
43
+ def test_should_not_have_any_versions
44
+ assert_equal [], @integration.versions
45
+ end
46
+
47
+ def test_should_track_version
48
+ version1 = @integration.version '1.0' do
49
+ def self.active?
50
+ true
51
+ end
52
+ end
53
+
54
+ version2 = @integration.version '2.0' do
55
+ def self.active?
56
+ false
57
+ end
58
+ end
59
+
60
+ assert_equal [version1, version2], @integration.versions
61
+ end
62
+
63
+ def test_should_allow_active_versions_to_override_default_behavior
64
+ @integration.class_eval do
65
+ def version1_included?
66
+ false
67
+ end
68
+
69
+ def version2_included?
70
+ false
71
+ end
72
+ end
73
+
74
+ @integration.version '1.0' do
75
+ def self.active?
76
+ true
77
+ end
78
+
79
+ def version1_included?
80
+ true
81
+ end
82
+ end
83
+
84
+ @integration.version '2.0' do
85
+ def self.active?
86
+ false
87
+ end
88
+
89
+ def version2_included?
90
+ true
91
+ end
92
+ end
93
+
94
+ @machine = StateMachine::Machine.new(Class.new, :integration => :custom)
95
+ assert @machine.version1_included?
96
+ assert !@machine.version2_included?
97
+ end
98
+
99
+ def teardown
100
+ StateMachine::Integrations.send(:remove_const, 'Custom')
101
+ super
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,2194 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ require 'dm-core'
4
+ require 'dm-core/version' unless defined?(DataMapper::VERSION)
5
+ require 'dm-observer'
6
+
7
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.3')
8
+ require 'dm-migrations'
9
+ end
10
+
11
+ # Establish database connection
12
+ DataMapper.setup(:default, 'sqlite3::memory:')
13
+ DataObjects::Sqlite3.logger = DataObjects::Logger.new("#{File.dirname(__FILE__)}/../../data_mapper.log", :debug)
14
+
15
+ module DataMapperTest
16
+ class BaseTestCase < Test::Unit::TestCase
17
+ def default_test
18
+ end
19
+
20
+ def teardown
21
+ super
22
+ @resources.uniq.each {|resource| DataMapperTest.send(:remove_const, resource)} if instance_variable_defined?('@resources')
23
+ end
24
+
25
+ protected
26
+ # Creates a new DataMapper resource (and the associated table)
27
+ def new_resource(create_table = :foo, &block)
28
+ base_table_name = create_table || :foo
29
+ name = base_table_name.to_s.capitalize
30
+ table_name = "#{base_table_name}_#{rand(1000000)}"
31
+
32
+ resource = Class.new
33
+ DataMapperTest.send(:remove_const, name) if DataMapperTest.const_defined?(name)
34
+ DataMapperTest.const_set(name, resource)
35
+ (@resources ||= []) << name
36
+
37
+ resource.class_eval do
38
+ include DataMapper::Resource
39
+
40
+ storage_names[:default] = table_name.to_s
41
+
42
+ property :id, resource.class_eval('Serial')
43
+ property :state, String
44
+ end
45
+ resource.class_eval(&block) if block_given?
46
+ resource.auto_migrate! if create_table
47
+ resource
48
+ end
49
+
50
+ # Creates a new DataMapper observer
51
+ def new_observer(resource, &block)
52
+ observer = Class.new do
53
+ include DataMapper::Observer
54
+ end
55
+ observer.observe(resource)
56
+ observer.class_eval(&block) if block_given?
57
+ observer
58
+ end
59
+ end
60
+
61
+ class IntegrationTest < BaseTestCase
62
+ def test_should_have_an_integration_name
63
+ assert_equal :data_mapper, StateMachine::Integrations::DataMapper.integration_name
64
+ end
65
+
66
+ def test_should_be_available
67
+ assert StateMachine::Integrations::DataMapper.available?
68
+ end
69
+
70
+ def test_should_match_if_class_includes_data_mapper
71
+ assert StateMachine::Integrations::DataMapper.matches?(new_resource)
72
+ end
73
+
74
+ def test_should_not_match_if_class_does_not_include_data_mapper
75
+ assert !StateMachine::Integrations::DataMapper.matches?(Class.new)
76
+ end
77
+
78
+ def test_should_have_defaults
79
+ assert_equal({:action => :save, :use_transactions => false}, StateMachine::Integrations::DataMapper.defaults)
80
+ end
81
+
82
+ def test_should_not_have_a_locale_path
83
+ assert_nil StateMachine::Integrations::DataMapper.locale_path
84
+ end
85
+ end
86
+
87
+ class MachineWithoutDatabaseTest < BaseTestCase
88
+ def setup
89
+ @resource = new_resource(false) do
90
+ # Simulate the database not being available entirely
91
+ def self.repository
92
+ raise DataObjects::SyntaxError
93
+ end
94
+ end
95
+ end
96
+
97
+ def test_should_allow_machine_creation
98
+ assert_nothing_raised { StateMachine::Machine.new(@resource) }
99
+ end
100
+ end
101
+
102
+ class MachineUnmigratedTest < BaseTestCase
103
+ def setup
104
+ @resource = new_resource(false)
105
+ end
106
+
107
+ def test_should_allow_machine_creation
108
+ assert_nothing_raised { StateMachine::Machine.new(@resource) }
109
+ end
110
+ end
111
+
112
+ class MachineWithoutPropertyTest < BaseTestCase
113
+ def setup
114
+ @resource = new_resource
115
+ StateMachine::Machine.new(@resource, :status)
116
+ end
117
+
118
+ def test_should_define_field_with_string_type
119
+ property = @resource.properties.detect {|p| p.name == :status}
120
+ assert_not_nil property
121
+
122
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('1.0.0')
123
+ assert_instance_of DataMapper::Property::String, property
124
+ else
125
+ assert_equal String, property.type
126
+ end
127
+ end
128
+ end
129
+
130
+ class MachineWithPropertyTest < BaseTestCase
131
+ def setup
132
+ @resource = new_resource do
133
+ property :status, Integer
134
+ end
135
+ StateMachine::Machine.new(@resource, :status)
136
+ end
137
+
138
+ def test_should_not_redefine_field
139
+ property = @resource.properties.detect {|p| p.name == :status}
140
+ assert_not_nil property
141
+
142
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('1.0.0')
143
+ assert_instance_of DataMapper::Property::Integer, property
144
+ else
145
+ assert_equal Integer, property.type
146
+ end
147
+ end
148
+ end
149
+
150
+ class MachineByDefaultTest < BaseTestCase
151
+ def setup
152
+ @resource = new_resource
153
+ @machine = StateMachine::Machine.new(@resource)
154
+ end
155
+
156
+ def test_should_use_save_as_action
157
+ assert_equal :save, @machine.action
158
+ end
159
+
160
+ def test_should_not_use_transactions
161
+ assert_equal false, @machine.use_transactions
162
+ end
163
+
164
+ def test_should_not_have_any_before_callbacks
165
+ assert_equal 0, @machine.callbacks[:before].size
166
+ end
167
+
168
+ def test_should_not_have_any_after_callbacks
169
+ assert_equal 0, @machine.callbacks[:after].size
170
+ end
171
+ end
172
+
173
+ class MachineWithStatesTest < BaseTestCase
174
+ def setup
175
+ @resource = new_resource
176
+ @machine = StateMachine::Machine.new(@resource)
177
+ @machine.state :first_gear
178
+ end
179
+
180
+ def test_should_humanize_name
181
+ assert_equal 'first gear', @machine.state(:first_gear).human_name
182
+ end
183
+ end
184
+
185
+ class MachineWithStaticInitialStateTest < BaseTestCase
186
+ def setup
187
+ @resource = new_resource(:vehicle) do
188
+ attr_accessor :value
189
+ end
190
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
191
+ end
192
+
193
+ def test_should_set_initial_state_on_created_object
194
+ record = @resource.new
195
+ assert_equal 'parked', record.state
196
+ end
197
+
198
+ def test_should_set_initial_state_with_nil_attributes
199
+ @resource.class_eval do
200
+ def attributes=(attributes)
201
+ super(attributes || {})
202
+ end
203
+ end
204
+
205
+ record = @resource.new(nil)
206
+ assert_equal 'parked', record.state
207
+ end
208
+
209
+ def test_should_still_set_attributes
210
+ record = @resource.new(:value => 1)
211
+ assert_equal 1, record.value
212
+ end
213
+
214
+ def test_should_not_allow_initialize_blocks
215
+ block_args = nil
216
+ @resource.new do |*args|
217
+ block_args = args
218
+ end
219
+
220
+ assert_nil block_args
221
+ end
222
+
223
+ def test_should_set_initial_state_before_setting_attributes
224
+ @resource.class_eval do
225
+ attr_accessor :state_during_setter
226
+
227
+ remove_method :value=
228
+ define_method(:value=) do |value|
229
+ self.state_during_setter = state
230
+ end
231
+ end
232
+
233
+ record = @resource.new(:value => 1)
234
+ assert_equal 'parked', record.state_during_setter
235
+ end
236
+
237
+ def test_should_not_set_initial_state_after_already_initialized
238
+ record = @resource.new(:value => 1)
239
+ assert_equal 'parked', record.state
240
+
241
+ record.state = 'idling'
242
+ record.attributes = {}
243
+ assert_equal 'idling', record.state
244
+ end
245
+
246
+ def test_should_persist_initial_state
247
+ record = @resource.new
248
+ record.save
249
+ record.reload
250
+ assert_equal 'parked', record.state
251
+ end
252
+
253
+ def test_should_persist_initial_state_on_dup
254
+ record = @resource.create.dup
255
+ record.save
256
+ record.reload
257
+ assert_equal 'parked', record.state
258
+ end
259
+
260
+ def test_should_use_stored_values_when_loading_from_database
261
+ @machine.state :idling
262
+
263
+ record = @resource.get(@resource.create(:state => 'idling').id)
264
+ assert_equal 'idling', record.state
265
+ end
266
+
267
+ def test_should_use_stored_values_when_loading_from_database_with_nil_state
268
+ @machine.state nil
269
+
270
+ record = @resource.get(@resource.create(:state => nil).id)
271
+ assert_nil record.state
272
+ end
273
+
274
+ def test_should_use_stored_values_when_loading_for_many_association
275
+ @machine.state :idling
276
+
277
+ @resource.property :owner_id, Integer
278
+ @resource.auto_migrate!
279
+
280
+ owner_resource = new_resource(:owner) do
281
+ has n, :vehicles
282
+ end
283
+
284
+ owner = owner_resource.create
285
+ record = @resource.new(:state => 'idling')
286
+ record.owner_id = owner.id
287
+ record.save
288
+ assert_equal 'idling', owner.vehicles[0].state
289
+ end
290
+
291
+ def test_should_use_stored_values_when_loading_for_one_association
292
+ @machine.state :idling
293
+
294
+ @resource.property :owner_id, Integer
295
+ @resource.auto_migrate!
296
+
297
+ owner_resource = new_resource(:owner) do
298
+ has 1, :vehicle
299
+ end
300
+
301
+ owner = owner_resource.create
302
+ record = @resource.new(:state => 'idling')
303
+ record.owner_id = owner.id
304
+ record.save
305
+ assert_equal 'idling', owner.vehicle.state
306
+ end
307
+
308
+ def test_should_use_stored_values_when_loading_for_belongs_to_association
309
+ @machine.state :idling
310
+
311
+ driver_resource = new_resource(:driver) do
312
+ belongs_to :vehicle
313
+ end
314
+
315
+ record = @resource.create(:state => 'idling')
316
+ driver = driver_resource.create(:vehicle_id => record.id)
317
+ assert_equal 'idling', driver.vehicle.state
318
+ end
319
+ end
320
+
321
+ class MachineWithDynamicInitialStateTest < BaseTestCase
322
+ def setup
323
+ @resource = new_resource do
324
+ attr_accessor :value
325
+ end
326
+ @machine = StateMachine::Machine.new(@resource, :initial => lambda {|object| :parked})
327
+ @machine.state :parked
328
+ end
329
+
330
+ def test_should_set_initial_state_on_created_object
331
+ record = @resource.new
332
+ assert_equal 'parked', record.state
333
+ end
334
+
335
+ def test_should_still_set_attributes
336
+ record = @resource.new(:value => 1)
337
+ assert_equal 1, record.value
338
+ end
339
+
340
+ def test_should_not_allow_initialize_blocks
341
+ block_args = nil
342
+ @resource.new do |*args|
343
+ block_args = args
344
+ end
345
+
346
+ assert_nil block_args
347
+ end
348
+
349
+ def test_should_set_initial_state_after_setting_attributes
350
+ @resource.class_eval do
351
+ attr_accessor :state_during_setter
352
+
353
+ remove_method :value=
354
+ define_method(:value=) do |value|
355
+ self.state_during_setter = state || 'nil'
356
+ end
357
+ end
358
+
359
+ record = @resource.new(:value => 1)
360
+ assert_equal 'nil', record.state_during_setter
361
+ end
362
+
363
+ def test_should_not_set_initial_state_after_already_initialized
364
+ record = @resource.new(:value => 1)
365
+ assert_equal 'parked', record.state
366
+
367
+ record.state = 'idling'
368
+ record.attributes = {}
369
+ assert_equal 'idling', record.state
370
+ end
371
+
372
+ def test_should_persist_initial_state
373
+ record = @resource.new
374
+ record.save
375
+ record.reload
376
+ assert_equal 'parked', record.state
377
+ end
378
+
379
+ def test_should_persist_initial_state_on_dup
380
+ record = @resource.create.dup
381
+ record.save
382
+ record.reload
383
+ assert_equal 'parked', record.state
384
+ end
385
+
386
+ def test_should_use_stored_values_when_loading_from_database
387
+ @machine.state :idling
388
+
389
+ record = @resource.get(@resource.create(:state => 'idling').id)
390
+ assert_equal 'idling', record.state
391
+ end
392
+
393
+ def test_should_use_stored_values_when_loading_from_database_with_nil_state
394
+ @machine.state nil
395
+
396
+ record = @resource.get(@resource.create(:state => nil).id)
397
+ assert_nil record.state
398
+ end
399
+ end
400
+
401
+ class MachineWithEventsTest < BaseTestCase
402
+ def setup
403
+ @resource = new_resource
404
+ @machine = StateMachine::Machine.new(@resource)
405
+ @machine.event :shift_up
406
+ end
407
+
408
+ def test_should_humanize_name
409
+ assert_equal 'shift up', @machine.event(:shift_up).human_name
410
+ end
411
+ end
412
+
413
+ class MachineWithSameColumnDefaultTest < BaseTestCase
414
+ def setup
415
+ @original_stderr, $stderr = $stderr, StringIO.new
416
+
417
+ @resource = new_resource do
418
+ property :status, String, :default => 'parked'
419
+ end
420
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
421
+ @record = @resource.new
422
+ end
423
+
424
+ def test_should_use_machine_default
425
+ assert_equal 'parked', @record.status
426
+ end
427
+
428
+ def test_should_not_generate_a_warning
429
+ assert_no_match(/have defined a different default/, $stderr.string)
430
+ end
431
+
432
+ def teardown
433
+ $stderr = @original_stderr
434
+ super
435
+ end
436
+ end
437
+
438
+ class MachineWithDifferentColumnDefaultTest < BaseTestCase
439
+ def setup
440
+ @original_stderr, $stderr = $stderr, StringIO.new
441
+
442
+ @resource = new_resource do
443
+ property :status, String, :default => 'idling'
444
+ end
445
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
446
+ @record = @resource.new
447
+ end
448
+
449
+ def test_should_use_machine_default
450
+ assert_equal 'parked', @record.status
451
+ end
452
+
453
+ def test_should_generate_a_warning
454
+ assert_match(/Both DataMapperTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
455
+ end
456
+
457
+ def teardown
458
+ $stderr = @original_stderr
459
+ super
460
+ end
461
+ end
462
+
463
+ class MachineWithDifferentIntegerColumnDefaultTest < BaseTestCase
464
+ def setup
465
+ @original_stderr, $stderr = $stderr, StringIO.new
466
+
467
+ @resource = new_resource do
468
+ property :status, Integer, :default => 0
469
+ end
470
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
471
+ @machine.state :parked, :value => 1
472
+ @record = @resource.new
473
+ end
474
+
475
+ def test_should_use_machine_default
476
+ assert_equal 1, @record.status
477
+ end
478
+
479
+ def test_should_generate_a_warning
480
+ assert_match(/Both DataMapperTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
481
+ end
482
+
483
+ def teardown
484
+ $stderr = @original_stderr
485
+ super
486
+ end
487
+ end
488
+
489
+ class MachineWithConflictingPredicateTest < BaseTestCase
490
+ def setup
491
+ @resource = new_resource do
492
+ def state?(*args)
493
+ true
494
+ end
495
+ end
496
+
497
+ @machine = StateMachine::Machine.new(@resource)
498
+ @record = @resource.new
499
+ end
500
+
501
+ def test_should_not_define_attribute_predicate
502
+ assert @record.state?
503
+ end
504
+ end
505
+
506
+ class MachineWithConflictingStateNameTest < BaseTestCase
507
+ def setup
508
+ require 'stringio'
509
+ @original_stderr, $stderr = $stderr, StringIO.new
510
+
511
+ @resource = new_resource
512
+ end
513
+
514
+ def test_should_output_warning_with_same_machine_name
515
+ @machine = StateMachine::Machine.new(@resource)
516
+ @machine.state :state
517
+
518
+ assert_match(/^Instance method "state\?" is already defined in DataMapperTest::Foo :state instance helpers, use generic helper instead.*\n$/, $stderr.string)
519
+ end
520
+
521
+ def test_should_not_output_warning_with_same_machine_attribute
522
+ @machine = StateMachine::Machine.new(@resource, :public_state, :attribute => :state)
523
+ @machine.state :state
524
+
525
+ assert_no_match(/^Instance method "state\?" is already defined.*\n$/, $stderr.string)
526
+ end
527
+
528
+ def teardown
529
+ $stderr = @original_stderr
530
+ super
531
+ end
532
+ end
533
+
534
+ class MachineWithColumnStateAttributeTest < BaseTestCase
535
+ def setup
536
+ @resource = new_resource
537
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
538
+ @machine.other_states(:idling)
539
+
540
+ @record = @resource.new
541
+ end
542
+
543
+ def test_should_not_override_the_column_reader
544
+ @record.attribute_set(:state, 'parked')
545
+ assert_equal 'parked', @record.state
546
+ end
547
+
548
+ def test_should_not_override_the_column_writer
549
+ @record.state = 'parked'
550
+ assert_equal 'parked', @record.attribute_get(:state)
551
+ end
552
+
553
+ def test_should_have_an_attribute_predicate
554
+ assert @record.respond_to?(:state?)
555
+ end
556
+
557
+ def test_should_raise_exception_for_predicate_without_parameters
558
+ assert_raise(ArgumentError) { @record.state? }
559
+ end
560
+
561
+ def test_should_return_false_for_predicate_if_does_not_match_current_value
562
+ assert !@record.state?(:idling)
563
+ end
564
+
565
+ def test_should_return_true_for_predicate_if_matches_current_value
566
+ assert @record.state?(:parked)
567
+ end
568
+
569
+ def test_should_raise_exception_for_predicate_if_invalid_state_specified
570
+ assert_raise(IndexError) { @record.state?(:invalid) }
571
+ end
572
+ end
573
+
574
+ class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
575
+ def setup
576
+ @resource = new_resource do
577
+ def initialize
578
+ # Skip attribute initialization
579
+ @initialized_state_machines = true
580
+ super
581
+ end
582
+ end
583
+
584
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => 'parked')
585
+ @record = @resource.new
586
+ end
587
+
588
+ def test_should_define_a_new_property_for_the_attribute
589
+ assert_not_nil @resource.properties[:status]
590
+ end
591
+
592
+ def test_should_define_a_reader_attribute_for_the_attribute
593
+ assert @record.respond_to?(:status)
594
+ end
595
+
596
+ def test_should_define_a_writer_attribute_for_the_attribute
597
+ assert @record.respond_to?(:status=)
598
+ end
599
+
600
+ def test_should_define_an_attribute_predicate
601
+ assert @record.respond_to?(:status?)
602
+ end
603
+ end
604
+
605
+ class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
606
+ def setup
607
+ @resource = new_resource do
608
+ attr_accessor :status
609
+ end
610
+
611
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
612
+ @machine.other_states(:idling)
613
+ @record = @resource.new
614
+ end
615
+
616
+ def test_should_return_false_for_predicate_if_does_not_match_current_value
617
+ assert !@record.status?(:idling)
618
+ end
619
+
620
+ def test_should_return_true_for_predicate_if_matches_current_value
621
+ assert @record.status?(:parked)
622
+ end
623
+
624
+ def test_should_raise_exception_for_predicate_if_invalid_state_specified
625
+ assert_raise(IndexError) { @record.status?(:invalid) }
626
+ end
627
+
628
+ def test_should_set_initial_state_on_created_object
629
+ assert_equal 'parked', @record.status
630
+ end
631
+ end
632
+
633
+ class MachineWithInitializedStateTest < BaseTestCase
634
+ def setup
635
+ @resource = new_resource
636
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
637
+ @machine.state :idling
638
+ end
639
+
640
+ def test_should_allow_nil_initial_state_when_static
641
+ @machine.state nil
642
+
643
+ record = @resource.new(:state => nil)
644
+ assert_nil record.state
645
+ end
646
+
647
+ def test_should_allow_nil_initial_state_when_dynamic
648
+ @machine.state nil
649
+
650
+ @machine.initial_state = lambda {:parked}
651
+ record = @resource.new(:state => nil)
652
+ assert_nil record.state
653
+ end
654
+
655
+ def test_should_allow_different_initial_state_when_static
656
+ record = @resource.new(:state => 'idling')
657
+ assert_equal 'idling', record.state
658
+ end
659
+
660
+ def test_should_allow_different_initial_state_when_dynamic
661
+ @machine.initial_state = lambda {:parked}
662
+ record = @resource.new(:state => 'idling')
663
+ assert_equal 'idling', record.state
664
+ end
665
+
666
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.9.8')
667
+ def test_should_raise_exception_if_protected
668
+ resource = new_resource do
669
+ protected :state=
670
+ end
671
+
672
+ machine = StateMachine::Machine.new(resource, :initial => :parked)
673
+ machine.state :idling
674
+
675
+ assert_raise(ArgumentError) { resource.new(:state => 'idling') }
676
+ end
677
+ end
678
+ end
679
+
680
+ class MachineMultipleTest < BaseTestCase
681
+ def setup
682
+ @resource = new_resource do
683
+ property :status, String
684
+ end
685
+ @state_machine = StateMachine::Machine.new(@resource, :initial => :parked)
686
+ @status_machine = StateMachine::Machine.new(@resource, :status, :initial => :idling)
687
+ end
688
+
689
+ def test_should_should_initialize_each_state
690
+ record = @resource.new
691
+ assert_equal 'parked', record.state
692
+ assert_equal 'idling', record.status
693
+ end
694
+ end
695
+
696
+ class MachineWithLoopbackTest < BaseTestCase
697
+ def setup
698
+ @resource = new_resource do
699
+ property :updated_at, DateTime
700
+
701
+ # Simulate dm-timestamps
702
+ before :update do
703
+ return unless dirty?
704
+ self.updated_at = DateTime.now
705
+ end
706
+ end
707
+
708
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
709
+ @machine.event :park
710
+
711
+ @record = @resource.create(:updated_at => Time.now - 1)
712
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
713
+
714
+ @timestamp = @record.updated_at
715
+ @transition.perform
716
+ end
717
+
718
+ def test_should_not_update_record
719
+ assert_equal @timestamp, @record.updated_at
720
+ end
721
+ end
722
+
723
+ class MachineWithDirtyAttributesTest < BaseTestCase
724
+ def setup
725
+ @resource = new_resource
726
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
727
+ @machine.event :ignite
728
+ @machine.state :idling
729
+
730
+ @record = @resource.create
731
+
732
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
733
+ @transition.perform(false)
734
+ end
735
+
736
+ def test_should_include_state_in_changed_attributes
737
+ assert_equal({@resource.properties[:state] => 'idling'}, @record.dirty_attributes)
738
+ end
739
+
740
+ def test_should_track_attribute_change
741
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.0')
742
+ assert_equal({@resource.properties[:state] => 'parked'}, @record.original_attributes)
743
+ else
744
+ assert_equal({:state => 'parked'}, @record.original_values)
745
+ end
746
+ end
747
+
748
+ def test_should_not_reset_changes_on_multiple_transitions
749
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
750
+ transition.perform(false)
751
+
752
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.0')
753
+ assert_equal({@resource.properties[:state] => 'parked'}, @record.original_attributes)
754
+ else
755
+ assert_equal({:state => 'parked'}, @record.original_values)
756
+ end
757
+ end
758
+
759
+ def test_should_not_have_changes_when_loaded_from_database
760
+ record = @resource.get(@record.id)
761
+ assert record.dirty_attributes.empty?
762
+ end
763
+ end
764
+
765
+ class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
766
+ def setup
767
+ @resource = new_resource
768
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
769
+ @machine.event :park
770
+
771
+ @record = @resource.create
772
+
773
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
774
+ @transition.perform(false)
775
+ end
776
+
777
+ def test_should_not_include_state_in_changed_attributes
778
+ assert_equal({}, @record.dirty_attributes)
779
+ end
780
+ end
781
+
782
+ class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
783
+ def setup
784
+ @resource = new_resource do
785
+ property :status, String
786
+ end
787
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
788
+ @machine.event :ignite
789
+ @machine.state :idling
790
+
791
+ @record = @resource.create
792
+
793
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
794
+ @transition.perform(false)
795
+ end
796
+
797
+ def test_should_include_state_in_changed_attributes
798
+ assert_equal({@resource.properties[:status] => 'idling'}, @record.dirty_attributes)
799
+ end
800
+
801
+ def test_should_track_attribute_change
802
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.0')
803
+ assert_equal({@resource.properties[:status] => 'parked'}, @record.original_attributes)
804
+ else
805
+ assert_equal({:status => 'parked'}, @record.original_values)
806
+ end
807
+ end
808
+
809
+ def test_should_not_reset_changes_on_multiple_transitions
810
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
811
+ transition.perform(false)
812
+
813
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.0')
814
+ assert_equal({@resource.properties[:status] => 'parked'}, @record.original_attributes)
815
+ else
816
+ assert_equal({:status => 'parked'}, @record.original_values)
817
+ end
818
+ end
819
+ end
820
+
821
+ class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
822
+ def setup
823
+ @resource = new_resource do
824
+ property :status, String
825
+ end
826
+ @machine = StateMachine::Machine.new(@resource, :status, :initial => :parked)
827
+ @machine.event :park
828
+
829
+ @record = @resource.create
830
+
831
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
832
+ @transition.perform(false)
833
+ end
834
+
835
+ def test_should_not_include_state_in_changed_attributes
836
+ assert_equal({}, @record.dirty_attributes)
837
+ end
838
+ end
839
+
840
+ class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
841
+ def setup
842
+ @resource = new_resource
843
+ @machine = StateMachine::Machine.new(@resource, :initial => :parked)
844
+ @machine.event :ignite
845
+
846
+ @record = @resource.create
847
+ @record.state_event = 'ignite'
848
+ end
849
+
850
+ def test_should_not_include_state_in_changed_attributes
851
+ assert_equal({}, @record.dirty_attributes)
852
+ end
853
+
854
+ def test_should_not_track_attribute_change
855
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.0')
856
+ assert_equal({}, @record.original_attributes)
857
+ else
858
+ assert_equal({}, @record.original_values)
859
+ end
860
+ end
861
+ end
862
+
863
+ class MachineWithoutTransactionsTest < BaseTestCase
864
+ def setup
865
+ @resource = new_resource
866
+ @machine = StateMachine::Machine.new(@resource, :use_transactions => false)
867
+ end
868
+
869
+ def test_should_not_rollback_transaction_if_false
870
+ @machine.within_transaction(@resource.new) do
871
+ @resource.create
872
+ false
873
+ end
874
+
875
+ assert_equal 1, @resource.all.size
876
+ end
877
+
878
+ def test_should_not_rollback_transaction_if_true
879
+ @machine.within_transaction(@resource.new) do
880
+ @resource.create
881
+ true
882
+ end
883
+
884
+ assert_equal 1, @resource.all.size
885
+ end
886
+ end
887
+
888
+ begin
889
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.3')
890
+ require 'dm-transactions'
891
+ end
892
+
893
+ class MachineWithTransactionsTest < BaseTestCase
894
+ def setup
895
+ @resource = new_resource
896
+ @machine = StateMachine::Machine.new(@resource, :use_transactions => true)
897
+ end
898
+
899
+ def test_should_rollback_transaction_if_false
900
+ @machine.within_transaction(@resource.new) do
901
+ @resource.create
902
+ false
903
+ end
904
+
905
+ assert_equal 0, @resource.all.size
906
+ end
907
+
908
+ def test_should_not_rollback_transaction_if_true
909
+ @machine.within_transaction(@resource.new) do
910
+ @resource.create
911
+ true
912
+ end
913
+
914
+ assert_equal 1, @resource.all.size
915
+ end
916
+ end
917
+ rescue LoadError
918
+ $stderr.puts "Skipping DataMapper Transaction tests."
919
+ end
920
+
921
+ class MachineWithCallbacksTest < BaseTestCase
922
+ def setup
923
+ @resource = new_resource
924
+ @machine = StateMachine::Machine.new(@resource)
925
+ @machine.state :parked, :idling
926
+ @machine.event :ignite
927
+
928
+ @record = @resource.new(:state => 'parked')
929
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
930
+ end
931
+
932
+ def test_should_run_before_callbacks
933
+ called = false
934
+ @machine.before_transition {called = true}
935
+
936
+ @transition.perform
937
+ assert called
938
+ end
939
+
940
+ def test_should_pass_transition_to_before_callbacks_with_one_argument
941
+ transition = nil
942
+ @machine.before_transition {|arg| transition = arg}
943
+
944
+ @transition.perform
945
+ assert_equal @transition, transition
946
+ end
947
+
948
+ def test_should_pass_transition_to_before_callbacks_with_multiple_arguments
949
+ callback_args = nil
950
+ @machine.before_transition {|*args| callback_args = args}
951
+
952
+ @transition.perform
953
+ assert_equal [@transition], callback_args
954
+ end
955
+
956
+ def test_should_run_before_callbacks_within_the_context_of_the_record
957
+ context = nil
958
+ @machine.before_transition {context = self}
959
+
960
+ @transition.perform
961
+ assert_equal @record, context
962
+ end
963
+
964
+ def test_should_run_after_callbacks
965
+ called = false
966
+ @machine.after_transition {called = true}
967
+
968
+ @transition.perform
969
+ assert called
970
+ end
971
+
972
+ def test_should_pass_transition_to_after_callbacks_with_multiple_arguments
973
+ callback_args = nil
974
+ @machine.after_transition {|*args| callback_args = args}
975
+
976
+ @transition.perform
977
+ assert_equal [@transition], callback_args
978
+ end
979
+
980
+ def test_should_run_after_callbacks_with_the_context_of_the_record
981
+ context = nil
982
+ @machine.after_transition {context = self}
983
+
984
+ @transition.perform
985
+ assert_equal @record, context
986
+ end
987
+
988
+ def test_should_run_around_callbacks
989
+ before_called = false
990
+ after_called = false
991
+ ensure_called = 0
992
+ @machine.around_transition do |block|
993
+ before_called = true
994
+ begin
995
+ block.call
996
+ ensure
997
+ ensure_called += 1
998
+ end
999
+ after_called = true
1000
+ end
1001
+
1002
+ @transition.perform
1003
+ assert before_called
1004
+ assert after_called
1005
+ assert_equal ensure_called, 1
1006
+ end
1007
+
1008
+ def test_should_run_around_callbacks_with_the_context_of_the_record
1009
+ context = nil
1010
+ @machine.around_transition {|block| context = self; block.call}
1011
+
1012
+ @transition.perform
1013
+ assert_equal @record, context
1014
+ end
1015
+
1016
+ def test_should_allow_symbolic_callbacks
1017
+ callback_args = nil
1018
+
1019
+ klass = class << @record; self; end
1020
+ klass.send(:define_method, :after_ignite) do |*args|
1021
+ callback_args = args
1022
+ end
1023
+
1024
+ @machine.before_transition(:after_ignite)
1025
+
1026
+ @transition.perform
1027
+ assert_equal [@transition], callback_args
1028
+ end
1029
+
1030
+ def test_should_allow_string_callbacks
1031
+ class << @record
1032
+ attr_reader :callback_result
1033
+ end
1034
+
1035
+ @machine.before_transition('@callback_result = [1, 2, 3]')
1036
+ @transition.perform
1037
+
1038
+ assert_equal [1, 2, 3], @record.callback_result
1039
+ end
1040
+
1041
+ def test_should_run_in_expected_order
1042
+ # Avoid Ruby 2.0.0 stack too deep issues
1043
+ @resource.class_eval do
1044
+ def valid?(*)
1045
+ super
1046
+ end
1047
+ end
1048
+
1049
+ expected = [
1050
+ :before_transition, :before_validation, :after_validation,
1051
+ :before_save, :before_create, :after_create, :after_save,
1052
+ :after_transition
1053
+ ]
1054
+
1055
+ callbacks = []
1056
+ @resource.before(:valid?) { callbacks << :before_validation }
1057
+ @resource.after(:valid?) { callbacks << :after_validation }
1058
+ @resource.before(:save) { callbacks << :before_save }
1059
+ @resource.before(:create) { callbacks << :before_create }
1060
+ @resource.after(:create) { callbacks << :after_create }
1061
+ @resource.after(:save) { callbacks << :after_save }
1062
+
1063
+ @machine.before_transition { callbacks << :before_transition }
1064
+ @machine.after_transition { callbacks << :after_transition }
1065
+
1066
+ @transition.perform
1067
+
1068
+ assert_equal expected, callbacks
1069
+ end
1070
+ end
1071
+
1072
+ class MachineWithFailedBeforeCallbacksTest < BaseTestCase
1073
+ def setup
1074
+ callbacks = []
1075
+
1076
+ @resource = new_resource
1077
+ @machine = StateMachine::Machine.new(@resource)
1078
+ @machine.state :parked, :idling
1079
+ @machine.event :ignite
1080
+ @machine.before_transition {callbacks << :before_1; throw :halt}
1081
+ @machine.before_transition {callbacks << :before_2}
1082
+ @machine.after_transition {callbacks << :after}
1083
+ @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
1084
+
1085
+ @record = @resource.new(:state => 'parked')
1086
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1087
+ @result = @transition.perform
1088
+
1089
+ @callbacks = callbacks
1090
+ end
1091
+
1092
+ def test_should_not_be_successful
1093
+ assert !@result
1094
+ end
1095
+
1096
+ def test_should_not_change_current_state
1097
+ assert_equal 'parked', @record.state
1098
+ end
1099
+
1100
+ def test_should_not_run_action
1101
+ assert @record.respond_to?(:new?) ? @record.new? : @record.new_record?
1102
+ end
1103
+
1104
+ def test_should_not_run_further_callbacks
1105
+ assert_equal [:before_1], @callbacks
1106
+ end
1107
+ end
1108
+
1109
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('1.0.0')
1110
+ class MachineNestedActionTest < BaseTestCase
1111
+ def setup
1112
+ @callbacks = []
1113
+
1114
+ @resource = new_resource
1115
+ @machine = StateMachine::Machine.new(@resource)
1116
+ @machine.event :ignite do
1117
+ transition :parked => :idling
1118
+ end
1119
+
1120
+ @record = @resource.new(:state => 'parked')
1121
+ end
1122
+
1123
+ def test_should_allow_transition_prior_to_creation_if_skipping_action
1124
+ record = @record
1125
+ @resource.before(:create) { record.ignite }
1126
+ result = @record.save
1127
+
1128
+ assert_equal true, result
1129
+ assert_equal "idling", @record.state
1130
+ @record.reload
1131
+ assert_equal "idling", @record.state
1132
+ end
1133
+
1134
+ def test_should_not_allow_transition_after_creation
1135
+ record = @record
1136
+ @resource.after(:create) { record.ignite(false) }
1137
+
1138
+ result = @record.save
1139
+
1140
+ assert_equal false, result
1141
+ end
1142
+ end
1143
+ end
1144
+
1145
+ class MachineWithFailedActionTest < BaseTestCase
1146
+ def setup
1147
+ @resource = new_resource do
1148
+ before(:create) { throw :halt }
1149
+ end
1150
+
1151
+ @machine = StateMachine::Machine.new(@resource)
1152
+ @machine.state :parked, :idling
1153
+ @machine.event :ignite
1154
+
1155
+ callbacks = []
1156
+ @machine.before_transition {callbacks << :before}
1157
+ @machine.after_transition {callbacks << :after}
1158
+ @machine.after_failure {callbacks << :after_failure}
1159
+ @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
1160
+
1161
+ @record = @resource.new(:state => 'parked')
1162
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1163
+ @result = @transition.perform
1164
+
1165
+ @callbacks = callbacks
1166
+ end
1167
+
1168
+ def test_should_not_be_successful
1169
+ assert !@result
1170
+ end
1171
+
1172
+ def test_should_not_change_current_state
1173
+ assert_equal 'parked', @record.state
1174
+ end
1175
+
1176
+ def test_should_not_save_record
1177
+ assert @record.respond_to?(:new?) ? @record.new? : @record.new_record?
1178
+ end
1179
+
1180
+ def test_should_run_before_callbacks_and_after_callbacks_with_failures
1181
+ assert_equal [:before, :around_before, :after_failure], @callbacks
1182
+ end
1183
+ end
1184
+
1185
+ class MachineWithFailedAfterCallbacksTest < BaseTestCase
1186
+ def setup
1187
+ callbacks = []
1188
+
1189
+ @resource = new_resource
1190
+ @machine = StateMachine::Machine.new(@resource)
1191
+ @machine.state :parked, :idling
1192
+ @machine.event :ignite
1193
+ @machine.after_transition {callbacks << :after_1; throw :halt}
1194
+ @machine.after_transition {callbacks << :after_2}
1195
+ @machine.around_transition {|block| callbacks << :around_before; block.call; callbacks << :around_after}
1196
+
1197
+ @record = @resource.new(:state => 'parked')
1198
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1199
+ @result = @transition.perform
1200
+
1201
+ @callbacks = callbacks
1202
+ end
1203
+
1204
+ def test_should_be_successful
1205
+ assert @result
1206
+ end
1207
+
1208
+ def test_should_change_current_state
1209
+ assert_equal 'idling', @record.state
1210
+ end
1211
+
1212
+ def test_should_save_record
1213
+ assert !(@record.respond_to?(:new?) ? @record.new? : @record.new_record?)
1214
+ end
1215
+
1216
+ def test_should_not_run_further_after_callbacks
1217
+ assert_equal [:around_before, :around_after, :after_1], @callbacks
1218
+ end
1219
+ end
1220
+
1221
+ begin
1222
+ require 'dm-validations'
1223
+
1224
+ class MachineWithValidationsTest < BaseTestCase
1225
+ def setup
1226
+ @resource = new_resource
1227
+ @machine = StateMachine::Machine.new(@resource)
1228
+ @machine.state :parked
1229
+
1230
+ @record = @resource.new
1231
+ end
1232
+
1233
+ def test_should_invalidate_using_errors
1234
+ @record.state = 'parked'
1235
+
1236
+ @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
1237
+ assert_equal ['cannot transition via "park"'], @record.errors.on(:state)
1238
+ end
1239
+
1240
+ def test_should_auto_prefix_custom_attributes_on_invalidation
1241
+ @machine.invalidate(@record, :event, :invalid)
1242
+
1243
+ assert_equal ['is invalid'], @record.errors.on(:state_event)
1244
+ end
1245
+
1246
+ def test_should_clear_errors_on_reset
1247
+ @record.state = 'parked'
1248
+ @record.errors.add(:state, 'is invalid')
1249
+
1250
+ @machine.reset(@record)
1251
+ assert_nil @record.errors.on(:id)
1252
+ end
1253
+
1254
+ def test_should_be_valid_if_state_is_known
1255
+ @record.state = 'parked'
1256
+
1257
+ assert @record.valid?
1258
+ end
1259
+
1260
+ def test_should_not_be_valid_if_state_is_unknown
1261
+ @record.state = 'invalid'
1262
+
1263
+ assert !@record.valid?
1264
+ assert_equal ['is invalid'], @record.errors.on(:state)
1265
+ end
1266
+ end
1267
+
1268
+ class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
1269
+ def setup
1270
+ @resource = new_resource
1271
+ @machine = StateMachine::Machine.new(@resource, :status, :attribute => :state)
1272
+ @machine.state :parked
1273
+
1274
+ @record = @resource.new
1275
+ end
1276
+
1277
+ def test_should_add_validation_errors_to_custom_attribute
1278
+ @record.state = 'invalid'
1279
+
1280
+ assert !@record.valid?
1281
+ assert_equal ['is invalid'], @record.errors.on(:state)
1282
+
1283
+ @record.state = 'parked'
1284
+ assert @record.valid?
1285
+ end
1286
+ end
1287
+
1288
+ class MachineErrorsTest < BaseTestCase
1289
+ def setup
1290
+ @resource = new_resource
1291
+ @machine = StateMachine::Machine.new(@resource)
1292
+ @record = @resource.new
1293
+ end
1294
+
1295
+ def test_should_be_able_to_describe_current_errors
1296
+ @record.errors.add(:id, 'cannot be blank')
1297
+ @record.errors.add(:state, 'is invalid')
1298
+ assert_equal ['id cannot be blank', 'state is invalid'], @machine.errors_for(@record).split(', ').sort
1299
+ end
1300
+
1301
+ def test_should_describe_as_halted_with_no_errors
1302
+ assert_equal 'Transition halted', @machine.errors_for(@record)
1303
+ end
1304
+ end
1305
+
1306
+ class MachineWithStateDrivenValidationsTest < BaseTestCase
1307
+ def setup
1308
+ @resource = resource = new_resource do
1309
+ attr_accessor :seatbelt
1310
+ end
1311
+
1312
+ @machine = StateMachine::Machine.new(@resource)
1313
+ @machine.state :first_gear, :second_gear do
1314
+ if resource.respond_to?(:validates_presence_of)
1315
+ validates_presence_of :seatbelt
1316
+ else
1317
+ validates_present :seatbelt
1318
+ end
1319
+ end
1320
+ @machine.other_states :parked
1321
+ end
1322
+
1323
+ def test_should_be_valid_if_validation_fails_outside_state_scope
1324
+ record = @resource.new(:state => 'parked', :seatbelt => nil)
1325
+ assert record.valid?
1326
+ end
1327
+
1328
+ def test_should_be_invalid_if_validation_fails_within_state_scope
1329
+ record = @resource.new(:state => 'first_gear', :seatbelt => nil)
1330
+ assert !record.valid?
1331
+ end
1332
+
1333
+ def test_should_be_valid_if_validation_succeeds_within_state_scope
1334
+ record = @resource.new(:state => 'second_gear', :seatbelt => true)
1335
+ assert record.valid?
1336
+ end
1337
+ end
1338
+
1339
+ # See README caveats
1340
+ if Gem::Version.new(DataMapper::VERSION) > Gem::Version.new('0.9.6')
1341
+ class MachineWithEventAttributesOnValidationTest < BaseTestCase
1342
+ def setup
1343
+ @resource = new_resource
1344
+ @machine = StateMachine::Machine.new(@resource)
1345
+ @machine.event :ignite do
1346
+ transition :parked => :idling
1347
+ end
1348
+
1349
+ @record = @resource.new
1350
+ @record.state = 'parked'
1351
+ @record.state_event = 'ignite'
1352
+ end
1353
+
1354
+ def test_should_fail_if_event_is_invalid
1355
+ @record.state_event = 'invalid'
1356
+ assert !@record.valid?
1357
+ assert_equal ['is invalid'], @record.errors.full_messages
1358
+ end
1359
+
1360
+ def test_should_fail_if_event_has_no_transition
1361
+ @record.state = 'idling'
1362
+ assert !@record.valid?
1363
+ assert_equal ['cannot transition when idling'], @record.errors.full_messages
1364
+ end
1365
+
1366
+ def test_should_be_successful_if_event_has_transition
1367
+ assert @record.valid?
1368
+ end
1369
+
1370
+ def test_should_run_before_callbacks
1371
+ ran_callback = false
1372
+ @machine.before_transition { ran_callback = true }
1373
+
1374
+ @record.valid?
1375
+ assert ran_callback
1376
+ end
1377
+
1378
+ def test_should_run_around_callbacks_before_yield
1379
+ ran_callback = false
1380
+ @machine.around_transition {|block| ran_callback = true; block.call }
1381
+
1382
+ begin
1383
+ @record.valid?
1384
+ rescue ArgumentError
1385
+ raise if StateMachine::Transition.pause_supported?
1386
+ end
1387
+ assert ran_callback
1388
+ end
1389
+
1390
+ def test_should_persist_new_state
1391
+ @record.valid?
1392
+ assert_equal 'idling', @record.state
1393
+ end
1394
+
1395
+ def test_should_not_run_after_callbacks
1396
+ ran_callback = false
1397
+ @machine.after_transition { ran_callback = true }
1398
+
1399
+ @record.valid?
1400
+ assert !ran_callback
1401
+ end
1402
+
1403
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
1404
+ @resource.class_eval do
1405
+ attr_accessor :seatbelt
1406
+ if respond_to?(:validates_presence_of)
1407
+ validates_presence_of :seatbelt
1408
+ else
1409
+ validates_present :seatbelt
1410
+ end
1411
+ end
1412
+
1413
+ ran_callback = false
1414
+ @machine.after_transition { ran_callback = true }
1415
+
1416
+ @record.valid?
1417
+ assert !ran_callback
1418
+ end
1419
+
1420
+ def test_should_run_failure_callbacks_if_validation_fails
1421
+ @resource.class_eval do
1422
+ attr_accessor :seatbelt
1423
+ if respond_to?(:validates_presence_of)
1424
+ validates_presence_of :seatbelt
1425
+ else
1426
+ validates_present :seatbelt
1427
+ end
1428
+ end
1429
+
1430
+ ran_callback = false
1431
+ @machine.after_failure { ran_callback = true }
1432
+
1433
+ @record.valid?
1434
+ assert ran_callback
1435
+ end
1436
+
1437
+ def test_should_not_run_around_callbacks_after_yield
1438
+ ran_callback = [false]
1439
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1440
+
1441
+ begin
1442
+ @record.valid?
1443
+ rescue ArgumentError
1444
+ raise if StateMachine::Transition.pause_supported?
1445
+ end
1446
+ assert !ran_callback[0]
1447
+ end
1448
+
1449
+ def test_should_not_run_around_callbacks_after_yield_with_failures_disabled_if_validation_fails
1450
+ @resource.class_eval do
1451
+ attr_accessor :seatbelt
1452
+ if respond_to?(:validates_presence_of)
1453
+ validates_presence_of :seatbelt
1454
+ else
1455
+ validates_present :seatbelt
1456
+ end
1457
+ end
1458
+
1459
+ ran_callback = [false]
1460
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1461
+
1462
+ begin
1463
+ @record.valid?
1464
+ rescue ArgumentError
1465
+ raise if StateMachine::Transition.pause_supported?
1466
+ end
1467
+ assert !ran_callback[0]
1468
+ end
1469
+
1470
+ def test_should_not_run_before_transitions_within_transaction
1471
+ @machine.before_transition { self.class.create; throw :halt }
1472
+
1473
+ assert !@record.valid?
1474
+ assert_equal 1, @resource.all.size
1475
+ end
1476
+ end
1477
+
1478
+ class MachineWithEventAttributesOnSaveTest < BaseTestCase
1479
+ def setup
1480
+ @resource = new_resource
1481
+ @machine = StateMachine::Machine.new(@resource)
1482
+ @machine.event :ignite do
1483
+ transition :parked => :idling
1484
+ end
1485
+
1486
+ @record = @resource.new
1487
+ @record.state = 'parked'
1488
+ @record.state_event = 'ignite'
1489
+ end
1490
+
1491
+ def test_should_fail_if_event_is_invalid
1492
+ @record.state_event = 'invalid'
1493
+ assert !@record.save
1494
+ end
1495
+
1496
+ def test_should_fail_if_event_has_no_transition
1497
+ @record.state = 'idling'
1498
+ assert !@record.save
1499
+ end
1500
+
1501
+ def test_should_be_successful_if_event_has_transition
1502
+ assert_equal true, @record.save
1503
+ end
1504
+
1505
+ def test_should_run_before_callbacks
1506
+ ran_callback = false
1507
+ @machine.before_transition { ran_callback = true }
1508
+
1509
+ @record.save
1510
+ assert ran_callback
1511
+ end
1512
+
1513
+ def test_should_run_before_callbacks_once
1514
+ before_count = 0
1515
+ @machine.before_transition { before_count += 1 }
1516
+
1517
+ @record.save
1518
+ assert_equal 1, before_count
1519
+ end
1520
+
1521
+ def test_should_run_around_callbacks_before_yield
1522
+ ran_callback = false
1523
+ @machine.around_transition {|block| ran_callback = true; block.call }
1524
+
1525
+ @record.save
1526
+ assert ran_callback
1527
+ end
1528
+
1529
+ def test_should_run_around_callbacks_before_yield_once
1530
+ around_before_count = 0
1531
+ @machine.around_transition {|block| around_before_count += 1; block.call }
1532
+
1533
+ @record.save
1534
+ assert_equal 1, around_before_count
1535
+ end
1536
+
1537
+ def test_should_persist_new_state
1538
+ @record.save
1539
+ assert_equal 'idling', @record.state
1540
+ end
1541
+
1542
+ def test_should_run_after_callbacks
1543
+ ran_callback = false
1544
+ @machine.after_transition { ran_callback = true }
1545
+
1546
+ @record.save
1547
+ assert ran_callback
1548
+ end
1549
+
1550
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
1551
+ @resource.before(:create) { throw :halt }
1552
+
1553
+ ran_callback = false
1554
+ @machine.after_transition { ran_callback = true }
1555
+
1556
+ @record.save
1557
+ assert !ran_callback
1558
+ end
1559
+
1560
+ def test_should_run_failure_callbacks_if_fails
1561
+ @resource.before(:create) { throw :halt }
1562
+
1563
+ ran_callback = false
1564
+ @machine.after_failure { ran_callback = true }
1565
+
1566
+ @record.save
1567
+ assert ran_callback
1568
+ end
1569
+
1570
+ def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
1571
+ @resource.before(:create) { throw :halt }
1572
+
1573
+ ran_callback = [false]
1574
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1575
+
1576
+ @record.save
1577
+ assert !ran_callback[0]
1578
+ end
1579
+
1580
+ def test_should_run_around_callbacks_after_yield
1581
+ ran_callback = [false]
1582
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1583
+
1584
+ @record.save
1585
+ assert ran_callback[0]
1586
+ end
1587
+
1588
+ def test_should_not_run_before_transitions_within_transaction
1589
+ @machine.before_transition { self.class.create; throw :halt }
1590
+
1591
+ assert_equal false, @record.save
1592
+ assert_equal 1, @resource.all.size
1593
+ end
1594
+
1595
+ def test_should_not_run_after_transitions_within_transaction
1596
+ @machine.before_transition { self.class.create; throw :halt }
1597
+
1598
+ assert_equal false, @record.save
1599
+ assert_equal 1, @resource.all.size
1600
+ end
1601
+
1602
+ def test_should_not_run_around_transition_within_transaction
1603
+ @machine.around_transition { self.class.create; throw :halt }
1604
+
1605
+ assert_equal false, @record.save
1606
+ assert_equal 1, @resource.all.size
1607
+ end
1608
+
1609
+ def test_should_allow_additional_transitions_to_new_state_in_after_transitions
1610
+ @machine.event :park do
1611
+ transition :idling => :parked
1612
+ end
1613
+
1614
+ @machine.after_transition(:on => :ignite) { park }
1615
+
1616
+ @record.save
1617
+ assert_equal 'parked', @record.state
1618
+
1619
+ @record.reload
1620
+ assert_equal 'parked', @record.state
1621
+ end
1622
+
1623
+ def test_should_allow_additional_transitions_to_previous_state_in_after_transitions
1624
+ @machine.event :shift_up do
1625
+ transition :idling => :first_gear
1626
+ end
1627
+
1628
+ @machine.after_transition(:on => :ignite) { shift_up }
1629
+
1630
+ @record.save
1631
+ assert_equal 'first_gear', @record.state
1632
+
1633
+ @record.reload
1634
+ assert_equal 'first_gear', @record.state
1635
+ end
1636
+ end
1637
+ end
1638
+
1639
+ if Gem::Version.new(DataMapper::VERSION) >= Gem::Version.new('0.10.0')
1640
+ class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
1641
+ def setup
1642
+ @resource = new_resource
1643
+ @machine = StateMachine::Machine.new(@resource)
1644
+ @machine.event :ignite do
1645
+ transition :parked => :idling
1646
+ end
1647
+
1648
+ @record = @resource.new
1649
+ @record.state = 'parked'
1650
+ @record.state_event = 'ignite'
1651
+ end
1652
+
1653
+ def test_should_fail_if_event_is_invalid
1654
+ @record.state_event = 'invalid'
1655
+ assert !@record.save!
1656
+ end
1657
+
1658
+ def test_should_fail_if_event_has_no_transition
1659
+ @record.state = 'idling'
1660
+ assert !@record.save!
1661
+ end
1662
+
1663
+ def test_should_be_successful_if_event_has_transition
1664
+ assert_equal true, @record.save!
1665
+ end
1666
+
1667
+ def test_should_run_before_callbacks
1668
+ ran_callback = false
1669
+ @machine.before_transition { ran_callback = true }
1670
+
1671
+ @record.save!
1672
+ assert ran_callback
1673
+ end
1674
+
1675
+ def test_should_run_before_callbacks_once
1676
+ before_count = 0
1677
+ @machine.before_transition { before_count += 1 }
1678
+
1679
+ @record.save!
1680
+ assert_equal 1, before_count
1681
+ end
1682
+
1683
+ def test_should_run_around_callbacks_before_yield
1684
+ ran_callback = false
1685
+ @machine.around_transition {|block| ran_callback = true; block.call }
1686
+
1687
+ @record.save!
1688
+ assert ran_callback
1689
+ end
1690
+
1691
+ def test_should_run_around_callbacks_before_yield_once
1692
+ around_before_count = 0
1693
+ @machine.around_transition {|block| around_before_count += 1; block.call }
1694
+
1695
+ @record.save!
1696
+ assert_equal 1, around_before_count
1697
+ end
1698
+
1699
+ def test_should_persist_new_state
1700
+ @record.save!
1701
+ assert_equal 'idling', @record.state
1702
+ end
1703
+
1704
+ def test_should_run_after_callbacks
1705
+ ran_callback = false
1706
+ @machine.after_transition { ran_callback = true }
1707
+
1708
+ @record.save!
1709
+ assert ran_callback
1710
+ end
1711
+
1712
+ def test_should_run_around_callbacks_after_yield
1713
+ ran_callback = [false]
1714
+ @machine.around_transition {|block| block.call; ran_callback[0] = true }
1715
+
1716
+ @record.save!
1717
+ assert ran_callback[0]
1718
+ end
1719
+ end
1720
+ end
1721
+
1722
+ if Gem::Version.new(DataMapper::VERSION) > Gem::Version.new('0.9.6')
1723
+ class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
1724
+ def setup
1725
+ @superclass = new_resource do
1726
+ def persist
1727
+ save
1728
+ end
1729
+ end
1730
+ @resource = Class.new(@superclass)
1731
+ @machine = StateMachine::Machine.new(@resource, :action => :persist)
1732
+ @machine.event :ignite do
1733
+ transition :parked => :idling
1734
+ end
1735
+
1736
+ @record = @resource.new
1737
+ @record.state = 'parked'
1738
+ @record.state_event = 'ignite'
1739
+ end
1740
+
1741
+ def test_should_not_transition_on_valid?
1742
+ @record.valid?
1743
+ assert_equal 'parked', @record.state
1744
+ end
1745
+
1746
+ def test_should_not_transition_on_save
1747
+ @record.save
1748
+ assert_equal 'parked', @record.state
1749
+ end
1750
+
1751
+ def test_should_transition_on_custom_action
1752
+ @record.persist
1753
+ assert_equal 'idling', @record.state
1754
+ end
1755
+ end
1756
+ end
1757
+ rescue LoadError
1758
+ $stderr.puts "Skipping DataMapper Validation tests."
1759
+ end
1760
+
1761
+ class MachineWithObserversTest < BaseTestCase
1762
+ def setup
1763
+ @resource = new_resource
1764
+ @machine = StateMachine::Machine.new(@resource)
1765
+ @machine.state :parked, :idling
1766
+ @machine.event :ignite
1767
+ @record = @resource.new(:state => 'parked')
1768
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1769
+ end
1770
+
1771
+ def test_should_provide_matcher_helpers
1772
+ matchers = []
1773
+
1774
+ new_observer(@resource) do
1775
+ matchers = [all, any, same]
1776
+ end
1777
+
1778
+ assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
1779
+ end
1780
+
1781
+ def test_should_call_before_transition_callback_if_requirements_match
1782
+ called = false
1783
+
1784
+ new_observer(@resource) do
1785
+ before_transition :from => :parked do
1786
+ called = true
1787
+ end
1788
+ end
1789
+
1790
+ @transition.perform
1791
+ assert called
1792
+ end
1793
+
1794
+ def test_should_not_call_before_transition_callback_if_requirements_do_not_match
1795
+ called = false
1796
+
1797
+ new_observer(@resource) do
1798
+ before_transition :from => :idling do
1799
+ called = true
1800
+ end
1801
+ end
1802
+
1803
+ @transition.perform
1804
+ assert !called
1805
+ end
1806
+
1807
+ def test_should_pass_transition_to_before_callbacks
1808
+ callback_args = nil
1809
+
1810
+ new_observer(@resource) do
1811
+ before_transition do |*args|
1812
+ callback_args = args
1813
+ end
1814
+ end
1815
+
1816
+ @transition.perform
1817
+ assert_equal [@transition], callback_args
1818
+ end
1819
+
1820
+ def test_should_call_after_transition_callback_if_requirements_match
1821
+ called = false
1822
+
1823
+ new_observer(@resource) do
1824
+ after_transition :from => :parked do
1825
+ called = true
1826
+ end
1827
+ end
1828
+
1829
+ @transition.perform
1830
+ assert called
1831
+ end
1832
+
1833
+ def test_should_not_call_after_transition_callback_if_requirements_do_not_match
1834
+ called = false
1835
+
1836
+ new_observer(@resource) do
1837
+ after_transition :from => :idling do
1838
+ called = true
1839
+ end
1840
+ end
1841
+
1842
+ @transition.perform
1843
+ assert !called
1844
+ end
1845
+
1846
+ def test_should_pass_transition_to_after_callbacks
1847
+ callback_args = nil
1848
+
1849
+ new_observer(@resource) do
1850
+ after_transition do |*args|
1851
+ callback_args = args
1852
+ end
1853
+ end
1854
+
1855
+ @transition.perform
1856
+ assert_equal [@transition], callback_args
1857
+ end
1858
+
1859
+ def test_should_call_around_transition_callback_if_requirements_match
1860
+ called = false
1861
+
1862
+ new_observer(@resource) do
1863
+ around_transition :from => :parked do |block|
1864
+ called = true
1865
+ block.call
1866
+ end
1867
+ end
1868
+
1869
+ @transition.perform
1870
+ assert called
1871
+ end
1872
+
1873
+ def test_should_not_call_around_transition_callback_if_requirements_do_not_match
1874
+ called = false
1875
+
1876
+ new_observer(@resource) do
1877
+ around_transition :from => :idling do |block|
1878
+ called = true
1879
+ block.call
1880
+ end
1881
+ end
1882
+
1883
+ @transition.perform
1884
+ assert !called
1885
+ end
1886
+
1887
+ def test_should_pass_transition_to_around_callbacks
1888
+ callback_args = nil
1889
+
1890
+ new_observer(@resource) do
1891
+ around_transition do |*args|
1892
+ block = args.pop
1893
+ callback_args = args
1894
+ block.call
1895
+ end
1896
+ end
1897
+
1898
+ @transition.perform
1899
+ assert_equal [@transition], callback_args
1900
+ end
1901
+
1902
+ def test_should_call_failure_callback_if_requirements_match
1903
+ @resource.before(:create) { throw :halt }
1904
+
1905
+ called = false
1906
+
1907
+ new_observer(@resource) do
1908
+ after_transition_failure :on => :ignite do
1909
+ called = true
1910
+ end
1911
+ end
1912
+
1913
+ @transition.perform
1914
+ assert called
1915
+ end
1916
+
1917
+ def test_should_not_call_failure_callback_if_requirements_do_not_match
1918
+ @resource.before(:create) { throw :halt }
1919
+
1920
+ called = false
1921
+
1922
+ new_observer(@resource) do
1923
+ after_transition_failure :on => :park do
1924
+ called = true
1925
+ end
1926
+ end
1927
+
1928
+ @transition.perform
1929
+ assert !called
1930
+ end
1931
+
1932
+ def test_should_pass_transition_to_failure_callbacks
1933
+ @resource.before(:create) { throw :halt }
1934
+
1935
+ callback_args = nil
1936
+
1937
+ new_observer(@resource) do
1938
+ after_transition_failure do |*args|
1939
+ callback_args = args
1940
+ end
1941
+ end
1942
+
1943
+ @transition.perform
1944
+ assert_equal [@transition], callback_args
1945
+ end
1946
+
1947
+ def test_should_raise_exception_if_targeting_invalid_machine
1948
+ assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) do
1949
+ new_observer(@resource) do
1950
+ before_transition :invalid, :from => :parked do
1951
+ end
1952
+ end
1953
+ end
1954
+ end
1955
+
1956
+ def test_should_allow_targeting_specific_machine
1957
+ @second_machine = StateMachine::Machine.new(@resource, :status, :namespace => 'alarm')
1958
+ @resource.auto_migrate!
1959
+
1960
+ called_state = false
1961
+ called_status = false
1962
+
1963
+ new_observer(@resource) do
1964
+ before_transition :state, :from => :parked do
1965
+ called_state = true
1966
+ end
1967
+
1968
+ before_transition :status, :from => :parked do
1969
+ called_status = true
1970
+ end
1971
+ end
1972
+
1973
+ @transition.perform
1974
+
1975
+ assert called_state
1976
+ assert !called_status
1977
+ end
1978
+
1979
+ def test_should_allow_targeting_multiple_specific_machines
1980
+ @second_machine = StateMachine::Machine.new(@resource, :status, :namespace => 'alarm')
1981
+ @second_machine.state :parked, :idling
1982
+ @second_machine.event :ignite
1983
+ @resource.auto_migrate!
1984
+
1985
+ called_attribute = nil
1986
+
1987
+ new_observer(@resource) do
1988
+ before_transition :state, :status, :from => :parked do |transition|
1989
+ called_attribute = transition.attribute
1990
+ end
1991
+ end
1992
+
1993
+ @transition.perform
1994
+ assert_equal :state, called_attribute
1995
+
1996
+ StateMachine::Transition.new(@record, @second_machine, :ignite, :parked, :idling).perform
1997
+ assert_equal :status, called_attribute
1998
+ end
1999
+ end
2000
+
2001
+ class MachineWithMixedCallbacksTest < BaseTestCase
2002
+ def setup
2003
+ @resource = new_resource
2004
+ @machine = StateMachine::Machine.new(@resource)
2005
+ @machine.state :parked, :idling
2006
+ @machine.event :ignite
2007
+ @record = @resource.new(:state => 'parked')
2008
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
2009
+
2010
+ @notifications = notifications = []
2011
+
2012
+ # Create callbacks
2013
+ @machine.before_transition {notifications << :callback_before_transition}
2014
+ @machine.after_transition {notifications << :callback_after_transition}
2015
+ @machine.around_transition do |block|
2016
+ notifications << :callback_around_before_transition
2017
+ block.call
2018
+ notifications << :callback_around_after_transition
2019
+ end
2020
+
2021
+ new_observer(@resource) do
2022
+ before_transition do
2023
+ notifications << :observer_before_transition
2024
+ end
2025
+
2026
+ after_transition do
2027
+ notifications << :observer_after_transition
2028
+ end
2029
+
2030
+ around_transition do |block|
2031
+ notifications << :observer_around_before_transition
2032
+ block.call
2033
+ notifications << :observer_around_after_transition
2034
+ end
2035
+ end
2036
+
2037
+ @transition.perform
2038
+ end
2039
+
2040
+ def test_should_invoke_callbacks_in_specific_order
2041
+ expected = [
2042
+ :callback_before_transition,
2043
+ :callback_around_before_transition,
2044
+ :observer_before_transition,
2045
+ :observer_around_before_transition,
2046
+ :observer_around_after_transition,
2047
+ :callback_around_after_transition,
2048
+ :callback_after_transition,
2049
+ :observer_after_transition
2050
+ ]
2051
+
2052
+ assert_equal expected, @notifications
2053
+ end
2054
+ end
2055
+
2056
+ class MachineWithScopesTest < BaseTestCase
2057
+ def setup
2058
+ @resource = new_resource
2059
+ @machine = StateMachine::Machine.new(@resource)
2060
+ @machine.state :parked, :first_gear
2061
+ @machine.state :idling, :value => lambda {'idling'}
2062
+ end
2063
+
2064
+ def test_should_create_singular_with_scope
2065
+ assert @resource.respond_to?(:with_state)
2066
+ end
2067
+
2068
+ def test_should_only_include_records_with_state_in_singular_with_scope
2069
+ parked = @resource.create :state => 'parked'
2070
+ @resource.create :state => 'idling'
2071
+
2072
+ assert_equal [parked], @resource.with_state(:parked)
2073
+ end
2074
+
2075
+ def test_should_create_plural_with_scope
2076
+ assert @resource.respond_to?(:with_states)
2077
+ end
2078
+
2079
+ def test_should_only_include_records_with_states_in_plural_with_scope
2080
+ parked = @resource.create :state => 'parked'
2081
+ idling = @resource.create :state => 'idling'
2082
+
2083
+ assert_equal [parked, idling], @resource.with_states(:parked, :idling)
2084
+ end
2085
+
2086
+ def test_should_allow_lookup_by_string_name
2087
+ parked = @resource.create :state => 'parked'
2088
+ idling = @resource.create :state => 'idling'
2089
+
2090
+ assert_equal [parked, idling], @resource.with_states('parked', 'idling')
2091
+ end
2092
+
2093
+ def test_should_create_singular_without_scope
2094
+ assert @resource.respond_to?(:without_state)
2095
+ end
2096
+
2097
+ def test_should_only_include_records_without_state_in_singular_without_scope
2098
+ parked = @resource.create :state => 'parked'
2099
+ idling = @resource.create :state => 'idling'
2100
+
2101
+ assert_equal [parked], @resource.without_state(:idling)
2102
+ end
2103
+
2104
+ def test_should_create_plural_without_scope
2105
+ assert @resource.respond_to?(:without_states)
2106
+ end
2107
+
2108
+ def test_should_only_include_records_without_states_in_plural_without_scope
2109
+ parked = @resource.create :state => 'parked'
2110
+ idling = @resource.create :state => 'idling'
2111
+ first_gear = @resource.create :state => 'first_gear'
2112
+
2113
+ assert_equal [parked, idling], @resource.without_states(:first_gear)
2114
+ end
2115
+
2116
+ def test_should_allow_chaining_scopes
2117
+ parked = @resource.create :state => 'parked'
2118
+ idling = @resource.create :state => 'idling'
2119
+
2120
+ assert_equal [idling], @resource.without_state(:parked).with_state(:idling)
2121
+ end
2122
+ end
2123
+
2124
+ class MachineWithScopesAndOwnerSubclassTest < BaseTestCase
2125
+ def setup
2126
+ @resource = new_resource
2127
+ @machine = StateMachine::Machine.new(@resource, :state)
2128
+
2129
+ @subclass = Class.new(@resource)
2130
+ DataMapperTest.const_set('Bar', @subclass)
2131
+ @resources << 'Bar'
2132
+ @subclass.auto_migrate!
2133
+ @subclass_machine = @subclass.state_machine(:state) {}
2134
+ @subclass_machine.state :parked, :idling, :first_gear
2135
+ end
2136
+
2137
+ def test_should_only_include_records_with_subclass_states_in_with_scope
2138
+ parked = @subclass.create :state => 'parked'
2139
+ idling = @subclass.create :state => 'idling'
2140
+
2141
+ assert_equal [parked, idling], @subclass.with_states(:parked, :idling)
2142
+ end
2143
+
2144
+ def test_should_only_include_records_without_subclass_states_in_without_scope
2145
+ parked = @subclass.create :state => 'parked'
2146
+ idling = @subclass.create :state => 'idling'
2147
+ first_gear = @subclass.create :state => 'first_gear'
2148
+
2149
+ assert_equal [parked, idling], @subclass.without_states(:first_gear)
2150
+ end
2151
+ end
2152
+
2153
+ class MachineWithComplexPluralizationScopesTest < BaseTestCase
2154
+ def setup
2155
+ @resource = new_resource
2156
+ @machine = StateMachine::Machine.new(@resource, :status)
2157
+ end
2158
+
2159
+ def test_should_create_singular_with_scope
2160
+ assert @resource.respond_to?(:with_status)
2161
+ end
2162
+
2163
+ def test_should_create_plural_with_scope
2164
+ assert @resource.respond_to?(:with_statuses)
2165
+ end
2166
+ end
2167
+
2168
+ class MachineWithScopesAndJoinsTest < BaseTestCase
2169
+ def setup
2170
+ @company = new_resource(:company)
2171
+
2172
+ @vehicle = new_resource(:vehicle) do
2173
+ property :company_id, Integer
2174
+
2175
+ belongs_to :company
2176
+ end
2177
+
2178
+ @company_machine = StateMachine::Machine.new(@company, :initial => :active)
2179
+ @vehicle_machine = StateMachine::Machine.new(@vehicle, :initial => :parked)
2180
+ @vehicle_machine.state :idling
2181
+
2182
+ @ford = @company.create
2183
+ @mustang = @vehicle.create(:company => @ford)
2184
+ end
2185
+
2186
+ def test_should_find_records_in_with_scope
2187
+ assert_equal [@mustang], @vehicle.with_states(:parked).all(Vehicle.company.state => 'active')
2188
+ end
2189
+
2190
+ def test_should_find_records_in_without_scope
2191
+ assert_equal [@mustang], @vehicle.without_states(:idling).all(Vehicle.company.state => 'active')
2192
+ end
2193
+ end
2194
+ end