glebtv_state_machine 1.3.0

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