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,31 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class StateMachineByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @klass = Class.new
6
+ @machine = @klass.state_machine
7
+ end
8
+
9
+ def test_should_use_state_attribute
10
+ assert_equal :state, @machine.attribute
11
+ end
12
+ end
13
+
14
+ class StateMachineTest < Test::Unit::TestCase
15
+ def setup
16
+ @klass = Class.new
17
+ end
18
+
19
+ def test_should_allow_state_machines_on_any_class
20
+ assert @klass.respond_to?(:state_machine)
21
+ end
22
+
23
+ def test_should_evaluate_block_within_machine_context
24
+ responded = false
25
+ @klass.state_machine(:state) do
26
+ responded = respond_to?(:event)
27
+ end
28
+
29
+ assert responded
30
+ end
31
+ end
@@ -0,0 +1,1101 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class StateByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @machine = StateMachine::Machine.new(Class.new)
6
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
7
+ end
8
+
9
+ def test_should_have_a_machine
10
+ assert_equal @machine, @state.machine
11
+ end
12
+
13
+ def test_should_have_a_name
14
+ assert_equal :parked, @state.name
15
+ end
16
+
17
+ def test_should_have_a_qualified_name
18
+ assert_equal :parked, @state.qualified_name
19
+ end
20
+
21
+ def test_should_have_a_human_name
22
+ assert_equal 'parked', @state.human_name
23
+ end
24
+
25
+ def test_should_use_stringify_the_name_as_the_value
26
+ assert_equal 'parked', @state.value
27
+ end
28
+
29
+ def test_should_not_be_initial
30
+ assert !@state.initial
31
+ end
32
+
33
+ def test_should_not_have_a_matcher
34
+ assert_nil @state.matcher
35
+ end
36
+
37
+ def test_should_not_have_any_methods
38
+ expected = {}
39
+ assert_equal expected, @state.context_methods
40
+ end
41
+ end
42
+
43
+ class StateTest < Test::Unit::TestCase
44
+ def setup
45
+ @machine = StateMachine::Machine.new(Class.new)
46
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
47
+ end
48
+
49
+ def test_should_raise_exception_if_invalid_option_specified
50
+ exception = assert_raise(ArgumentError) {StateMachine::State.new(@machine, :parked, :invalid => true)}
51
+ assert_equal 'Invalid key(s): invalid', exception.message
52
+ end
53
+
54
+ def test_should_allow_changing_machine
55
+ new_machine = StateMachine::Machine.new(Class.new)
56
+ @state.machine = new_machine
57
+ assert_equal new_machine, @state.machine
58
+ end
59
+
60
+ def test_should_allow_changing_value
61
+ @state.value = 1
62
+ assert_equal 1, @state.value
63
+ end
64
+
65
+ def test_should_allow_changing_initial
66
+ @state.initial = true
67
+ assert @state.initial
68
+ end
69
+
70
+ def test_should_allow_changing_matcher
71
+ matcher = lambda {}
72
+ @state.matcher = matcher
73
+ assert_equal matcher, @state.matcher
74
+ end
75
+
76
+ def test_should_allow_changing_human_name
77
+ @state.human_name = 'stopped'
78
+ assert_equal 'stopped', @state.human_name
79
+ end
80
+
81
+ def test_should_use_pretty_inspect
82
+ assert_equal '#<StateMachine::State name=:parked value="parked" initial=false>', @state.inspect
83
+ end
84
+ end
85
+
86
+ class StateWithoutNameTest < Test::Unit::TestCase
87
+ def setup
88
+ @klass = Class.new
89
+ @machine = StateMachine::Machine.new(@klass)
90
+ @machine.states << @state = StateMachine::State.new(@machine, nil)
91
+ end
92
+
93
+ def test_should_have_a_nil_name
94
+ assert_nil @state.name
95
+ end
96
+
97
+ def test_should_have_a_nil_qualified_name
98
+ assert_nil @state.qualified_name
99
+ end
100
+
101
+ def test_should_have_an_empty_human_name
102
+ assert_equal 'nil', @state.human_name
103
+ end
104
+
105
+ def test_should_have_a_nil_value
106
+ assert_nil @state.value
107
+ end
108
+
109
+ def test_should_not_redefine_nil_predicate
110
+ object = @klass.new
111
+ assert !object.nil?
112
+ assert !object.respond_to?('?')
113
+ end
114
+
115
+ def test_should_have_a_description
116
+ assert_equal 'nil', @state.description
117
+ end
118
+
119
+ def test_should_have_a_description_using_human_name
120
+ assert_equal 'nil', @state.description(:human_name => true)
121
+ end
122
+ end
123
+
124
+ class StateWithNameTest < Test::Unit::TestCase
125
+ def setup
126
+ @klass = Class.new
127
+ @machine = StateMachine::Machine.new(@klass)
128
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
129
+ end
130
+
131
+ def test_should_have_a_name
132
+ assert_equal :parked, @state.name
133
+ end
134
+
135
+ def test_should_have_a_qualified_name
136
+ assert_equal :parked, @state.name
137
+ end
138
+
139
+ def test_should_have_a_human_name
140
+ assert_equal 'parked', @state.human_name
141
+ end
142
+
143
+ def test_should_use_stringify_the_name_as_the_value
144
+ assert_equal 'parked', @state.value
145
+ end
146
+
147
+ def test_should_match_stringified_name
148
+ assert @state.matches?('parked')
149
+ assert !@state.matches?('idling')
150
+ end
151
+
152
+ def test_should_not_include_value_in_description
153
+ assert_equal 'parked', @state.description
154
+ end
155
+
156
+ def test_should_allow_using_human_name_in_description
157
+ @state.human_name = 'Parked'
158
+ assert_equal 'Parked', @state.description(:human_name => true)
159
+ end
160
+
161
+ def test_should_define_predicate
162
+ assert @klass.new.respond_to?(:parked?)
163
+ end
164
+ end
165
+
166
+ class StateWithNilValueTest < Test::Unit::TestCase
167
+ def setup
168
+ @klass = Class.new
169
+ @machine = StateMachine::Machine.new(@klass)
170
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => nil)
171
+ end
172
+
173
+ def test_should_have_a_name
174
+ assert_equal :parked, @state.name
175
+ end
176
+
177
+ def test_should_have_a_nil_value
178
+ assert_nil @state.value
179
+ end
180
+
181
+ def test_should_match_nil_values
182
+ assert @state.matches?(nil)
183
+ end
184
+
185
+ def test_should_have_a_description
186
+ assert_equal 'parked (nil)', @state.description
187
+ end
188
+
189
+ def test_should_have_a_description_with_human_name
190
+ @state.human_name = 'Parked'
191
+ assert_equal 'Parked (nil)', @state.description(:human_name => true)
192
+ end
193
+
194
+ def test_should_define_predicate
195
+ object = @klass.new
196
+ assert object.respond_to?(:parked?)
197
+ end
198
+ end
199
+
200
+ class StateWithSymbolicValueTest < Test::Unit::TestCase
201
+ def setup
202
+ @klass = Class.new
203
+ @machine = StateMachine::Machine.new(@klass)
204
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => :parked)
205
+ end
206
+
207
+ def test_should_use_custom_value
208
+ assert_equal :parked, @state.value
209
+ end
210
+
211
+ def test_should_not_include_value_in_description
212
+ assert_equal 'parked', @state.description
213
+ end
214
+
215
+ def test_should_allow_human_name_in_description
216
+ @state.human_name = 'Parked'
217
+ assert_equal 'Parked', @state.description(:human_name => true)
218
+ end
219
+
220
+ def test_should_match_symbolic_value
221
+ assert @state.matches?(:parked)
222
+ assert !@state.matches?('parked')
223
+ end
224
+
225
+ def test_should_define_predicate
226
+ object = @klass.new
227
+ assert object.respond_to?(:parked?)
228
+ end
229
+ end
230
+
231
+ class StateWithIntegerValueTest < Test::Unit::TestCase
232
+ def setup
233
+ @klass = Class.new
234
+ @machine = StateMachine::Machine.new(@klass)
235
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => 1)
236
+ end
237
+
238
+ def test_should_use_custom_value
239
+ assert_equal 1, @state.value
240
+ end
241
+
242
+ def test_should_include_value_in_description
243
+ assert_equal 'parked (1)', @state.description
244
+ end
245
+
246
+ def test_should_allow_human_name_in_description
247
+ @state.human_name = 'Parked'
248
+ assert_equal 'Parked (1)', @state.description(:human_name => true)
249
+ end
250
+
251
+ def test_should_match_integer_value
252
+ assert @state.matches?(1)
253
+ assert !@state.matches?(2)
254
+ end
255
+
256
+ def test_should_define_predicate
257
+ object = @klass.new
258
+ assert object.respond_to?(:parked?)
259
+ end
260
+ end
261
+
262
+ class StateWithLambdaValueTest < Test::Unit::TestCase
263
+ def setup
264
+ @klass = Class.new
265
+ @args = nil
266
+ @machine = StateMachine::Machine.new(@klass)
267
+ @value = lambda {|*args| @args = args; :parked}
268
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @value)
269
+ end
270
+
271
+ def test_should_use_evaluated_value_by_default
272
+ assert_equal :parked, @state.value
273
+ end
274
+
275
+ def test_should_allow_access_to_original_value
276
+ assert_equal @value, @state.value(false)
277
+ end
278
+
279
+ def test_should_include_masked_value_in_description
280
+ assert_equal 'parked (*)', @state.description
281
+ end
282
+
283
+ def test_should_not_pass_in_any_arguments
284
+ @state.value
285
+ assert_equal [], @args
286
+ end
287
+
288
+ def test_should_define_predicate
289
+ object = @klass.new
290
+ assert object.respond_to?(:parked?)
291
+ end
292
+
293
+ def test_should_match_evaluated_value
294
+ assert @state.matches?(:parked)
295
+ end
296
+ end
297
+
298
+ class StateWithCachedLambdaValueTest < Test::Unit::TestCase
299
+ def setup
300
+ @klass = Class.new
301
+ @machine = StateMachine::Machine.new(@klass)
302
+ @dynamic_value = lambda {'value'}
303
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @dynamic_value, :cache => true)
304
+ end
305
+
306
+ def test_should_be_caching
307
+ assert @state.cache
308
+ end
309
+
310
+ def test_should_evaluate_value
311
+ assert_equal 'value', @state.value
312
+ end
313
+
314
+ def test_should_only_evaluate_value_once
315
+ value = @state.value
316
+ assert_same value, @state.value
317
+ end
318
+
319
+ def test_should_update_value_index_for_state_collection
320
+ @state.value
321
+ assert_equal @state, @machine.states['value', :value]
322
+ assert_nil @machine.states[@dynamic_value, :value]
323
+ end
324
+ end
325
+
326
+ class StateWithoutCachedLambdaValueTest < Test::Unit::TestCase
327
+ def setup
328
+ @klass = Class.new
329
+ @machine = StateMachine::Machine.new(@klass)
330
+ @dynamic_value = lambda {'value'}
331
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => @dynamic_value)
332
+ end
333
+
334
+ def test_should_not_be_caching
335
+ assert !@state.cache
336
+ end
337
+
338
+ def test_should_evaluate_value_each_time
339
+ value = @state.value
340
+ assert_not_same value, @state.value
341
+ end
342
+
343
+ def test_should_not_update_value_index_for_state_collection
344
+ @state.value
345
+ assert_nil @machine.states['value', :value]
346
+ assert_equal @state, @machine.states[@dynamic_value, :value]
347
+ end
348
+ end
349
+
350
+ class StateWithMatcherTest < Test::Unit::TestCase
351
+ def setup
352
+ @klass = Class.new
353
+ @args = nil
354
+ @machine = StateMachine::Machine.new(@klass)
355
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :if => lambda {|value| value == 1})
356
+ end
357
+
358
+ def test_should_not_match_actual_value
359
+ assert !@state.matches?('parked')
360
+ end
361
+
362
+ def test_should_match_evaluated_block
363
+ assert @state.matches?(1)
364
+ end
365
+ end
366
+
367
+ class StateWithHumanNameTest < Test::Unit::TestCase
368
+ def setup
369
+ @klass = Class.new
370
+ @machine = StateMachine::Machine.new(@klass)
371
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :human_name => 'stopped')
372
+ end
373
+
374
+ def test_should_use_custom_human_name
375
+ assert_equal 'stopped', @state.human_name
376
+ end
377
+ end
378
+
379
+ class StateWithDynamicHumanNameTest < Test::Unit::TestCase
380
+ def setup
381
+ @klass = Class.new
382
+ @machine = StateMachine::Machine.new(@klass)
383
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :human_name => lambda {|state, object| ['stopped', object]})
384
+ end
385
+
386
+ def test_should_use_custom_human_name
387
+ human_name, klass = @state.human_name
388
+ assert_equal 'stopped', human_name
389
+ assert_equal @klass, klass
390
+ end
391
+
392
+ def test_should_allow_custom_class_to_be_passed_through
393
+ human_name, klass = @state.human_name(1)
394
+ assert_equal 'stopped', human_name
395
+ assert_equal 1, klass
396
+ end
397
+
398
+ def test_should_not_cache_value
399
+ assert_not_same @state.human_name, @state.human_name
400
+ end
401
+ end
402
+
403
+ class StateInitialTest < Test::Unit::TestCase
404
+ def setup
405
+ @machine = StateMachine::Machine.new(Class.new)
406
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :initial => true)
407
+ end
408
+
409
+ def test_should_be_initial
410
+ assert @state.initial
411
+ assert @state.initial?
412
+ end
413
+ end
414
+
415
+ class StateNotInitialTest < Test::Unit::TestCase
416
+ def setup
417
+ @machine = StateMachine::Machine.new(Class.new)
418
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :initial => false)
419
+ end
420
+
421
+ def test_should_not_be_initial
422
+ assert !@state.initial
423
+ assert !@state.initial?
424
+ end
425
+ end
426
+
427
+ class StateFinalTest < Test::Unit::TestCase
428
+ def setup
429
+ @machine = StateMachine::Machine.new(Class.new)
430
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
431
+ end
432
+
433
+ def test_should_be_final_without_input_transitions
434
+ assert @state.final?
435
+ end
436
+
437
+ def test_should_be_final_with_input_transitions
438
+ @machine.event :park do
439
+ transition :idling => :parked
440
+ end
441
+
442
+ assert @state.final?
443
+ end
444
+
445
+ def test_should_be_final_with_loopback
446
+ @machine.event :ignite do
447
+ transition :parked => same
448
+ end
449
+
450
+ assert @state.final?
451
+ end
452
+ end
453
+
454
+ class StateNotFinalTest < Test::Unit::TestCase
455
+ def setup
456
+ @machine = StateMachine::Machine.new(Class.new)
457
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
458
+ end
459
+
460
+ def test_should_not_be_final_with_outgoing_whitelist_transitions
461
+ @machine.event :ignite do
462
+ transition :parked => :idling
463
+ end
464
+
465
+ assert !@state.final?
466
+ end
467
+
468
+ def test_should_not_be_final_with_outgoing_all_transitions
469
+ @machine.event :ignite do
470
+ transition all => :idling
471
+ end
472
+
473
+ assert !@state.final?
474
+ end
475
+
476
+ def test_should_not_be_final_with_outgoing_blacklist_transitions
477
+ @machine.event :ignite do
478
+ transition all - :first_gear => :idling
479
+ end
480
+
481
+ assert !@state.final?
482
+ end
483
+ end
484
+
485
+ class StateWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
486
+ def setup
487
+ require 'stringio'
488
+ @original_stderr, $stderr = $stderr, StringIO.new
489
+
490
+ @superclass = Class.new do
491
+ def parked?
492
+ 0
493
+ end
494
+ end
495
+ @klass = Class.new(@superclass)
496
+ @machine = StateMachine::Machine.new(@klass)
497
+ @machine.state :parked
498
+ @object = @klass.new
499
+ end
500
+
501
+ def test_should_not_override_state_predicate
502
+ assert_equal 0, @object.parked?
503
+ end
504
+
505
+ def test_should_output_warning
506
+ assert_equal "Instance method \"parked?\" is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
507
+ end
508
+
509
+ def teardown
510
+ $stderr = @original_stderr
511
+ end
512
+ end
513
+
514
+ class StateWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
515
+ def setup
516
+ require 'stringio'
517
+ @original_stderr, $stderr = $stderr, StringIO.new
518
+
519
+ @klass = Class.new do
520
+ def parked?
521
+ 0
522
+ end
523
+ end
524
+ @machine = StateMachine::Machine.new(@klass)
525
+ @machine.state :parked
526
+ @object = @klass.new
527
+ end
528
+
529
+ def test_should_not_override_state_predicate
530
+ assert_equal 0, @object.parked?
531
+ end
532
+
533
+ def test_should_still_allow_super_chaining
534
+ @klass.class_eval do
535
+ def parked?
536
+ super
537
+ end
538
+ end
539
+
540
+ assert_equal false, @object.parked?
541
+ end
542
+
543
+ def test_should_not_output_warning
544
+ assert_equal '', $stderr.string
545
+ end
546
+
547
+ def teardown
548
+ $stderr = @original_stderr
549
+ end
550
+ end
551
+
552
+ class StateWithConflictingMachineTest < Test::Unit::TestCase
553
+ def setup
554
+ require 'stringio'
555
+ @original_stderr, $stderr = $stderr, StringIO.new
556
+
557
+ @klass = Class.new
558
+ @state_machine = StateMachine::Machine.new(@klass, :state)
559
+ @state_machine.states << @state = StateMachine::State.new(@state_machine, :parked)
560
+ end
561
+
562
+ def test_should_output_warning_if_using_different_attribute
563
+ @status_machine = StateMachine::Machine.new(@klass, :status)
564
+ @status_machine.states << @state = StateMachine::State.new(@status_machine, :parked)
565
+
566
+ assert_equal "State :parked for :status is already defined in :state\n", $stderr.string
567
+ end
568
+
569
+ def test_should_not_output_warning_if_using_same_attribute
570
+ @status_machine = StateMachine::Machine.new(@klass, :status, :attribute => :state)
571
+ @status_machine.states << @state = StateMachine::State.new(@status_machine, :parked)
572
+
573
+ assert_equal '', $stderr.string
574
+ end
575
+
576
+ def test_should_not_output_warning_if_using_different_namespace
577
+ @status_machine = StateMachine::Machine.new(@klass, :status, :namespace => 'alarm')
578
+ @status_machine.states << @state = StateMachine::State.new(@status_machine, :parked)
579
+
580
+ assert_equal '', $stderr.string
581
+ end
582
+
583
+ def teardown
584
+ $stderr = @original_stderr
585
+ end
586
+ end
587
+
588
+ class StateWithConflictingMachineNameTest < Test::Unit::TestCase
589
+ def setup
590
+ require 'stringio'
591
+ @original_stderr, $stderr = $stderr, StringIO.new
592
+
593
+ @klass = Class.new
594
+ @state_machine = StateMachine::Machine.new(@klass, :state)
595
+ end
596
+
597
+ def test_should_output_warning_if_name_conflicts
598
+ StateMachine::State.new(@state_machine, :state)
599
+ assert_equal "Instance method \"state?\" is already defined in #{@klass} :state instance helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string
600
+ end
601
+
602
+ def teardown
603
+ $stderr = @original_stderr
604
+ end
605
+ end
606
+
607
+ class StateWithNamespaceTest < Test::Unit::TestCase
608
+ def setup
609
+ @klass = Class.new
610
+ @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
611
+ @machine.states << @state = StateMachine::State.new(@machine, :active)
612
+ @object = @klass.new
613
+ end
614
+
615
+ def test_should_have_a_name
616
+ assert_equal :active, @state.name
617
+ end
618
+
619
+ def test_should_have_a_qualified_name
620
+ assert_equal :alarm_active, @state.qualified_name
621
+ end
622
+
623
+ def test_should_namespace_predicate
624
+ assert @object.respond_to?(:alarm_active?)
625
+ end
626
+ end
627
+
628
+ class StateAfterBeingCopiedTest < Test::Unit::TestCase
629
+ def setup
630
+ @machine = StateMachine::Machine.new(Class.new)
631
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
632
+ @copied_state = @state.dup
633
+ end
634
+
635
+ def test_should_not_have_the_context
636
+ state_context = nil
637
+ @state.context { state_context = self }
638
+
639
+ copied_state_context = nil
640
+ @copied_state.context { copied_state_context = self }
641
+
642
+ assert_not_same state_context, copied_state_context
643
+ end
644
+ end
645
+
646
+ class StateWithContextTest < Test::Unit::TestCase
647
+ def setup
648
+ @klass = Class.new
649
+ @machine = StateMachine::Machine.new(@klass)
650
+ @ancestors = @klass.ancestors
651
+ @machine.states << @state = StateMachine::State.new(@machine, :idling)
652
+
653
+ context = nil
654
+ speed_method = nil
655
+ rpm_method = nil
656
+ @result = @state.context do
657
+ context = self
658
+
659
+ def speed
660
+ 0
661
+ end
662
+ speed_method = instance_method(:speed)
663
+
664
+ def rpm
665
+ 1000
666
+ end
667
+ rpm_method = instance_method(:rpm)
668
+ end
669
+
670
+ @context = context
671
+ @speed_method = speed_method
672
+ @rpm_method = rpm_method
673
+ end
674
+
675
+ def test_should_return_true
676
+ assert_equal true, @result
677
+ end
678
+
679
+ def test_should_include_new_module_in_owner_class
680
+ assert_not_equal @ancestors, @klass.ancestors
681
+ assert_equal [@context], @klass.ancestors - @ancestors
682
+ end
683
+
684
+ def test_should_define_each_context_method_in_owner_class
685
+ %w(speed rpm).each {|method| assert @klass.method_defined?(method)}
686
+ end
687
+
688
+ def test_should_define_aliased_context_method_in_owner_class
689
+ %w(speed rpm).each {|method| assert @klass.method_defined?("__state_idling_#{method}_#{@context.object_id}__")}
690
+ end
691
+
692
+ def test_should_not_use_context_methods_as_owner_class_methods
693
+ assert_not_equal @speed_method, @state.context_methods[:speed]
694
+ assert_not_equal @rpm_method, @state.context_methods[:rpm]
695
+ end
696
+
697
+ def test_should_use_context_methods_as_aliased_owner_class_methods
698
+ assert_equal @speed_method, @state.context_methods[:"__state_idling_speed_#{@context.object_id}__"]
699
+ assert_equal @rpm_method, @state.context_methods[:"__state_idling_rpm_#{@context.object_id}__"]
700
+ end
701
+ end
702
+
703
+ class StateWithMultipleContextsTest < Test::Unit::TestCase
704
+ def setup
705
+ @klass = Class.new
706
+ @machine = StateMachine::Machine.new(@klass)
707
+ @ancestors = @klass.ancestors
708
+ @machine.states << @state = StateMachine::State.new(@machine, :idling)
709
+
710
+ context = nil
711
+ speed_method = nil
712
+ @state.context do
713
+ context = self
714
+ def speed
715
+ 0
716
+ end
717
+
718
+ speed_method = instance_method(:speed)
719
+ end
720
+ @context = context
721
+ @speed_method = speed_method
722
+
723
+ rpm_method = nil
724
+ @state.context do
725
+ def rpm
726
+ 1000
727
+ end
728
+
729
+ rpm_method = instance_method(:rpm)
730
+ end
731
+ @rpm_method = rpm_method
732
+ end
733
+
734
+ def test_should_include_new_module_in_owner_class
735
+ assert_not_equal @ancestors, @klass.ancestors
736
+ assert_equal [@context], @klass.ancestors - @ancestors
737
+ end
738
+
739
+ def test_should_define_each_context_method_in_owner_class
740
+ %w(speed rpm).each {|method| assert @klass.method_defined?(method)}
741
+ end
742
+
743
+ def test_should_define_aliased_context_method_in_owner_class
744
+ %w(speed rpm).each {|method| assert @klass.method_defined?("__state_idling_#{method}_#{@context.object_id}__")}
745
+ end
746
+
747
+ def test_should_not_use_context_methods_as_owner_class_methods
748
+ assert_not_equal @speed_method, @state.context_methods[:speed]
749
+ assert_not_equal @rpm_method, @state.context_methods[:rpm]
750
+ end
751
+
752
+ def test_should_use_context_methods_as_aliased_owner_class_methods
753
+ assert_equal @speed_method, @state.context_methods[:"__state_idling_speed_#{@context.object_id}__"]
754
+ assert_equal @rpm_method, @state.context_methods[:"__state_idling_rpm_#{@context.object_id}__"]
755
+ end
756
+ end
757
+
758
+ class StateWithExistingContextMethodTest < Test::Unit::TestCase
759
+ def setup
760
+ @klass = Class.new do
761
+ def speed
762
+ 60
763
+ end
764
+ end
765
+ @original_speed_method = @klass.instance_method(:speed)
766
+
767
+ @machine = StateMachine::Machine.new(@klass)
768
+ @machine.states << @state = StateMachine::State.new(@machine, :idling)
769
+ @state.context do
770
+ def speed
771
+ 0
772
+ end
773
+ end
774
+ end
775
+
776
+ def test_should_not_override_method
777
+ assert_equal @original_speed_method, @klass.instance_method(:speed)
778
+ end
779
+ end
780
+
781
+ class StateWithRedefinedContextMethodTest < Test::Unit::TestCase
782
+ def setup
783
+ @klass = Class.new
784
+ @machine = StateMachine::Machine.new(@klass)
785
+ @machine.states << @state = StateMachine::State.new(@machine, 'on')
786
+
787
+ old_context = nil
788
+ old_speed_method = nil
789
+ @state.context do
790
+ old_context = self
791
+ def speed
792
+ 0
793
+ end
794
+ old_speed_method = instance_method(:speed)
795
+ end
796
+ @old_context = old_context
797
+ @old_speed_method = old_speed_method
798
+
799
+ current_context = nil
800
+ current_speed_method = nil
801
+ @state.context do
802
+ current_context = self
803
+ def speed
804
+ 'green'
805
+ end
806
+ current_speed_method = instance_method(:speed)
807
+ end
808
+ @current_context = current_context
809
+ @current_speed_method = current_speed_method
810
+ end
811
+
812
+ def test_should_track_latest_defined_method
813
+ assert_equal @current_speed_method, @state.context_methods[:"__state_on_speed_#{@current_context.object_id}__"]
814
+ end
815
+
816
+ def test_should_have_the_same_context
817
+ assert_equal @current_context, @old_context
818
+ end
819
+ end
820
+
821
+ class StateWithInvalidMethodCallTest < Test::Unit::TestCase
822
+ def setup
823
+ @klass = Class.new
824
+ @machine = StateMachine::Machine.new(@klass)
825
+ @ancestors = @klass.ancestors
826
+ @machine.states << @state = StateMachine::State.new(@machine, :idling)
827
+ @state.context do
828
+ def speed
829
+ 0
830
+ end
831
+ end
832
+
833
+ @object = @klass.new
834
+ end
835
+
836
+ def test_should_call_method_missing_arg
837
+ assert_equal 1, @state.call(@object, :invalid, :method_missing => lambda {1})
838
+ end
839
+ end
840
+
841
+ class StateWithValidMethodCallForDifferentStateTest < Test::Unit::TestCase
842
+ def setup
843
+ @klass = Class.new
844
+ @machine = StateMachine::Machine.new(@klass)
845
+ @ancestors = @klass.ancestors
846
+ @machine.states << @state = StateMachine::State.new(@machine, :idling)
847
+ @state.context do
848
+ def speed
849
+ 0
850
+ end
851
+ end
852
+
853
+ @object = @klass.new
854
+ end
855
+
856
+ def test_should_call_method_missing_arg
857
+ assert_equal 1, @state.call(@object, :speed, :method_missing => lambda {1})
858
+ end
859
+
860
+ def test_should_raise_invalid_context_on_no_method_error
861
+ exception = assert_raise(StateMachine::InvalidContext) do
862
+ @state.call(@object, :speed, :method_missing => lambda { raise NoMethodError.new('Invalid', :speed, [])})
863
+ end
864
+ assert_equal @object, exception.object
865
+ assert_equal 'State nil for :state is not a valid context for calling #speed', exception.message
866
+ end
867
+
868
+ def test_should_raise_original_error_on_no_method_error_with_different_arguments
869
+ assert_raise(NoMethodError) do
870
+ @state.call(@object, :speed, :method_missing => lambda { raise NoMethodError.new('Invalid', :speed, [1])})
871
+ end
872
+ end
873
+
874
+ def test_should_raise_original_error_on_no_method_error_for_different_method
875
+ assert_raise(NoMethodError) do
876
+ @state.call(@object, :speed, :method_missing => lambda { raise NoMethodError.new('Invalid', :rpm, [])})
877
+ end
878
+ end
879
+ end
880
+
881
+ class StateWithValidMethodCallForCurrentStateTest < Test::Unit::TestCase
882
+ def setup
883
+ @klass = Class.new
884
+ @machine = StateMachine::Machine.new(@klass, :initial => :idling)
885
+ @ancestors = @klass.ancestors
886
+ @state = @machine.state(:idling)
887
+ @state.context do
888
+ def speed(arg = nil)
889
+ block_given? ? [arg, yield] : arg
890
+ end
891
+ end
892
+
893
+ @object = @klass.new
894
+ end
895
+
896
+ def test_should_not_raise_an_exception
897
+ assert_nothing_raised { @state.call(@object, :speed, :method_missing => lambda {raise}) }
898
+ end
899
+
900
+ def test_should_pass_arguments_through
901
+ assert_equal 1, @state.call(@object, :speed, 1, :method_missing => lambda {})
902
+ end
903
+
904
+ def test_should_pass_blocks_through
905
+ assert_equal [nil, 1], @state.call(@object, :speed) {1}
906
+ end
907
+
908
+ def test_should_pass_both_arguments_and_blocks_through
909
+ assert_equal [1, 2], @state.call(@object, :speed, 1, :method_missing => lambda {}) {2}
910
+ end
911
+ end
912
+
913
+ if RUBY_VERSION > '1.8.7'
914
+ class StateWithValidInheritedMethodCallForCurrentStateTest < Test::Unit::TestCase
915
+ def setup
916
+ @superclass = Class.new do
917
+ def speed(arg = nil)
918
+ [arg]
919
+ end
920
+ end
921
+ @klass = Class.new(@superclass)
922
+ @machine = StateMachine::Machine.new(@klass, :initial => :idling)
923
+ @ancestors = @klass.ancestors
924
+ @state = @machine.state(:idling)
925
+ @state.context do
926
+ def speed(arg = nil)
927
+ [arg] + super(2)
928
+ end
929
+ end
930
+
931
+ @object = @klass.new
932
+ end
933
+
934
+ def test_should_not_raise_an_exception
935
+ assert_nothing_raised { @state.call(@object, :speed, :method_missing => lambda {raise}) }
936
+ end
937
+
938
+ def test_should_be_able_to_call_super
939
+ assert_equal [1, 2], @state.call(@object, :speed, 1)
940
+ end
941
+
942
+ def test_should_allow_redefinition
943
+ @state.context do
944
+ def speed(arg = nil)
945
+ [arg] + super(3)
946
+ end
947
+ end
948
+
949
+ assert_equal [1, 3], @state.call(@object, :speed, 1)
950
+ end
951
+ end
952
+ end
953
+
954
+ begin
955
+ # Load library
956
+ require 'graphviz'
957
+
958
+ class StateDrawingTest < Test::Unit::TestCase
959
+ def setup
960
+ @machine = StateMachine::Machine.new(Class.new)
961
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => 1)
962
+ @machine.event :ignite do
963
+ transition :parked => :idling
964
+ end
965
+
966
+ graph = StateMachine::Graph.new('test')
967
+ @state.draw(graph)
968
+ @node = graph.get_node('parked')
969
+ end
970
+
971
+ def test_should_use_ellipse_shape
972
+ assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
973
+ end
974
+
975
+ def test_should_set_width_to_one
976
+ assert_equal '1', @node['width'].to_s.gsub('"', '')
977
+ end
978
+
979
+ def test_should_set_height_to_one
980
+ assert_equal '1', @node['height'].to_s.gsub('"', '')
981
+ end
982
+
983
+ def test_should_use_description_as_label
984
+ assert_equal 'parked (1)', @node['label'].to_s.gsub('"', '')
985
+ end
986
+ end
987
+
988
+ class StateDrawingInitialTest < Test::Unit::TestCase
989
+ def setup
990
+ @machine = StateMachine::Machine.new(Class.new)
991
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :initial => true)
992
+ @machine.event :ignite do
993
+ transition :parked => :idling
994
+ end
995
+
996
+ @graph = StateMachine::Graph.new('test')
997
+ @state.draw(@graph)
998
+ @node = @graph.get_node('parked')
999
+ end
1000
+
1001
+ def test_should_use_ellipse_as_shape
1002
+ assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
1003
+ end
1004
+
1005
+ def test_should_draw_edge_between_point_and_state
1006
+ assert_equal 2, @graph.node_count
1007
+ assert_equal 1, @graph.edge_count
1008
+ end
1009
+ end
1010
+
1011
+ class StateDrawingNilNameTest < Test::Unit::TestCase
1012
+ def setup
1013
+ @machine = StateMachine::Machine.new(Class.new)
1014
+ @machine.states << @state = StateMachine::State.new(@machine, nil)
1015
+
1016
+ graph = StateMachine::Graph.new('test')
1017
+ @state.draw(graph)
1018
+ @node = graph.get_node('nil')
1019
+ end
1020
+
1021
+ def test_should_have_a_node
1022
+ assert_not_nil @node
1023
+ end
1024
+
1025
+ def test_should_use_description_as_label
1026
+ assert_equal 'nil', @node['label'].to_s.gsub('"', '')
1027
+ end
1028
+ end
1029
+
1030
+ class StateDrawingLambdaValueTest < Test::Unit::TestCase
1031
+ def setup
1032
+ @machine = StateMachine::Machine.new(Class.new)
1033
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :value => lambda {})
1034
+
1035
+ graph = StateMachine::Graph.new('test')
1036
+ @state.draw(graph)
1037
+ @node = graph.get_node('parked')
1038
+ end
1039
+
1040
+ def test_should_have_a_node
1041
+ assert_not_nil @node
1042
+ end
1043
+
1044
+ def test_should_use_description_as_label
1045
+ assert_equal 'parked (*)', @node['label'].to_s.gsub('"', '')
1046
+ end
1047
+ end
1048
+
1049
+ class StateDrawingNonFinalTest < Test::Unit::TestCase
1050
+ def setup
1051
+ @machine = StateMachine::Machine.new(Class.new)
1052
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
1053
+ @machine.event :ignite do
1054
+ transition :parked => :idling
1055
+ end
1056
+
1057
+ graph = StateMachine::Graph.new('test')
1058
+ @state.draw(graph)
1059
+ @node = graph.get_node('parked')
1060
+ end
1061
+
1062
+ def test_should_use_ellipse_as_shape
1063
+ assert_equal 'ellipse', @node['shape'].to_s.gsub('"', '')
1064
+ end
1065
+ end
1066
+
1067
+ class StateDrawingFinalTest < Test::Unit::TestCase
1068
+ def setup
1069
+ @machine = StateMachine::Machine.new(Class.new)
1070
+ @machine.states << @state = StateMachine::State.new(@machine, :parked)
1071
+
1072
+ graph = StateMachine::Graph.new('test')
1073
+ @state.draw(graph)
1074
+ @node = graph.get_node('parked')
1075
+ end
1076
+
1077
+ def test_should_use_doublecircle_as_shape
1078
+ assert_equal 'doublecircle', @node['shape'].to_s.gsub('"', '')
1079
+ end
1080
+ end
1081
+
1082
+ class StateDrawingWithHumanNameTest < Test::Unit::TestCase
1083
+ def setup
1084
+ @machine = StateMachine::Machine.new(Class.new)
1085
+ @machine.states << @state = StateMachine::State.new(@machine, :parked, :human_name => 'Parked')
1086
+ @machine.event :ignite do
1087
+ transition :parked => :idling
1088
+ end
1089
+
1090
+ graph = StateMachine::Graph.new('test')
1091
+ @state.draw(graph, :human_name => true)
1092
+ @node = graph.get_node('parked')
1093
+ end
1094
+
1095
+ def test_should_use_description_with_human_name_as_label
1096
+ assert_equal 'Parked', @node['label'].to_s.gsub('"', '')
1097
+ end
1098
+ end
1099
+ rescue LoadError
1100
+ $stderr.puts 'Skipping GraphViz StateMachine::State tests. `gem install ruby-graphviz` >= v0.9.17 and try again.'
1101
+ end unless ENV['TRAVIS']