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,1196 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class EventByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @klass = Class.new
6
+ @machine = StateMachine::Machine.new(@klass)
7
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
8
+
9
+ @object = @klass.new
10
+ end
11
+
12
+ def test_should_have_a_machine
13
+ assert_equal @machine, @event.machine
14
+ end
15
+
16
+ def test_should_have_a_name
17
+ assert_equal :ignite, @event.name
18
+ end
19
+
20
+ def test_should_have_a_qualified_name
21
+ assert_equal :ignite, @event.qualified_name
22
+ end
23
+
24
+ def test_should_have_a_human_name
25
+ assert_equal 'ignite', @event.human_name
26
+ end
27
+
28
+ def test_should_not_have_any_branches
29
+ assert @event.branches.empty?
30
+ end
31
+
32
+ def test_should_have_no_known_states
33
+ assert @event.known_states.empty?
34
+ end
35
+
36
+ def test_should_not_be_able_to_fire
37
+ assert !@event.can_fire?(@object)
38
+ end
39
+
40
+ def test_should_not_have_a_transition
41
+ assert_nil @event.transition_for(@object)
42
+ end
43
+
44
+ def test_should_define_a_predicate
45
+ assert @object.respond_to?(:can_ignite?)
46
+ end
47
+
48
+ def test_should_define_a_transition_accessor
49
+ assert @object.respond_to?(:ignite_transition)
50
+ end
51
+
52
+ def test_should_define_an_action
53
+ assert @object.respond_to?(:ignite)
54
+ end
55
+
56
+ def test_should_define_a_bang_action
57
+ assert @object.respond_to?(:ignite!)
58
+ end
59
+ end
60
+
61
+ class EventTest < Test::Unit::TestCase
62
+ def setup
63
+ @machine = StateMachine::Machine.new(Class.new)
64
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
65
+ @event.transition :parked => :idling
66
+ end
67
+
68
+ def test_should_allow_changing_machine
69
+ new_machine = StateMachine::Machine.new(Class.new)
70
+ @event.machine = new_machine
71
+ assert_equal new_machine, @event.machine
72
+ end
73
+
74
+ def test_should_allow_changing_human_name
75
+ @event.human_name = 'Stop'
76
+ assert_equal 'Stop', @event.human_name
77
+ end
78
+
79
+ def test_should_provide_matcher_helpers_during_initialization
80
+ matchers = []
81
+
82
+ @event.instance_eval do
83
+ matchers = [all, any, same]
84
+ end
85
+
86
+ assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
87
+ end
88
+
89
+ def test_should_use_pretty_inspect
90
+ assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling]>", @event.inspect
91
+ end
92
+ end
93
+
94
+ class EventWithHumanNameTest < Test::Unit::TestCase
95
+ def setup
96
+ @klass = Class.new
97
+ @machine = StateMachine::Machine.new(@klass)
98
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => 'start')
99
+ end
100
+
101
+ def test_should_use_custom_human_name
102
+ assert_equal 'start', @event.human_name
103
+ end
104
+ end
105
+
106
+ class EventWithDynamicHumanNameTest < Test::Unit::TestCase
107
+ def setup
108
+ @klass = Class.new
109
+ @machine = StateMachine::Machine.new(@klass)
110
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => lambda {|event, object| ['start', object]})
111
+ end
112
+
113
+ def test_should_use_custom_human_name
114
+ human_name, klass = @event.human_name
115
+ assert_equal 'start', human_name
116
+ assert_equal @klass, klass
117
+ end
118
+
119
+ def test_should_allow_custom_class_to_be_passed_through
120
+ human_name, klass = @event.human_name(1)
121
+ assert_equal 'start', human_name
122
+ assert_equal 1, klass
123
+ end
124
+
125
+ def test_should_not_cache_value
126
+ assert_not_same @event.human_name, @event.human_name
127
+ end
128
+ end
129
+
130
+ class EventWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
131
+ def setup
132
+ require 'stringio'
133
+ @original_stderr, $stderr = $stderr, StringIO.new
134
+
135
+ @superclass = Class.new do
136
+ def can_ignite?
137
+ 0
138
+ end
139
+
140
+ def ignite_transition
141
+ 0
142
+ end
143
+
144
+ def ignite
145
+ 0
146
+ end
147
+
148
+ def ignite!
149
+ 0
150
+ end
151
+ end
152
+ @klass = Class.new(@superclass)
153
+ @machine = StateMachine::Machine.new(@klass)
154
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
155
+ @object = @klass.new
156
+ end
157
+
158
+ def test_should_not_redefine_predicate
159
+ assert_equal 0, @object.can_ignite?
160
+ end
161
+
162
+ def test_should_not_redefine_transition_accessor
163
+ assert_equal 0, @object.ignite_transition
164
+ end
165
+
166
+ def test_should_not_redefine_action
167
+ assert_equal 0, @object.ignite
168
+ end
169
+
170
+ def test_should_not_redefine_bang_action
171
+ assert_equal 0, @object.ignite!
172
+ end
173
+
174
+ def test_should_output_warning
175
+ expected = %w(can_ignite? ignite_transition ignite ignite!).map do |method|
176
+ "Instance method \"#{method}\" is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n"
177
+ end.join
178
+
179
+ assert_equal expected, $stderr.string
180
+ end
181
+
182
+ def teardown
183
+ $stderr = @original_stderr
184
+ end
185
+ end
186
+
187
+ class EventWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
188
+ def setup
189
+ require 'stringio'
190
+ @original_stderr, $stderr = $stderr, StringIO.new
191
+
192
+ @klass = Class.new do
193
+ def can_ignite?
194
+ 0
195
+ end
196
+
197
+ def ignite_transition
198
+ 0
199
+ end
200
+
201
+ def ignite
202
+ 0
203
+ end
204
+
205
+ def ignite!
206
+ 0
207
+ end
208
+ end
209
+ @machine = StateMachine::Machine.new(@klass)
210
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
211
+ @object = @klass.new
212
+ end
213
+
214
+ def test_should_not_redefine_predicate
215
+ assert_equal 0, @object.can_ignite?
216
+ end
217
+
218
+ def test_should_not_redefine_transition_accessor
219
+ assert_equal 0, @object.ignite_transition
220
+ end
221
+
222
+ def test_should_not_redefine_action
223
+ assert_equal 0, @object.ignite
224
+ end
225
+
226
+ def test_should_not_redefine_bang_action
227
+ assert_equal 0, @object.ignite!
228
+ end
229
+
230
+ def test_should_allow_super_chaining
231
+ @klass.class_eval do
232
+ def can_ignite?
233
+ super
234
+ end
235
+
236
+ def ignite_transition
237
+ super
238
+ end
239
+
240
+ def ignite
241
+ super
242
+ end
243
+
244
+ def ignite!
245
+ super
246
+ end
247
+ end
248
+
249
+ assert_equal false, @object.can_ignite?
250
+ assert_equal nil, @object.ignite_transition
251
+ assert_equal false, @object.ignite
252
+ assert_raise(StateMachine::InvalidTransition) { @object.ignite! }
253
+ end
254
+
255
+ def test_should_not_output_warning
256
+ assert_equal '', $stderr.string
257
+ end
258
+
259
+ def teardown
260
+ $stderr = @original_stderr
261
+ end
262
+ end
263
+
264
+ class EventWithConflictingMachineTest < Test::Unit::TestCase
265
+ def setup
266
+ require 'stringio'
267
+ @original_stderr, $stderr = $stderr, StringIO.new
268
+
269
+ @klass = Class.new
270
+ @state_machine = StateMachine::Machine.new(@klass, :state)
271
+ @state_machine.state :parked, :idling
272
+ @state_machine.events << @state_event = StateMachine::Event.new(@state_machine, :ignite)
273
+ end
274
+
275
+ def test_should_not_overwrite_first_event
276
+ @status_machine = StateMachine::Machine.new(@klass, :status)
277
+ @status_machine.state :first_gear, :second_gear
278
+ @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
279
+
280
+ @object = @klass.new
281
+ @object.state = 'parked'
282
+ @object.status = 'first_gear'
283
+
284
+ @state_event.transition(:parked => :idling)
285
+ @status_event.transition(:parked => :first_gear)
286
+
287
+ @object.ignite
288
+ assert_equal 'idling', @object.state
289
+ assert_equal 'first_gear', @object.status
290
+ end
291
+
292
+ def test_should_output_warning
293
+ @status_machine = StateMachine::Machine.new(@klass, :status)
294
+ @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
295
+
296
+ assert_equal "Event :ignite for :status is already defined in :state\n", $stderr.string
297
+ end
298
+
299
+ def test_should_not_output_warning_if_using_different_namespace
300
+ @status_machine = StateMachine::Machine.new(@klass, :status, :namespace => 'alarm')
301
+ @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
302
+
303
+ assert_equal '', $stderr.string
304
+ end
305
+
306
+ def teardown
307
+ $stderr = @original_stderr
308
+ end
309
+ end
310
+
311
+ class EventWithNamespaceTest < Test::Unit::TestCase
312
+ def setup
313
+ @klass = Class.new
314
+ @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
315
+ @machine.events << @event = StateMachine::Event.new(@machine, :enable)
316
+ @object = @klass.new
317
+ end
318
+
319
+ def test_should_have_a_name
320
+ assert_equal :enable, @event.name
321
+ end
322
+
323
+ def test_should_have_a_qualified_name
324
+ assert_equal :enable_alarm, @event.qualified_name
325
+ end
326
+
327
+ def test_should_namespace_predicate
328
+ assert @object.respond_to?(:can_enable_alarm?)
329
+ end
330
+
331
+ def test_should_namespace_transition_accessor
332
+ assert @object.respond_to?(:enable_alarm_transition)
333
+ end
334
+
335
+ def test_should_namespace_action
336
+ assert @object.respond_to?(:enable_alarm)
337
+ end
338
+
339
+ def test_should_namespace_bang_action
340
+ assert @object.respond_to?(:enable_alarm!)
341
+ end
342
+ end
343
+
344
+ class EventContextTest < Test::Unit::TestCase
345
+ def setup
346
+ @klass = Class.new
347
+ @machine = StateMachine::Machine.new(@klass)
348
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => 'start')
349
+ end
350
+
351
+ def test_should_evaluate_within_the_event
352
+ scope = nil
353
+ @event.context { scope = self }
354
+ assert_equal @event, scope
355
+ end
356
+ end
357
+
358
+ class EventTransitionsTest < Test::Unit::TestCase
359
+ def setup
360
+ @machine = StateMachine::Machine.new(Class.new)
361
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
362
+ end
363
+
364
+ def test_should_not_raise_exception_if_implicit_option_specified
365
+ assert_nothing_raised {@event.transition(:invalid => :valid)}
366
+ end
367
+
368
+ def test_should_not_allow_on_option
369
+ exception = assert_raise(ArgumentError) {@event.transition(:on => :ignite)}
370
+ assert_equal 'Invalid key(s): on', exception.message
371
+ end
372
+
373
+ def test_should_automatically_set_on_option
374
+ branch = @event.transition(:to => :idling)
375
+ assert_instance_of StateMachine::WhitelistMatcher, branch.event_requirement
376
+ assert_equal [:ignite], branch.event_requirement.values
377
+ end
378
+
379
+ def test_should_not_allow_except_on_option
380
+ exception = assert_raise(ArgumentError) {@event.transition(:except_on => :ignite)}
381
+ assert_equal 'Invalid key(s): except_on', exception.message
382
+ end
383
+
384
+ def test_should_allow_transitioning_without_a_to_state
385
+ assert_nothing_raised {@event.transition(:from => :parked)}
386
+ end
387
+
388
+ def test_should_allow_transitioning_without_a_from_state
389
+ assert_nothing_raised {@event.transition(:to => :idling)}
390
+ end
391
+
392
+ def test_should_allow_except_from_option
393
+ assert_nothing_raised {@event.transition(:except_from => :idling)}
394
+ end
395
+
396
+ def test_should_allow_except_to_option
397
+ assert_nothing_raised {@event.transition(:except_to => :idling)}
398
+ end
399
+
400
+ def test_should_allow_transitioning_from_a_single_state
401
+ assert @event.transition(:parked => :idling)
402
+ end
403
+
404
+ def test_should_allow_transitioning_from_multiple_states
405
+ assert @event.transition([:parked, :idling] => :idling)
406
+ end
407
+
408
+ def test_should_allow_transitions_to_multiple_states
409
+ assert @event.transition(:parked => [:parked, :idling])
410
+ end
411
+
412
+ def test_should_have_transitions
413
+ branch = @event.transition(:to => :idling)
414
+ assert_equal [branch], @event.branches
415
+ end
416
+ end
417
+
418
+ class EventAfterBeingCopiedTest < Test::Unit::TestCase
419
+ def setup
420
+ @machine = StateMachine::Machine.new(Class.new)
421
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
422
+ @copied_event = @event.dup
423
+ end
424
+
425
+ def test_should_not_have_the_same_collection_of_branches
426
+ assert_not_same @event.branches, @copied_event.branches
427
+ end
428
+
429
+ def test_should_not_have_the_same_collection_of_known_states
430
+ assert_not_same @event.known_states, @copied_event.known_states
431
+ end
432
+ end
433
+
434
+ class EventWithoutTransitionsTest < Test::Unit::TestCase
435
+ def setup
436
+ @klass = Class.new
437
+ @machine = StateMachine::Machine.new(@klass)
438
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
439
+ @object = @klass.new
440
+ end
441
+
442
+ def test_should_not_be_able_to_fire
443
+ assert !@event.can_fire?(@object)
444
+ end
445
+
446
+ def test_should_not_have_a_transition
447
+ assert_nil @event.transition_for(@object)
448
+ end
449
+
450
+ def test_should_not_fire
451
+ assert !@event.fire(@object)
452
+ end
453
+
454
+ def test_should_not_change_the_current_state
455
+ @event.fire(@object)
456
+ assert_nil @object.state
457
+ end
458
+ end
459
+
460
+ class EventWithTransitionsTest < Test::Unit::TestCase
461
+ def setup
462
+ @klass = Class.new
463
+ @machine = StateMachine::Machine.new(@klass)
464
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
465
+ @event.transition(:parked => :idling)
466
+ @event.transition(:first_gear => :idling)
467
+ end
468
+
469
+ def test_should_include_all_transition_states_in_known_states
470
+ assert_equal [:parked, :idling, :first_gear], @event.known_states
471
+ end
472
+
473
+ def test_should_include_new_transition_states_after_calling_known_states
474
+ @event.known_states
475
+ @event.transition(:stalled => :idling)
476
+
477
+ assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states
478
+ end
479
+
480
+ def test_should_clear_known_states_on_reset
481
+ @event.reset
482
+ assert_equal [], @event.known_states
483
+ end
484
+
485
+ def test_should_use_pretty_inspect
486
+ assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling, :first_gear => :idling]>", @event.inspect
487
+ end
488
+ end
489
+
490
+ class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
491
+ def setup
492
+ @klass = Class.new
493
+ @machine = StateMachine::Machine.new(@klass)
494
+ @machine.state :parked, :idling
495
+
496
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
497
+ @event.transition(:parked => :idling)
498
+
499
+ @object = @klass.new
500
+ @object.state = 'idling'
501
+ end
502
+
503
+ def test_should_not_be_able_to_fire
504
+ assert !@event.can_fire?(@object)
505
+ end
506
+
507
+ def test_should_be_able_to_fire_with_custom_from_state
508
+ assert @event.can_fire?(@object, :from => :parked)
509
+ end
510
+
511
+ def test_should_not_have_a_transition
512
+ assert_nil @event.transition_for(@object)
513
+ end
514
+
515
+ def test_should_have_a_transition_with_custom_from_state
516
+ assert_not_nil @event.transition_for(@object, :from => :parked)
517
+ end
518
+
519
+ def test_should_not_fire
520
+ assert !@event.fire(@object)
521
+ end
522
+
523
+ def test_should_not_change_the_current_state
524
+ @event.fire(@object)
525
+ assert_equal 'idling', @object.state
526
+ end
527
+ end
528
+
529
+ class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
530
+ def setup
531
+ StateMachine::Integrations.const_set('Custom', Module.new do
532
+ include StateMachine::Integrations::Base
533
+
534
+ def invalidate(object, attribute, message, values = [])
535
+ (object.errors ||= []) << generate_message(message, values)
536
+ end
537
+
538
+ def reset(object)
539
+ object.errors = []
540
+ end
541
+ end)
542
+
543
+ @klass = Class.new do
544
+ attr_accessor :errors
545
+ end
546
+
547
+ @machine = StateMachine::Machine.new(@klass, :integration => :custom)
548
+ @machine.state :parked, :idling
549
+
550
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
551
+ @event.transition(:parked => :idling, :if => lambda {false})
552
+
553
+ @object = @klass.new
554
+ @object.state = 'parked'
555
+ end
556
+
557
+ def test_should_not_be_able_to_fire
558
+ assert !@event.can_fire?(@object)
559
+ end
560
+
561
+ def test_should_be_able_to_fire_with_disabled_guards
562
+ assert @event.can_fire?(@object, :guard => false)
563
+ end
564
+
565
+ def test_should_not_have_a_transition
566
+ assert_nil @event.transition_for(@object)
567
+ end
568
+
569
+ def test_should_have_a_transition_with_disabled_guards
570
+ assert_not_nil @event.transition_for(@object, :guard => false)
571
+ end
572
+
573
+ def test_should_not_fire
574
+ assert !@event.fire(@object)
575
+ end
576
+
577
+ def test_should_not_change_the_current_state
578
+ @event.fire(@object)
579
+ assert_equal 'parked', @object.state
580
+ end
581
+
582
+ def test_should_invalidate_the_state
583
+ @event.fire(@object)
584
+ assert_equal ['cannot transition via "ignite"'], @object.errors
585
+ end
586
+
587
+ def test_should_invalidate_with_human_event_name
588
+ @event.human_name = 'start'
589
+ @event.fire(@object)
590
+ assert_equal ['cannot transition via "start"'], @object.errors
591
+ end
592
+
593
+ def test_should_invalid_with_human_state_name_if_specified
594
+ klass = Class.new do
595
+ attr_accessor :errors
596
+ end
597
+
598
+ machine = StateMachine::Machine.new(klass, :integration => :custom, :messages => {:invalid_transition => 'cannot transition via "%s" from "%s"'})
599
+ parked, idling = machine.state :parked, :idling
600
+ parked.human_name = 'stopped'
601
+
602
+ machine.events << event = StateMachine::Event.new(machine, :ignite)
603
+ event.transition(:parked => :idling, :if => lambda {false})
604
+
605
+ object = @klass.new
606
+ object.state = 'parked'
607
+
608
+ event.fire(object)
609
+ assert_equal ['cannot transition via "ignite" from "stopped"'], object.errors
610
+ end
611
+
612
+ def test_should_reset_existing_error
613
+ @object.errors = ['invalid']
614
+
615
+ @event.fire(@object)
616
+ assert_equal ['cannot transition via "ignite"'], @object.errors
617
+ end
618
+
619
+ def test_should_run_failure_callbacks
620
+ callback_args = nil
621
+ @machine.after_failure {|*args| callback_args = args}
622
+
623
+ @event.fire(@object)
624
+
625
+ object, transition = callback_args
626
+ assert_equal @object, object
627
+ assert_not_nil transition
628
+ assert_equal @object, transition.object
629
+ assert_equal @machine, transition.machine
630
+ assert_equal :ignite, transition.event
631
+ assert_equal :parked, transition.from_name
632
+ assert_equal :parked, transition.to_name
633
+ end
634
+
635
+ def teardown
636
+ StateMachine::Integrations.send(:remove_const, 'Custom')
637
+ end
638
+ end
639
+
640
+ class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
641
+ def setup
642
+ StateMachine::Integrations.const_set('Custom', Module.new do
643
+ include StateMachine::Integrations::Base
644
+
645
+ def invalidate(object, attribute, message, values = [])
646
+ (object.errors ||= []) << generate_message(message, values)
647
+ end
648
+
649
+ def reset(object)
650
+ object.errors = []
651
+ end
652
+ end)
653
+
654
+ @klass = Class.new do
655
+ attr_accessor :errors
656
+ end
657
+
658
+ @machine = StateMachine::Machine.new(@klass, :integration => :custom)
659
+ @machine.state :parked, :idling
660
+
661
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
662
+ @event.transition(:parked => :idling)
663
+
664
+ @object = @klass.new
665
+ @object.state = 'parked'
666
+ end
667
+
668
+ def test_should_be_able_to_fire
669
+ assert @event.can_fire?(@object)
670
+ end
671
+
672
+ def test_should_have_a_transition
673
+ transition = @event.transition_for(@object)
674
+ assert_not_nil transition
675
+ assert_equal 'parked', transition.from
676
+ assert_equal 'idling', transition.to
677
+ assert_equal :ignite, transition.event
678
+ end
679
+
680
+ def test_should_fire
681
+ assert @event.fire(@object)
682
+ end
683
+
684
+ def test_should_change_the_current_state
685
+ @event.fire(@object)
686
+ assert_equal 'idling', @object.state
687
+ end
688
+
689
+ def test_should_reset_existing_error
690
+ @object.errors = ['invalid']
691
+
692
+ @event.fire(@object)
693
+ assert_equal [], @object.errors
694
+ end
695
+
696
+ def test_should_not_invalidate_the_state
697
+ @event.fire(@object)
698
+ assert_equal [], @object.errors
699
+ end
700
+
701
+ def test_should_not_be_able_to_fire_on_reset
702
+ @event.reset
703
+ assert !@event.can_fire?(@object)
704
+ end
705
+
706
+ def teardown
707
+ StateMachine::Integrations.send(:remove_const, 'Custom')
708
+ end
709
+ end
710
+
711
+ class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
712
+ def setup
713
+ @klass = Class.new
714
+ @machine = StateMachine::Machine.new(@klass)
715
+ @machine.state :parked
716
+
717
+ @machine.events << @event = StateMachine::Event.new(@machine, :park)
718
+ @event.transition(:from => :parked)
719
+
720
+ @object = @klass.new
721
+ @object.state = 'parked'
722
+ end
723
+
724
+ def test_should_be_able_to_fire
725
+ assert @event.can_fire?(@object)
726
+ end
727
+
728
+ def test_should_have_a_transition
729
+ transition = @event.transition_for(@object)
730
+ assert_not_nil transition
731
+ assert_equal 'parked', transition.from
732
+ assert_equal 'parked', transition.to
733
+ assert_equal :park, transition.event
734
+ end
735
+
736
+ def test_should_fire
737
+ assert @event.fire(@object)
738
+ end
739
+
740
+ def test_should_not_change_the_current_state
741
+ @event.fire(@object)
742
+ assert_equal 'parked', @object.state
743
+ end
744
+ end
745
+
746
+ class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
747
+ def setup
748
+ @klass = Class.new
749
+ @machine = StateMachine::Machine.new(@klass)
750
+ @machine.state nil, :idling
751
+
752
+ @machine.events << @event = StateMachine::Event.new(@machine, :park)
753
+ @event.transition(:idling => nil)
754
+
755
+ @object = @klass.new
756
+ @object.state = 'idling'
757
+ end
758
+
759
+ def test_should_be_able_to_fire
760
+ assert @event.can_fire?(@object)
761
+ end
762
+
763
+ def test_should_have_a_transition
764
+ transition = @event.transition_for(@object)
765
+ assert_not_nil transition
766
+ assert_equal 'idling', transition.from
767
+ assert_equal nil, transition.to
768
+ assert_equal :park, transition.event
769
+ end
770
+
771
+ def test_should_fire
772
+ assert @event.fire(@object)
773
+ end
774
+
775
+ def test_should_not_change_the_current_state
776
+ @event.fire(@object)
777
+ assert_equal nil, @object.state
778
+ end
779
+ end
780
+
781
+ class EventWithTransitionWithLoopbackStateTest < Test::Unit::TestCase
782
+ def setup
783
+ @klass = Class.new
784
+ @machine = StateMachine::Machine.new(@klass)
785
+ @machine.state :parked
786
+
787
+ @machine.events << @event = StateMachine::Event.new(@machine, :park)
788
+ @event.transition(:from => :parked, :to => StateMachine::LoopbackMatcher.instance)
789
+
790
+ @object = @klass.new
791
+ @object.state = 'parked'
792
+ end
793
+
794
+ def test_should_be_able_to_fire
795
+ assert @event.can_fire?(@object)
796
+ end
797
+
798
+ def test_should_have_a_transition
799
+ transition = @event.transition_for(@object)
800
+ assert_not_nil transition
801
+ assert_equal 'parked', transition.from
802
+ assert_equal 'parked', transition.to
803
+ assert_equal :park, transition.event
804
+ end
805
+
806
+ def test_should_fire
807
+ assert @event.fire(@object)
808
+ end
809
+
810
+ def test_should_not_change_the_current_state
811
+ @event.fire(@object)
812
+ assert_equal 'parked', @object.state
813
+ end
814
+ end
815
+
816
+ class EventWithTransitionWithBlacklistedToStateTest < Test::Unit::TestCase
817
+ def setup
818
+ @klass = Class.new
819
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
820
+ @machine.state :parked, :idling, :first_gear, :second_gear
821
+
822
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
823
+ @event.transition(:from => :parked, :to => StateMachine::BlacklistMatcher.new([:parked, :idling]))
824
+
825
+ @object = @klass.new
826
+ @object.state = 'parked'
827
+ end
828
+
829
+ def test_should_be_able_to_fire
830
+ assert @event.can_fire?(@object)
831
+ end
832
+
833
+ def test_should_have_a_transition
834
+ transition = @event.transition_for(@object)
835
+ assert_not_nil transition
836
+ assert_equal 'parked', transition.from
837
+ assert_equal 'first_gear', transition.to
838
+ assert_equal :ignite, transition.event
839
+ end
840
+
841
+ def test_should_allow_loopback_first_when_possible
842
+ @event.transition(:from => :second_gear, :to => StateMachine::BlacklistMatcher.new([:parked, :idling]))
843
+ @object.state = 'second_gear'
844
+
845
+ transition = @event.transition_for(@object)
846
+ assert_not_nil transition
847
+ assert_equal 'second_gear', transition.from
848
+ assert_equal 'second_gear', transition.to
849
+ assert_equal :ignite, transition.event
850
+ end
851
+
852
+ def test_should_allow_specific_transition_selection_using_to
853
+ transition = @event.transition_for(@object, :from => :parked, :to => :second_gear)
854
+
855
+ assert_not_nil transition
856
+ assert_equal 'parked', transition.from
857
+ assert_equal 'second_gear', transition.to
858
+ assert_equal :ignite, transition.event
859
+ end
860
+
861
+ def test_should_not_allow_transition_selection_if_not_matching
862
+ transition = @event.transition_for(@object, :from => :parked, :to => :parked)
863
+ assert_nil transition
864
+ end
865
+
866
+ def test_should_fire
867
+ assert @event.fire(@object)
868
+ end
869
+
870
+ def test_should_change_the_current_state
871
+ @event.fire(@object)
872
+ assert_equal 'first_gear', @object.state
873
+ end
874
+ end
875
+
876
+ class EventWithTransitionWithWhitelistedToStateTest < Test::Unit::TestCase
877
+ def setup
878
+ @klass = Class.new
879
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
880
+ @machine.state :parked, :idling, :first_gear, :second_gear
881
+
882
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
883
+ @event.transition(:from => :parked, :to => StateMachine::WhitelistMatcher.new([:first_gear, :second_gear]))
884
+
885
+ @object = @klass.new
886
+ @object.state = 'parked'
887
+ end
888
+
889
+ def test_should_be_able_to_fire
890
+ assert @event.can_fire?(@object)
891
+ end
892
+
893
+ def test_should_have_a_transition
894
+ transition = @event.transition_for(@object)
895
+ assert_not_nil transition
896
+ assert_equal 'parked', transition.from
897
+ assert_equal 'first_gear', transition.to
898
+ assert_equal :ignite, transition.event
899
+ end
900
+
901
+ def test_should_allow_specific_transition_selection_using_to
902
+ transition = @event.transition_for(@object, :from => :parked, :to => :second_gear)
903
+
904
+ assert_not_nil transition
905
+ assert_equal 'parked', transition.from
906
+ assert_equal 'second_gear', transition.to
907
+ assert_equal :ignite, transition.event
908
+ end
909
+
910
+ def test_should_not_allow_transition_selection_if_not_matching
911
+ transition = @event.transition_for(@object, :from => :parked, :to => :parked)
912
+ assert_nil transition
913
+ end
914
+
915
+ def test_should_fire
916
+ assert @event.fire(@object)
917
+ end
918
+
919
+ def test_should_change_the_current_state
920
+ @event.fire(@object)
921
+ assert_equal 'first_gear', @object.state
922
+ end
923
+ end
924
+
925
+ class EventWithMultipleTransitionsTest < Test::Unit::TestCase
926
+ def setup
927
+ @klass = Class.new
928
+ @machine = StateMachine::Machine.new(@klass)
929
+ @machine.state :parked, :idling
930
+
931
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
932
+ @event.transition(:idling => :idling)
933
+ @event.transition(:parked => :idling)
934
+ @event.transition(:parked => :parked)
935
+
936
+ @object = @klass.new
937
+ @object.state = 'parked'
938
+ end
939
+
940
+ def test_should_be_able_to_fire
941
+ assert @event.can_fire?(@object)
942
+ end
943
+
944
+ def test_should_have_a_transition
945
+ transition = @event.transition_for(@object)
946
+ assert_not_nil transition
947
+ assert_equal 'parked', transition.from
948
+ assert_equal 'idling', transition.to
949
+ assert_equal :ignite, transition.event
950
+ end
951
+
952
+ def test_should_allow_specific_transition_selection_using_from
953
+ transition = @event.transition_for(@object, :from => :idling)
954
+
955
+ assert_not_nil transition
956
+ assert_equal 'idling', transition.from
957
+ assert_equal 'idling', transition.to
958
+ assert_equal :ignite, transition.event
959
+ end
960
+
961
+ def test_should_allow_specific_transition_selection_using_to
962
+ transition = @event.transition_for(@object, :from => :parked, :to => :parked)
963
+
964
+ assert_not_nil transition
965
+ assert_equal 'parked', transition.from
966
+ assert_equal 'parked', transition.to
967
+ assert_equal :ignite, transition.event
968
+ end
969
+
970
+ def test_should_not_allow_specific_transition_selection_using_on
971
+ exception = assert_raise(ArgumentError) { @event.transition_for(@object, :on => :park) }
972
+ assert_equal 'Invalid key(s): on', exception.message
973
+ end
974
+
975
+ def test_should_fire
976
+ assert @event.fire(@object)
977
+ end
978
+
979
+ def test_should_change_the_current_state
980
+ @event.fire(@object)
981
+ assert_equal 'idling', @object.state
982
+ end
983
+ end
984
+
985
+ class EventWithMachineActionTest < Test::Unit::TestCase
986
+ def setup
987
+ @klass = Class.new do
988
+ attr_reader :saved
989
+
990
+ def save
991
+ @saved = true
992
+ end
993
+ end
994
+
995
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
996
+ @machine.state :parked, :idling
997
+
998
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
999
+ @event.transition(:parked => :idling)
1000
+
1001
+ @object = @klass.new
1002
+ @object.state = 'parked'
1003
+ end
1004
+
1005
+ def test_should_run_action_on_fire
1006
+ @event.fire(@object)
1007
+ assert @object.saved
1008
+ end
1009
+
1010
+ def test_should_not_run_action_if_configured_to_skip
1011
+ @event.fire(@object, false)
1012
+ assert !@object.saved
1013
+ end
1014
+ end
1015
+
1016
+ class EventWithInvalidCurrentStateTest < Test::Unit::TestCase
1017
+ def setup
1018
+ @klass = Class.new
1019
+ @machine = StateMachine::Machine.new(@klass)
1020
+ @machine.state :parked, :idling
1021
+
1022
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
1023
+ @event.transition(:parked => :idling)
1024
+
1025
+ @object = @klass.new
1026
+ @object.state = 'invalid'
1027
+ end
1028
+
1029
+ def test_should_raise_exception_when_checking_availability
1030
+ exception = assert_raise(ArgumentError) { @event.can_fire?(@object) }
1031
+ assert_equal '"invalid" is not a known state value', exception.message
1032
+ end
1033
+
1034
+ def test_should_raise_exception_when_finding_transition
1035
+ exception = assert_raise(ArgumentError) { @event.transition_for(@object) }
1036
+ assert_equal '"invalid" is not a known state value', exception.message
1037
+ end
1038
+
1039
+ def test_should_raise_exception_when_firing
1040
+ exception = assert_raise(ArgumentError) { @event.fire(@object) }
1041
+ assert_equal '"invalid" is not a known state value', exception.message
1042
+ end
1043
+ end
1044
+
1045
+ class EventOnFailureTest < Test::Unit::TestCase
1046
+ def setup
1047
+ StateMachine::Integrations.const_set('Custom', Module.new do
1048
+ include StateMachine::Integrations::Base
1049
+
1050
+ def invalidate(object, attribute, message, values = [])
1051
+ (object.errors ||= []) << generate_message(message, values)
1052
+ end
1053
+
1054
+ def reset(object)
1055
+ object.errors = []
1056
+ end
1057
+ end)
1058
+
1059
+ @klass = Class.new do
1060
+ attr_accessor :errors
1061
+ end
1062
+
1063
+ @machine = StateMachine::Machine.new(@klass, :integration => :custom)
1064
+ @machine.state :parked
1065
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
1066
+
1067
+ @object = @klass.new
1068
+ @object.state = 'parked'
1069
+ end
1070
+
1071
+ def test_should_invalidate_the_state
1072
+ @event.fire(@object)
1073
+ assert_equal ['cannot transition via "ignite"'], @object.errors
1074
+ end
1075
+
1076
+ def test_should_run_failure_callbacks
1077
+ callback_args = nil
1078
+ @machine.after_failure {|*args| callback_args = args}
1079
+
1080
+ @event.fire(@object)
1081
+
1082
+ object, transition = callback_args
1083
+ assert_equal @object, object
1084
+ assert_not_nil transition
1085
+ assert_equal @object, transition.object
1086
+ assert_equal @machine, transition.machine
1087
+ assert_equal :ignite, transition.event
1088
+ assert_equal :parked, transition.from_name
1089
+ assert_equal :parked, transition.to_name
1090
+ end
1091
+
1092
+ def teardown
1093
+ StateMachine::Integrations.send(:remove_const, 'Custom')
1094
+ end
1095
+ end
1096
+
1097
+ class EventWithMarshallingTest < Test::Unit::TestCase
1098
+ def setup
1099
+ @klass = Class.new do
1100
+ def save
1101
+ true
1102
+ end
1103
+ end
1104
+ self.class.const_set('Example', @klass)
1105
+
1106
+ @machine = StateMachine::Machine.new(@klass, :action => :save)
1107
+ @machine.state :parked, :idling
1108
+
1109
+ @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
1110
+ @event.transition(:parked => :idling)
1111
+
1112
+ @object = @klass.new
1113
+ @object.state = 'parked'
1114
+ end
1115
+
1116
+ def test_should_marshal_during_before_callbacks
1117
+ @machine.before_transition {|object, transition| Marshal.dump(object)}
1118
+ assert_nothing_raised { @event.fire(@object) }
1119
+ end
1120
+
1121
+ def test_should_marshal_during_action
1122
+ @klass.class_eval do
1123
+ remove_method :save
1124
+ def save
1125
+ Marshal.dump(self)
1126
+ end
1127
+ end
1128
+
1129
+ assert_nothing_raised { @event.fire(@object) }
1130
+ end
1131
+
1132
+ def test_should_marshal_during_after_callbacks
1133
+ @machine.after_transition {|object, transition| Marshal.dump(object)}
1134
+ assert_nothing_raised { @event.fire(@object) }
1135
+ end
1136
+
1137
+ def teardown
1138
+ self.class.send(:remove_const, 'Example')
1139
+ end
1140
+ end
1141
+
1142
+ begin
1143
+ # Load library
1144
+ require 'graphviz'
1145
+
1146
+ class EventDrawingTest < Test::Unit::TestCase
1147
+ def setup
1148
+ states = [:parked, :idling, :first_gear]
1149
+
1150
+ @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
1151
+ @machine.other_states(*states)
1152
+
1153
+ @graph = StateMachine::Graph.new('test')
1154
+ states.each {|state| @graph.add_nodes(state.to_s)}
1155
+
1156
+ @machine.events << @event = StateMachine::Event.new(@machine , :park)
1157
+ @event.transition :parked => :idling
1158
+ @event.transition :first_gear => :parked
1159
+ @event.transition :except_from => :parked, :to => :parked
1160
+
1161
+ @event.draw(@graph)
1162
+ end
1163
+
1164
+ def test_should_generate_edges_for_each_transition
1165
+ assert_equal 4, @graph.edge_count
1166
+ end
1167
+
1168
+ def test_should_use_event_name_for_edge_label
1169
+ assert_equal 'park', @graph.get_edge_at_index(0)['label'].to_s.gsub('"', '')
1170
+ end
1171
+ end
1172
+
1173
+ class EventDrawingWithHumanNameTest < Test::Unit::TestCase
1174
+ def setup
1175
+ states = [:parked, :idling]
1176
+
1177
+ @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
1178
+ @machine.other_states(*states)
1179
+
1180
+ graph = StateMachine::Graph.new('test')
1181
+ states.each {|state| graph.add_nodes(state.to_s)}
1182
+
1183
+ @machine.events << @event = StateMachine::Event.new(@machine , :park, :human_name => 'Park')
1184
+ @event.transition :parked => :idling
1185
+
1186
+ @event.draw(graph, :human_name => true)
1187
+ @edge = graph.get_edge_at_index(0)
1188
+ end
1189
+
1190
+ def test_should_use_event_human_name_for_edge_label
1191
+ assert_equal 'Park', @edge['label'].to_s.gsub('"', '')
1192
+ end
1193
+ end
1194
+ rescue LoadError
1195
+ $stderr.puts 'Skipping GraphViz StateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.17 and try again.'
1196
+ end unless ENV['TRAVIS']