PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/gemcache/ruby/1.9.1/gems/state_machine-1.1.2/test/unit/event_test.rb

https://bitbucket.org/technopunk2099/metasploit-framework
Ruby | 1047 lines | 821 code | 225 blank | 1 comment | 1 complexity | f1702dea3c1abbe36e8966fca62a6034 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1, GPL-2.0, MIT
  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 EventWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase
  103. def setup
  104. require 'stringio'
  105. @original_stderr, $stderr = $stderr, StringIO.new
  106. @superclass = Class.new do
  107. def can_ignite?
  108. 0
  109. end
  110. def ignite_transition
  111. 0
  112. end
  113. def ignite
  114. 0
  115. end
  116. def ignite!
  117. 0
  118. end
  119. end
  120. @klass = Class.new(@superclass)
  121. @machine = StateMachine::Machine.new(@klass)
  122. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  123. @object = @klass.new
  124. end
  125. def test_should_not_redefine_predicate
  126. assert_equal 0, @object.can_ignite?
  127. end
  128. def test_should_not_redefine_transition_accessor
  129. assert_equal 0, @object.ignite_transition
  130. end
  131. def test_should_not_redefine_action
  132. assert_equal 0, @object.ignite
  133. end
  134. def test_should_not_redefine_bang_action
  135. assert_equal 0, @object.ignite!
  136. end
  137. def test_should_output_warning
  138. expected = %w(can_ignite? ignite_transition ignite ignite!).map do |method|
  139. "Instance method \"#{method}\" is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n"
  140. end.join
  141. assert_equal expected, $stderr.string
  142. end
  143. def teardown
  144. $stderr = @original_stderr
  145. end
  146. end
  147. class EventWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase
  148. def setup
  149. require 'stringio'
  150. @original_stderr, $stderr = $stderr, StringIO.new
  151. @klass = Class.new do
  152. def can_ignite?
  153. 0
  154. end
  155. def ignite_transition
  156. 0
  157. end
  158. def ignite
  159. 0
  160. end
  161. def ignite!
  162. 0
  163. end
  164. end
  165. @machine = StateMachine::Machine.new(@klass)
  166. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  167. @object = @klass.new
  168. end
  169. def test_should_not_redefine_predicate
  170. assert_equal 0, @object.can_ignite?
  171. end
  172. def test_should_not_redefine_transition_accessor
  173. assert_equal 0, @object.ignite_transition
  174. end
  175. def test_should_not_redefine_action
  176. assert_equal 0, @object.ignite
  177. end
  178. def test_should_not_redefine_bang_action
  179. assert_equal 0, @object.ignite!
  180. end
  181. def test_should_allow_super_chaining
  182. @klass.class_eval do
  183. def can_ignite?
  184. super
  185. end
  186. def ignite_transition
  187. super
  188. end
  189. def ignite
  190. super
  191. end
  192. def ignite!
  193. super
  194. end
  195. end
  196. assert_equal false, @object.can_ignite?
  197. assert_equal nil, @object.ignite_transition
  198. assert_equal false, @object.ignite
  199. assert_raise(StateMachine::InvalidTransition) { @object.ignite! }
  200. end
  201. def test_should_not_output_warning
  202. assert_equal '', $stderr.string
  203. end
  204. def teardown
  205. $stderr = @original_stderr
  206. end
  207. end
  208. class EventWithConflictingMachineTest < Test::Unit::TestCase
  209. def setup
  210. require 'stringio'
  211. @original_stderr, $stderr = $stderr, StringIO.new
  212. @klass = Class.new
  213. @state_machine = StateMachine::Machine.new(@klass, :state)
  214. @state_machine.state :parked, :idling
  215. @state_machine.events << @state_event = StateMachine::Event.new(@state_machine, :ignite)
  216. end
  217. def test_should_not_overwrite_first_event
  218. @status_machine = StateMachine::Machine.new(@klass, :status)
  219. @status_machine.state :first_gear, :second_gear
  220. @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
  221. @object = @klass.new
  222. @object.state = 'parked'
  223. @object.status = 'first_gear'
  224. @state_event.transition(:parked => :idling)
  225. @status_event.transition(:parked => :first_gear)
  226. @object.ignite
  227. assert_equal 'idling', @object.state
  228. assert_equal 'first_gear', @object.status
  229. end
  230. def test_should_output_warning
  231. @status_machine = StateMachine::Machine.new(@klass, :status)
  232. @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
  233. assert_equal "Event :ignite for :status is already defined in :state\n", $stderr.string
  234. end
  235. def test_should_not_output_warning_if_using_different_namespace
  236. @status_machine = StateMachine::Machine.new(@klass, :status, :namespace => 'alarm')
  237. @status_machine.events << @status_event = StateMachine::Event.new(@status_machine, :ignite)
  238. assert_equal '', $stderr.string
  239. end
  240. def teardown
  241. $stderr = @original_stderr
  242. end
  243. end
  244. class EventWithNamespaceTest < Test::Unit::TestCase
  245. def setup
  246. @klass = Class.new
  247. @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
  248. @machine.events << @event = StateMachine::Event.new(@machine, :enable)
  249. @object = @klass.new
  250. end
  251. def test_should_have_a_name
  252. assert_equal :enable, @event.name
  253. end
  254. def test_should_have_a_qualified_name
  255. assert_equal :enable_alarm, @event.qualified_name
  256. end
  257. def test_should_namespace_predicate
  258. assert @object.respond_to?(:can_enable_alarm?)
  259. end
  260. def test_should_namespace_transition_accessor
  261. assert @object.respond_to?(:enable_alarm_transition)
  262. end
  263. def test_should_namespace_action
  264. assert @object.respond_to?(:enable_alarm)
  265. end
  266. def test_should_namespace_bang_action
  267. assert @object.respond_to?(:enable_alarm!)
  268. end
  269. end
  270. class EventContextTest < Test::Unit::TestCase
  271. def setup
  272. @klass = Class.new
  273. @machine = StateMachine::Machine.new(@klass)
  274. @machine.events << @event = StateMachine::Event.new(@machine, :ignite, :human_name => 'start')
  275. end
  276. def test_should_evaluate_within_the_event
  277. scope = nil
  278. @event.context { scope = self }
  279. assert_equal @event, scope
  280. end
  281. end
  282. class EventTransitionsTest < Test::Unit::TestCase
  283. def setup
  284. @machine = StateMachine::Machine.new(Class.new)
  285. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  286. end
  287. def test_should_not_raise_exception_if_implicit_option_specified
  288. assert_nothing_raised {@event.transition(:invalid => :valid)}
  289. end
  290. def test_should_not_allow_on_option
  291. exception = assert_raise(ArgumentError) {@event.transition(:on => :ignite)}
  292. assert_equal 'Invalid key(s): on', exception.message
  293. end
  294. def test_should_automatically_set_on_option
  295. branch = @event.transition(:to => :idling)
  296. assert_instance_of StateMachine::WhitelistMatcher, branch.event_requirement
  297. assert_equal [:ignite], branch.event_requirement.values
  298. end
  299. def test_should_not_allow_except_to_option
  300. exception = assert_raise(ArgumentError) {@event.transition(:except_to => :parked)}
  301. assert_equal 'Invalid key(s): except_to', exception.message
  302. end
  303. def test_should_not_allow_except_on_option
  304. exception = assert_raise(ArgumentError) {@event.transition(:except_on => :ignite)}
  305. assert_equal 'Invalid key(s): except_on', exception.message
  306. end
  307. def test_should_allow_transitioning_without_a_to_state
  308. assert_nothing_raised {@event.transition(:from => :parked)}
  309. end
  310. def test_should_allow_transitioning_without_a_from_state
  311. assert_nothing_raised {@event.transition(:to => :idling)}
  312. end
  313. def test_should_allow_except_from_option
  314. assert_nothing_raised {@event.transition(:except_from => :idling)}
  315. end
  316. def test_should_allow_transitioning_from_a_single_state
  317. assert @event.transition(:parked => :idling)
  318. end
  319. def test_should_allow_transitioning_from_multiple_states
  320. assert @event.transition([:parked, :idling] => :idling)
  321. end
  322. def test_should_have_transitions
  323. branch = @event.transition(:to => :idling)
  324. assert_equal [branch], @event.branches
  325. end
  326. end
  327. class EventAfterBeingCopiedTest < Test::Unit::TestCase
  328. def setup
  329. @machine = StateMachine::Machine.new(Class.new)
  330. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  331. @copied_event = @event.dup
  332. end
  333. def test_should_not_have_the_same_collection_of_branches
  334. assert_not_same @event.branches, @copied_event.branches
  335. end
  336. def test_should_not_have_the_same_collection_of_known_states
  337. assert_not_same @event.known_states, @copied_event.known_states
  338. end
  339. end
  340. class EventWithoutTransitionsTest < Test::Unit::TestCase
  341. def setup
  342. @klass = Class.new
  343. @machine = StateMachine::Machine.new(@klass)
  344. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  345. @object = @klass.new
  346. end
  347. def test_should_not_be_able_to_fire
  348. assert !@event.can_fire?(@object)
  349. end
  350. def test_should_not_have_a_transition
  351. assert_nil @event.transition_for(@object)
  352. end
  353. def test_should_not_fire
  354. assert !@event.fire(@object)
  355. end
  356. def test_should_not_change_the_current_state
  357. @event.fire(@object)
  358. assert_nil @object.state
  359. end
  360. end
  361. class EventWithTransitionsTest < Test::Unit::TestCase
  362. def setup
  363. @klass = Class.new
  364. @machine = StateMachine::Machine.new(@klass)
  365. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  366. @event.transition(:parked => :idling)
  367. @event.transition(:first_gear => :idling)
  368. end
  369. def test_should_include_all_transition_states_in_known_states
  370. assert_equal [:parked, :idling, :first_gear], @event.known_states
  371. end
  372. def test_should_include_new_transition_states_after_calling_known_states
  373. @event.known_states
  374. @event.transition(:stalled => :idling)
  375. assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states
  376. end
  377. def test_should_clear_known_states_on_reset
  378. @event.reset
  379. assert_equal [], @event.known_states
  380. end
  381. def test_should_use_pretty_inspect
  382. assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling, :first_gear => :idling]>", @event.inspect
  383. end
  384. end
  385. class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
  386. def setup
  387. @klass = Class.new
  388. @machine = StateMachine::Machine.new(@klass)
  389. @machine.state :parked, :idling
  390. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  391. @event.transition(:parked => :idling)
  392. @object = @klass.new
  393. @object.state = 'idling'
  394. end
  395. def test_should_not_be_able_to_fire
  396. assert !@event.can_fire?(@object)
  397. end
  398. def test_should_be_able_to_fire_with_custom_from_state
  399. assert @event.can_fire?(@object, :from => :parked)
  400. end
  401. def test_should_not_have_a_transition
  402. assert_nil @event.transition_for(@object)
  403. end
  404. def test_should_have_a_transition_with_custom_from_state
  405. assert_not_nil @event.transition_for(@object, :from => :parked)
  406. end
  407. def test_should_not_fire
  408. assert !@event.fire(@object)
  409. end
  410. def test_should_not_change_the_current_state
  411. @event.fire(@object)
  412. assert_equal 'idling', @object.state
  413. end
  414. end
  415. class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
  416. def setup
  417. StateMachine::Integrations.const_set('Custom', Module.new do
  418. include StateMachine::Integrations::Base
  419. def invalidate(object, attribute, message, values = [])
  420. (object.errors ||= []) << generate_message(message, values)
  421. end
  422. def reset(object)
  423. object.errors = []
  424. end
  425. end)
  426. @klass = Class.new do
  427. attr_accessor :errors
  428. end
  429. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  430. @machine.state :parked, :idling
  431. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  432. @event.transition(:parked => :idling, :if => lambda {false})
  433. @object = @klass.new
  434. @object.state = 'parked'
  435. end
  436. def test_should_not_be_able_to_fire
  437. assert !@event.can_fire?(@object)
  438. end
  439. def test_should_be_able_to_fire_with_disabled_guards
  440. assert @event.can_fire?(@object, :guard => false)
  441. end
  442. def test_should_not_have_a_transition
  443. assert_nil @event.transition_for(@object)
  444. end
  445. def test_should_have_a_transition_with_disabled_guards
  446. assert_not_nil @event.transition_for(@object, :guard => false)
  447. end
  448. def test_should_not_fire
  449. assert !@event.fire(@object)
  450. end
  451. def test_should_not_change_the_current_state
  452. @event.fire(@object)
  453. assert_equal 'parked', @object.state
  454. end
  455. def test_should_invalidate_the_state
  456. @event.fire(@object)
  457. assert_equal ['cannot transition via "ignite"'], @object.errors
  458. end
  459. def test_should_invalidate_with_human_event_name
  460. @event.human_name = 'start'
  461. @event.fire(@object)
  462. assert_equal ['cannot transition via "start"'], @object.errors
  463. end
  464. def test_should_invalid_with_human_state_name_if_specified
  465. klass = Class.new do
  466. attr_accessor :errors
  467. end
  468. machine = StateMachine::Machine.new(klass, :integration => :custom, :messages => {:invalid_transition => 'cannot transition via "%s" from "%s"'})
  469. parked, idling = machine.state :parked, :idling
  470. parked.human_name = 'stopped'
  471. machine.events << event = StateMachine::Event.new(machine, :ignite)
  472. event.transition(:parked => :idling, :if => lambda {false})
  473. object = @klass.new
  474. object.state = 'parked'
  475. event.fire(object)
  476. assert_equal ['cannot transition via "ignite" from "stopped"'], object.errors
  477. end
  478. def test_should_reset_existing_error
  479. @object.errors = ['invalid']
  480. @event.fire(@object)
  481. assert_equal ['cannot transition via "ignite"'], @object.errors
  482. end
  483. def test_should_run_failure_callbacks
  484. callback_args = nil
  485. @machine.after_failure {|*args| callback_args = args}
  486. @event.fire(@object)
  487. object, transition = callback_args
  488. assert_equal @object, object
  489. assert_not_nil transition
  490. assert_equal @object, transition.object
  491. assert_equal @machine, transition.machine
  492. assert_equal :ignite, transition.event
  493. assert_equal :parked, transition.from_name
  494. assert_equal :parked, transition.to_name
  495. end
  496. def teardown
  497. StateMachine::Integrations.send(:remove_const, 'Custom')
  498. end
  499. end
  500. class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
  501. def setup
  502. StateMachine::Integrations.const_set('Custom', Module.new do
  503. include StateMachine::Integrations::Base
  504. def invalidate(object, attribute, message, values = [])
  505. (object.errors ||= []) << generate_message(message, values)
  506. end
  507. def reset(object)
  508. object.errors = []
  509. end
  510. end)
  511. @klass = Class.new do
  512. attr_accessor :errors
  513. end
  514. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  515. @machine.state :parked, :idling
  516. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  517. @event.transition(:parked => :idling)
  518. @object = @klass.new
  519. @object.state = 'parked'
  520. end
  521. def test_should_be_able_to_fire
  522. assert @event.can_fire?(@object)
  523. end
  524. def test_should_have_a_transition
  525. transition = @event.transition_for(@object)
  526. assert_not_nil transition
  527. assert_equal 'parked', transition.from
  528. assert_equal 'idling', transition.to
  529. assert_equal :ignite, transition.event
  530. end
  531. def test_should_fire
  532. assert @event.fire(@object)
  533. end
  534. def test_should_change_the_current_state
  535. @event.fire(@object)
  536. assert_equal 'idling', @object.state
  537. end
  538. def test_should_reset_existing_error
  539. @object.errors = ['invalid']
  540. @event.fire(@object)
  541. assert_equal [], @object.errors
  542. end
  543. def test_should_not_invalidate_the_state
  544. @event.fire(@object)
  545. assert_equal [], @object.errors
  546. end
  547. def test_should_not_be_able_to_fire_on_reset
  548. @event.reset
  549. assert !@event.can_fire?(@object)
  550. end
  551. def teardown
  552. StateMachine::Integrations.send(:remove_const, 'Custom')
  553. end
  554. end
  555. class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
  556. def setup
  557. @klass = Class.new
  558. @machine = StateMachine::Machine.new(@klass)
  559. @machine.state :parked
  560. @machine.events << @event = StateMachine::Event.new(@machine, :park)
  561. @event.transition(:from => :parked)
  562. @object = @klass.new
  563. @object.state = 'parked'
  564. end
  565. def test_should_be_able_to_fire
  566. assert @event.can_fire?(@object)
  567. end
  568. def test_should_have_a_transition
  569. transition = @event.transition_for(@object)
  570. assert_not_nil transition
  571. assert_equal 'parked', transition.from
  572. assert_equal 'parked', transition.to
  573. assert_equal :park, transition.event
  574. end
  575. def test_should_fire
  576. assert @event.fire(@object)
  577. end
  578. def test_should_not_change_the_current_state
  579. @event.fire(@object)
  580. assert_equal 'parked', @object.state
  581. end
  582. end
  583. class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
  584. def setup
  585. @klass = Class.new
  586. @machine = StateMachine::Machine.new(@klass)
  587. @machine.state nil, :idling
  588. @machine.events << @event = StateMachine::Event.new(@machine, :park)
  589. @event.transition(:idling => nil)
  590. @object = @klass.new
  591. @object.state = 'idling'
  592. end
  593. def test_should_be_able_to_fire
  594. assert @event.can_fire?(@object)
  595. end
  596. def test_should_have_a_transition
  597. transition = @event.transition_for(@object)
  598. assert_not_nil transition
  599. assert_equal 'idling', transition.from
  600. assert_equal nil, transition.to
  601. assert_equal :park, transition.event
  602. end
  603. def test_should_fire
  604. assert @event.fire(@object)
  605. end
  606. def test_should_not_change_the_current_state
  607. @event.fire(@object)
  608. assert_equal nil, @object.state
  609. end
  610. end
  611. class EventWithMultipleTransitionsTest < Test::Unit::TestCase
  612. def setup
  613. @klass = Class.new
  614. @machine = StateMachine::Machine.new(@klass)
  615. @machine.state :parked, :idling
  616. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  617. @event.transition(:idling => :idling)
  618. @event.transition(:parked => :idling) # This one should get used
  619. @event.transition(:parked => :parked)
  620. @object = @klass.new
  621. @object.state = 'parked'
  622. end
  623. def test_should_be_able_to_fire
  624. assert @event.can_fire?(@object)
  625. end
  626. def test_should_have_a_transition
  627. transition = @event.transition_for(@object)
  628. assert_not_nil transition
  629. assert_equal 'parked', transition.from
  630. assert_equal 'idling', transition.to
  631. assert_equal :ignite, transition.event
  632. end
  633. def test_should_allow_specific_transition_selection_using_from
  634. transition = @event.transition_for(@object, :from => :idling)
  635. assert_not_nil transition
  636. assert_equal 'idling', transition.from
  637. assert_equal 'idling', transition.to
  638. assert_equal :ignite, transition.event
  639. end
  640. def test_should_allow_specific_transition_selection_using_to
  641. transition = @event.transition_for(@object, :from => :parked, :to => :parked)
  642. assert_not_nil transition
  643. assert_equal 'parked', transition.from
  644. assert_equal 'parked', transition.to
  645. assert_equal :ignite, transition.event
  646. end
  647. def test_should_not_allow_specific_transition_selection_using_on
  648. exception = assert_raise(ArgumentError) { @event.transition_for(@object, :on => :park) }
  649. assert_equal 'Invalid key(s): on', exception.message
  650. end
  651. def test_should_fire
  652. assert @event.fire(@object)
  653. end
  654. def test_should_change_the_current_state
  655. @event.fire(@object)
  656. assert_equal 'idling', @object.state
  657. end
  658. end
  659. class EventWithMachineActionTest < Test::Unit::TestCase
  660. def setup
  661. @klass = Class.new do
  662. attr_reader :saved
  663. def save
  664. @saved = true
  665. end
  666. end
  667. @machine = StateMachine::Machine.new(@klass, :action => :save)
  668. @machine.state :parked, :idling
  669. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  670. @event.transition(:parked => :idling)
  671. @object = @klass.new
  672. @object.state = 'parked'
  673. end
  674. def test_should_run_action_on_fire
  675. @event.fire(@object)
  676. assert @object.saved
  677. end
  678. def test_should_not_run_action_if_configured_to_skip
  679. @event.fire(@object, false)
  680. assert !@object.saved
  681. end
  682. end
  683. class EventWithInvalidCurrentStateTest < Test::Unit::TestCase
  684. def setup
  685. @klass = Class.new
  686. @machine = StateMachine::Machine.new(@klass)
  687. @machine.state :parked, :idling
  688. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  689. @event.transition(:parked => :idling)
  690. @object = @klass.new
  691. @object.state = 'invalid'
  692. end
  693. def test_should_raise_exception_when_checking_availability
  694. exception = assert_raise(ArgumentError) { @event.can_fire?(@object) }
  695. assert_equal '"invalid" is not a known state value', exception.message
  696. end
  697. def test_should_raise_exception_when_finding_transition
  698. exception = assert_raise(ArgumentError) { @event.transition_for(@object) }
  699. assert_equal '"invalid" is not a known state value', exception.message
  700. end
  701. def test_should_raise_exception_when_firing
  702. exception = assert_raise(ArgumentError) { @event.fire(@object) }
  703. assert_equal '"invalid" is not a known state value', exception.message
  704. end
  705. end
  706. class EventOnFailureTest < Test::Unit::TestCase
  707. def setup
  708. StateMachine::Integrations.const_set('Custom', Module.new do
  709. include StateMachine::Integrations::Base
  710. def invalidate(object, attribute, message, values = [])
  711. (object.errors ||= []) << generate_message(message, values)
  712. end
  713. def reset(object)
  714. object.errors = []
  715. end
  716. end)
  717. @klass = Class.new do
  718. attr_accessor :errors
  719. end
  720. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  721. @machine.state :parked
  722. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  723. @object = @klass.new
  724. @object.state = 'parked'
  725. end
  726. def test_should_invalidate_the_state
  727. @event.fire(@object)
  728. assert_equal ['cannot transition via "ignite"'], @object.errors
  729. end
  730. def test_should_run_failure_callbacks
  731. callback_args = nil
  732. @machine.after_failure {|*args| callback_args = args}
  733. @event.fire(@object)
  734. object, transition = callback_args
  735. assert_equal @object, object
  736. assert_not_nil transition
  737. assert_equal @object, transition.object
  738. assert_equal @machine, transition.machine
  739. assert_equal :ignite, transition.event
  740. assert_equal :parked, transition.from_name
  741. assert_equal :parked, transition.to_name
  742. end
  743. def teardown
  744. StateMachine::Integrations.send(:remove_const, 'Custom')
  745. end
  746. end
  747. class EventWithMarshallingTest < Test::Unit::TestCase
  748. def setup
  749. @klass = Class.new do
  750. def save
  751. true
  752. end
  753. end
  754. self.class.const_set('Example', @klass)
  755. @machine = StateMachine::Machine.new(@klass, :action => :save)
  756. @machine.state :parked, :idling
  757. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  758. @event.transition(:parked => :idling)
  759. @object = @klass.new
  760. @object.state = 'parked'
  761. end
  762. def test_should_marshal_during_before_callbacks
  763. @machine.before_transition {|object, transition| Marshal.dump(object)}
  764. assert_nothing_raised { @event.fire(@object) }
  765. end
  766. def test_should_marshal_during_action
  767. @klass.class_eval do
  768. def save
  769. Marshal.dump(self)
  770. end
  771. end
  772. assert_nothing_raised { @event.fire(@object) }
  773. end
  774. def test_should_marshal_during_after_callbacks
  775. @machine.after_transition {|object, transition| Marshal.dump(object)}
  776. assert_nothing_raised { @event.fire(@object) }
  777. end
  778. def teardown
  779. self.class.send(:remove_const, 'Example')
  780. end
  781. end
  782. begin
  783. # Load library
  784. require 'graphviz'
  785. class EventDrawingTest < Test::Unit::TestCase
  786. def setup
  787. states = [:parked, :idling, :first_gear]
  788. @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
  789. @machine.other_states(*states)
  790. graph = GraphViz.new('G')
  791. states.each {|state| graph.add_node(state.to_s)}
  792. @machine.events << @event = StateMachine::Event.new(@machine , :park)
  793. @event.transition :parked => :idling
  794. @event.transition :first_gear => :parked
  795. @event.transition :except_from => :parked, :to => :parked
  796. @edges = @event.draw(graph)
  797. end
  798. def test_should_generate_edges_for_each_transition
  799. assert_equal 4, @edges.size
  800. end
  801. def test_should_use_event_name_for_edge_label
  802. assert_equal 'park', @edges.first['label'].to_s.gsub('"', '')
  803. end
  804. end
  805. class EventDrawingWithHumanNameTest < Test::Unit::TestCase
  806. def setup
  807. states = [:parked, :idling]
  808. @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
  809. @machine.other_states(*states)
  810. graph = GraphViz.new('G')
  811. states.each {|state| graph.add_node(state.to_s)}
  812. @machine.events << @event = StateMachine::Event.new(@machine , :park, :human_name => 'Park')
  813. @event.transition :parked => :idling
  814. @edges = @event.draw(graph, :human_name => true)
  815. end
  816. def test_should_use_event_human_name_for_edge_label
  817. assert_equal 'Park', @edges.first['label'].to_s.gsub('"', '')
  818. end
  819. end
  820. rescue LoadError
  821. $stderr.puts 'Skipping GraphViz StateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
  822. end unless ENV['TRAVIS']