PageRenderTime 63ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/plugins/state_machine/test/unit/transition_test.rb

https://github.com/adamcarlile/Admin-Framework
Ruby | 1364 lines | 1075 code | 289 blank | 0 comment | 0 complexity | 63edf5e97f661cb75d904cef169ba10b MD5 | raw file
  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. class TransitionTest < Test::Unit::TestCase
  3. def setup
  4. @klass = Class.new
  5. @machine = StateMachine::Machine.new(@klass)
  6. @machine.state :parked, :idling
  7. @machine.event :ignite
  8. @object = @klass.new
  9. @object.state = 'parked'
  10. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  11. end
  12. def test_should_have_an_object
  13. assert_equal @object, @transition.object
  14. end
  15. def test_should_have_a_machine
  16. assert_equal @machine, @transition.machine
  17. end
  18. def test_should_have_an_event
  19. assert_equal :ignite, @transition.event
  20. end
  21. def test_should_have_a_qualified_event
  22. assert_equal :ignite, @transition.qualified_event
  23. end
  24. def test_should_have_a_from_value
  25. assert_equal 'parked', @transition.from
  26. end
  27. def test_should_have_a_from_name
  28. assert_equal :parked, @transition.from_name
  29. end
  30. def test_should_have_a_qualified_from_name
  31. assert_equal :parked, @transition.qualified_from_name
  32. end
  33. def test_should_have_a_to_value
  34. assert_equal 'idling', @transition.to
  35. end
  36. def test_should_have_a_to_name
  37. assert_equal :idling, @transition.to_name
  38. end
  39. def test_should_have_a_qualified_to_name
  40. assert_equal :idling, @transition.qualified_to_name
  41. end
  42. def test_should_have_an_attribute
  43. assert_equal :state, @transition.attribute
  44. end
  45. def test_should_not_have_an_action
  46. assert_nil @transition.action
  47. end
  48. def test_should_not_be_transient
  49. assert_equal false, @transition.transient?
  50. end
  51. def test_should_generate_attributes
  52. expected = {:object => @object, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
  53. assert_equal expected, @transition.attributes
  54. end
  55. def test_should_have_empty_args
  56. assert_equal [], @transition.args
  57. end
  58. def test_should_not_have_a_result
  59. assert_nil @transition.result
  60. end
  61. def test_should_use_pretty_inspect
  62. assert_equal '#<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>', @transition.inspect
  63. end
  64. end
  65. class TransitionWithInvalidNodesTest < Test::Unit::TestCase
  66. def setup
  67. @klass = Class.new
  68. @machine = StateMachine::Machine.new(@klass)
  69. @machine.state :parked, :idling
  70. @machine.event :ignite
  71. @object = @klass.new
  72. @object.state = 'parked'
  73. end
  74. def test_should_raise_exception_without_event
  75. assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, nil, :parked, :idling) }
  76. end
  77. def test_should_raise_exception_with_invalid_event
  78. assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :invalid, :parked, :idling) }
  79. end
  80. def test_should_raise_exception_with_invalid_from_state
  81. assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :ignite, :invalid, :idling) }
  82. end
  83. def test_should_raise_exception_with_invalid_to_state
  84. assert_raise(IndexError) { StateMachine::Transition.new(@object, @machine, :ignite, :parked, :invalid) }
  85. end
  86. end
  87. class TransitionWithDynamicToValueTest < Test::Unit::TestCase
  88. def setup
  89. @klass = Class.new
  90. @machine = StateMachine::Machine.new(@klass)
  91. @machine.state :parked
  92. @machine.state :idling, :value => lambda {1}
  93. @machine.event :ignite
  94. @object = @klass.new
  95. @object.state = 'parked'
  96. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  97. end
  98. def test_should_evaluate_to_value
  99. assert_equal 1, @transition.to
  100. end
  101. end
  102. class TransitionLoopbackTest < Test::Unit::TestCase
  103. def setup
  104. @klass = Class.new
  105. @machine = StateMachine::Machine.new(@klass)
  106. @machine.state :parked
  107. @machine.event :park
  108. @object = @klass.new
  109. @object.state = 'parked'
  110. @transition = StateMachine::Transition.new(@object, @machine, :park, :parked, :parked)
  111. end
  112. def test_should_be_loopback
  113. assert @transition.loopback?
  114. end
  115. end
  116. class TransitionWithDifferentStatesTest < Test::Unit::TestCase
  117. def setup
  118. @klass = Class.new
  119. @machine = StateMachine::Machine.new(@klass)
  120. @machine.state :parked, :idling
  121. @machine.event :ignite
  122. @object = @klass.new
  123. @object.state = 'parked'
  124. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  125. end
  126. def test_should_not_be_loopback
  127. assert !@transition.loopback?
  128. end
  129. end
  130. class TransitionWithNamespaceTest < Test::Unit::TestCase
  131. def setup
  132. @klass = Class.new
  133. @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
  134. @machine.state :off, :active
  135. @machine.event :activate
  136. @object = @klass.new
  137. @object.state = 'off'
  138. @transition = StateMachine::Transition.new(@object, @machine, :activate, :off, :active)
  139. end
  140. def test_should_have_an_event
  141. assert_equal :activate, @transition.event
  142. end
  143. def test_should_have_a_qualified_event
  144. assert_equal :activate_alarm, @transition.qualified_event
  145. end
  146. def test_should_have_a_from_name
  147. assert_equal :off, @transition.from_name
  148. end
  149. def test_should_have_a_qualified_from_name
  150. assert_equal :alarm_off, @transition.qualified_from_name
  151. end
  152. def test_should_have_a_to_name
  153. assert_equal :active, @transition.to_name
  154. end
  155. def test_should_have_a_qualified_to_name
  156. assert_equal :alarm_active, @transition.qualified_to_name
  157. end
  158. end
  159. class TransitionWithCustomMachineAttributeTest < Test::Unit::TestCase
  160. def setup
  161. @klass = Class.new
  162. @machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id)
  163. @machine.state :off, :value => 1
  164. @machine.state :active, :value => 2
  165. @machine.event :activate
  166. @object = @klass.new
  167. @object.state_id = 1
  168. @transition = StateMachine::Transition.new(@object, @machine, :activate, :off, :active)
  169. end
  170. def test_should_persist
  171. @transition.persist
  172. assert_equal 2, @object.state_id
  173. end
  174. def test_should_rollback
  175. @object.state_id = 2
  176. @transition.rollback
  177. assert_equal 1, @object.state_id
  178. end
  179. end
  180. class TransitionWithoutReadingStateTest < Test::Unit::TestCase
  181. def setup
  182. @klass = Class.new
  183. @machine = StateMachine::Machine.new(@klass)
  184. @machine.state :parked, :idling
  185. @machine.event :ignite
  186. @object = @klass.new
  187. @object.state = 'idling'
  188. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling, false)
  189. end
  190. def test_should_not_read_from_value_from_object
  191. assert_equal 'parked', @transition.from
  192. end
  193. def test_should_have_to_value
  194. assert_equal 'idling', @transition.to
  195. end
  196. end
  197. class TransitionWithActionTest < Test::Unit::TestCase
  198. def setup
  199. @klass = Class.new do
  200. def save
  201. end
  202. end
  203. @machine = StateMachine::Machine.new(@klass, :action => :save)
  204. @machine.state :parked, :idling
  205. @machine.event :ignite
  206. @object = @klass.new
  207. @object.state = 'parked'
  208. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  209. end
  210. def test_should_have_an_action
  211. assert_equal :save, @transition.action
  212. end
  213. def test_should_not_have_a_result
  214. assert_nil @transition.result
  215. end
  216. end
  217. class TransitionAfterBeingPersistedTest < Test::Unit::TestCase
  218. def setup
  219. @klass = Class.new
  220. @machine = StateMachine::Machine.new(@klass, :action => :save)
  221. @machine.state :parked, :idling
  222. @machine.event :ignite
  223. @object = @klass.new
  224. @object.state = 'parked'
  225. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  226. @transition.persist
  227. end
  228. def test_should_update_state_value
  229. assert_equal 'idling', @object.state
  230. end
  231. def test_should_not_change_from_state
  232. assert_equal 'parked', @transition.from
  233. end
  234. def test_should_not_change_to_state
  235. assert_equal 'idling', @transition.to
  236. end
  237. def test_should_not_be_able_to_persist_twice
  238. @object.state = 'parked'
  239. @transition.persist
  240. assert_equal 'parked', @object.state
  241. end
  242. def test_should_be_able_to_persist_again_after_resetting
  243. @object.state = 'parked'
  244. @transition.reset
  245. @transition.persist
  246. assert_equal 'idling', @object.state
  247. end
  248. def test_should_revert_to_from_state_on_rollback
  249. @transition.rollback
  250. assert_equal 'parked', @object.state
  251. end
  252. end
  253. class TransitionAfterBeingRolledBackTest < Test::Unit::TestCase
  254. def setup
  255. @klass = Class.new
  256. @machine = StateMachine::Machine.new(@klass, :action => :save)
  257. @machine.state :parked, :idling
  258. @machine.event :ignite
  259. @object = @klass.new
  260. @object.state = 'parked'
  261. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  262. @object.state = 'idling'
  263. @transition.rollback
  264. end
  265. def test_should_update_state_value_to_from_state
  266. assert_equal 'parked', @object.state
  267. end
  268. def test_should_not_change_from_state
  269. assert_equal 'parked', @transition.from
  270. end
  271. def test_should_not_change_to_state
  272. assert_equal 'idling', @transition.to
  273. end
  274. def test_should_still_be_able_to_persist
  275. @transition.persist
  276. assert_equal 'idling', @object.state
  277. end
  278. end
  279. class TransitionWithoutCallbacksTest < Test::Unit::TestCase
  280. def setup
  281. @klass = Class.new
  282. @machine = StateMachine::Machine.new(@klass)
  283. @machine.state :parked, :idling
  284. @machine.event :ignite
  285. @object = @klass.new
  286. @object.state = 'parked'
  287. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  288. end
  289. def test_should_succeed
  290. assert_equal true, @transition.run_callbacks
  291. end
  292. def test_should_succeed_if_after_callbacks_skipped
  293. assert_equal true, @transition.run_callbacks(:after => false)
  294. end
  295. def test_should_call_block_if_provided
  296. @transition.run_callbacks { @ran_block = true; {} }
  297. assert @ran_block
  298. end
  299. def test_should_track_block_result
  300. @transition.run_callbacks {{:result => 1}}
  301. assert_equal 1, @transition.result
  302. end
  303. end
  304. class TransitionWithBeforeCallbacksTest < Test::Unit::TestCase
  305. def setup
  306. @klass = Class.new
  307. @machine = StateMachine::Machine.new(@klass)
  308. @machine.state :parked, :idling
  309. @machine.event :ignite
  310. @object = @klass.new
  311. @object.state = 'parked'
  312. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  313. end
  314. def test_should_run_before_callbacks
  315. @machine.before_transition {@run = true}
  316. result = @transition.run_callbacks
  317. assert_equal true, result
  318. assert_equal true, @run
  319. end
  320. def test_should_only_run_those_that_match_transition_context
  321. @count = 0
  322. callback = lambda {@count += 1}
  323. @machine.before_transition :from => :parked, :to => :idling, :on => :park, :do => callback
  324. @machine.before_transition :from => :parked, :to => :parked, :on => :park, :do => callback
  325. @machine.before_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
  326. @machine.before_transition :from => :idling, :to => :idling, :on => :park, :do => callback
  327. @transition.run_callbacks
  328. assert_equal 1, @count
  329. end
  330. def test_should_pass_transition_as_argument
  331. @machine.before_transition {|*args| @args = args}
  332. @transition.run_callbacks
  333. assert_equal [@object, @transition], @args
  334. end
  335. def test_should_catch_halts
  336. @machine.before_transition {throw :halt}
  337. result = nil
  338. assert_nothing_thrown { result = @transition.run_callbacks }
  339. assert_equal false, result
  340. end
  341. def test_should_not_catch_exceptions
  342. @machine.before_transition {raise ArgumentError}
  343. assert_raise(ArgumentError) { @transition.run_callbacks }
  344. end
  345. def test_should_not_be_able_to_run_twice
  346. @count = 0
  347. @machine.before_transition {@count += 1}
  348. @transition.run_callbacks
  349. @transition.run_callbacks
  350. assert_equal 1, @count
  351. end
  352. def test_should_be_able_to_run_again_after_halt
  353. @count = 0
  354. @machine.before_transition {@count += 1; throw :halt}
  355. @transition.run_callbacks
  356. @transition.run_callbacks
  357. assert_equal 2, @count
  358. end
  359. def test_should_be_able_to_run_again_after_resetting
  360. @count = 0
  361. @machine.before_transition {@count += 1}
  362. @transition.run_callbacks
  363. @transition.reset
  364. @transition.run_callbacks
  365. assert_equal 2, @count
  366. end
  367. def test_should_succeed_if_block_result_is_false
  368. @machine.before_transition {@run = true}
  369. assert_equal true, @transition.run_callbacks {{:result => false}}
  370. assert @run
  371. end
  372. def test_should_succeed_if_block_result_is_true
  373. @machine.before_transition {@run = true}
  374. assert_equal true, @transition.run_callbacks {{:result => true}}
  375. assert @run
  376. end
  377. def test_should_succeed_if_block_success_is_false
  378. @machine.before_transition {@run = true}
  379. assert_equal true, @transition.run_callbacks {{:success => false}}
  380. assert @run
  381. end
  382. def test_should_succeed_if_block_success_is_false
  383. @machine.before_transition {@run = true}
  384. assert_equal true, @transition.run_callbacks {{:success => true}}
  385. assert @run
  386. end
  387. end
  388. class TransitionWithMultipleBeforeCallbacksTest < Test::Unit::TestCase
  389. def setup
  390. @klass = Class.new
  391. @machine = StateMachine::Machine.new(@klass)
  392. @machine.state :parked, :idling
  393. @machine.event :ignite
  394. @object = @klass.new
  395. @object.state = 'parked'
  396. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  397. end
  398. def test_should_run_in_the_order_they_were_defined
  399. @callbacks = []
  400. @machine.before_transition {@callbacks << 1}
  401. @machine.before_transition {@callbacks << 2}
  402. @transition.run_callbacks
  403. assert_equal [1, 2], @callbacks
  404. end
  405. def test_should_not_run_further_callbacks_if_halted
  406. @callbacks = []
  407. @machine.before_transition {@callbacks << 1; throw :halt}
  408. @machine.before_transition {@callbacks << 2}
  409. assert_equal false, @transition.run_callbacks
  410. assert_equal [1], @callbacks
  411. end
  412. def test_should_fail_if_any_callback_halted
  413. @machine.before_transition {true}
  414. @machine.before_transition {throw :halt}
  415. assert_equal false, @transition.run_callbacks
  416. end
  417. end
  418. class TransitionWithAfterCallbacksTest < Test::Unit::TestCase
  419. def setup
  420. @klass = Class.new
  421. @machine = StateMachine::Machine.new(@klass)
  422. @machine.state :parked, :idling
  423. @machine.event :ignite
  424. @object = @klass.new
  425. @object.state = 'parked'
  426. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  427. end
  428. def test_should_run_after_callbacks
  429. @machine.after_transition {|object| @run = true}
  430. result = @transition.run_callbacks
  431. assert_equal true, result
  432. assert_equal true, @run
  433. end
  434. def test_should_only_run_those_that_match_transition_context
  435. @count = 0
  436. callback = lambda {@count += 1}
  437. @machine.after_transition :from => :parked, :to => :idling, :on => :park, :do => callback
  438. @machine.after_transition :from => :parked, :to => :parked, :on => :park, :do => callback
  439. @machine.after_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
  440. @machine.after_transition :from => :idling, :to => :idling, :on => :park, :do => callback
  441. @transition.run_callbacks
  442. assert_equal 1, @count
  443. end
  444. def test_should_not_run_if_not_successful
  445. @machine.after_transition {|object| @run = true}
  446. @transition.run_callbacks {{:success => false}}
  447. assert !@run
  448. end
  449. def test_should_run_if_not_successful_and_includes_failures
  450. @machine.after_transition(:include_failures => true) {|object| @run = true}
  451. @transition.run_callbacks {{:success => false}}
  452. assert @run
  453. end
  454. def test_should_run_if_successful
  455. @machine.after_transition {|object| @run = true}
  456. @transition.run_callbacks {{:success => true}}
  457. assert @run
  458. end
  459. def test_should_run_if_successful_and_includes_failures
  460. @machine.after_transition(:include_failures => true) {|object| @run = true}
  461. @transition.run_callbacks {{:success => true}}
  462. assert @run
  463. end
  464. def test_should_pass_transition_as_argument
  465. @machine.after_transition {|*args| @args = args}
  466. @transition.run_callbacks
  467. assert_equal [@object, @transition], @args
  468. end
  469. def test_should_catch_halts
  470. @machine.after_transition {throw :halt}
  471. result = nil
  472. assert_nothing_thrown { result = @transition.run_callbacks }
  473. assert_equal true, result
  474. end
  475. def test_should_not_catch_exceptions
  476. @machine.after_transition {raise ArgumentError}
  477. assert_raise(ArgumentError) { @transition.run_callbacks }
  478. end
  479. def test_should_not_be_able_to_run_twice
  480. @count = 0
  481. @machine.after_transition {@count += 1}
  482. @transition.run_callbacks
  483. @transition.run_callbacks
  484. assert_equal 1, @count
  485. end
  486. def test_should_not_be_able_to_run_twice_if_halted
  487. @count = 0
  488. @machine.after_transition {@count += 1; throw :halt}
  489. @transition.run_callbacks
  490. @transition.run_callbacks
  491. assert_equal 1, @count
  492. end
  493. def test_should_be_able_to_run_again_after_resetting
  494. @count = 0
  495. @machine.after_transition {@count += 1}
  496. @transition.run_callbacks
  497. @transition.reset
  498. @transition.run_callbacks
  499. assert_equal 2, @count
  500. end
  501. end
  502. class TransitionWithMultipleAfterCallbacksTest < Test::Unit::TestCase
  503. def setup
  504. @klass = Class.new
  505. @machine = StateMachine::Machine.new(@klass)
  506. @machine.state :parked, :idling
  507. @machine.event :ignite
  508. @object = @klass.new
  509. @object.state = 'parked'
  510. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  511. end
  512. def test_should_run_in_the_order_they_were_defined
  513. @callbacks = []
  514. @machine.after_transition {@callbacks << 1}
  515. @machine.after_transition {@callbacks << 2}
  516. @transition.run_callbacks
  517. assert_equal [1, 2], @callbacks
  518. end
  519. def test_should_not_run_further_callbacks_if_halted
  520. @callbacks = []
  521. @machine.after_transition {@callbacks << 1; throw :halt}
  522. @machine.after_transition {@callbacks << 2}
  523. assert_equal true, @transition.run_callbacks
  524. assert_equal [1], @callbacks
  525. end
  526. def test_should_fail_if_any_callback_halted
  527. @machine.after_transition {true}
  528. @machine.after_transition {throw :halt}
  529. assert_equal true, @transition.run_callbacks
  530. end
  531. end
  532. class TransitionWithAroundCallbacksTest < Test::Unit::TestCase
  533. def setup
  534. @klass = Class.new
  535. @machine = StateMachine::Machine.new(@klass)
  536. @machine.state :parked, :idling
  537. @machine.event :ignite
  538. @object = @klass.new
  539. @object.state = 'parked'
  540. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  541. end
  542. def test_should_run_around_callbacks
  543. @machine.around_transition {|object, transition, block| @run_before = true; block.call; @run_after = true}
  544. result = @transition.run_callbacks
  545. assert_equal true, result
  546. assert_equal true, @run_before
  547. assert_equal true, @run_after
  548. end
  549. def test_should_only_run_those_that_match_transition_context
  550. @count = 0
  551. callback = lambda {|object, transition, block| @count += 1; block.call}
  552. @machine.around_transition :from => :parked, :to => :idling, :on => :park, :do => callback
  553. @machine.around_transition :from => :parked, :to => :parked, :on => :park, :do => callback
  554. @machine.around_transition :from => :parked, :to => :idling, :on => :ignite, :do => callback
  555. @machine.around_transition :from => :idling, :to => :idling, :on => :park, :do => callback
  556. @transition.run_callbacks
  557. assert_equal 1, @count
  558. end
  559. def test_should_pass_transition_as_argument
  560. @machine.around_transition {|*args| block = args.pop; @args = args; block.call}
  561. @transition.run_callbacks
  562. assert_equal [@object, @transition], @args
  563. end
  564. def test_should_run_block_between_callback
  565. @callbacks = []
  566. @machine.around_transition {|block| @callbacks << :before; block.call; @callbacks << :after}
  567. @transition.run_callbacks { @callbacks << :within; {:success => true} }
  568. assert_equal [:before, :within, :after], @callbacks
  569. end
  570. def test_should_have_access_to_result_after_yield
  571. @machine.around_transition {|block| @before_result = @transition.result; block.call; @after_result = @transition.result}
  572. @transition.run_callbacks {{:result => 1, :success => true}}
  573. assert_nil @before_result
  574. assert_equal 1, @after_result
  575. end
  576. def test_should_catch_before_yield_halts
  577. @machine.around_transition {throw :halt}
  578. result = nil
  579. assert_nothing_thrown { result = @transition.run_callbacks }
  580. assert_equal false, result
  581. end
  582. def test_should_catch_after_yield_halts
  583. @machine.around_transition {|block| block.call; throw :halt}
  584. result = nil
  585. assert_nothing_thrown { result = @transition.run_callbacks }
  586. assert_equal true, result
  587. end
  588. def test_should_not_catch_before_yield
  589. @machine.around_transition {raise ArgumentError}
  590. assert_raise(ArgumentError) { @transition.run_callbacks }
  591. end
  592. def test_should_not_catch_after_yield
  593. @machine.around_transition {|block| block.call; raise ArgumentError}
  594. assert_raise(ArgumentError) { @transition.run_callbacks }
  595. end
  596. def test_should_fail_if_not_yielded
  597. @machine.around_transition {}
  598. result = nil
  599. assert_nothing_thrown { result = @transition.run_callbacks }
  600. assert_equal false, result
  601. end
  602. def test_should_not_be_able_to_run_twice
  603. @before_count = 0
  604. @after_count = 0
  605. @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
  606. @transition.run_callbacks
  607. @transition.run_callbacks
  608. assert_equal 1, @before_count
  609. assert_equal 1, @after_count
  610. end
  611. def test_should_be_able_to_run_again_after_resetting
  612. @before_count = 0
  613. @after_count = 0
  614. @machine.around_transition {|block| @before_count += 1; block.call; @after_count += 1}
  615. @transition.run_callbacks
  616. @transition.reset
  617. @transition.run_callbacks
  618. assert_equal 2, @before_count
  619. assert_equal 2, @after_count
  620. end
  621. def test_should_succeed_if_block_result_is_false
  622. @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
  623. assert_equal true, @transition.run_callbacks {{:success => true, :result => false}}
  624. assert @before_run
  625. assert @after_run
  626. end
  627. def test_should_succeed_if_block_result_is_true
  628. @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
  629. assert_equal true, @transition.run_callbacks {{:success => true, :result => true}}
  630. assert @before_run
  631. assert @after_run
  632. end
  633. def test_should_only_run_before_if_block_success_is_false
  634. @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
  635. assert_equal true, @transition.run_callbacks {{:success => false}}
  636. assert @before_run
  637. assert !@after_run
  638. end
  639. def test_should_succeed_if_including_failure_and_block_success_is_false
  640. @machine.around_transition(:include_failures => true) {|block| @before_run = true; block.call; @after_run = true}
  641. assert_equal true, @transition.run_callbacks {{:success => false}}
  642. assert @before_run
  643. assert @after_run
  644. end
  645. def test_should_succeed_if_block_success_is_false
  646. @machine.around_transition {|block| @before_run = true; block.call; @after_run = true}
  647. assert_equal true, @transition.run_callbacks {{:success => true}}
  648. assert @before_run
  649. assert @after_run
  650. end
  651. end
  652. class TransitionWithMultipleAroundCallbacksTest < Test::Unit::TestCase
  653. def setup
  654. @klass = Class.new
  655. @machine = StateMachine::Machine.new(@klass)
  656. @machine.state :parked, :idling
  657. @machine.event :ignite
  658. @object = @klass.new
  659. @object.state = 'parked'
  660. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  661. end
  662. def test_should_before_yield_in_the_order_they_were_defined
  663. @callbacks = []
  664. @machine.around_transition {|block| @callbacks << 1; block.call}
  665. @machine.around_transition {|block| @callbacks << 2; block.call}
  666. @transition.run_callbacks
  667. assert_equal [1, 2], @callbacks
  668. end
  669. def test_should_before_yield_multiple_methods_in_the_order_they_were_defined
  670. @callbacks = []
  671. @machine.around_transition(lambda {|block| @callbacks << 1; block.call}, lambda {|block| @callbacks << 2; block.call})
  672. @machine.around_transition(lambda {|block| @callbacks << 3; block.call}, lambda {|block| @callbacks << 4; block.call})
  673. @transition.run_callbacks
  674. assert_equal [1, 2, 3, 4], @callbacks
  675. end
  676. def test_should_after_yield_in_the_reverse_order_they_were_defined
  677. @callbacks = []
  678. @machine.around_transition {|block| block.call; @callbacks << 1}
  679. @machine.around_transition {|block| block.call; @callbacks << 2}
  680. @transition.run_callbacks
  681. assert_equal [2, 1], @callbacks
  682. end
  683. def test_should_after_yield_multiple_methods_in_the_reverse_order_they_were_defined
  684. @callbacks = []
  685. @machine.around_transition(lambda {|block| block.call; @callbacks << 1}) {|block| block.call; @callbacks << 2}
  686. @machine.around_transition(lambda {|block| block.call; @callbacks << 3}) {|block| block.call; @callbacks << 4}
  687. @transition.run_callbacks
  688. assert_equal [4, 3, 2, 1], @callbacks
  689. end
  690. def test_should_run_block_between_callback
  691. @callbacks = []
  692. @machine.around_transition {|block| @callbacks << :before_1; block.call; @callbacks << :after_1}
  693. @machine.around_transition {|block| @callbacks << :before_2; block.call; @callbacks << :after_2}
  694. @transition.run_callbacks { @callbacks << :within; {:success => true} }
  695. assert_equal [:before_1, :before_2, :within, :after_2, :after_1], @callbacks
  696. end
  697. def test_should_have_access_to_result_after_yield
  698. @machine.around_transition {|block| @before_result_1 = @transition.result; block.call; @after_result_1 = @transition.result}
  699. @machine.around_transition {|block| @before_result_2 = @transition.result; block.call; @after_result_2 = @transition.result}
  700. @transition.run_callbacks {{:result => 1, :success => true}}
  701. assert_nil @before_result_1
  702. assert_nil @before_result_2
  703. assert_equal 1, @after_result_1
  704. assert_equal 1, @after_result_2
  705. end
  706. def test_should_fail_if_any_before_yield_halted
  707. @machine.around_transition {|block| block.call}
  708. @machine.around_transition {throw :halt}
  709. assert_equal false, @transition.run_callbacks
  710. end
  711. def test_should_not_continue_around_callbacks_if_before_yield_halted
  712. @callbacks = []
  713. @machine.around_transition {@callbacks << 1; throw :halt}
  714. @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
  715. assert_equal false, @transition.run_callbacks
  716. assert_equal [1], @callbacks
  717. end
  718. def test_should_not_continue_around_callbacks_if_later_before_yield_halted
  719. @callbacks = []
  720. @machine.around_transition {|block| block.call; @callbacks << 1}
  721. @machine.around_transition {throw :halt}
  722. @transition.run_callbacks
  723. assert_equal [], @callbacks
  724. end
  725. def test_should_not_run_further_callbacks_if_after_yield_halted
  726. @callbacks = []
  727. @machine.around_transition {|block| block.call; @callbacks << 1}
  728. @machine.around_transition {|block| block.call; throw :halt}
  729. assert_equal true, @transition.run_callbacks
  730. assert_equal [], @callbacks
  731. end
  732. def test_should_fail_if_any_fail_to_yield
  733. @callbacks = []
  734. @machine.around_transition {@callbacks << 1}
  735. @machine.around_transition {|block| @callbacks << 2; block.call; @callbacks << 3}
  736. assert_equal false, @transition.run_callbacks
  737. assert_equal [1], @callbacks
  738. end
  739. end
  740. class TransitionWithMixedCallbacksTest < Test::Unit::TestCase
  741. def setup
  742. @klass = Class.new
  743. @machine = StateMachine::Machine.new(@klass)
  744. @machine.state :parked, :idling
  745. @machine.event :ignite
  746. @object = @klass.new
  747. @object.state = 'parked'
  748. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  749. end
  750. def test_should_before_and_around_callbacks_in_order_defined
  751. @callbacks = []
  752. @machine.before_transition {@callbacks << :before_1}
  753. @machine.around_transition {|block| @callbacks << :around; block.call}
  754. @machine.before_transition {@callbacks << :before_2}
  755. assert_equal true, @transition.run_callbacks
  756. assert_equal [:before_1, :around, :before_2], @callbacks
  757. end
  758. def test_should_run_around_callbacks_before_after_callbacks
  759. @callbacks = []
  760. @machine.after_transition {@callbacks << :after_1}
  761. @machine.around_transition {|block| block.call; @callbacks << :after_2}
  762. @machine.after_transition {@callbacks << :after_3}
  763. assert_equal true, @transition.run_callbacks
  764. assert_equal [:after_2, :after_1, :after_3], @callbacks
  765. end
  766. def test_should_have_access_to_result_for_both_after_and_around_callbacks
  767. @machine.after_transition {@after_result = @transition.result}
  768. @machine.around_transition {|block| block.call; @around_result = @transition.result}
  769. @transition.run_callbacks {{:result => 1, :success => true}}
  770. assert_equal 1, @after_result
  771. assert_equal 1, @around_result
  772. end
  773. def test_should_not_run_further_callbacks_if_before_callback_halts
  774. @callbacks = []
  775. @machine.before_transition {@callbacks << :before_1}
  776. @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
  777. @machine.before_transition {@callbacks << :before_2; throw :halt}
  778. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
  779. @machine.after_transition {@callbacks << :after}
  780. assert_equal false, @transition.run_callbacks
  781. assert_equal [:before_1, :before_around_1, :before_2], @callbacks
  782. end
  783. def test_should_not_run_further_callbacks_if_before_yield_halts
  784. @callbacks = []
  785. @machine.before_transition {@callbacks << :before_1}
  786. @machine.around_transition {|block| @callbacks << :before_around_1; throw :halt}
  787. @machine.before_transition {@callbacks << :before_2; throw :halt}
  788. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
  789. @machine.after_transition {@callbacks << :after}
  790. assert_equal false, @transition.run_callbacks
  791. assert_equal [:before_1, :before_around_1], @callbacks
  792. end
  793. def test_should_not_run_further_callbacks_if_around_callback_fails_to_yield
  794. @callbacks = []
  795. @machine.before_transition {@callbacks << :before_1}
  796. @machine.around_transition {|block| @callbacks << :before_around_1}
  797. @machine.before_transition {@callbacks << :before_2; throw :halt}
  798. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
  799. @machine.after_transition {@callbacks << :after}
  800. assert_equal false, @transition.run_callbacks
  801. assert_equal [:before_1, :before_around_1], @callbacks
  802. end
  803. def test_should_not_run_further_callbacks_if_after_yield_halts
  804. @callbacks = []
  805. @machine.before_transition {@callbacks << :before_1}
  806. @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1; throw :halt}
  807. @machine.before_transition {@callbacks << :before_2}
  808. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
  809. @machine.after_transition {@callbacks << :after}
  810. assert_equal true, @transition.run_callbacks
  811. assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1], @callbacks
  812. end
  813. def test_should_not_run_further_callbacks_if_after_callback_halts
  814. @callbacks = []
  815. @machine.before_transition {@callbacks << :before_1}
  816. @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
  817. @machine.before_transition {@callbacks << :before_2}
  818. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
  819. @machine.after_transition {@callbacks << :after_1; throw :halt}
  820. @machine.after_transition {@callbacks << :after_2}
  821. assert_equal true, @transition.run_callbacks
  822. assert_equal [:before_1, :before_around_1, :before_2, :before_around_2, :after_around_2, :after_around_1, :after_1], @callbacks
  823. end
  824. def test_should_run_any_callbacks_that_include_failures_if_block_success_is_false
  825. @callbacks = []
  826. @machine.around_transition {|block| block.call; @callbacks << :after_around_1}
  827. @machine.around_transition(:include_failures => true) {|block| block.call; @callbacks << :after_around_2}
  828. @machine.after_transition {@callbacks << :after_1}
  829. @machine.after_transition(:include_failures => true) {@callbacks << :after_2}
  830. assert_equal true, @transition.run_callbacks {{:success => false}}
  831. assert_equal [:after_around_2, :after_2], @callbacks
  832. end
  833. end
  834. class TransitionWithAfterCallbacksSkippedTest < Test::Unit::TestCase
  835. def setup
  836. @klass = Class.new
  837. @machine = StateMachine::Machine.new(@klass)
  838. @machine.state :parked, :idling
  839. @machine.event :ignite
  840. @object = @klass.new
  841. @object.state = 'parked'
  842. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  843. end
  844. def test_should_run_before_callbacks
  845. @machine.before_transition {@run = true}
  846. assert_equal true, @transition.run_callbacks(:after => false)
  847. assert @run
  848. end
  849. def test_should_run_around_callbacks_before_yield
  850. @machine.around_transition {|block| @run = true; block.call}
  851. assert_equal true, @transition.run_callbacks(:after => false)
  852. assert @run
  853. end
  854. def test_should_not_run_after_callbacks
  855. @machine.after_transition {@run = true}
  856. assert_equal true, @transition.run_callbacks(:after => false)
  857. assert !@run
  858. end
  859. def test_should_not_run_around_callbacks_after_yield
  860. @machine.around_transition {|block| block.call; @run = true}
  861. assert_equal true, @transition.run_callbacks(:after => false)
  862. assert !@run
  863. end
  864. def test_should_run_after_callbacks_that_include_failures_if_block_success_is_false
  865. @machine.after_transition(:include_failures => true) {@run = true}
  866. assert_equal true, @transition.run_callbacks(:after => false) {{:success => false}}
  867. assert @run
  868. end
  869. def test_should_run_around_callbacks_that_include_failures_if_block_success_is_false
  870. @machine.around_transition(:include_failures => true) {|block| block.call; @run = true}
  871. assert_equal true, @transition.run_callbacks(:after => false) {{:success => false}}
  872. assert @run
  873. end
  874. def test_should_continue_around_transition_execution_on_second_call
  875. @callbacks = []
  876. @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
  877. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2}
  878. @machine.after_transition {@callbacks << :after}
  879. assert_equal true, @transition.run_callbacks(:after => false)
  880. assert_equal [:before_around_1, :before_around_2], @callbacks
  881. assert_equal true, @transition.run_callbacks
  882. assert_equal [:before_around_1, :before_around_2, :after_around_2, :after_around_1, :after], @callbacks
  883. end
  884. def test_should_not_run_further_callbacks_if_halted_during_continue_around_transition
  885. @callbacks = []
  886. @machine.around_transition {|block| @callbacks << :before_around_1; block.call; @callbacks << :after_around_1}
  887. @machine.around_transition {|block| @callbacks << :before_around_2; block.call; @callbacks << :after_around_2; throw :halt}
  888. @machine.after_transition {@callbacks << :after}
  889. assert_equal true, @transition.run_callbacks(:after => false)
  890. assert_equal [:before_around_1, :before_around_2], @callbacks
  891. assert_equal true, @transition.run_callbacks
  892. assert_equal [:before_around_1, :before_around_2, :after_around_2], @callbacks
  893. end
  894. def test_should_not_be_able_to_continue_twice
  895. @count = 0
  896. @machine.around_transition {|block| block.call; @count += 1}
  897. @machine.after_transition {@count += 1}
  898. @transition.run_callbacks(:after => false)
  899. 2.times do
  900. assert_equal true, @transition.run_callbacks
  901. assert_equal 2, @count
  902. end
  903. end
  904. def test_should_not_be_able_to_continue_again_after_halted
  905. @count = 0
  906. @machine.around_transition {|block| block.call; @count += 1; throw :halt}
  907. @machine.after_transition {@count += 1}
  908. @transition.run_callbacks(:after => false)
  909. 2.times do
  910. assert_equal true, @transition.run_callbacks
  911. assert_equal 1, @count
  912. end
  913. end
  914. def test_should_have_access_to_result_after_continued
  915. @machine.around_transition {|block| @around_before_result = @transition.result; block.call; @around_after_result = @transition.result}
  916. @machine.after_transition {@after_result = @transition.result}
  917. @transition.run_callbacks(:after => false)
  918. @transition.run_callbacks {{:result => 1}}
  919. assert_nil @around_before_result
  920. assert_equal 1, @around_after_result
  921. assert_equal 1, @after_result
  922. end
  923. def test_should_raise_exceptions_during_around_callbacks_after_yield_in_second_execution
  924. @machine.around_transition {|block| block.call; raise ArgumentError}
  925. assert_nothing_raised { @transition.run_callbacks(:after => false) }
  926. assert_raise(ArgumentError) { @transition.run_callbacks }
  927. end
  928. end
  929. class TransitionAfterBeingPerformedTest < Test::Unit::TestCase
  930. def setup
  931. @klass = Class.new do
  932. attr_reader :saved, :save_state
  933. def save
  934. @save_state = state
  935. @saved = true
  936. 1
  937. end
  938. end
  939. @machine = StateMachine::Machine.new(@klass, :action => :save)
  940. @machine.state :parked, :idling
  941. @machine.event :ignite
  942. @object = @klass.new
  943. @object.state = 'parked'
  944. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  945. @result = @transition.perform
  946. end
  947. def test_should_have_empty_args
  948. assert_equal [], @transition.args
  949. end
  950. def test_should_have_a_result
  951. assert_equal 1, @transition.result
  952. end
  953. def test_should_be_successful
  954. assert_equal true, @result
  955. end
  956. def test_should_change_the_current_state
  957. assert_equal 'idling', @object.state
  958. end
  959. def test_should_run_the_action
  960. assert @object.saved
  961. end
  962. def test_should_run_the_action_after_saving_the_state
  963. assert_equal 'idling', @object.save_state
  964. end
  965. end
  966. class TransitionWithPerformArgumentsTest < Test::Unit::TestCase
  967. def setup
  968. @klass = Class.new do
  969. attr_reader :saved
  970. def save
  971. @saved = true
  972. end
  973. end
  974. @machine = StateMachine::Machine.new(@klass, :action => :save)
  975. @machine.state :parked, :idling
  976. @machine.event :ignite
  977. @object = @klass.new
  978. @object.state = 'parked'
  979. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  980. end
  981. def test_should_have_arguments
  982. @transition.perform(1, 2)
  983. assert_equal [1, 2], @transition.args
  984. assert @object.saved
  985. end
  986. def test_should_not_include_run_action_in_arguments
  987. @transition.perform(1, 2, false)
  988. assert_equal [1, 2], @transition.args
  989. assert !@object.saved
  990. end
  991. end
  992. class TransitionWithoutRunningActionTest < Test::Unit::TestCase
  993. def setup
  994. @klass = Class.new do
  995. attr_reader :saved
  996. def save
  997. @saved = true
  998. end
  999. end
  1000. @machine = StateMachine::Machine.new(@klass, :action => :save)
  1001. @machine.state :parked, :idling
  1002. @machine.event :ignite
  1003. @machine.after_transition {|object| @run_after = true}
  1004. @object = @klass.new
  1005. @object.state = 'parked'
  1006. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  1007. @result = @transition.perform(false)
  1008. end
  1009. def test_should_have_empty_args
  1010. assert_equal [], @transition.args
  1011. end
  1012. def test_should_not_have_a_result
  1013. assert_nil @transition.result
  1014. end
  1015. def test_should_be_successful
  1016. assert_equal true, @result
  1017. end
  1018. def test_should_change_the_current_state
  1019. assert_equal 'idling', @object.state
  1020. end
  1021. def test_should_not_run_the_action
  1022. assert !@object.saved
  1023. end
  1024. def test_should_run_after_callbacks
  1025. assert @run_after
  1026. end
  1027. end
  1028. class TransitionWithTransactionsTest < Test::Unit::TestCase
  1029. def setup
  1030. @klass = Class.new do
  1031. class << self
  1032. attr_accessor :running_transaction
  1033. end
  1034. attr_accessor :result
  1035. def save
  1036. @result = self.class.running_transaction
  1037. true
  1038. end
  1039. end
  1040. @machine = StateMachine::Machine.new(@klass, :action => :save)
  1041. @machine.state :parked, :idling
  1042. @machine.event :ignite
  1043. @object = @klass.new
  1044. @object.state = 'parked'
  1045. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  1046. class << @machine
  1047. def within_transaction(object)
  1048. owner_class.running_transaction = object
  1049. yield
  1050. owner_class.running_transaction = false
  1051. end
  1052. end
  1053. end
  1054. def test_should_run_blocks_within_transaction_for_object
  1055. @transition.within_transaction do
  1056. @result = @klass.running_transaction
  1057. end
  1058. assert_equal @object, @result
  1059. end
  1060. end
  1061. class TransitionTransientTest < Test::Unit::TestCase
  1062. def setup
  1063. @klass = Class.new
  1064. @machine = StateMachine::Machine.new(@klass)
  1065. @machine.state :parked, :idling
  1066. @machine.event :ignite
  1067. @object = @klass.new
  1068. @object.state = 'parked'
  1069. @transition = StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)
  1070. @transition.transient = true
  1071. end
  1072. def test_should_be_transient
  1073. assert @transition.transient?
  1074. end
  1075. end