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,2309 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ require 'mongoid'
4
+ require 'mongoid/version'
5
+
6
+ # Establish database connection
7
+ Mongoid.configure do |config|
8
+ if Mongoid::VERSION =~ /^2\./
9
+ connection = Mongo::Connection.new('127.0.0.1', 27017, :slave_ok => true, :logger => Logger.new("#{File.dirname(__FILE__)}/../../mongoid.log"))
10
+ config.master = connection.db('test')
11
+ else
12
+ Mongoid.logger = Moped.logger = Logger.new("#{File.dirname(__FILE__)}/../../mongoid.log")
13
+ config.connect_to('test')
14
+ end
15
+ end
16
+
17
+
18
+ module MongoidTest
19
+ class BaseTestCase < Test::Unit::TestCase
20
+ def default_test
21
+ end
22
+
23
+ def teardown
24
+ if @table_names
25
+ db = Mongoid::VERSION =~ /^2\./ ? Mongoid.master : Mongoid::Sessions.default
26
+ db.collections.each {|c| c.drop if @table_names.include?(c.name)}
27
+ end
28
+ end
29
+
30
+ protected
31
+ # Creates a new Mongoid model (and the associated table)
32
+ def new_model(name = :foo, &block)
33
+ table_name = "#{name}_#{rand(1000000)}"
34
+ @table_names ||= []
35
+ @table_names << table_name
36
+
37
+ model = Class.new do
38
+ (class << self; self; end).class_eval do
39
+ define_method(:name) { "MongoidTest::#{name.to_s.capitalize}" }
40
+ define_method(:to_s) { self.name }
41
+ end
42
+ end
43
+
44
+ model.class_eval do
45
+ include Mongoid::Document
46
+ if Mongoid::VERSION =~ /^2\./
47
+ self.collection_name = table_name
48
+ else
49
+ self.default_collection_name = table_name
50
+ end
51
+
52
+ field :state, :type => String
53
+ end
54
+ model.class_eval(&block) if block_given?
55
+ model
56
+ end
57
+
58
+ # Creates a new Mongoid observer
59
+ def new_observer(model, &block)
60
+ observer = Class.new(Mongoid::Observer) do
61
+ attr_accessor :notifications
62
+
63
+ def initialize
64
+ super
65
+ @notifications = []
66
+ end
67
+ end
68
+
69
+ (class << observer; self; end).class_eval do
70
+ define_method(:name) do
71
+ "#{model.name}Observer"
72
+ end
73
+ end
74
+
75
+ observer.observe(model)
76
+ observer.class_eval(&block) if block_given?
77
+ observer
78
+ end
79
+ end
80
+
81
+ class IntegrationTest < BaseTestCase
82
+ def test_should_have_an_integration_name
83
+ assert_equal :mongoid, StateMachine::Integrations::Mongoid.integration_name
84
+ end
85
+
86
+ def test_should_be_available
87
+ assert StateMachine::Integrations::Mongoid.available?
88
+ end
89
+
90
+ def test_should_match_if_class_includes_mongoid
91
+ assert StateMachine::Integrations::Mongoid.matches?(new_model)
92
+ end
93
+
94
+ def test_should_not_match_if_class_does_not_include_mongoid
95
+ assert !StateMachine::Integrations::Mongoid.matches?(Class.new)
96
+ end
97
+
98
+ def test_should_have_defaults
99
+ assert_equal({:action => :save}, StateMachine::Integrations::Mongoid.defaults)
100
+ end
101
+
102
+ def test_should_have_a_locale_path
103
+ assert_not_nil StateMachine::Integrations::Mongoid.locale_path
104
+ end
105
+ end
106
+
107
+ class MachineWithoutFieldTest < BaseTestCase
108
+ def setup
109
+ @model = new_model
110
+ StateMachine::Machine.new(@model, :status)
111
+ end
112
+
113
+ def test_should_define_field_with_string_type
114
+ field = @model.fields['status']
115
+ assert_not_nil field
116
+ assert_equal String, field.type
117
+ end
118
+ end
119
+
120
+ class MachineWithFieldTest < BaseTestCase
121
+ def setup
122
+ @model = new_model do
123
+ field :status, :type => Integer
124
+ end
125
+ StateMachine::Machine.new(@model, :status)
126
+ end
127
+
128
+ def test_should_not_redefine_field
129
+ field = @model.fields['status']
130
+ assert_not_nil field
131
+ assert_equal Integer, field.type
132
+ end
133
+ end
134
+
135
+ class MachineByDefaultTest < BaseTestCase
136
+ def setup
137
+ @model = new_model
138
+ @machine = StateMachine::Machine.new(@model)
139
+ end
140
+
141
+ def test_should_use_save_as_action
142
+ assert_equal :save, @machine.action
143
+ end
144
+
145
+ def test_should_create_notifier_before_callback
146
+ assert_equal 1, @machine.callbacks[:before].size
147
+ end
148
+
149
+ def test_should_create_notifier_after_callback
150
+ assert_equal 1, @machine.callbacks[:after].size
151
+ end
152
+ end
153
+
154
+ class MachineWithStatesTest < BaseTestCase
155
+ def setup
156
+ @model = new_model
157
+ @machine = StateMachine::Machine.new(@model)
158
+ @machine.state :first_gear
159
+ end
160
+
161
+ def test_should_humanize_name
162
+ assert_equal 'first gear', @machine.state(:first_gear).human_name
163
+ end
164
+ end
165
+
166
+ class MachineWithStaticInitialStateTest < BaseTestCase
167
+ def setup
168
+ @model = new_model(:vehicle) do
169
+ attr_accessor :value
170
+ end
171
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
172
+ end
173
+
174
+ def test_should_set_initial_state_on_created_object
175
+ record = @model.new
176
+ assert_equal 'parked', record.state
177
+ end
178
+
179
+ def test_should_set_initial_state_with_nil_attributes
180
+ record = @model.new(nil)
181
+ assert_equal 'parked', record.state
182
+ end
183
+
184
+ def test_should_still_set_attributes
185
+ record = @model.new(:value => 1)
186
+ assert_equal 1, record.value
187
+ end
188
+
189
+ def test_should_still_allow_initialize_blocks
190
+ block_args = nil
191
+ record = @model.new do |*args|
192
+ block_args = args
193
+ end
194
+
195
+ assert_equal [record], block_args
196
+ end
197
+
198
+ def test_should_set_attributes_prior_to_initialize_block
199
+ state = nil
200
+ @model.new do |record|
201
+ state = record.state
202
+ end
203
+
204
+ assert_equal 'parked', state
205
+ end
206
+
207
+ def test_should_set_attributes_prior_to_after_initialize_hook
208
+ state = nil
209
+ @model.after_initialize do |record|
210
+ state = record.state
211
+ end
212
+ @model.new
213
+ assert_equal 'parked', state
214
+ end
215
+
216
+ def test_should_persist_initial_state
217
+ record = @model.new
218
+ record.save
219
+ record.reload
220
+ assert_equal 'parked', record.state
221
+ end
222
+
223
+ def test_should_persist_initial_state_on_dup
224
+ record = @model.create.dup
225
+ record.save
226
+ record.reload
227
+ assert_equal 'parked', record.state
228
+ end
229
+
230
+ def test_should_set_initial_state_before_setting_attributes
231
+ @model.class_eval do
232
+ attr_accessor :state_during_setter
233
+
234
+ remove_method :value=
235
+ define_method(:value=) do |value|
236
+ self.state_during_setter = state
237
+ end
238
+ end
239
+
240
+ record = @model.new(:value => 1)
241
+ assert_equal 'parked', record.state_during_setter
242
+ end
243
+
244
+ def test_should_not_set_initial_state_after_already_initialized
245
+ record = @model.new(:value => 1)
246
+ assert_equal 'parked', record.state
247
+
248
+ record.state = 'idling'
249
+ record.attributes = {}
250
+ assert_equal 'idling', record.state
251
+ end
252
+
253
+ def test_should_use_stored_values_when_loading_from_database
254
+ @machine.state :idling
255
+
256
+ record = @model.find(@model.create(:state => 'idling').id)
257
+ assert_equal 'idling', record.state
258
+ end
259
+
260
+ def test_should_use_stored_values_when_loading_from_database_with_nil_state
261
+ @machine.state nil
262
+
263
+ record = @model.find(@model.create(:state => nil).id)
264
+ assert_nil record.state
265
+ end
266
+
267
+ if Mongoid::VERSION >= '2.1.0'
268
+ def test_should_use_stored_values_when_loading_for_many_association
269
+ @machine.state :idling
270
+
271
+ @model.belongs_to :owner, :class_name => 'MongoidTest::Owner'
272
+ MongoidTest.const_set('Vehicle', @model)
273
+
274
+ owner_model = new_model(:owner) do
275
+ has_many :vehicles, :class_name => 'MongoidTest::Vehicle'
276
+ end
277
+ MongoidTest.const_set('Owner', owner_model)
278
+
279
+ owner = owner_model.create
280
+ record = @model.create(:state => 'idling', :owner_id => owner.id)
281
+ assert_equal 'idling', owner.vehicles[0].state
282
+ end
283
+
284
+ def test_should_use_stored_values_when_loading_for_one_association
285
+ @machine.state :idling
286
+
287
+ @model.belongs_to :owner, :class_name => 'MongoidTest::Owner'
288
+ MongoidTest.const_set('Vehicle', @model)
289
+
290
+ owner_model = new_model(:owner) do
291
+ has_one :vehicle, :class_name => 'MongoidTest::Vehicle'
292
+ end
293
+ MongoidTest.const_set('Owner', owner_model)
294
+
295
+ owner = owner_model.create
296
+ record = @model.create(:state => 'idling', :owner_id => owner.id)
297
+ owner.reload
298
+ assert_equal 'idling', owner.vehicle.state
299
+ end
300
+
301
+ def test_should_use_stored_values_when_loading_for_belongs_to_association
302
+ @machine.state :idling
303
+
304
+ MongoidTest.const_set('Vehicle', @model)
305
+
306
+ driver_model = new_model(:driver) do
307
+ belongs_to :vehicle, :class_name => 'MongoidTest::Vehicle'
308
+ end
309
+ MongoidTest.const_set('Driver', driver_model)
310
+
311
+ record = @model.create(:state => 'idling')
312
+ driver = driver_model.create(:vehicle_id => record.id)
313
+ assert_equal 'idling', driver.vehicle.state
314
+ end
315
+ end
316
+
317
+ def teardown
318
+ MongoidTest.class_eval do
319
+ remove_const('Vehicle') if defined?(MongoidTest::Vehicle)
320
+ remove_const('Owner') if defined?(MongoidTest::Owner)
321
+ remove_const('Driver') if defined?(MongoidTest::Driver)
322
+ end
323
+ super
324
+ end
325
+ end
326
+
327
+ class MachineWithDynamicInitialStateTest < BaseTestCase
328
+ def setup
329
+ @model = new_model do
330
+ attr_accessor :value
331
+ end
332
+ @machine = StateMachine::Machine.new(@model, :initial => lambda {|object| :parked})
333
+ @machine.state :parked
334
+ end
335
+
336
+ def test_should_set_initial_state_on_created_object
337
+ record = @model.new
338
+ assert_equal 'parked', record.state
339
+ end
340
+
341
+ def test_should_still_set_attributes
342
+ record = @model.new(:value => 1)
343
+ assert_equal 1, record.value
344
+ end
345
+
346
+ def test_should_still_allow_initialize_blocks
347
+ block_args = nil
348
+ record = @model.new do |*args|
349
+ block_args = args
350
+ end
351
+
352
+ assert_equal [record], block_args
353
+ end
354
+
355
+ def test_should_set_attributes_prior_to_initialize_block
356
+ state = nil
357
+ @model.new do |record|
358
+ state = record.state
359
+ end
360
+
361
+ assert_equal 'parked', state
362
+ end
363
+
364
+ def test_should_set_attributes_prior_to_after_initialize_hook
365
+ state = nil
366
+ @model.after_initialize do |record|
367
+ state = record.state
368
+ end
369
+ @model.new
370
+ assert_equal 'parked', state
371
+ end
372
+
373
+ def test_should_set_initial_state_after_setting_attributes
374
+ @model.class_eval do
375
+ attr_accessor :state_during_setter
376
+
377
+ remove_method :value=
378
+ define_method(:value=) do |value|
379
+ self.state_during_setter = state || 'nil'
380
+ end
381
+ end
382
+
383
+ record = @model.new(:value => 1)
384
+ assert_equal 'nil', record.state_during_setter
385
+ end
386
+
387
+ def test_should_not_set_initial_state_after_already_initialized
388
+ record = @model.new(:value => 1)
389
+ assert_equal 'parked', record.state
390
+
391
+ record.state = 'idling'
392
+ record.attributes = {}
393
+ assert_equal 'idling', record.state
394
+ end
395
+
396
+ def test_should_persist_initial_state
397
+ record = @model.new
398
+ record.save
399
+ record.reload
400
+ assert_equal 'parked', record.state
401
+ end
402
+
403
+ def test_should_persist_initial_state_on_dup
404
+ record = @model.create.dup
405
+ record.save
406
+ record.reload
407
+ assert_equal 'parked', record.state
408
+ end
409
+
410
+ def test_should_use_stored_values_when_loading_from_database
411
+ @machine.state :idling
412
+
413
+ record = @model.find(@model.create(:state => 'idling').id)
414
+ assert_equal 'idling', record.state
415
+ end
416
+
417
+ def test_should_use_stored_values_when_loading_from_database_with_nil_state
418
+ @machine.state nil
419
+
420
+ record = @model.find(@model.create(:state => nil).id)
421
+ assert_nil record.state
422
+ end
423
+ end
424
+
425
+ class MachineWithEventsTest < BaseTestCase
426
+ def setup
427
+ @model = new_model
428
+ @machine = StateMachine::Machine.new(@model)
429
+ @machine.event :shift_up
430
+ end
431
+
432
+ def test_should_humanize_name
433
+ assert_equal 'shift up', @machine.event(:shift_up).human_name
434
+ end
435
+ end
436
+
437
+ class MachineWithDifferentSameDefaultTest < BaseTestCase
438
+ def setup
439
+ @original_stderr, $stderr = $stderr, StringIO.new
440
+
441
+ @model = new_model do
442
+ field :status, :type => String, :default => 'parked'
443
+ end
444
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
445
+ @record = @model.new
446
+ end
447
+
448
+ def test_should_use_machine_default
449
+ assert_equal 'parked', @record.status
450
+ end
451
+
452
+ def test_should_not_generate_a_warning
453
+ assert_no_match(/have defined a different default/, $stderr.string)
454
+ end
455
+
456
+ def teardown
457
+ $stderr = @original_stderr
458
+ super
459
+ end
460
+ end
461
+
462
+ class MachineWithDifferentColumnDefaultTest < BaseTestCase
463
+ def setup
464
+ @original_stderr, $stderr = $stderr, StringIO.new
465
+
466
+ @model = new_model do
467
+ field :status, :type => String, :default => 'idling'
468
+ end
469
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
470
+ @record = @model.new
471
+ end
472
+
473
+ def test_should_use_machine_default
474
+ assert_equal 'parked', @record.status
475
+ end
476
+
477
+ def test_should_generate_a_warning
478
+ assert_match(/Both MongoidTest::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)
479
+ end
480
+
481
+ def teardown
482
+ $stderr = @original_stderr
483
+ super
484
+ end
485
+ end
486
+
487
+ class MachineWithDifferentIntegerColumnDefaultTest < BaseTestCase
488
+ def setup
489
+ @original_stderr, $stderr = $stderr, StringIO.new
490
+
491
+ @model = new_model do
492
+ field :status, :type => Integer, :default => 0
493
+ end
494
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
495
+ @machine.state :parked, :value => 1
496
+ @record = @model.new
497
+ end
498
+
499
+ def test_should_use_machine_default
500
+ assert_equal 1, @record.status
501
+ end
502
+
503
+ def test_should_generate_a_warning
504
+ assert_match(/Both MongoidTest::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)
505
+ end
506
+
507
+ def teardown
508
+ $stderr = @original_stderr
509
+ super
510
+ end
511
+ end
512
+
513
+ class MachineWithConflictingPredicateTest < BaseTestCase
514
+ def setup
515
+ @model = new_model do
516
+ def state?(*args)
517
+ true
518
+ end
519
+ end
520
+
521
+ @machine = StateMachine::Machine.new(@model)
522
+ @record = @model.new
523
+ end
524
+
525
+ def test_should_not_define_attribute_predicate
526
+ assert @record.state?
527
+ end
528
+ end
529
+
530
+ class MachineWithConflictingStateNameTest < BaseTestCase
531
+ def setup
532
+ require 'stringio'
533
+ @original_stderr, $stderr = $stderr, StringIO.new
534
+
535
+ @model = new_model
536
+ end
537
+
538
+ def test_should_output_warning_with_same_machine_name
539
+ @machine = StateMachine::Machine.new(@model)
540
+ @machine.state :state
541
+
542
+ assert_match(/^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string)
543
+ end
544
+
545
+ def test_should_output_warning_with_same_machine_attribute
546
+ @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
547
+ @machine.state :state
548
+
549
+ assert_match(/^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string)
550
+ end
551
+
552
+ def teardown
553
+ $stderr = @original_stderr
554
+ super
555
+ end
556
+ end
557
+
558
+ class MachineWithColumnStateAttributeTest < BaseTestCase
559
+ def setup
560
+ @model = new_model
561
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
562
+ @machine.other_states(:idling)
563
+
564
+ @record = @model.new
565
+ end
566
+
567
+ def test_should_not_override_the_column_reader
568
+ @record[:state] = 'parked'
569
+ assert_equal 'parked', @record.state
570
+ end
571
+
572
+ def test_should_not_override_the_column_writer
573
+ @record.state = 'parked'
574
+ assert_equal 'parked', @record[:state]
575
+ end
576
+
577
+ def test_should_have_an_attribute_predicate
578
+ assert @record.respond_to?(:state?)
579
+ end
580
+
581
+ def test_should_test_for_existence_on_predicate_without_parameters
582
+ assert @record.state?
583
+
584
+ @record.state = nil
585
+ assert !@record.state?
586
+ end
587
+
588
+ def test_should_return_false_for_predicate_if_does_not_match_current_value
589
+ assert !@record.state?(:idling)
590
+ end
591
+
592
+ def test_should_return_true_for_predicate_if_matches_current_value
593
+ assert @record.state?(:parked)
594
+ end
595
+
596
+ def test_should_raise_exception_for_predicate_if_invalid_state_specified
597
+ assert_raise(IndexError) { @record.state?(:invalid) }
598
+ end
599
+ end
600
+
601
+ class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
602
+ def setup
603
+ @model = new_model do
604
+ def initialize
605
+ # Skip attribute initialization
606
+ @initialized_state_machines = true
607
+ super
608
+ end
609
+ end
610
+
611
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
612
+ @machine.other_states(:idling)
613
+ @record = @model.new
614
+ end
615
+
616
+ def test_should_define_a_new_key_for_the_attribute
617
+ assert_not_nil @model.fields['status']
618
+ end
619
+
620
+ def test_should_define_a_reader_attribute_for_the_attribute
621
+ assert @record.respond_to?(:status)
622
+ end
623
+
624
+ def test_should_define_a_writer_attribute_for_the_attribute
625
+ assert @record.respond_to?(:status=)
626
+ end
627
+
628
+ def test_should_define_an_attribute_predicate
629
+ assert @record.respond_to?(:status?)
630
+ end
631
+ end
632
+
633
+ class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
634
+ def setup
635
+ @model = new_model do
636
+ def status
637
+ self['status']
638
+ end
639
+
640
+ def status=(value)
641
+ self['status'] = value
642
+ end
643
+ end
644
+
645
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
646
+ @machine.other_states(:idling)
647
+ @record = @model.new
648
+ end
649
+
650
+ def test_should_return_false_for_predicate_if_does_not_match_current_value
651
+ assert !@record.status?(:idling)
652
+ end
653
+
654
+ def test_should_return_true_for_predicate_if_matches_current_value
655
+ assert @record.status?(:parked)
656
+ end
657
+
658
+ def test_should_raise_exception_for_predicate_if_invalid_state_specified
659
+ assert_raise(IndexError) { @record.status?(:invalid) }
660
+ end
661
+
662
+ def test_should_set_initial_state_on_created_object
663
+ assert_equal 'parked', @record.status
664
+ end
665
+ end
666
+
667
+ class MachineWithAliasedAttributeTest < BaseTestCase
668
+ def setup
669
+ @model = new_model do
670
+ alias_attribute :vehicle_status, :state
671
+ end
672
+
673
+ @machine = StateMachine::Machine.new(@model, :status, :attribute => :vehicle_status)
674
+ @machine.state :parked
675
+
676
+ @record = @model.new
677
+ end
678
+
679
+ def test_should_check_custom_attribute_for_predicate
680
+ @record.vehicle_status = nil
681
+ assert !@record.status?(:parked)
682
+
683
+ @record.vehicle_status = 'parked'
684
+ assert @record.status?(:parked)
685
+ end
686
+ end
687
+
688
+ class MachineWithAliasedFieldTest < BaseTestCase
689
+ def setup
690
+ @model = new_model do
691
+ field :status, :as => :vehicle_status
692
+ end
693
+
694
+ @machine = StateMachine::Machine.new(@model, :vehicle_status)
695
+ @machine.state :parked
696
+
697
+ @record = @model.new
698
+ end
699
+
700
+ def test_should_check_custom_attribute_for_predicate
701
+ @record.vehicle_status = nil
702
+ assert !@record.vehicle_status?(:parked)
703
+
704
+ @record.vehicle_status = 'parked'
705
+ assert @record.vehicle_status?(:parked)
706
+ end
707
+ end
708
+
709
+ class MachineWithCustomAttributeTest < BaseTestCase
710
+ def setup
711
+ require 'stringio'
712
+ @original_stderr, $stderr = $stderr, StringIO.new
713
+
714
+ @model = new_model
715
+ @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
716
+ @record = @model.new
717
+ end
718
+
719
+ def test_should_not_delegate_attribute_predicate_with_different_attribute
720
+ assert_raise(ArgumentError) { @record.public_state? }
721
+ end
722
+
723
+ def teardown
724
+ $stderr = @original_stderr
725
+ super
726
+ end
727
+ end
728
+
729
+ class MachineWithInitializedStateTest < BaseTestCase
730
+ def setup
731
+ @model = new_model
732
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
733
+ @machine.state :idling
734
+ end
735
+
736
+ def test_should_allow_nil_initial_state_when_static
737
+ @machine.state nil
738
+
739
+ record = @model.new(:state => nil)
740
+ assert_nil record.state
741
+ end
742
+
743
+ def test_should_allow_nil_initial_state_when_dynamic
744
+ @machine.state nil
745
+
746
+ @machine.initial_state = lambda {:parked}
747
+ record = @model.new(:state => nil)
748
+ assert_nil record.state
749
+ end
750
+
751
+ def test_should_allow_different_initial_state_when_static
752
+ record = @model.new(:state => 'idling')
753
+ assert_equal 'idling', record.state
754
+ end
755
+
756
+ def test_should_allow_different_initial_state_when_dynamic
757
+ @machine.initial_state = lambda {:parked}
758
+ record = silence_warnings { @model.new(:state => 'idling') }
759
+ assert_equal 'idling', record.state
760
+ end
761
+
762
+ def test_should_use_default_state_if_protected
763
+ Mongoid.logger = nil
764
+
765
+ @model.class_eval do
766
+ attr_protected :state
767
+ end
768
+
769
+ record = @model.new(:state => 'idling')
770
+ assert_equal 'parked', record.state
771
+ end
772
+ end
773
+
774
+ class MachineMultipleTest < BaseTestCase
775
+ def setup
776
+ @model = new_model do
777
+ field :status, :type => String
778
+ end
779
+ @state_machine = StateMachine::Machine.new(@model, :initial => :parked)
780
+ @status_machine = StateMachine::Machine.new(@model, :status, :initial => :idling)
781
+ end
782
+
783
+ def test_should_should_initialize_each_state
784
+ record = @model.new
785
+ assert_equal 'parked', record.state
786
+ assert_equal 'idling', record.status
787
+ end
788
+ end
789
+
790
+ class MachineWithLoopbackTest < BaseTestCase
791
+ def setup
792
+ @model = new_model do
793
+ field :updated_at, :type => Time
794
+
795
+ before_update do |record|
796
+ record.updated_at = Time.now
797
+ end
798
+ end
799
+
800
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
801
+ @machine.event :park
802
+
803
+ @record = @model.create(:updated_at => Time.now - 1)
804
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
805
+
806
+ @timestamp = @record.updated_at
807
+ @transition.perform
808
+ end
809
+
810
+ def test_should_update_record
811
+ assert_not_equal @timestamp, @record.updated_at
812
+ end
813
+ end
814
+
815
+ class MachineWithDirtyAttributesTest < BaseTestCase
816
+ def setup
817
+ @model = new_model
818
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
819
+ @machine.event :ignite
820
+ @machine.state :idling
821
+
822
+ @record = @model.create
823
+
824
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
825
+ @transition.perform(false)
826
+ end
827
+
828
+ def test_should_include_state_in_changed_attributes
829
+ assert_equal %w(state), @record.changed
830
+ end
831
+
832
+ def test_should_track_attribute_change
833
+ assert_equal %w(parked idling), @record.changes['state']
834
+ end
835
+
836
+ def test_should_not_reset_changes_on_multiple_transitions
837
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
838
+ transition.perform(false)
839
+
840
+ assert_equal %w(parked idling), @record.changes['state']
841
+ end
842
+
843
+ def test_should_not_have_changes_when_loaded_from_database
844
+ record = @model.find(@record.id)
845
+ assert !record.changed?
846
+ end
847
+ end
848
+
849
+ class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
850
+ def setup
851
+ @model = new_model
852
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
853
+ @machine.event :park
854
+
855
+ @record = @model.create
856
+
857
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
858
+ @transition.perform(false)
859
+ end
860
+
861
+ def test_should_not_include_state_in_changed_attributes
862
+ assert_equal [], @record.changed
863
+ end
864
+
865
+ def test_should_not_track_attribute_changes
866
+ assert_equal nil, @record.send(:attribute_change, 'state')
867
+ end
868
+ end
869
+
870
+ class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
871
+ def setup
872
+ @model = new_model do
873
+ field :status, :type => String
874
+ end
875
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
876
+ @machine.event :ignite
877
+ @machine.state :idling
878
+
879
+ @record = @model.create
880
+
881
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
882
+ @transition.perform(false)
883
+ end
884
+
885
+ def test_should_include_state_in_changed_attributes
886
+ assert_equal %w(status), @record.changed
887
+ end
888
+
889
+ def test_should_track_attribute_change
890
+ assert_equal %w(parked idling), @record.changes['status']
891
+ end
892
+
893
+ def test_should_not_reset_changes_on_multiple_transitions
894
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
895
+ transition.perform(false)
896
+
897
+ assert_equal %w(parked idling), @record.changes['status']
898
+ end
899
+ end
900
+
901
+ class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
902
+ def setup
903
+ @model = new_model do
904
+ field :status, :type => String
905
+ end
906
+ @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
907
+ @machine.event :park
908
+
909
+ @record = @model.create
910
+
911
+ @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
912
+ @transition.perform(false)
913
+ end
914
+
915
+ def test_should_include_state_in_changed_attributes
916
+ assert_equal [], @record.changed
917
+ end
918
+
919
+ def test_should_track_attribute_changes
920
+ assert_equal nil, @record.send(:attribute_change, 'status')
921
+ end
922
+ end
923
+
924
+ class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
925
+ def setup
926
+ @model = new_model
927
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
928
+ @machine.event :ignite
929
+
930
+ @record = @model.create
931
+ @record.state_event = 'ignite'
932
+ end
933
+
934
+ def test_should_not_include_state_in_changed_attributes
935
+ assert_equal [], @record.changed
936
+ end
937
+
938
+ def test_should_not_track_attribute_change
939
+ assert_equal nil, @record.send(:attribute_change, 'state')
940
+ end
941
+ end
942
+
943
+ class MachineWithCallbacksTest < BaseTestCase
944
+ def setup
945
+ @model = new_model
946
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
947
+ @machine.other_states :idling
948
+ @machine.event :ignite
949
+
950
+ @record = @model.new(:state => 'parked')
951
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
952
+ end
953
+
954
+ def test_should_run_before_callbacks
955
+ called = false
956
+ @machine.before_transition {called = true}
957
+
958
+ @transition.perform
959
+ assert called
960
+ end
961
+
962
+ def test_should_pass_record_to_before_callbacks_with_one_argument
963
+ record = nil
964
+ @machine.before_transition {|arg| record = arg}
965
+
966
+ @transition.perform
967
+ assert_equal @record, record
968
+ end
969
+
970
+ def test_should_pass_record_and_transition_to_before_callbacks_with_multiple_arguments
971
+ callback_args = nil
972
+ @machine.before_transition {|*args| callback_args = args}
973
+
974
+ @transition.perform
975
+ assert_equal [@record, @transition], callback_args
976
+ end
977
+
978
+ def test_should_run_before_callbacks_outside_the_context_of_the_record
979
+ context = nil
980
+ @machine.before_transition {context = self}
981
+
982
+ @transition.perform
983
+ assert_equal self, context
984
+ end
985
+
986
+ def test_should_run_after_callbacks
987
+ called = false
988
+ @machine.after_transition {called = true}
989
+
990
+ @transition.perform
991
+ assert called
992
+ end
993
+
994
+ def test_should_pass_record_to_after_callbacks_with_one_argument
995
+ record = nil
996
+ @machine.after_transition {|arg| record = arg}
997
+
998
+ @transition.perform
999
+ assert_equal @record, record
1000
+ end
1001
+
1002
+ def test_should_pass_record_and_transition_to_after_callbacks_with_multiple_arguments
1003
+ callback_args = nil
1004
+ @machine.after_transition {|*args| callback_args = args}
1005
+
1006
+ @transition.perform
1007
+ assert_equal [@record, @transition], callback_args
1008
+ end
1009
+
1010
+ def test_should_run_after_callbacks_outside_the_context_of_the_record
1011
+ context = nil
1012
+ @machine.after_transition {context = self}
1013
+
1014
+ @transition.perform
1015
+ assert_equal self, context
1016
+ end
1017
+
1018
+ def test_should_run_after_callbacks_if_model_callback_added_prior_to_state_machine_definition
1019
+ model = new_model do
1020
+ after_save { nil }
1021
+ end
1022
+ machine = StateMachine::Machine.new(model, :initial => :parked)
1023
+ machine.other_states :idling
1024
+ machine.event :ignite
1025
+ after_called = false
1026
+ machine.after_transition {after_called = true}
1027
+
1028
+ record = model.new(:state => 'parked')
1029
+ transition = StateMachine::Transition.new(record, machine, :ignite, :parked, :idling)
1030
+ transition.perform
1031
+ assert_equal true, after_called
1032
+ end
1033
+
1034
+ def test_should_run_around_callbacks
1035
+ before_called = false
1036
+ after_called = false
1037
+ ensure_called = 0
1038
+ @machine.around_transition do |block|
1039
+ before_called = true
1040
+ begin
1041
+ block.call
1042
+ ensure
1043
+ ensure_called += 1
1044
+ end
1045
+ after_called = true
1046
+ end
1047
+
1048
+ @transition.perform
1049
+ assert before_called
1050
+ assert after_called
1051
+ assert_equal ensure_called, 1
1052
+ end
1053
+
1054
+ def test_should_include_transition_states_in_known_states
1055
+ @machine.before_transition :to => :first_gear, :do => lambda {}
1056
+
1057
+ assert_equal [:parked, :idling, :first_gear], @machine.states.map {|state| state.name}
1058
+ end
1059
+
1060
+ def test_should_allow_symbolic_callbacks
1061
+ callback_args = nil
1062
+
1063
+ klass = class << @record; self; end
1064
+ klass.send(:define_method, :after_ignite) do |*args|
1065
+ callback_args = args
1066
+ end
1067
+
1068
+ @machine.before_transition(:after_ignite)
1069
+
1070
+ @transition.perform
1071
+ assert_equal [@transition], callback_args
1072
+ end
1073
+
1074
+ def test_should_allow_string_callbacks
1075
+ class << @record
1076
+ attr_reader :callback_result
1077
+ end
1078
+
1079
+ @machine.before_transition('@callback_result = [1, 2, 3]')
1080
+ @transition.perform
1081
+
1082
+ assert_equal [1, 2, 3], @record.callback_result
1083
+ end
1084
+
1085
+ def test_should_run_in_expected_order
1086
+ expected = [
1087
+ :before_transition, :before_validation, :after_validation,
1088
+ :before_save, :before_create, :after_create, :after_save,
1089
+ :after_transition
1090
+ ]
1091
+
1092
+ callbacks = []
1093
+ @model.before_validation { callbacks << :before_validation }
1094
+ @model.after_validation { callbacks << :after_validation }
1095
+ @model.before_save { callbacks << :before_save }
1096
+ @model.before_create { callbacks << :before_create }
1097
+ @model.after_create { callbacks << :after_create }
1098
+ @model.after_save { callbacks << :after_save }
1099
+
1100
+ @machine.before_transition { callbacks << :before_transition }
1101
+ @machine.after_transition { callbacks << :after_transition }
1102
+
1103
+ @transition.perform
1104
+
1105
+ assert_equal expected, callbacks
1106
+ end
1107
+ end
1108
+
1109
+ class MachineWithFailedBeforeCallbacksTest < BaseTestCase
1110
+ def setup
1111
+ @callbacks = []
1112
+
1113
+ @model = new_model
1114
+ @machine = StateMachine::Machine.new(@model)
1115
+ @machine.state :parked, :idling
1116
+ @machine.event :ignite
1117
+ @machine.before_transition {@callbacks << :before_1; false}
1118
+ @machine.before_transition {@callbacks << :before_2}
1119
+ @machine.after_transition {@callbacks << :after}
1120
+ @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
1121
+
1122
+ @record = @model.new(:state => 'parked')
1123
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1124
+ @result = @transition.perform
1125
+ end
1126
+
1127
+ def test_should_not_be_successful
1128
+ assert !@result
1129
+ end
1130
+
1131
+ def test_should_not_change_current_state
1132
+ assert_equal 'parked', @record.state
1133
+ end
1134
+
1135
+ def test_should_not_run_action
1136
+ assert @record.new_record?
1137
+ end
1138
+
1139
+ def test_should_not_run_further_callbacks
1140
+ assert_equal [:before_1], @callbacks
1141
+ end
1142
+ end
1143
+
1144
+ class MachineNestedActionTest < BaseTestCase
1145
+ def setup
1146
+ @callbacks = []
1147
+
1148
+ @model = new_model
1149
+ @machine = StateMachine::Machine.new(@model)
1150
+ @machine.event :ignite do
1151
+ transition :parked => :idling
1152
+ end
1153
+
1154
+ @record = @model.new(:state => 'parked')
1155
+ end
1156
+
1157
+ def test_should_allow_transition_prior_to_creation_if_skipping_action
1158
+ record = @record
1159
+ @model.before_create { record.ignite(false) }
1160
+ result = @record.save
1161
+
1162
+ assert_equal true, result
1163
+ assert_equal "idling", @record.state
1164
+ @record.reload
1165
+ assert_equal "idling", @record.state
1166
+ end
1167
+
1168
+ if Mongoid::VERSION !~ /^2\.1\./
1169
+ def test_should_allow_transition_after_creation
1170
+ record = @record
1171
+ @model.after_create { record.ignite }
1172
+ result = @record.save
1173
+
1174
+ assert_equal true, result
1175
+ assert_equal "idling", @record.state
1176
+ @record.reload
1177
+ assert_equal "idling", @record.state
1178
+ end
1179
+ end
1180
+ end
1181
+
1182
+ class MachineWithFailedActionTest < BaseTestCase
1183
+ def setup
1184
+ @model = new_model do
1185
+ validates_numericality_of :state
1186
+ end
1187
+
1188
+ @machine = StateMachine::Machine.new(@model)
1189
+ @machine.state :parked, :idling
1190
+ @machine.event :ignite
1191
+
1192
+ @callbacks = []
1193
+ @machine.before_transition {@callbacks << :before}
1194
+ @machine.after_transition {@callbacks << :after}
1195
+ @machine.after_failure {@callbacks << :after_failure}
1196
+ @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
1197
+
1198
+ @record = @model.new(:state => 'parked')
1199
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1200
+ @result = @transition.perform
1201
+ end
1202
+
1203
+ def test_should_not_be_successful
1204
+ assert !@result
1205
+ end
1206
+
1207
+ def test_should_not_change_current_state
1208
+ assert_equal 'parked', @record.state
1209
+ end
1210
+
1211
+ def test_should_not_save_record
1212
+ assert @record.new_record?
1213
+ end
1214
+
1215
+ def test_should_run_before_callbacks_and_after_callbacks_with_failures
1216
+ assert_equal [:before, :around_before, :after_failure], @callbacks
1217
+ end
1218
+ end
1219
+
1220
+ class MachineWithFailedAfterCallbacksTest < BaseTestCase
1221
+ def setup
1222
+ @callbacks = []
1223
+
1224
+ @model = new_model
1225
+ @machine = StateMachine::Machine.new(@model)
1226
+ @machine.state :parked, :idling
1227
+ @machine.event :ignite
1228
+ @machine.after_transition {@callbacks << :after_1; false}
1229
+ @machine.after_transition {@callbacks << :after_2}
1230
+ @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
1231
+
1232
+ @record = @model.new(:state => 'parked')
1233
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1234
+ @result = @transition.perform
1235
+ end
1236
+
1237
+ def test_should_be_successful
1238
+ assert @result
1239
+ end
1240
+
1241
+ def test_should_change_current_state
1242
+ assert_equal 'idling', @record.state
1243
+ end
1244
+
1245
+ def test_should_save_record
1246
+ assert !@record.new_record?
1247
+ end
1248
+
1249
+ def test_should_not_run_further_after_callbacks
1250
+ assert_equal [:around_before, :around_after, :after_1], @callbacks
1251
+ end
1252
+ end
1253
+
1254
+ class MachineWithValidationsTest < BaseTestCase
1255
+ def setup
1256
+ @model = new_model
1257
+ @machine = StateMachine::Machine.new(@model)
1258
+ @machine.state :parked
1259
+
1260
+ @record = @model.new
1261
+ end
1262
+
1263
+ def test_should_invalidate_using_errors
1264
+ I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:ActiveModel)
1265
+ @record.state = 'parked'
1266
+
1267
+ @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
1268
+ assert_equal ['State cannot transition via "park"'], @record.errors.full_messages
1269
+ end
1270
+
1271
+ def test_should_auto_prefix_custom_attributes_on_invalidation
1272
+ @machine.invalidate(@record, :event, :invalid)
1273
+
1274
+ assert_equal ['State event is invalid'], @record.errors.full_messages
1275
+ end
1276
+
1277
+ def test_should_clear_errors_on_reset
1278
+ @record.state = 'parked'
1279
+ @record.errors.add(:state, 'is invalid')
1280
+
1281
+ @machine.reset(@record)
1282
+ assert_equal [], @record.errors.full_messages
1283
+ end
1284
+
1285
+ def test_should_be_valid_if_state_is_known
1286
+ @record.state = 'parked'
1287
+
1288
+ assert @record.valid?
1289
+ end
1290
+
1291
+ def test_should_not_be_valid_if_state_is_unknown
1292
+ @record.state = 'invalid'
1293
+
1294
+ assert !@record.valid?
1295
+ assert_equal ['State is invalid'], @record.errors.full_messages
1296
+ end
1297
+ end
1298
+
1299
+ class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
1300
+ def setup
1301
+ @model = new_model
1302
+ @machine = StateMachine::Machine.new(@model, :status, :attribute => :state)
1303
+ @machine.state :parked
1304
+
1305
+ @record = @model.new
1306
+ end
1307
+
1308
+ def test_should_add_validation_errors_to_custom_attribute
1309
+ @record.state = 'invalid'
1310
+
1311
+ assert !@record.valid?
1312
+ assert_equal ['State is invalid'], @record.errors.full_messages
1313
+
1314
+ @record.state = 'parked'
1315
+ assert @record.valid?
1316
+ end
1317
+ end
1318
+
1319
+ class MachineErrorsTest < BaseTestCase
1320
+ def setup
1321
+ @model = new_model
1322
+ @machine = StateMachine::Machine.new(@model)
1323
+ @record = @model.new
1324
+ end
1325
+
1326
+ def test_should_be_able_to_describe_current_errors
1327
+ @record.errors.add(:id, 'cannot be blank')
1328
+ @record.errors.add(:state, 'is invalid')
1329
+ assert_equal ['Id cannot be blank', 'State is invalid'], @machine.errors_for(@record).split(', ').sort
1330
+ end
1331
+
1332
+ def test_should_describe_as_halted_with_no_errors
1333
+ assert_equal 'Transition halted', @machine.errors_for(@record)
1334
+ end
1335
+ end
1336
+
1337
+ class MachineWithStateDrivenValidationsTest < BaseTestCase
1338
+ def setup
1339
+ @model = new_model do
1340
+ attr_accessor :seatbealt
1341
+ end
1342
+
1343
+ @machine = StateMachine::Machine.new(@model)
1344
+ @machine.state :first_gear do
1345
+ validates_presence_of :seatbelt, :key => :first_gear
1346
+ end
1347
+ @machine.state :second_gear do
1348
+ validates_presence_of :seatbelt, :key => :second_gear
1349
+ end
1350
+ @machine.other_states :parked
1351
+ end
1352
+
1353
+ def test_should_be_valid_if_validation_fails_outside_state_scope
1354
+ record = @model.new(:state => 'parked', :seatbelt => nil)
1355
+ assert record.valid?
1356
+ end
1357
+
1358
+ def test_should_be_invalid_if_validation_fails_within_state_scope
1359
+ record = @model.new(:state => 'first_gear', :seatbelt => nil)
1360
+ assert !record.valid?
1361
+ end
1362
+
1363
+ def test_should_be_valid_if_validation_succeeds_within_state_scope
1364
+ record = @model.new(:state => 'second_gear', :seatbelt => true)
1365
+ assert record.valid?
1366
+ end
1367
+ end
1368
+
1369
+ class MachineWithEventAttributesOnValidationTest < BaseTestCase
1370
+ def setup
1371
+ @model = new_model
1372
+ @machine = StateMachine::Machine.new(@model)
1373
+ @machine.event :ignite do
1374
+ transition :parked => :idling
1375
+ end
1376
+
1377
+ @record = @model.new
1378
+ @record.state = 'parked'
1379
+ @record.state_event = 'ignite'
1380
+ end
1381
+
1382
+ def test_should_fail_if_event_is_invalid
1383
+ @record.state_event = 'invalid'
1384
+ assert !@record.valid?
1385
+ assert_equal ['State event is invalid'], @record.errors.full_messages
1386
+ end
1387
+
1388
+ def test_should_fail_if_event_has_no_transition
1389
+ @record.state = 'idling'
1390
+ assert !@record.valid?
1391
+ assert_equal ['State event cannot transition when idling'], @record.errors.full_messages
1392
+ end
1393
+
1394
+ def test_should_be_successful_if_event_has_transition
1395
+ assert @record.valid?
1396
+ end
1397
+
1398
+ def test_should_run_before_callbacks
1399
+ ran_callback = false
1400
+ @machine.before_transition { ran_callback = true }
1401
+
1402
+ @record.valid?
1403
+ assert ran_callback
1404
+ end
1405
+
1406
+ def test_should_run_around_callbacks_before_yield
1407
+ ran_callback = false
1408
+ @machine.around_transition {|block| ran_callback = true; block.call }
1409
+
1410
+ begin
1411
+ @record.valid?
1412
+ rescue ArgumentError
1413
+ raise if StateMachine::Transition.pause_supported?
1414
+ end
1415
+ assert ran_callback
1416
+ end
1417
+
1418
+ def test_should_persist_new_state
1419
+ @record.valid?
1420
+ assert_equal 'idling', @record.state
1421
+ end
1422
+
1423
+ def test_should_not_run_after_callbacks
1424
+ ran_callback = false
1425
+ @machine.after_transition { ran_callback = true }
1426
+
1427
+ @record.valid?
1428
+ assert !ran_callback
1429
+ end
1430
+
1431
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
1432
+ @model.class_eval do
1433
+ attr_accessor :seatbelt
1434
+ validates_presence_of :seatbelt
1435
+ end
1436
+
1437
+ ran_callback = false
1438
+ @machine.after_transition { ran_callback = true }
1439
+
1440
+ @record.valid?
1441
+ assert !ran_callback
1442
+ end
1443
+
1444
+ def test_should_not_run_around_callbacks_after_yield
1445
+ ran_callback = false
1446
+ @machine.around_transition {|block| block.call; ran_callback = true }
1447
+
1448
+ begin
1449
+ @record.valid?
1450
+ rescue ArgumentError
1451
+ raise if StateMachine::Transition.pause_supported?
1452
+ end
1453
+ assert !ran_callback
1454
+ end
1455
+
1456
+ def test_should_not_run_around_callbacks_after_yield_with_failures_disabled_if_validation_fails
1457
+ @model.class_eval do
1458
+ attr_accessor :seatbelt
1459
+ validates_presence_of :seatbelt
1460
+ end
1461
+
1462
+ ran_callback = false
1463
+ @machine.around_transition {|block| block.call; ran_callback = true }
1464
+
1465
+ @record.valid?
1466
+ assert !ran_callback
1467
+ end
1468
+
1469
+ def test_should_run_failure_callbacks_if_validation_fails
1470
+ @model.class_eval do
1471
+ attr_accessor :seatbelt
1472
+ validates_presence_of :seatbelt
1473
+ end
1474
+
1475
+ ran_callback = false
1476
+ @machine.after_failure { ran_callback = true }
1477
+
1478
+ @record.valid?
1479
+ assert ran_callback
1480
+ end
1481
+ end
1482
+
1483
+ class MachineWithEventAttributesOnSaveTest < BaseTestCase
1484
+ def setup
1485
+ @model = new_model
1486
+ @machine = StateMachine::Machine.new(@model)
1487
+ @machine.event :ignite do
1488
+ transition :parked => :idling
1489
+ end
1490
+
1491
+ @record = @model.new
1492
+ @record.state = 'parked'
1493
+ @record.state_event = 'ignite'
1494
+ end
1495
+
1496
+ def test_should_fail_if_event_is_invalid
1497
+ @record.state_event = 'invalid'
1498
+ assert_equal false, @record.save
1499
+ end
1500
+
1501
+ def test_should_fail_if_event_has_no_transition
1502
+ @record.state = 'idling'
1503
+ assert_equal false, @record.save
1504
+ end
1505
+
1506
+ def test_should_be_successful_if_event_has_transition
1507
+ assert_equal true, @record.save
1508
+ end
1509
+
1510
+ def test_should_run_before_callbacks
1511
+ ran_callback = false
1512
+ @machine.before_transition { ran_callback = true }
1513
+
1514
+ @record.save
1515
+ assert ran_callback
1516
+ end
1517
+
1518
+ def test_should_run_before_callbacks_once
1519
+ before_count = 0
1520
+ @machine.before_transition { before_count += 1 }
1521
+
1522
+ @record.save
1523
+ assert_equal 1, before_count
1524
+ end
1525
+
1526
+ def test_should_run_around_callbacks_before_yield
1527
+ ran_callback = false
1528
+ @machine.around_transition {|block| ran_callback = true; block.call }
1529
+
1530
+ @record.save
1531
+ assert ran_callback
1532
+ end
1533
+
1534
+ def test_should_run_around_callbacks_before_yield_once
1535
+ around_before_count = 0
1536
+ @machine.around_transition {|block| around_before_count += 1; block.call }
1537
+
1538
+ @record.save
1539
+ assert_equal 1, around_before_count
1540
+ end
1541
+
1542
+ def test_should_persist_new_state
1543
+ @record.save
1544
+ assert_equal 'idling', @record.state
1545
+ end
1546
+
1547
+ def test_should_run_after_callbacks
1548
+ ran_callback = false
1549
+ @machine.after_transition { ran_callback = true }
1550
+
1551
+ @record.save
1552
+ assert ran_callback
1553
+ end
1554
+
1555
+ def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
1556
+ @model.class_eval do
1557
+ validates_numericality_of :state
1558
+ end
1559
+
1560
+ ran_callback = false
1561
+ @machine.after_transition { ran_callback = true }
1562
+
1563
+ begin; @record.save; rescue; end
1564
+ assert !ran_callback
1565
+ end
1566
+
1567
+ def test_should_run_failure_callbacks__if_fails
1568
+ @model.class_eval do
1569
+ validates_numericality_of :state
1570
+ end
1571
+
1572
+ ran_callback = false
1573
+ @machine.after_failure { ran_callback = true }
1574
+
1575
+ begin; @record.save; rescue; end
1576
+ assert ran_callback
1577
+ end
1578
+
1579
+ def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
1580
+ @model.class_eval do
1581
+ validates_numericality_of :state
1582
+ end
1583
+
1584
+ ran_callback = false
1585
+ @machine.around_transition {|block| block.call; ran_callback = true }
1586
+
1587
+ begin; @record.save; rescue; end
1588
+ assert !ran_callback
1589
+ end
1590
+
1591
+ def test_should_run_around_callbacks_after_yield
1592
+ ran_callback = false
1593
+ @machine.around_transition {|block| block.call; ran_callback = true }
1594
+
1595
+ @record.save
1596
+ assert ran_callback
1597
+ end
1598
+
1599
+ def test_should_allow_additional_transitions_to_new_state_in_after_transitions
1600
+ @machine.event :park do
1601
+ transition :idling => :parked
1602
+ end
1603
+
1604
+ @machine.after_transition(:on => :ignite) { @record.park }
1605
+
1606
+ @record.save
1607
+ assert_equal 'parked', @record.state
1608
+
1609
+ @record.reload
1610
+ assert_equal 'parked', @record.state
1611
+ end
1612
+
1613
+ def test_should_allow_additional_transitions_to_previous_state_in_after_transitions
1614
+ @machine.event :shift_up do
1615
+ transition :idling => :first_gear
1616
+ end
1617
+
1618
+ @machine.after_transition(:on => :ignite) { @record.shift_up }
1619
+
1620
+ @record.save
1621
+ assert_equal 'first_gear', @record.state
1622
+
1623
+ @record.reload
1624
+ assert_equal 'first_gear', @record.state
1625
+ end
1626
+ end
1627
+
1628
+ if Mongoid::VERSION >= '2.1.0'
1629
+ class MachineWithEventAttributesOnAutosaveTest < BaseTestCase
1630
+ def setup
1631
+ @vehicle_model = new_model(:vehicle) do
1632
+ belongs_to :owner, :class_name => 'MongoidTest::Owner'
1633
+ end
1634
+ MongoidTest.const_set('Vehicle', @vehicle_model)
1635
+
1636
+ @owner_model = new_model(:owner)
1637
+ MongoidTest.const_set('Owner', @owner_model)
1638
+
1639
+ machine = StateMachine::Machine.new(@vehicle_model)
1640
+ machine.event :ignite do
1641
+ transition :parked => :idling
1642
+ end
1643
+
1644
+ @owner = @owner_model.create
1645
+ end
1646
+
1647
+ def test_should_persist_many_association
1648
+ @owner_model.has_many :vehicles, :class_name => 'MongoidTest::Vehicle', :autosave => true
1649
+ @vehicle = @vehicle_model.create(:state => 'parked', :owner_id => @owner.id)
1650
+
1651
+ @owner.vehicles[0].state_event = 'ignite'
1652
+ @owner.save
1653
+
1654
+ @vehicle.reload
1655
+ assert_equal 'idling', @vehicle.state
1656
+ end
1657
+
1658
+ def test_should_persist_one_association
1659
+ @owner_model.has_one :vehicle, :class_name => 'MongoidTest::Vehicle', :autosave => true
1660
+ @vehicle = @vehicle_model.create(:state => 'parked', :owner_id => @owner.id)
1661
+
1662
+ @owner.vehicle.state_event = 'ignite'
1663
+ @owner.save
1664
+
1665
+ @vehicle.reload
1666
+ assert_equal 'idling', @vehicle.state
1667
+ end
1668
+
1669
+ def teardown
1670
+ MongoidTest.class_eval do
1671
+ remove_const('Vehicle')
1672
+ remove_const('Owner')
1673
+ end
1674
+ super
1675
+ end
1676
+ end
1677
+ end
1678
+
1679
+ class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
1680
+ def setup
1681
+ @model = new_model
1682
+ @machine = StateMachine::Machine.new(@model)
1683
+ @machine.event :ignite do
1684
+ transition :parked => :idling
1685
+ end
1686
+
1687
+ @record = @model.new
1688
+ @record.state = 'parked'
1689
+ @record.state_event = 'ignite'
1690
+ end
1691
+
1692
+ def test_should_fail_if_event_is_invalid
1693
+ @record.state_event = 'invalid'
1694
+ assert_raise(Mongoid::Errors::Validations) { @record.save! }
1695
+ end
1696
+
1697
+ def test_should_fail_if_event_has_no_transition
1698
+ @record.state = 'idling'
1699
+ assert_raise(Mongoid::Errors::Validations) { @record.save! }
1700
+ end
1701
+
1702
+ def test_should_be_successful_if_event_has_transition
1703
+ assert_equal true, @record.save!
1704
+ end
1705
+
1706
+ def test_should_run_before_callbacks
1707
+ ran_callback = false
1708
+ @machine.before_transition { ran_callback = true }
1709
+
1710
+ @record.save!
1711
+ assert ran_callback
1712
+ end
1713
+
1714
+ def test_should_run_before_callbacks_once
1715
+ before_count = 0
1716
+ @machine.before_transition { before_count += 1 }
1717
+
1718
+ @record.save!
1719
+ assert_equal 1, before_count
1720
+ end
1721
+
1722
+ def test_should_run_around_callbacks_before_yield
1723
+ ran_callback = false
1724
+ @machine.around_transition {|block| ran_callback = true; block.call }
1725
+
1726
+ @record.save!
1727
+ assert ran_callback
1728
+ end
1729
+
1730
+ def test_should_run_around_callbacks_before_yield_once
1731
+ around_before_count = 0
1732
+ @machine.around_transition {|block| around_before_count += 1; block.call }
1733
+
1734
+ @record.save!
1735
+ assert_equal 1, around_before_count
1736
+ end
1737
+
1738
+ def test_should_persist_new_state
1739
+ @record.save!
1740
+ assert_equal 'idling', @record.state
1741
+ end
1742
+
1743
+ def test_should_run_after_callbacks
1744
+ ran_callback = false
1745
+ @machine.after_transition { ran_callback = true }
1746
+
1747
+ @record.save!
1748
+ assert ran_callback
1749
+ end
1750
+
1751
+ def test_should_run_around_callbacks_after_yield
1752
+ ran_callback = false
1753
+ @machine.around_transition {|block| block.call; ran_callback = true }
1754
+
1755
+ @record.save!
1756
+ assert ran_callback
1757
+ end
1758
+ end
1759
+
1760
+ class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
1761
+ def setup
1762
+ @superclass = new_model do
1763
+ def persist
1764
+ upsert
1765
+ end
1766
+ end
1767
+ @model = Class.new(@superclass)
1768
+ @machine = StateMachine::Machine.new(@model, :action => :persist)
1769
+ @machine.event :ignite do
1770
+ transition :parked => :idling
1771
+ end
1772
+
1773
+ @record = @model.new
1774
+ @record.state = 'parked'
1775
+ @record.state_event = 'ignite'
1776
+ end
1777
+
1778
+ def test_should_not_transition_on_valid?
1779
+ @record.valid?
1780
+ assert_equal 'parked', @record.state
1781
+ end
1782
+
1783
+ def test_should_not_transition_on_save
1784
+ @record.save
1785
+ assert_equal 'parked', @record.state
1786
+ end
1787
+
1788
+ def test_should_not_transition_on_save!
1789
+ @record.save!
1790
+ assert_equal 'parked', @record.state
1791
+ end
1792
+
1793
+ def test_should_transition_on_custom_action
1794
+ @record.persist
1795
+ assert_equal 'idling', @record.state
1796
+ end
1797
+ end
1798
+
1799
+ class MachineWithObserversTest < BaseTestCase
1800
+ def setup
1801
+ @model = new_model
1802
+ @machine = StateMachine::Machine.new(@model)
1803
+ @machine.state :parked, :idling
1804
+ @machine.event :ignite
1805
+ @record = @model.new(:state => 'parked')
1806
+ @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
1807
+ end
1808
+
1809
+ def test_should_call_all_transition_callback_permutations
1810
+ callbacks = [
1811
+ :before_ignite_from_parked_to_idling,
1812
+ :before_ignite_from_parked,
1813
+ :before_ignite_to_idling,
1814
+ :before_ignite,
1815
+ :before_transition_state_from_parked_to_idling,
1816
+ :before_transition_state_from_parked,
1817
+ :before_transition_state_to_idling,
1818
+ :before_transition_state,
1819
+ :before_transition
1820
+ ]
1821
+
1822
+ observer = new_observer(@model) do
1823
+ callbacks.each do |callback|
1824
+ define_method(callback) do |*args|
1825
+ notifications << callback
1826
+ end
1827
+ end
1828
+ end
1829
+
1830
+ instance = observer.instance
1831
+
1832
+ @transition.perform
1833
+ assert_equal callbacks, instance.notifications
1834
+ end
1835
+
1836
+ def test_should_call_no_transition_callbacks_when_observers_disabled
1837
+ return unless ::ActiveModel::VERSION::MAJOR >= 3 && ::ActiveModel::VERSION::MINOR >= 1
1838
+
1839
+ callbacks = [
1840
+ :before_ignite,
1841
+ :before_transition
1842
+ ]
1843
+
1844
+ observer = new_observer(@model) do
1845
+ callbacks.each do |callback|
1846
+ define_method(callback) do |*args|
1847
+ notifications << callback
1848
+ end
1849
+ end
1850
+ end
1851
+
1852
+ instance = observer.instance
1853
+
1854
+ @model.observers.disable(observer) do
1855
+ @transition.perform
1856
+ end
1857
+
1858
+ assert_equal [], instance.notifications
1859
+ end
1860
+
1861
+ def test_should_pass_record_and_transition_to_before_callbacks
1862
+ observer = new_observer(@model) do
1863
+ def before_transition(*args)
1864
+ notifications << args
1865
+ end
1866
+ end
1867
+ instance = observer.instance
1868
+
1869
+ @transition.perform
1870
+ assert_equal [[@record, @transition]], instance.notifications
1871
+ end
1872
+
1873
+ def test_should_pass_record_and_transition_to_after_callbacks
1874
+ observer = new_observer(@model) do
1875
+ def after_transition(*args)
1876
+ notifications << args
1877
+ end
1878
+ end
1879
+ instance = observer.instance
1880
+
1881
+ @transition.perform
1882
+ assert_equal [[@record, @transition]], instance.notifications
1883
+ end
1884
+
1885
+ def test_should_call_methods_outside_the_context_of_the_record
1886
+ observer = new_observer(@model) do
1887
+ def before_ignite(*args)
1888
+ notifications << self
1889
+ end
1890
+ end
1891
+ instance = observer.instance
1892
+
1893
+ @transition.perform
1894
+ assert_equal [instance], instance.notifications
1895
+ end
1896
+
1897
+ def test_should_support_nil_from_states
1898
+ callbacks = [
1899
+ :before_ignite_from_nil_to_idling,
1900
+ :before_ignite_from_nil,
1901
+ :before_transition_state_from_nil_to_idling,
1902
+ :before_transition_state_from_nil
1903
+ ]
1904
+
1905
+ observer = new_observer(@model) do
1906
+ callbacks.each do |callback|
1907
+ define_method(callback) do |*args|
1908
+ notifications << callback
1909
+ end
1910
+ end
1911
+ end
1912
+
1913
+ instance = observer.instance
1914
+
1915
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, nil, :idling)
1916
+ transition.perform
1917
+ assert_equal callbacks, instance.notifications
1918
+ end
1919
+
1920
+ def test_should_support_nil_to_states
1921
+ callbacks = [
1922
+ :before_ignite_from_parked_to_nil,
1923
+ :before_ignite_to_nil,
1924
+ :before_transition_state_from_parked_to_nil,
1925
+ :before_transition_state_to_nil
1926
+ ]
1927
+
1928
+ observer = new_observer(@model) do
1929
+ callbacks.each do |callback|
1930
+ define_method(callback) do |*args|
1931
+ notifications << callback
1932
+ end
1933
+ end
1934
+ end
1935
+
1936
+ instance = observer.instance
1937
+
1938
+ transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, nil)
1939
+ transition.perform
1940
+ assert_equal callbacks, instance.notifications
1941
+ end
1942
+ end
1943
+
1944
+ class MachineWithNamespacedObserversTest < BaseTestCase
1945
+ def setup
1946
+ @model = new_model
1947
+ @machine = StateMachine::Machine.new(@model, :state, :namespace => 'alarm')
1948
+ @machine.state :active, :off
1949
+ @machine.event :enable
1950
+ @record = @model.new(:state => 'off')
1951
+ @transition = StateMachine::Transition.new(@record, @machine, :enable, :off, :active)
1952
+ end
1953
+
1954
+ def test_should_call_namespaced_before_event_method
1955
+ observer = new_observer(@model) do
1956
+ def before_enable_alarm(*args)
1957
+ notifications << args
1958
+ end
1959
+ end
1960
+ instance = observer.instance
1961
+
1962
+ @transition.perform
1963
+ assert_equal [[@record, @transition]], instance.notifications
1964
+ end
1965
+
1966
+ def test_should_call_namespaced_after_event_method
1967
+ observer = new_observer(@model) do
1968
+ def after_enable_alarm(*args)
1969
+ notifications << args
1970
+ end
1971
+ end
1972
+ instance = observer.instance
1973
+
1974
+ @transition.perform
1975
+ assert_equal [[@record, @transition]], instance.notifications
1976
+ end
1977
+ end
1978
+
1979
+ class MachineWithScopesTest < BaseTestCase
1980
+ def setup
1981
+ @model = new_model
1982
+ @machine = StateMachine::Machine.new(@model)
1983
+ @machine.state :parked, :first_gear
1984
+ @machine.state :idling, :value => lambda {'idling'}
1985
+ end
1986
+
1987
+ def test_should_create_singular_with_scope
1988
+ assert @model.respond_to?(:with_state)
1989
+ end
1990
+
1991
+ def test_should_only_include_records_with_state_in_singular_with_scope
1992
+ parked = @model.create :state => 'parked'
1993
+ @model.create :state => 'idling'
1994
+
1995
+ assert_equal [parked], @model.with_state(:parked).to_a
1996
+ end
1997
+
1998
+ def test_should_create_plural_with_scope
1999
+ assert @model.respond_to?(:with_states)
2000
+ end
2001
+
2002
+ def test_should_only_include_records_with_states_in_plural_with_scope
2003
+ parked = @model.create :state => 'parked'
2004
+ idling = @model.create :state => 'idling'
2005
+
2006
+ assert_equal [parked, idling], @model.with_states(:parked, :idling).to_a
2007
+ end
2008
+
2009
+ def test_should_allow_lookup_by_string_name
2010
+ parked = @model.create :state => 'parked'
2011
+ idling = @model.create :state => 'idling'
2012
+
2013
+ assert_equal [parked, idling], @model.with_states('parked', 'idling').to_a
2014
+ end
2015
+
2016
+ def test_should_create_singular_without_scope
2017
+ assert @model.respond_to?(:without_state)
2018
+ end
2019
+
2020
+ def test_should_only_include_records_without_state_in_singular_without_scope
2021
+ parked = @model.create :state => 'parked'
2022
+ idling = @model.create :state => 'idling'
2023
+
2024
+ assert_equal [parked], @model.without_state(:idling).to_a
2025
+ end
2026
+
2027
+ def test_should_create_plural_without_scope
2028
+ assert @model.respond_to?(:without_states)
2029
+ end
2030
+
2031
+ def test_should_only_include_records_without_states_in_plural_without_scope
2032
+ parked = @model.create :state => 'parked'
2033
+ idling = @model.create :state => 'idling'
2034
+ first_gear = @model.create :state => 'first_gear'
2035
+
2036
+ assert_equal [parked, idling], @model.without_states(:first_gear).to_a
2037
+ end
2038
+
2039
+ def test_should_allow_chaining_scopes
2040
+ parked = @model.create :state => 'parked'
2041
+ idling = @model.create :state => 'idling'
2042
+
2043
+ assert_equal [idling], @model.without_state(:parked).with_state(:idling).all
2044
+ end
2045
+ end
2046
+
2047
+ class MachineWithScopesAndOwnerSubclassTest < BaseTestCase
2048
+ def setup
2049
+ @model = new_model
2050
+ @machine = StateMachine::Machine.new(@model, :state)
2051
+
2052
+ MongoidTest.const_set('Foo', @model)
2053
+
2054
+ # Remove the #name override so that Mongoid picks up the subclass name
2055
+ # properly
2056
+ class << @model; remove_method(:name); end
2057
+ @subclass = MongoidTest.class_eval <<-end_eval
2058
+ class SubFoo < MongoidTest::Foo
2059
+ self
2060
+ end
2061
+ end_eval
2062
+ @subclass_machine = @subclass.state_machine(:state) {}
2063
+ @subclass_machine.state :parked, :idling, :first_gear
2064
+ end
2065
+
2066
+ def test_should_only_include_records_with_subclass_states_in_with_scope
2067
+ parked = @subclass.create :state => 'parked'
2068
+ idling = @subclass.create :state => 'idling'
2069
+
2070
+ assert_equal [parked, idling], @subclass.with_states(:parked, :idling).to_a
2071
+ end
2072
+
2073
+ def test_should_only_include_records_without_subclass_states_in_without_scope
2074
+ parked = @subclass.create :state => 'parked'
2075
+ idling = @subclass.create :state => 'idling'
2076
+ first_gear = @subclass.create :state => 'first_gear'
2077
+
2078
+ assert_equal [parked, idling], @subclass.without_states(:first_gear).to_a
2079
+ end
2080
+
2081
+ def teardown
2082
+ MongoidTest.send(:remove_const, 'SubFoo')
2083
+ MongoidTest.send(:remove_const, 'Foo')
2084
+ super
2085
+ end
2086
+ end
2087
+
2088
+ class MachineWithComplexPluralizationScopesTest < BaseTestCase
2089
+ def setup
2090
+ @model = new_model
2091
+ @machine = StateMachine::Machine.new(@model, :status)
2092
+ end
2093
+
2094
+ def test_should_create_singular_with_scope
2095
+ assert @model.respond_to?(:with_status)
2096
+ end
2097
+
2098
+ def test_should_create_plural_with_scope
2099
+ assert @model.respond_to?(:with_statuses)
2100
+ end
2101
+ end
2102
+
2103
+ class MachineWithDefaultScope < BaseTestCase
2104
+ def setup
2105
+ @model = new_model
2106
+ @machine = StateMachine::Machine.new(@model, :initial => :parked)
2107
+ @machine.state :idling
2108
+
2109
+ @model.class_eval do
2110
+ default_scope with_state(:parked, :idling)
2111
+ end
2112
+ end
2113
+
2114
+ def test_should_set_initial_state_on_created_object
2115
+ object = @model.new
2116
+ assert_equal 'parked', object.state
2117
+ end
2118
+ end
2119
+
2120
+ class MachineWithInternationalizationTest < BaseTestCase
2121
+ def setup
2122
+ I18n.backend = I18n::Backend::Simple.new
2123
+
2124
+ # Initialize the backend
2125
+ StateMachine::Machine.new(new_model)
2126
+ I18n.backend.translate(:en, 'mongoid.errors.messages.invalid_transition', :event => 'ignite', :value => 'idling')
2127
+
2128
+ @model = new_model
2129
+ end
2130
+
2131
+ def test_should_use_defaults
2132
+ I18n.backend.store_translations(:en, {
2133
+ :mongoid => {:errors => {:messages => {:invalid_transition => 'cannot %{event}'}}}
2134
+ })
2135
+
2136
+ machine = StateMachine::Machine.new(@model)
2137
+ machine.state :parked, :idling
2138
+ machine.event :ignite
2139
+
2140
+ record = @model.new(:state => 'idling')
2141
+
2142
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
2143
+ assert_equal ['State cannot ignite'], record.errors.full_messages
2144
+ end
2145
+
2146
+ def test_should_allow_customized_error_key
2147
+ I18n.backend.store_translations(:en, {
2148
+ :mongoid => {:errors => {:messages => {:bad_transition => 'cannot %{event}'}}}
2149
+ })
2150
+
2151
+ machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => :bad_transition})
2152
+ machine.state :parked, :idling
2153
+
2154
+ record = @model.new(:state => 'idling')
2155
+
2156
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
2157
+ assert_equal ['State cannot ignite'], record.errors.full_messages
2158
+ end
2159
+
2160
+ def test_should_allow_customized_error_string
2161
+ machine = StateMachine::Machine.new(@model, :messages => {:invalid_transition => 'cannot %{event}'})
2162
+ machine.state :parked, :idling
2163
+
2164
+ record = @model.new(:state => 'idling')
2165
+
2166
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
2167
+ assert_equal ['State cannot ignite'], record.errors.full_messages
2168
+ end
2169
+
2170
+ def test_should_allow_customized_state_key_scoped_to_class_and_machine
2171
+ I18n.backend.store_translations(:en, {
2172
+ :mongoid => {:state_machines => {:'mongoid_test/foo' => {:state => {:states => {:parked => 'shutdown'}}}}}
2173
+ })
2174
+
2175
+ machine = StateMachine::Machine.new(@model)
2176
+ machine.state :parked
2177
+
2178
+ assert_equal 'shutdown', machine.state(:parked).human_name
2179
+ end
2180
+
2181
+ def test_should_allow_customized_state_key_scoped_to_class
2182
+ I18n.backend.store_translations(:en, {
2183
+ :mongoid => {:state_machines => {:'mongoid_test/foo' => {:states => {:parked => 'shutdown'}}}}
2184
+ })
2185
+
2186
+ machine = StateMachine::Machine.new(@model)
2187
+ machine.state :parked
2188
+
2189
+ assert_equal 'shutdown', machine.state(:parked).human_name
2190
+ end
2191
+
2192
+ def test_should_allow_customized_state_key_scoped_to_machine
2193
+ I18n.backend.store_translations(:en, {
2194
+ :mongoid => {:state_machines => {:state => {:states => {:parked => 'shutdown'}}}}
2195
+ })
2196
+
2197
+ machine = StateMachine::Machine.new(@model)
2198
+ machine.state :parked
2199
+
2200
+ assert_equal 'shutdown', machine.state(:parked).human_name
2201
+ end
2202
+
2203
+ def test_should_allow_customized_state_key_unscoped
2204
+ I18n.backend.store_translations(:en, {
2205
+ :mongoid => {:state_machines => {:states => {:parked => 'shutdown'}}}
2206
+ })
2207
+
2208
+ machine = StateMachine::Machine.new(@model)
2209
+ machine.state :parked
2210
+
2211
+ assert_equal 'shutdown', machine.state(:parked).human_name
2212
+ end
2213
+
2214
+ def test_should_support_nil_state_key
2215
+ I18n.backend.store_translations(:en, {
2216
+ :mongoid => {:state_machines => {:states => {:nil => 'empty'}}}
2217
+ })
2218
+
2219
+ machine = StateMachine::Machine.new(@model)
2220
+
2221
+ assert_equal 'empty', machine.state(nil).human_name
2222
+ end
2223
+
2224
+ def test_should_allow_customized_event_key_scoped_to_class_and_machine
2225
+ I18n.backend.store_translations(:en, {
2226
+ :mongoid => {:state_machines => {:'mongoid_test/foo' => {:state => {:events => {:park => 'stop'}}}}}
2227
+ })
2228
+
2229
+ machine = StateMachine::Machine.new(@model)
2230
+ machine.event :park
2231
+
2232
+ assert_equal 'stop', machine.event(:park).human_name
2233
+ end
2234
+
2235
+ def test_should_allow_customized_event_key_scoped_to_class
2236
+ I18n.backend.store_translations(:en, {
2237
+ :mongoid => {:state_machines => {:'mongoid_test/foo' => {:events => {:park => 'stop'}}}}
2238
+ })
2239
+
2240
+ machine = StateMachine::Machine.new(@model)
2241
+ machine.event :park
2242
+
2243
+ assert_equal 'stop', machine.event(:park).human_name
2244
+ end
2245
+
2246
+ def test_should_allow_customized_event_key_scoped_to_machine
2247
+ I18n.backend.store_translations(:en, {
2248
+ :mongoid => {:state_machines => {:state => {:events => {:park => 'stop'}}}}
2249
+ })
2250
+
2251
+ machine = StateMachine::Machine.new(@model)
2252
+ machine.event :park
2253
+
2254
+ assert_equal 'stop', machine.event(:park).human_name
2255
+ end
2256
+
2257
+ def test_should_allow_customized_event_key_unscoped
2258
+ I18n.backend.store_translations(:en, {
2259
+ :mongoid => {:state_machines => {:events => {:park => 'stop'}}}
2260
+ })
2261
+
2262
+ machine = StateMachine::Machine.new(@model)
2263
+ machine.event :park
2264
+
2265
+ assert_equal 'stop', machine.event(:park).human_name
2266
+ end
2267
+
2268
+ def test_should_only_add_locale_once_in_load_path
2269
+ assert_equal 1, I18n.load_path.select {|path| path =~ %r{mongoid/locale\.rb$}}.length
2270
+
2271
+ # Create another Mongoid model that will triger the i18n feature
2272
+ new_model
2273
+
2274
+ assert_equal 1, I18n.load_path.select {|path| path =~ %r{mongoid/locale\.rb$}}.length
2275
+ end
2276
+
2277
+ def test_should_add_locale_to_beginning_of_load_path
2278
+ @original_load_path = I18n.load_path
2279
+ I18n.backend = I18n::Backend::Simple.new
2280
+
2281
+ app_locale = File.dirname(__FILE__) + '/../../files/en.yml'
2282
+ default_locale = File.dirname(__FILE__) + '/../../../lib/state_machine/integrations/mongoid/locale.rb'
2283
+ I18n.load_path = [app_locale]
2284
+
2285
+ StateMachine::Machine.new(@model)
2286
+
2287
+ assert_equal [default_locale, app_locale].map {|path| File.expand_path(path)}, I18n.load_path.map {|path| File.expand_path(path)}
2288
+ ensure
2289
+ I18n.load_path = @original_load_path
2290
+ end
2291
+
2292
+ def test_should_prefer_other_locales_first
2293
+ @original_load_path = I18n.load_path
2294
+ I18n.backend = I18n::Backend::Simple.new
2295
+ I18n.load_path = [File.dirname(__FILE__) + '/../../files/en.yml']
2296
+
2297
+ machine = StateMachine::Machine.new(@model)
2298
+ machine.state :parked, :idling
2299
+ machine.event :ignite
2300
+
2301
+ record = @model.new(:state => 'idling')
2302
+
2303
+ machine.invalidate(record, :state, :invalid_transition, [[:event, 'ignite']])
2304
+ assert_equal ['State cannot transition'], record.errors.full_messages
2305
+ ensure
2306
+ I18n.load_path = @original_load_path
2307
+ end
2308
+ end
2309
+ end