telvue_state_machine 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +72 -0
  4. data/.yardopts +5 -0
  5. data/Appraisals +491 -0
  6. data/CHANGELOG.md +502 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +20 -0
  9. data/README.md +1263 -0
  10. data/Rakefile +41 -0
  11. data/examples/AutoShop_state.png +0 -0
  12. data/examples/Car_state.png +0 -0
  13. data/examples/Gemfile +5 -0
  14. data/examples/Gemfile.lock +14 -0
  15. data/examples/TrafficLight_state.png +0 -0
  16. data/examples/Vehicle_state.png +0 -0
  17. data/examples/auto_shop.rb +13 -0
  18. data/examples/car.rb +21 -0
  19. data/examples/doc/AutoShop.html +2856 -0
  20. data/examples/doc/AutoShop_state.png +0 -0
  21. data/examples/doc/Car.html +919 -0
  22. data/examples/doc/Car_state.png +0 -0
  23. data/examples/doc/TrafficLight.html +2230 -0
  24. data/examples/doc/TrafficLight_state.png +0 -0
  25. data/examples/doc/Vehicle.html +7921 -0
  26. data/examples/doc/Vehicle_state.png +0 -0
  27. data/examples/doc/_index.html +136 -0
  28. data/examples/doc/class_list.html +47 -0
  29. data/examples/doc/css/common.css +1 -0
  30. data/examples/doc/css/full_list.css +55 -0
  31. data/examples/doc/css/style.css +322 -0
  32. data/examples/doc/file_list.html +46 -0
  33. data/examples/doc/frames.html +13 -0
  34. data/examples/doc/index.html +136 -0
  35. data/examples/doc/js/app.js +205 -0
  36. data/examples/doc/js/full_list.js +173 -0
  37. data/examples/doc/js/jquery.js +16 -0
  38. data/examples/doc/method_list.html +734 -0
  39. data/examples/doc/top-level-namespace.html +105 -0
  40. data/examples/merb-rest/controller.rb +51 -0
  41. data/examples/merb-rest/model.rb +28 -0
  42. data/examples/merb-rest/view_edit.html.erb +24 -0
  43. data/examples/merb-rest/view_index.html.erb +23 -0
  44. data/examples/merb-rest/view_new.html.erb +13 -0
  45. data/examples/merb-rest/view_show.html.erb +17 -0
  46. data/examples/rails-rest/controller.rb +43 -0
  47. data/examples/rails-rest/migration.rb +7 -0
  48. data/examples/rails-rest/model.rb +23 -0
  49. data/examples/rails-rest/view__form.html.erb +34 -0
  50. data/examples/rails-rest/view_edit.html.erb +6 -0
  51. data/examples/rails-rest/view_index.html.erb +25 -0
  52. data/examples/rails-rest/view_new.html.erb +5 -0
  53. data/examples/rails-rest/view_show.html.erb +19 -0
  54. data/examples/traffic_light.rb +9 -0
  55. data/examples/vehicle.rb +33 -0
  56. data/gemfiles/active_model_3.0.0.gemfile +7 -0
  57. data/gemfiles/active_model_3.0.0.gemfile.lock +35 -0
  58. data/gemfiles/active_model_3.0.5.gemfile +7 -0
  59. data/gemfiles/active_model_3.0.5.gemfile.lock +35 -0
  60. data/gemfiles/active_model_3.1.1.gemfile +7 -0
  61. data/gemfiles/active_model_3.1.1.gemfile.lock +36 -0
  62. data/gemfiles/active_model_3.2.1.gemfile +7 -0
  63. data/gemfiles/active_model_3.2.12.gemfile +7 -0
  64. data/gemfiles/active_model_3.2.12.gemfile.lock +36 -0
  65. data/gemfiles/active_model_3.2.13.rc1.gemfile +7 -0
  66. data/gemfiles/active_model_3.2.13.rc1.gemfile.lock +36 -0
  67. data/gemfiles/active_model_4.0.0.gemfile +9 -0
  68. data/gemfiles/active_model_4.0.0.gemfile.lock +78 -0
  69. data/gemfiles/active_record_2.0.0.gemfile +9 -0
  70. data/gemfiles/active_record_2.0.0.gemfile.lock +39 -0
  71. data/gemfiles/active_record_2.0.5.gemfile +9 -0
  72. data/gemfiles/active_record_2.0.5.gemfile.lock +39 -0
  73. data/gemfiles/active_record_2.1.0.gemfile +9 -0
  74. data/gemfiles/active_record_2.1.0.gemfile.lock +39 -0
  75. data/gemfiles/active_record_2.1.2.gemfile +9 -0
  76. data/gemfiles/active_record_2.1.2.gemfile.lock +39 -0
  77. data/gemfiles/active_record_2.2.3.gemfile +9 -0
  78. data/gemfiles/active_record_2.2.3.gemfile.lock +39 -0
  79. data/gemfiles/active_record_2.3.12.gemfile +9 -0
  80. data/gemfiles/active_record_2.3.12.gemfile.lock +39 -0
  81. data/gemfiles/active_record_2.3.5.gemfile +9 -0
  82. data/gemfiles/active_record_2.3.5.gemfile.lock +39 -0
  83. data/gemfiles/active_record_3.0.0.gemfile +9 -0
  84. data/gemfiles/active_record_3.0.0.gemfile.lock +51 -0
  85. data/gemfiles/active_record_3.0.5.gemfile +9 -0
  86. data/gemfiles/active_record_3.0.5.gemfile.lock +50 -0
  87. data/gemfiles/active_record_3.1.1.gemfile +9 -0
  88. data/gemfiles/active_record_3.1.1.gemfile.lock +51 -0
  89. data/gemfiles/active_record_3.2.12.gemfile +9 -0
  90. data/gemfiles/active_record_3.2.12.gemfile.lock +51 -0
  91. data/gemfiles/active_record_3.2.13.rc1.gemfile +9 -0
  92. data/gemfiles/active_record_3.2.13.rc1.gemfile.lock +51 -0
  93. data/gemfiles/active_record_4.0.0.gemfile +11 -0
  94. data/gemfiles/active_record_4.0.0.gemfile.lock +83 -0
  95. data/gemfiles/data_mapper_0.10.2.gemfile +13 -0
  96. data/gemfiles/data_mapper_0.10.2.gemfile.lock +56 -0
  97. data/gemfiles/data_mapper_0.9.11.gemfile +13 -0
  98. data/gemfiles/data_mapper_0.9.11.gemfile.lock +71 -0
  99. data/gemfiles/data_mapper_0.9.4.gemfile +12 -0
  100. data/gemfiles/data_mapper_0.9.4.gemfile.lock +70 -0
  101. data/gemfiles/data_mapper_0.9.7.gemfile +13 -0
  102. data/gemfiles/data_mapper_0.9.7.gemfile.lock +67 -0
  103. data/gemfiles/data_mapper_1.0.0.gemfile +12 -0
  104. data/gemfiles/data_mapper_1.0.0.gemfile.lock +63 -0
  105. data/gemfiles/data_mapper_1.0.1.gemfile +12 -0
  106. data/gemfiles/data_mapper_1.0.1.gemfile.lock +63 -0
  107. data/gemfiles/data_mapper_1.0.2.gemfile +12 -0
  108. data/gemfiles/data_mapper_1.0.2.gemfile.lock +63 -0
  109. data/gemfiles/data_mapper_1.1.0.gemfile +12 -0
  110. data/gemfiles/data_mapper_1.1.0.gemfile.lock +61 -0
  111. data/gemfiles/data_mapper_1.2.0.gemfile +12 -0
  112. data/gemfiles/data_mapper_1.2.0.gemfile.lock +61 -0
  113. data/gemfiles/default.gemfile +7 -0
  114. data/gemfiles/default.gemfile.lock +27 -0
  115. data/gemfiles/graphviz_0.9.17.gemfile +7 -0
  116. data/gemfiles/graphviz_0.9.17.gemfile.lock +29 -0
  117. data/gemfiles/graphviz_0.9.21.gemfile +7 -0
  118. data/gemfiles/graphviz_0.9.21.gemfile.lock +29 -0
  119. data/gemfiles/graphviz_1.0.0.gemfile +7 -0
  120. data/gemfiles/graphviz_1.0.0.gemfile.lock +29 -0
  121. data/gemfiles/graphviz_1.0.3.gemfile +7 -0
  122. data/gemfiles/graphviz_1.0.3.gemfile.lock +29 -0
  123. data/gemfiles/graphviz_1.0.8.gemfile +7 -0
  124. data/gemfiles/graphviz_1.0.8.gemfile.lock +29 -0
  125. data/gemfiles/mongo_mapper_0.10.0.gemfile +8 -0
  126. data/gemfiles/mongo_mapper_0.10.0.gemfile.lock +47 -0
  127. data/gemfiles/mongo_mapper_0.11.2.gemfile +9 -0
  128. data/gemfiles/mongo_mapper_0.11.2.gemfile.lock +48 -0
  129. data/gemfiles/mongo_mapper_0.12.0.gemfile +9 -0
  130. data/gemfiles/mongo_mapper_0.12.0.gemfile.lock +48 -0
  131. data/gemfiles/mongo_mapper_0.5.5.gemfile +8 -0
  132. data/gemfiles/mongo_mapper_0.5.5.gemfile.lock +36 -0
  133. data/gemfiles/mongo_mapper_0.5.8.gemfile +8 -0
  134. data/gemfiles/mongo_mapper_0.5.8.gemfile.lock +36 -0
  135. data/gemfiles/mongo_mapper_0.6.0.gemfile +8 -0
  136. data/gemfiles/mongo_mapper_0.6.0.gemfile.lock +36 -0
  137. data/gemfiles/mongo_mapper_0.6.10.gemfile +8 -0
  138. data/gemfiles/mongo_mapper_0.6.10.gemfile.lock +36 -0
  139. data/gemfiles/mongo_mapper_0.7.0.gemfile +8 -0
  140. data/gemfiles/mongo_mapper_0.7.0.gemfile.lock +36 -0
  141. data/gemfiles/mongo_mapper_0.7.5.gemfile +8 -0
  142. data/gemfiles/mongo_mapper_0.7.5.gemfile.lock +39 -0
  143. data/gemfiles/mongo_mapper_0.8.0.gemfile +10 -0
  144. data/gemfiles/mongo_mapper_0.8.0.gemfile.lock +43 -0
  145. data/gemfiles/mongo_mapper_0.8.3.gemfile +10 -0
  146. data/gemfiles/mongo_mapper_0.8.3.gemfile.lock +43 -0
  147. data/gemfiles/mongo_mapper_0.8.4.gemfile +8 -0
  148. data/gemfiles/mongo_mapper_0.8.4.gemfile.lock +42 -0
  149. data/gemfiles/mongo_mapper_0.8.6.gemfile +8 -0
  150. data/gemfiles/mongo_mapper_0.8.6.gemfile.lock +42 -0
  151. data/gemfiles/mongo_mapper_0.9.0.gemfile +7 -0
  152. data/gemfiles/mongo_mapper_0.9.0.gemfile.lock +45 -0
  153. data/gemfiles/mongoid_2.0.0.gemfile +9 -0
  154. data/gemfiles/mongoid_2.0.0.gemfile.lock +49 -0
  155. data/gemfiles/mongoid_2.1.4.gemfile +9 -0
  156. data/gemfiles/mongoid_2.1.4.gemfile.lock +47 -0
  157. data/gemfiles/mongoid_2.2.4.gemfile +9 -0
  158. data/gemfiles/mongoid_2.2.4.gemfile.lock +47 -0
  159. data/gemfiles/mongoid_2.3.3.gemfile +9 -0
  160. data/gemfiles/mongoid_2.3.3.gemfile.lock +47 -0
  161. data/gemfiles/mongoid_2.4.0.gemfile +9 -0
  162. data/gemfiles/mongoid_2.4.0.gemfile.lock +47 -0
  163. data/gemfiles/mongoid_2.4.10.gemfile +9 -0
  164. data/gemfiles/mongoid_2.4.10.gemfile.lock +47 -0
  165. data/gemfiles/mongoid_2.5.2.gemfile +9 -0
  166. data/gemfiles/mongoid_2.5.2.gemfile.lock +47 -0
  167. data/gemfiles/mongoid_2.6.0.gemfile +9 -0
  168. data/gemfiles/mongoid_2.6.0.gemfile.lock +47 -0
  169. data/gemfiles/mongoid_3.0.0.gemfile +8 -0
  170. data/gemfiles/mongoid_3.0.0.gemfile.lock +45 -0
  171. data/gemfiles/mongoid_3.0.22.gemfile +8 -0
  172. data/gemfiles/mongoid_3.0.22.gemfile.lock +45 -0
  173. data/gemfiles/mongoid_3.1.0.gemfile +8 -0
  174. data/gemfiles/mongoid_3.1.0.gemfile.lock +45 -0
  175. data/gemfiles/sequel_2.11.0.gemfile +9 -0
  176. data/gemfiles/sequel_2.11.0.gemfile.lock +33 -0
  177. data/gemfiles/sequel_2.12.0.gemfile +9 -0
  178. data/gemfiles/sequel_2.12.0.gemfile.lock +33 -0
  179. data/gemfiles/sequel_2.8.0.gemfile +9 -0
  180. data/gemfiles/sequel_2.8.0.gemfile.lock +33 -0
  181. data/gemfiles/sequel_3.0.0.gemfile +9 -0
  182. data/gemfiles/sequel_3.0.0.gemfile.lock +33 -0
  183. data/gemfiles/sequel_3.10.0.gemfile +9 -0
  184. data/gemfiles/sequel_3.10.0.gemfile.lock +33 -0
  185. data/gemfiles/sequel_3.13.0.gemfile +9 -0
  186. data/gemfiles/sequel_3.13.0.gemfile.lock +33 -0
  187. data/gemfiles/sequel_3.14.0.gemfile +9 -0
  188. data/gemfiles/sequel_3.14.0.gemfile.lock +33 -0
  189. data/gemfiles/sequel_3.23.0.gemfile +9 -0
  190. data/gemfiles/sequel_3.23.0.gemfile.lock +33 -0
  191. data/gemfiles/sequel_3.24.0.gemfile +9 -0
  192. data/gemfiles/sequel_3.24.0.gemfile.lock +33 -0
  193. data/gemfiles/sequel_3.29.0.gemfile +9 -0
  194. data/gemfiles/sequel_3.29.0.gemfile.lock +33 -0
  195. data/gemfiles/sequel_3.34.0.gemfile +9 -0
  196. data/gemfiles/sequel_3.34.0.gemfile.lock +33 -0
  197. data/gemfiles/sequel_3.35.0.gemfile +9 -0
  198. data/gemfiles/sequel_3.35.0.gemfile.lock +33 -0
  199. data/gemfiles/sequel_3.4.0.gemfile +9 -0
  200. data/gemfiles/sequel_3.4.0.gemfile.lock +33 -0
  201. data/gemfiles/sequel_3.44.0.gemfile +9 -0
  202. data/gemfiles/sequel_3.44.0.gemfile.lock +33 -0
  203. data/init.rb +1 -0
  204. data/lib/state_machine.rb +8 -0
  205. data/lib/state_machine/assertions.rb +36 -0
  206. data/lib/state_machine/branch.rb +225 -0
  207. data/lib/state_machine/callback.rb +236 -0
  208. data/lib/state_machine/core.rb +12 -0
  209. data/lib/state_machine/core_ext.rb +2 -0
  210. data/lib/state_machine/core_ext/class/state_machine.rb +5 -0
  211. data/lib/state_machine/error.rb +13 -0
  212. data/lib/state_machine/eval_helpers.rb +87 -0
  213. data/lib/state_machine/event.rb +257 -0
  214. data/lib/state_machine/event_collection.rb +141 -0
  215. data/lib/state_machine/extensions.rb +149 -0
  216. data/lib/state_machine/graph.rb +92 -0
  217. data/lib/state_machine/helper_module.rb +17 -0
  218. data/lib/state_machine/initializers.rb +4 -0
  219. data/lib/state_machine/initializers/merb.rb +1 -0
  220. data/lib/state_machine/initializers/rails.rb +25 -0
  221. data/lib/state_machine/integrations.rb +121 -0
  222. data/lib/state_machine/integrations/active_model.rb +585 -0
  223. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  224. data/lib/state_machine/integrations/active_model/observer.rb +33 -0
  225. data/lib/state_machine/integrations/active_model/observer_update.rb +42 -0
  226. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  227. data/lib/state_machine/integrations/active_record.rb +552 -0
  228. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  229. data/lib/state_machine/integrations/active_record/versions.rb +123 -0
  230. data/lib/state_machine/integrations/base.rb +100 -0
  231. data/lib/state_machine/integrations/data_mapper.rb +511 -0
  232. data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
  233. data/lib/state_machine/integrations/data_mapper/versions.rb +85 -0
  234. data/lib/state_machine/integrations/mongo_mapper.rb +389 -0
  235. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  236. data/lib/state_machine/integrations/mongo_mapper/versions.rb +89 -0
  237. data/lib/state_machine/integrations/mongoid.rb +465 -0
  238. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  239. data/lib/state_machine/integrations/mongoid/versions.rb +81 -0
  240. data/lib/state_machine/integrations/sequel.rb +486 -0
  241. data/lib/state_machine/integrations/sequel/versions.rb +95 -0
  242. data/lib/state_machine/machine.rb +2292 -0
  243. data/lib/state_machine/machine_collection.rb +86 -0
  244. data/lib/state_machine/macro_methods.rb +522 -0
  245. data/lib/state_machine/matcher.rb +123 -0
  246. data/lib/state_machine/matcher_helpers.rb +54 -0
  247. data/lib/state_machine/node_collection.rb +222 -0
  248. data/lib/state_machine/path.rb +120 -0
  249. data/lib/state_machine/path_collection.rb +90 -0
  250. data/lib/state_machine/state.rb +297 -0
  251. data/lib/state_machine/state_collection.rb +112 -0
  252. data/lib/state_machine/state_context.rb +138 -0
  253. data/lib/state_machine/transition.rb +470 -0
  254. data/lib/state_machine/transition_collection.rb +245 -0
  255. data/lib/state_machine/version.rb +3 -0
  256. data/lib/state_machine/yard.rb +8 -0
  257. data/lib/state_machine/yard/handlers.rb +12 -0
  258. data/lib/state_machine/yard/handlers/base.rb +32 -0
  259. data/lib/state_machine/yard/handlers/event.rb +25 -0
  260. data/lib/state_machine/yard/handlers/machine.rb +344 -0
  261. data/lib/state_machine/yard/handlers/state.rb +25 -0
  262. data/lib/state_machine/yard/handlers/transition.rb +47 -0
  263. data/lib/state_machine/yard/templates.rb +3 -0
  264. data/lib/state_machine/yard/templates/default/class/html/setup.rb +30 -0
  265. data/lib/state_machine/yard/templates/default/class/html/state_machines.erb +12 -0
  266. data/lib/tasks/state_machine.rake +1 -0
  267. data/lib/tasks/state_machine.rb +30 -0
  268. data/lib/yard-state_machine.rb +2 -0
  269. data/state_machine.gemspec +22 -0
  270. data/test/files/en.yml +17 -0
  271. data/test/files/switch.rb +15 -0
  272. data/test/functional/state_machine_test.rb +1066 -0
  273. data/test/test_helper.rb +7 -0
  274. data/test/unit/assertions_test.rb +40 -0
  275. data/test/unit/branch_test.rb +969 -0
  276. data/test/unit/callback_test.rb +704 -0
  277. data/test/unit/error_test.rb +43 -0
  278. data/test/unit/eval_helpers_test.rb +270 -0
  279. data/test/unit/event_collection_test.rb +398 -0
  280. data/test/unit/event_test.rb +1196 -0
  281. data/test/unit/graph_test.rb +98 -0
  282. data/test/unit/helper_module_test.rb +17 -0
  283. data/test/unit/integrations/active_model_test.rb +1245 -0
  284. data/test/unit/integrations/active_record_test.rb +2551 -0
  285. data/test/unit/integrations/base_test.rb +104 -0
  286. data/test/unit/integrations/data_mapper_test.rb +2194 -0
  287. data/test/unit/integrations/mongo_mapper_test.rb +2026 -0
  288. data/test/unit/integrations/mongoid_test.rb +2309 -0
  289. data/test/unit/integrations/sequel_test.rb +1896 -0
  290. data/test/unit/integrations_test.rb +83 -0
  291. data/test/unit/invalid_event_test.rb +20 -0
  292. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  293. data/test/unit/invalid_transition_test.rb +115 -0
  294. data/test/unit/machine_collection_test.rb +603 -0
  295. data/test/unit/machine_test.rb +3431 -0
  296. data/test/unit/matcher_helpers_test.rb +37 -0
  297. data/test/unit/matcher_test.rb +155 -0
  298. data/test/unit/node_collection_test.rb +362 -0
  299. data/test/unit/path_collection_test.rb +266 -0
  300. data/test/unit/path_test.rb +485 -0
  301. data/test/unit/state_collection_test.rb +352 -0
  302. data/test/unit/state_context_test.rb +441 -0
  303. data/test/unit/state_machine_test.rb +31 -0
  304. data/test/unit/state_test.rb +1101 -0
  305. data/test/unit/transition_collection_test.rb +2168 -0
  306. data/test/unit/transition_test.rb +1558 -0
  307. metadata +435 -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