PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/test/unit/event_test.rb

https://github.com/johnsonzes/state_machine
Ruby | 922 lines | 726 code | 195 blank | 1 comment | 1 complexity | 8052779e3e528dd7c970a0af3c1231e1 MD5 | raw file
  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. class EventByDefaultTest < Test::Unit::TestCase
  3. def setup
  4. @klass = Class.new
  5. @machine = StateMachine::Machine.new(@klass)
  6. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  7. @object = @klass.new
  8. end
  9. def test_should_have_a_machine
  10. assert_equal @machine, @event.machine
  11. end
  12. def test_should_have_a_name
  13. assert_equal :ignite, @event.name
  14. end
  15. def test_should_have_a_qualified_name
  16. assert_equal :ignite, @event.qualified_name
  17. end
  18. def test_should_have_a_human_name
  19. assert_equal 'ignite', @event.human_name
  20. end
  21. def test_should_not_have_any_branches
  22. assert @event.branches.empty?
  23. end
  24. def test_should_have_no_known_states
  25. assert @event.known_states.empty?
  26. end
  27. def test_should_not_be_able_to_fire
  28. assert !@event.can_fire?(@object)
  29. end
  30. def test_should_not_have_a_transition
  31. assert_nil @event.transition_for(@object)
  32. end
  33. def test_should_define_a_predicate
  34. assert @object.respond_to?(:can_ignite?)
  35. end
  36. def test_should_define_a_transition_accessor
  37. assert @object.respond_to?(:ignite_transition)
  38. end
  39. def test_should_define_an_action
  40. assert @object.respond_to?(:ignite)
  41. end
  42. def test_should_define_a_bang_action
  43. assert @object.respond_to?(:ignite!)
  44. end
  45. end
  46. class EventTest < Test::Unit::TestCase
  47. def setup
  48. @machine = StateMachine::Machine.new(Class.new)
  49. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  50. @event.transition :parked => :idling
  51. end
  52. def test_should_allow_changing_machine
  53. new_machine = StateMachine::Machine.new(Class.new)
  54. @event.machine = new_machine
  55. assert_equal new_machine, @event.machine
  56. end
  57. def test_should_allow_changing_human_name
  58. @event.human_name = 'Stop'
  59. assert_equal 'Stop', @event.human_name
  60. end
  61. def test_should_provide_matcher_helpers_during_initialization
  62. matchers = []
  63. @event.instance_eval do
  64. matchers = [all, any, same]
  65. end
  66. assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
  67. end
  68. def test_should_use_pretty_inspect
  69. assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling]>", @event.inspect
  70. end
  71. end
  72. class EventWithHumanNameTest < Test::Unit::TestCase
  73. def setup
  74. @klass = Class.new
  75. @machine = StateMachine::Machine.new(@klass)
  76. @machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => 'start')
  77. end
  78. def test_should_use_custom_human_name
  79. assert_equal 'start', @event.human_name
  80. end
  81. end
  82. class EventWithDynamicHumanNameTest < Test::Unit::TestCase
  83. def setup
  84. @klass = Class.new
  85. @machine = StateMachine::Machine.new(@klass)
  86. @machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => lambda {|event, object| ['start', object]})
  87. end
  88. def test_should_use_custom_human_name
  89. human_name, klass = @event.human_name
  90. assert_equal 'start', human_name
  91. assert_equal @klass, klass
  92. end
  93. def test_should_allow_custom_class_to_be_passed_through
  94. human_name, klass = @event.human_name(1)
  95. assert_equal 'start', human_name
  96. assert_equal 1, klass
  97. end
  98. def test_should_not_cache_value
  99. assert_not_same @event.human_name, @event.human_name
  100. end
  101. end
  102. class EventWithConflictingHelpersTest < Test::Unit::TestCase
  103. def setup
  104. @klass = Class.new do
  105. def can_ignite?
  106. 0
  107. end
  108. def ignite_transition
  109. 0
  110. end
  111. def ignite
  112. 0
  113. end
  114. def ignite!
  115. 0
  116. end
  117. end
  118. @machine = StateMachine::Machine.new(@klass)
  119. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  120. @object = @klass.new
  121. end
  122. def test_should_not_redefine_predicate
  123. assert_equal 0, @object.can_ignite?
  124. end
  125. def test_should_not_redefine_transition_accessor
  126. assert_equal 0, @object.ignite_transition
  127. end
  128. def test_should_not_redefine_action
  129. assert_equal 0, @object.ignite
  130. end
  131. def test_should_not_redefine_bang_action
  132. assert_equal 0, @object.ignite!
  133. end
  134. def test_should_allow_super_chaining
  135. @klass.class_eval do
  136. def can_ignite?
  137. super ? 1 : 0
  138. end
  139. def ignite_transition
  140. super ? 1 : 0
  141. end
  142. def ignite
  143. super ? 1 : 0
  144. end
  145. def ignite!
  146. begin
  147. super
  148. 1
  149. rescue Exception => ex
  150. 0
  151. end
  152. end
  153. end
  154. assert_equal 0, @object.can_ignite?
  155. assert_equal 0, @object.ignite_transition
  156. assert_equal 0, @object.ignite
  157. assert_equal 1, @object.ignite!
  158. end
  159. end
  160. class EventWithConflictingMachineTest < Test::Unit::TestCase
  161. def setup
  162. require 'stringio'
  163. @original_stderr, $stderr = $stderr, StringIO.new
  164. @klass = Class.new
  165. @state_machine = StateMachine::Machine.new(@klass, :state)
  166. @state_machine.state :parked, :idling
  167. @state_machine.events << @state_event = StateMachine::Event.new(@state_machine, :ignite)
  168. end
  169. def test_should_not_overwrite_first_event
  170. @status_machine = StateMachine::Machine.new(@klass, :status)
  171. @status_machine.state :first_gear, :second_gear
  172. @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
  173. @object = @klass.new
  174. @object.state = 'parked'
  175. @object.status = 'first_gear'
  176. @state_event.transition(:parked => :idling)
  177. @status_event.transition(:parked => :first_gear)
  178. @object.ignite
  179. assert_equal 'idling', @object.state
  180. assert_equal 'first_gear', @object.status
  181. end
  182. def test_should_output_warning
  183. @status_machine = StateMachine::Machine.new(@klass, :status)
  184. @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
  185. assert_equal "Event :ignite for :status is already defined in :state\n", $stderr.string
  186. end
  187. def test_should_not_output_warning_if_using_different_namespace
  188. @status_machine = StateMachine::Machine.new(@klass, :status, :namespace => 'alarm')
  189. @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
  190. assert_equal '', $stderr.string
  191. end
  192. def teardown
  193. $stderr = @original_stderr
  194. end
  195. end
  196. class EventWithNamespaceTest < Test::Unit::TestCase
  197. def setup
  198. @klass = Class.new
  199. @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
  200. @machine.events << @event = StateMachine::Event.new(@machine, :enable)
  201. @object = @klass.new
  202. end
  203. def test_should_have_a_name
  204. assert_equal :enable, @event.name
  205. end
  206. def test_should_have_a_qualified_name
  207. assert_equal :enable_alarm, @event.qualified_name
  208. end
  209. def test_should_namespace_predicate
  210. assert @object.respond_to?(:can_enable_alarm?)
  211. end
  212. def test_should_namespace_transition_accessor
  213. assert @object.respond_to?(:enable_alarm_transition)
  214. end
  215. def test_should_namespace_action
  216. assert @object.respond_to?(:enable_alarm)
  217. end
  218. def test_should_namespace_bang_action
  219. assert @object.respond_to?(:enable_alarm!)
  220. end
  221. end
  222. class EventTransitionsTest < Test::Unit::TestCase
  223. def setup
  224. @machine = StateMachine::Machine.new(Class.new)
  225. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  226. end
  227. def test_should_not_raise_exception_if_implicit_option_specified
  228. assert_nothing_raised {@event.transition(:invalid => :valid)}
  229. end
  230. def test_should_not_allow_on_option
  231. exception = assert_raise(ArgumentError) {@event.transition(:on => :ignite)}
  232. assert_equal 'Invalid key(s): on', exception.message
  233. end
  234. def test_should_automatically_set_on_option
  235. branch = @event.transition(:to => :idling)
  236. assert_instance_of StateMachine::WhitelistMatcher, branch.event_requirement
  237. assert_equal [:ignite], branch.event_requirement.values
  238. end
  239. def test_should_not_allow_except_to_option
  240. exception = assert_raise(ArgumentError) {@event.transition(:except_to => :parked)}
  241. assert_equal 'Invalid key(s): except_to', exception.message
  242. end
  243. def test_should_not_allow_except_on_option
  244. exception = assert_raise(ArgumentError) {@event.transition(:except_on => :ignite)}
  245. assert_equal 'Invalid key(s): except_on', exception.message
  246. end
  247. def test_should_allow_transitioning_without_a_to_state
  248. assert_nothing_raised {@event.transition(:from => :parked)}
  249. end
  250. def test_should_allow_transitioning_without_a_from_state
  251. assert_nothing_raised {@event.transition(:to => :idling)}
  252. end
  253. def test_should_allow_except_from_option
  254. assert_nothing_raised {@event.transition(:except_from => :idling)}
  255. end
  256. def test_should_allow_transitioning_from_a_single_state
  257. assert @event.transition(:parked => :idling)
  258. end
  259. def test_should_allow_transitioning_from_multiple_states
  260. assert @event.transition([:parked, :idling] => :idling)
  261. end
  262. def test_should_have_transitions
  263. branch = @event.transition(:to => :idling)
  264. assert_equal [branch], @event.branches
  265. end
  266. end
  267. class EventAfterBeingCopiedTest < Test::Unit::TestCase
  268. def setup
  269. @machine = StateMachine::Machine.new(Class.new)
  270. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  271. @copied_event = @event.dup
  272. end
  273. def test_should_not_have_the_same_collection_of_branches
  274. assert_not_same @event.branches, @copied_event.branches
  275. end
  276. def test_should_not_have_the_same_collection_of_known_states
  277. assert_not_same @event.known_states, @copied_event.known_states
  278. end
  279. end
  280. class EventWithoutTransitionsTest < Test::Unit::TestCase
  281. def setup
  282. @klass = Class.new
  283. @machine = StateMachine::Machine.new(@klass)
  284. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  285. @object = @klass.new
  286. end
  287. def test_should_not_be_able_to_fire
  288. assert !@event.can_fire?(@object)
  289. end
  290. def test_should_not_have_a_transition
  291. assert_nil @event.transition_for(@object)
  292. end
  293. def test_should_not_fire
  294. assert !@event.fire(@object)
  295. end
  296. def test_should_not_change_the_current_state
  297. @event.fire(@object)
  298. assert_nil @object.state
  299. end
  300. end
  301. class EventWithTransitionsTest < Test::Unit::TestCase
  302. def setup
  303. @klass = Class.new
  304. @machine = StateMachine::Machine.new(@klass)
  305. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  306. @event.transition(:parked => :idling)
  307. @event.transition(:first_gear => :idling)
  308. end
  309. def test_should_include_all_transition_states_in_known_states
  310. assert_equal [:parked, :idling, :first_gear], @event.known_states
  311. end
  312. def test_should_include_new_transition_states_after_calling_known_states
  313. @event.known_states
  314. @event.transition(:stalled => :idling)
  315. assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states
  316. end
  317. def test_should_use_pretty_inspect
  318. assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling, :first_gear => :idling]>", @event.inspect
  319. end
  320. end
  321. class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
  322. def setup
  323. @klass = Class.new
  324. @machine = StateMachine::Machine.new(@klass)
  325. @machine.state :parked, :idling
  326. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  327. @event.transition(:parked => :idling)
  328. @object = @klass.new
  329. @object.state = 'idling'
  330. end
  331. def test_should_not_be_able_to_fire
  332. assert !@event.can_fire?(@object)
  333. end
  334. def test_should_be_able_to_fire_with_custom_from_state
  335. assert @event.can_fire?(@object, :from => :parked)
  336. end
  337. def test_should_not_have_a_transition
  338. assert_nil @event.transition_for(@object)
  339. end
  340. def test_should_have_a_transition_with_custom_from_state
  341. assert_not_nil @event.transition_for(@object, :from => :parked)
  342. end
  343. def test_should_not_fire
  344. assert !@event.fire(@object)
  345. end
  346. def test_should_not_change_the_current_state
  347. @event.fire(@object)
  348. assert_equal 'idling', @object.state
  349. end
  350. end
  351. class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
  352. def setup
  353. StateMachine::Integrations.const_set('Custom', Module.new do
  354. include StateMachine::Integrations::Base
  355. def invalidate(object, attribute, message, values = [])
  356. (object.errors ||= []) << generate_message(message, values)
  357. end
  358. def reset(object)
  359. object.errors = []
  360. end
  361. end)
  362. @klass = Class.new do
  363. attr_accessor :errors
  364. end
  365. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  366. @machine.state :parked, :idling
  367. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  368. @event.transition(:parked => :idling, :if => lambda {false})
  369. @object = @klass.new
  370. @object.state = 'parked'
  371. end
  372. def test_should_not_be_able_to_fire
  373. assert !@event.can_fire?(@object)
  374. end
  375. def test_should_be_able_to_fire_with_disabled_guards
  376. assert @event.can_fire?(@object, :guard => false)
  377. end
  378. def test_should_not_have_a_transition
  379. assert_nil @event.transition_for(@object)
  380. end
  381. def test_should_have_a_transition_with_disabled_guards
  382. assert_not_nil @event.transition_for(@object, :guard => false)
  383. end
  384. def test_should_not_fire
  385. assert !@event.fire(@object)
  386. end
  387. def test_should_not_change_the_current_state
  388. @event.fire(@object)
  389. assert_equal 'parked', @object.state
  390. end
  391. def test_should_invalidate_the_state
  392. @event.fire(@object)
  393. assert_equal ['cannot transition via "ignite"'], @object.errors
  394. end
  395. def test_should_invalidate_with_human_event_name
  396. @event.human_name = 'start'
  397. @event.fire(@object)
  398. assert_equal ['cannot transition via "start"'], @object.errors
  399. end
  400. def test_should_reset_existing_error
  401. @object.errors = ['invalid']
  402. @event.fire(@object)
  403. assert_equal ['cannot transition via "ignite"'], @object.errors
  404. end
  405. def test_should_run_failure_callbacks
  406. callback_args = nil
  407. @machine.after_failure {|*args| callback_args = args}
  408. @event.fire(@object)
  409. object, transition = callback_args
  410. assert_equal @object, object
  411. assert_not_nil transition
  412. assert_equal @object, transition.object
  413. assert_equal @machine, transition.machine
  414. assert_equal :ignite, transition.event
  415. assert_equal :parked, transition.from_name
  416. assert_equal :parked, transition.to_name
  417. end
  418. def teardown
  419. StateMachine::Integrations.send(:remove_const, 'Custom')
  420. end
  421. end
  422. class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
  423. def setup
  424. StateMachine::Integrations.const_set('Custom', Module.new do
  425. include StateMachine::Integrations::Base
  426. def invalidate(object, attribute, message, values = [])
  427. (object.errors ||= []) << generate_message(message, values)
  428. end
  429. def reset(object)
  430. object.errors = []
  431. end
  432. end)
  433. @klass = Class.new do
  434. attr_accessor :errors
  435. end
  436. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  437. @machine.state :parked, :idling
  438. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  439. @event.transition(:parked => :idling)
  440. @object = @klass.new
  441. @object.state = 'parked'
  442. end
  443. def test_should_be_able_to_fire
  444. assert @event.can_fire?(@object)
  445. end
  446. def test_should_have_a_transition
  447. transition = @event.transition_for(@object)
  448. assert_not_nil transition
  449. assert_equal 'parked', transition.from
  450. assert_equal 'idling', transition.to
  451. assert_equal :ignite, transition.event
  452. end
  453. def test_should_fire
  454. assert @event.fire(@object)
  455. end
  456. def test_should_change_the_current_state
  457. @event.fire(@object)
  458. assert_equal 'idling', @object.state
  459. end
  460. def test_should_reset_existing_error
  461. @object.errors = ['invalid']
  462. @event.fire(@object)
  463. assert_equal [], @object.errors
  464. end
  465. def test_should_not_invalidate_the_state
  466. @event.fire(@object)
  467. assert_equal [], @object.errors
  468. end
  469. def teardown
  470. StateMachine::Integrations.send(:remove_const, 'Custom')
  471. end
  472. end
  473. class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
  474. def setup
  475. @klass = Class.new
  476. @machine = StateMachine::Machine.new(@klass)
  477. @machine.state :parked
  478. @machine.events << @event = StateMachine::Event.new(@machine, :park)
  479. @event.transition(:from => :parked)
  480. @object = @klass.new
  481. @object.state = 'parked'
  482. end
  483. def test_should_be_able_to_fire
  484. assert @event.can_fire?(@object)
  485. end
  486. def test_should_have_a_transition
  487. transition = @event.transition_for(@object)
  488. assert_not_nil transition
  489. assert_equal 'parked', transition.from
  490. assert_equal 'parked', transition.to
  491. assert_equal :park, transition.event
  492. end
  493. def test_should_fire
  494. assert @event.fire(@object)
  495. end
  496. def test_should_not_change_the_current_state
  497. @event.fire(@object)
  498. assert_equal 'parked', @object.state
  499. end
  500. end
  501. class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
  502. def setup
  503. @klass = Class.new
  504. @machine = StateMachine::Machine.new(@klass)
  505. @machine.state nil, :idling
  506. @machine.events << @event = StateMachine::Event.new(@machine, :park)
  507. @event.transition(:idling => nil)
  508. @object = @klass.new
  509. @object.state = 'idling'
  510. end
  511. def test_should_be_able_to_fire
  512. assert @event.can_fire?(@object)
  513. end
  514. def test_should_have_a_transition
  515. transition = @event.transition_for(@object)
  516. assert_not_nil transition
  517. assert_equal 'idling', transition.from
  518. assert_equal nil, transition.to
  519. assert_equal :park, transition.event
  520. end
  521. def test_should_fire
  522. assert @event.fire(@object)
  523. end
  524. def test_should_not_change_the_current_state
  525. @event.fire(@object)
  526. assert_equal nil, @object.state
  527. end
  528. end
  529. class EventWithMultipleTransitionsTest < Test::Unit::TestCase
  530. def setup
  531. @klass = Class.new
  532. @machine = StateMachine::Machine.new(@klass)
  533. @machine.state :parked, :idling
  534. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  535. @event.transition(:idling => :idling)
  536. @event.transition(:parked => :idling) # This one should get used
  537. @event.transition(:parked => :parked)
  538. @object = @klass.new
  539. @object.state = 'parked'
  540. end
  541. def test_should_be_able_to_fire
  542. assert @event.can_fire?(@object)
  543. end
  544. def test_should_have_a_transition
  545. transition = @event.transition_for(@object)
  546. assert_not_nil transition
  547. assert_equal 'parked', transition.from
  548. assert_equal 'idling', transition.to
  549. assert_equal :ignite, transition.event
  550. end
  551. def test_should_allow_specific_transition_selection_using_from
  552. transition = @event.transition_for(@object, :from => :idling)
  553. assert_not_nil transition
  554. assert_equal 'idling', transition.from
  555. assert_equal 'idling', transition.to
  556. assert_equal :ignite, transition.event
  557. end
  558. def test_should_allow_specific_transition_selection_using_to
  559. transition = @event.transition_for(@object, :from => :parked, :to => :parked)
  560. assert_not_nil transition
  561. assert_equal 'parked', transition.from
  562. assert_equal 'parked', transition.to
  563. assert_equal :ignite, transition.event
  564. end
  565. def test_should_not_allow_specific_transition_selection_using_on
  566. exception = assert_raise(ArgumentError) { @event.transition_for(@object, :on => :park) }
  567. assert_equal 'Invalid key(s): on', exception.message
  568. end
  569. def test_should_fire
  570. assert @event.fire(@object)
  571. end
  572. def test_should_change_the_current_state
  573. @event.fire(@object)
  574. assert_equal 'idling', @object.state
  575. end
  576. end
  577. class EventWithMachineActionTest < Test::Unit::TestCase
  578. def setup
  579. @klass = Class.new do
  580. attr_reader :saved
  581. def save
  582. @saved = true
  583. end
  584. end
  585. @machine = StateMachine::Machine.new(@klass, :action => :save)
  586. @machine.state :parked, :idling
  587. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  588. @event.transition(:parked => :idling)
  589. @object = @klass.new
  590. @object.state = 'parked'
  591. end
  592. def test_should_run_action_on_fire
  593. @event.fire(@object)
  594. assert @object.saved
  595. end
  596. def test_should_not_run_action_if_configured_to_skip
  597. @event.fire(@object, false)
  598. assert !@object.saved
  599. end
  600. end
  601. class EventWithInvalidCurrentStateTest < Test::Unit::TestCase
  602. def setup
  603. @klass = Class.new
  604. @machine = StateMachine::Machine.new(@klass)
  605. @machine.state :parked, :idling
  606. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  607. @event.transition(:parked => :idling)
  608. @object = @klass.new
  609. @object.state = 'invalid'
  610. end
  611. def test_should_raise_exception_when_checking_availability
  612. exception = assert_raise(ArgumentError) { @event.can_fire?(@object) }
  613. assert_equal '"invalid" is not a known state value', exception.message
  614. end
  615. def test_should_raise_exception_when_finding_transition
  616. exception = assert_raise(ArgumentError) { @event.transition_for(@object) }
  617. assert_equal '"invalid" is not a known state value', exception.message
  618. end
  619. def test_should_raise_exception_when_firing
  620. exception = assert_raise(ArgumentError) { @event.fire(@object) }
  621. assert_equal '"invalid" is not a known state value', exception.message
  622. end
  623. end
  624. class EventOnFailureTest < Test::Unit::TestCase
  625. def setup
  626. StateMachine::Integrations.const_set('Custom', Module.new do
  627. include StateMachine::Integrations::Base
  628. def invalidate(object, attribute, message, values = [])
  629. (object.errors ||= []) << generate_message(message, values)
  630. end
  631. def reset(object)
  632. object.errors = []
  633. end
  634. end)
  635. @klass = Class.new do
  636. attr_accessor :errors
  637. end
  638. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  639. @machine.state :parked
  640. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  641. @object = @klass.new
  642. @object.state = 'parked'
  643. end
  644. def test_should_invalidate_the_state
  645. @event.fire(@object)
  646. assert_equal ['cannot transition via "ignite"'], @object.errors
  647. end
  648. def test_should_run_failure_callbacks
  649. callback_args = nil
  650. @machine.after_failure {|*args| callback_args = args}
  651. @event.fire(@object)
  652. object, transition = callback_args
  653. assert_equal @object, object
  654. assert_not_nil transition
  655. assert_equal @object, transition.object
  656. assert_equal @machine, transition.machine
  657. assert_equal :ignite, transition.event
  658. assert_equal :parked, transition.from_name
  659. assert_equal :parked, transition.to_name
  660. end
  661. def teardown
  662. StateMachine::Integrations.send(:remove_const, 'Custom')
  663. end
  664. end
  665. class EventWithMarshallingTest < Test::Unit::TestCase
  666. def setup
  667. @klass = Class.new do
  668. def save
  669. true
  670. end
  671. end
  672. self.class.const_set('Example', @klass)
  673. @machine = StateMachine::Machine.new(@klass, :action => :save)
  674. @machine.state :parked, :idling
  675. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  676. @event.transition(:parked => :idling)
  677. @object = @klass.new
  678. @object.state = 'parked'
  679. end
  680. def test_should_marshal_during_before_callbacks
  681. @machine.before_transition {|object, transition| Marshal.dump(object)}
  682. assert_nothing_raised { @event.fire(@object) }
  683. end
  684. def test_should_marshal_during_action
  685. @klass.class_eval do
  686. def save
  687. Marshal.dump(self)
  688. end
  689. end
  690. assert_nothing_raised { @event.fire(@object) }
  691. end
  692. def test_should_marshal_during_after_callbacks
  693. @machine.after_transition {|object, transition| Marshal.dump(object)}
  694. assert_nothing_raised { @event.fire(@object) }
  695. end
  696. def teardown
  697. self.class.send(:remove_const, 'Example')
  698. end
  699. end
  700. begin
  701. # Load library
  702. require 'rubygems'
  703. gem 'ruby-graphviz', '>=0.9.0'
  704. require 'graphviz'
  705. class EventDrawingTest < Test::Unit::TestCase
  706. def setup
  707. states = [:parked, :idling, :first_gear]
  708. @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
  709. @machine.other_states(*states)
  710. graph = GraphViz.new('G')
  711. states.each {|state| graph.add_node(state.to_s)}
  712. @machine.events << @event = StateMachine::Event.new(@machine , :park)
  713. @event.transition :parked => :idling
  714. @event.transition :first_gear => :parked
  715. @event.transition :except_from => :parked, :to => :parked
  716. @edges = @event.draw(graph)
  717. end
  718. def test_should_generate_edges_for_each_transition
  719. assert_equal 4, @edges.size
  720. end
  721. def test_should_use_event_name_for_edge_label
  722. assert_equal 'park', @edges.first['label'].to_s.gsub('"', '')
  723. end
  724. end
  725. rescue LoadError
  726. $stderr.puts 'Skipping GraphViz StateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
  727. end