PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/adamcarlile/Admin-Framework
Ruby | 744 lines | 587 code | 156 blank | 1 comment | 0 complexity | 62b0d471b8005c01c8dab37d71c8d4b9 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. @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_not_have_any_guards
  19. assert @event.guards.empty?
  20. end
  21. def test_should_have_no_known_states
  22. assert @event.known_states.empty?
  23. end
  24. def test_should_not_be_able_to_fire
  25. assert !@event.can_fire?(@object)
  26. end
  27. def test_should_not_have_a_transition
  28. assert_nil @event.transition_for(@object)
  29. end
  30. def test_should_define_a_predicate
  31. assert @object.respond_to?(:can_ignite?)
  32. end
  33. def test_should_define_a_transition_accessor
  34. assert @object.respond_to?(:ignite_transition)
  35. end
  36. def test_should_define_an_action
  37. assert @object.respond_to?(:ignite)
  38. end
  39. def test_should_define_a_bang_action
  40. assert @object.respond_to?(:ignite!)
  41. end
  42. end
  43. class EventTest < Test::Unit::TestCase
  44. def setup
  45. @machine = StateMachine::Machine.new(Class.new)
  46. @event = StateMachine::Event.new(@machine, :ignite)
  47. @event.transition :parked => :idling
  48. end
  49. def test_should_allow_changing_machine
  50. new_machine = StateMachine::Machine.new(Class.new)
  51. @event.machine = new_machine
  52. assert_equal new_machine, @event.machine
  53. end
  54. def test_should_provide_matcher_helpers_during_initialization
  55. matchers = []
  56. @event.instance_eval do
  57. matchers = [all, any, same]
  58. end
  59. assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
  60. end
  61. def test_should_use_pretty_inspect
  62. assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling]>", @event.inspect
  63. end
  64. end
  65. class EventWithConflictingHelpersTest < Test::Unit::TestCase
  66. def setup
  67. @klass = Class.new do
  68. def can_ignite?
  69. 0
  70. end
  71. def ignite_transition
  72. 0
  73. end
  74. def ignite
  75. 0
  76. end
  77. def ignite!
  78. 0
  79. end
  80. end
  81. @machine = StateMachine::Machine.new(@klass)
  82. @state = StateMachine::Event.new(@machine, :ignite)
  83. @object = @klass.new
  84. end
  85. def test_should_not_redefine_predicate
  86. assert_equal 0, @object.can_ignite?
  87. end
  88. def test_should_not_redefine_transition_accessor
  89. assert_equal 0, @object.ignite_transition
  90. end
  91. def test_should_not_redefine_action
  92. assert_equal 0, @object.ignite
  93. end
  94. def test_should_not_redefine_bang_action
  95. assert_equal 0, @object.ignite!
  96. end
  97. def test_should_allow_super_chaining
  98. @klass.class_eval do
  99. def can_ignite?
  100. super ? 1 : 0
  101. end
  102. def ignite_transition
  103. super ? 1 : 0
  104. end
  105. def ignite
  106. super ? 1 : 0
  107. end
  108. def ignite!
  109. begin
  110. super
  111. 1
  112. rescue Exception => ex
  113. 0
  114. end
  115. end
  116. end
  117. assert_equal 0, @object.can_ignite?
  118. assert_equal 0, @object.ignite_transition
  119. assert_equal 0, @object.ignite
  120. assert_equal 1, @object.ignite!
  121. end
  122. end
  123. class EventWithNamespaceTest < Test::Unit::TestCase
  124. def setup
  125. @klass = Class.new
  126. @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm')
  127. @event = StateMachine::Event.new(@machine, :enable)
  128. @object = @klass.new
  129. end
  130. def test_should_have_a_name
  131. assert_equal :enable, @event.name
  132. end
  133. def test_should_have_a_qualified_name
  134. assert_equal :enable_alarm, @event.qualified_name
  135. end
  136. def test_should_namespace_predicate
  137. assert @object.respond_to?(:can_enable_alarm?)
  138. end
  139. def test_should_namespace_transition_accessor
  140. assert @object.respond_to?(:enable_alarm_transition)
  141. end
  142. def test_should_namespace_action
  143. assert @object.respond_to?(:enable_alarm)
  144. end
  145. def test_should_namespace_bang_action
  146. assert @object.respond_to?(:enable_alarm!)
  147. end
  148. end
  149. class EventTransitionsTest < Test::Unit::TestCase
  150. def setup
  151. @machine = StateMachine::Machine.new(Class.new)
  152. @event = StateMachine::Event.new(@machine, :ignite)
  153. end
  154. def test_should_not_raise_exception_if_implicit_option_specified
  155. assert_nothing_raised {@event.transition(:invalid => :valid)}
  156. end
  157. def test_should_not_allow_on_option
  158. exception = assert_raise(ArgumentError) {@event.transition(:on => :ignite)}
  159. assert_equal 'Invalid key(s): on', exception.message
  160. end
  161. def test_should_automatically_set_on_option
  162. guard = @event.transition(:to => :idling)
  163. assert_instance_of StateMachine::WhitelistMatcher, guard.event_requirement
  164. assert_equal [:ignite], guard.event_requirement.values
  165. end
  166. def test_should_not_allow_except_to_option
  167. exception = assert_raise(ArgumentError) {@event.transition(:except_to => :parked)}
  168. assert_equal 'Invalid key(s): except_to', exception.message
  169. end
  170. def test_should_not_allow_except_on_option
  171. exception = assert_raise(ArgumentError) {@event.transition(:except_on => :ignite)}
  172. assert_equal 'Invalid key(s): except_on', exception.message
  173. end
  174. def test_should_allow_transitioning_without_a_to_state
  175. assert_nothing_raised {@event.transition(:from => :parked)}
  176. end
  177. def test_should_allow_transitioning_without_a_from_state
  178. assert_nothing_raised {@event.transition(:to => :idling)}
  179. end
  180. def test_should_allow_except_from_option
  181. assert_nothing_raised {@event.transition(:except_from => :idling)}
  182. end
  183. def test_should_allow_transitioning_from_a_single_state
  184. assert @event.transition(:parked => :idling)
  185. end
  186. def test_should_allow_transitioning_from_multiple_states
  187. assert @event.transition([:parked, :idling] => :idling)
  188. end
  189. def test_should_have_transitions
  190. guard = @event.transition(:to => :idling)
  191. assert_equal [guard], @event.guards
  192. end
  193. end
  194. class EventAfterBeingCopiedTest < Test::Unit::TestCase
  195. def setup
  196. @machine = StateMachine::Machine.new(Class.new)
  197. @event = StateMachine::Event.new(@machine, :ignite)
  198. @copied_event = @event.dup
  199. end
  200. def test_should_not_have_the_same_collection_of_guards
  201. assert_not_same @event.guards, @copied_event.guards
  202. end
  203. def test_should_not_have_the_same_collection_of_known_states
  204. assert_not_same @event.known_states, @copied_event.known_states
  205. end
  206. end
  207. class EventWithoutTransitionsTest < Test::Unit::TestCase
  208. def setup
  209. @klass = Class.new
  210. @machine = StateMachine::Machine.new(@klass)
  211. @event = StateMachine::Event.new(@machine, :ignite)
  212. @object = @klass.new
  213. end
  214. def test_should_not_be_able_to_fire
  215. assert !@event.can_fire?(@object)
  216. end
  217. def test_should_not_have_a_transition
  218. assert_nil @event.transition_for(@object)
  219. end
  220. def test_should_not_fire
  221. assert !@event.fire(@object)
  222. end
  223. def test_should_not_change_the_current_state
  224. @event.fire(@object)
  225. assert_nil @object.state
  226. end
  227. end
  228. class EventWithTransitionsTest < Test::Unit::TestCase
  229. def setup
  230. @klass = Class.new
  231. @machine = StateMachine::Machine.new(@klass)
  232. @event = StateMachine::Event.new(@machine, :ignite)
  233. @event.transition(:parked => :idling)
  234. @event.transition(:first_gear => :idling)
  235. end
  236. def test_should_include_all_transition_states_in_known_states
  237. assert_equal [:parked, :idling, :first_gear], @event.known_states
  238. end
  239. def test_should_include_new_transition_states_after_calling_known_states
  240. @event.known_states
  241. @event.transition(:stalled => :idling)
  242. assert_equal [:parked, :idling, :first_gear, :stalled], @event.known_states
  243. end
  244. def test_should_use_pretty_inspect
  245. assert_match "#<StateMachine::Event name=:ignite transitions=[:parked => :idling, :first_gear => :idling]>", @event.inspect
  246. end
  247. end
  248. class EventWithoutMatchingTransitionsTest < Test::Unit::TestCase
  249. def setup
  250. @klass = Class.new
  251. @machine = StateMachine::Machine.new(@klass)
  252. @machine.state :parked, :idling
  253. @event = StateMachine::Event.new(@machine, :ignite)
  254. @event.transition(:parked => :idling)
  255. @object = @klass.new
  256. @object.state = 'idling'
  257. end
  258. def test_should_not_be_able_to_fire
  259. assert !@event.can_fire?(@object)
  260. end
  261. def test_should_not_have_a_transition
  262. assert_nil @event.transition_for(@object)
  263. end
  264. def test_should_not_fire
  265. assert !@event.fire(@object)
  266. end
  267. def test_should_not_change_the_current_state
  268. @event.fire(@object)
  269. assert_equal 'idling', @object.state
  270. end
  271. end
  272. class EventWithMatchingDisabledTransitionsTest < Test::Unit::TestCase
  273. def setup
  274. StateMachine::Integrations.const_set('Custom', Module.new do
  275. def invalidate(object, attribute, message, values = [])
  276. (object.errors ||= []) << generate_message(message, values)
  277. end
  278. def reset(object)
  279. object.errors = []
  280. end
  281. end)
  282. @klass = Class.new do
  283. attr_accessor :errors
  284. end
  285. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  286. @machine.state :parked, :idling
  287. @event = StateMachine::Event.new(@machine, :ignite)
  288. @event.transition(:parked => :idling, :if => lambda {false})
  289. @object = @klass.new
  290. @object.state = 'parked'
  291. end
  292. def test_should_not_be_able_to_fire
  293. assert !@event.can_fire?(@object)
  294. end
  295. def test_should_not_have_a_transition
  296. assert_nil @event.transition_for(@object)
  297. end
  298. def test_should_not_fire
  299. assert !@event.fire(@object)
  300. end
  301. def test_should_not_change_the_current_state
  302. @event.fire(@object)
  303. assert_equal 'parked', @object.state
  304. end
  305. def test_should_invalidate_the_state
  306. @event.fire(@object)
  307. assert_equal ['cannot transition via "ignite"'], @object.errors
  308. end
  309. def test_should_reset_existing_error
  310. @object.errors = ['invalid']
  311. @event.fire(@object)
  312. assert_equal ['cannot transition via "ignite"'], @object.errors
  313. end
  314. def teardown
  315. StateMachine::Integrations.send(:remove_const, 'Custom')
  316. end
  317. end
  318. class EventWithMatchingEnabledTransitionsTest < Test::Unit::TestCase
  319. def setup
  320. StateMachine::Integrations.const_set('Custom', Module.new do
  321. def invalidate(object, attribute, message, values = [])
  322. (object.errors ||= []) << generate_message(message, values)
  323. end
  324. def reset(object)
  325. object.errors = []
  326. end
  327. end)
  328. @klass = Class.new do
  329. attr_accessor :errors
  330. end
  331. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  332. @machine.state :parked, :idling
  333. @machine.event :ignite
  334. @event = StateMachine::Event.new(@machine, :ignite)
  335. @event.transition(:parked => :idling)
  336. @object = @klass.new
  337. @object.state = 'parked'
  338. end
  339. def test_should_be_able_to_fire
  340. assert @event.can_fire?(@object)
  341. end
  342. def test_should_have_a_transition
  343. transition = @event.transition_for(@object)
  344. assert_not_nil transition
  345. assert_equal 'parked', transition.from
  346. assert_equal 'idling', transition.to
  347. assert_equal :ignite, transition.event
  348. end
  349. def test_should_fire
  350. assert @event.fire(@object)
  351. end
  352. def test_should_change_the_current_state
  353. @event.fire(@object)
  354. assert_equal 'idling', @object.state
  355. end
  356. def test_should_reset_existing_error
  357. @object.errors = ['invalid']
  358. @event.fire(@object)
  359. assert_equal [], @object.errors
  360. end
  361. def test_should_not_invalidate_the_state
  362. @event.fire(@object)
  363. assert_equal [], @object.errors
  364. end
  365. def teardown
  366. StateMachine::Integrations.send(:remove_const, 'Custom')
  367. end
  368. end
  369. class EventWithTransitionWithoutToStateTest < Test::Unit::TestCase
  370. def setup
  371. @klass = Class.new
  372. @machine = StateMachine::Machine.new(@klass)
  373. @machine.state :parked
  374. @machine.event :park
  375. @event = StateMachine::Event.new(@machine, :park)
  376. @event.transition(:from => :parked)
  377. @object = @klass.new
  378. @object.state = 'parked'
  379. end
  380. def test_should_be_able_to_fire
  381. assert @event.can_fire?(@object)
  382. end
  383. def test_should_have_a_transition
  384. transition = @event.transition_for(@object)
  385. assert_not_nil transition
  386. assert_equal 'parked', transition.from
  387. assert_equal 'parked', transition.to
  388. assert_equal :park, transition.event
  389. end
  390. def test_should_fire
  391. assert @event.fire(@object)
  392. end
  393. def test_should_not_change_the_current_state
  394. @event.fire(@object)
  395. assert_equal 'parked', @object.state
  396. end
  397. end
  398. class EventWithTransitionWithNilToStateTest < Test::Unit::TestCase
  399. def setup
  400. @klass = Class.new
  401. @machine = StateMachine::Machine.new(@klass)
  402. @machine.state nil, :idling
  403. @machine.event :park
  404. @event = StateMachine::Event.new(@machine, :park)
  405. @event.transition(:idling => nil)
  406. @object = @klass.new
  407. @object.state = 'idling'
  408. end
  409. def test_should_be_able_to_fire
  410. assert @event.can_fire?(@object)
  411. end
  412. def test_should_have_a_transition
  413. transition = @event.transition_for(@object)
  414. assert_not_nil transition
  415. assert_equal 'idling', transition.from
  416. assert_equal nil, transition.to
  417. assert_equal :park, transition.event
  418. end
  419. def test_should_fire
  420. assert @event.fire(@object)
  421. end
  422. def test_should_not_change_the_current_state
  423. @event.fire(@object)
  424. assert_equal nil, @object.state
  425. end
  426. end
  427. class EventWithMultipleTransitionsTest < Test::Unit::TestCase
  428. def setup
  429. @klass = Class.new
  430. @machine = StateMachine::Machine.new(@klass)
  431. @machine.state :parked, :idling
  432. @machine.event :ignite
  433. @event = StateMachine::Event.new(@machine, :ignite)
  434. @event.transition(:idling => :idling)
  435. @event.transition(:parked => :idling) # This one should get used
  436. @event.transition(:parked => :parked)
  437. @object = @klass.new
  438. @object.state = 'parked'
  439. end
  440. def test_should_be_able_to_fire
  441. assert @event.can_fire?(@object)
  442. end
  443. def test_should_have_a_transition
  444. transition = @event.transition_for(@object)
  445. assert_not_nil transition
  446. assert_equal 'parked', transition.from
  447. assert_equal 'idling', transition.to
  448. assert_equal :ignite, transition.event
  449. end
  450. def test_should_allow_specific_transition_selection_using_from
  451. transition = @event.transition_for(@object, :from => :idling)
  452. assert_not_nil transition
  453. assert_equal 'idling', transition.from
  454. assert_equal 'idling', transition.to
  455. assert_equal :ignite, transition.event
  456. end
  457. def test_should_allow_specific_transition_selection_using_to
  458. transition = @event.transition_for(@object, :from => :parked, :to => :parked)
  459. assert_not_nil transition
  460. assert_equal 'parked', transition.from
  461. assert_equal 'parked', transition.to
  462. assert_equal :ignite, transition.event
  463. end
  464. def test_should_allow_specific_transition_selection_using_on
  465. transition = @event.transition_for(@object, :on => :park)
  466. assert_nil transition
  467. transition = @event.transition_for(@object, :on => :ignite)
  468. assert_not_nil transition
  469. end
  470. def test_should_fire
  471. assert @event.fire(@object)
  472. end
  473. def test_should_change_the_current_state
  474. @event.fire(@object)
  475. assert_equal 'idling', @object.state
  476. end
  477. end
  478. class EventWithMachineActionTest < Test::Unit::TestCase
  479. def setup
  480. @klass = Class.new do
  481. attr_reader :saved
  482. def save
  483. @saved = true
  484. end
  485. end
  486. @machine = StateMachine::Machine.new(@klass, :action => :save)
  487. @machine.state :parked, :idling
  488. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  489. @event.transition(:parked => :idling)
  490. @object = @klass.new
  491. @object.state = 'parked'
  492. end
  493. def test_should_run_action_on_fire
  494. @event.fire(@object)
  495. assert @object.saved
  496. end
  497. def test_should_not_run_action_if_configured_to_skip
  498. @event.fire(@object, false)
  499. assert !@object.saved
  500. end
  501. end
  502. class EventWithInvalidCurrentStateTest < 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. @event = StateMachine::Event.new(@machine, :ignite)
  509. @event.transition(:parked => :idling)
  510. @object = @klass.new
  511. @object.state = 'invalid'
  512. end
  513. def test_should_raise_exception_when_checking_availability
  514. exception = assert_raise(ArgumentError) { @event.can_fire?(@object) }
  515. assert_equal '"invalid" is not a known state value', exception.message
  516. end
  517. def test_should_raise_exception_when_finding_transition
  518. exception = assert_raise(ArgumentError) { @event.transition_for(@object) }
  519. assert_equal '"invalid" is not a known state value', exception.message
  520. end
  521. def test_should_raise_exception_when_firing
  522. exception = assert_raise(ArgumentError) { @event.fire(@object) }
  523. assert_equal '"invalid" is not a known state value', exception.message
  524. end
  525. end
  526. class EventWithMarshallingTest < Test::Unit::TestCase
  527. def setup
  528. @klass = Class.new do
  529. def save
  530. true
  531. end
  532. end
  533. self.class.const_set('Example', @klass)
  534. @machine = StateMachine::Machine.new(@klass, :action => :save)
  535. @machine.state :parked, :idling
  536. @machine.events << @event = StateMachine::Event.new(@machine, :ignite)
  537. @event.transition(:parked => :idling)
  538. @object = @klass.new
  539. @object.state = 'parked'
  540. end
  541. def test_should_marshal_during_before_callbacks
  542. @machine.before_transition {|object, transition| Marshal.dump(object)}
  543. assert_nothing_raised { @event.fire(@object) }
  544. end
  545. def test_should_marshal_during_action
  546. @klass.class_eval do
  547. def save
  548. Marshal.dump(self)
  549. end
  550. end
  551. assert_nothing_raised { @event.fire(@object) }
  552. end
  553. def test_should_marshal_during_after_callbacks
  554. @machine.after_transition {|object, transition| Marshal.dump(object)}
  555. assert_nothing_raised { @event.fire(@object) }
  556. end
  557. def teardown
  558. self.class.send(:remove_const, 'Example')
  559. end
  560. end
  561. begin
  562. # Load library
  563. require 'rubygems'
  564. gem 'ruby-graphviz', '>=0.9.0'
  565. require 'graphviz'
  566. class EventDrawingTest < Test::Unit::TestCase
  567. def setup
  568. states = [:parked, :idling, :first_gear]
  569. @machine = StateMachine::Machine.new(Class.new, :initial => :parked)
  570. @machine.other_states(*states)
  571. graph = GraphViz.new('G')
  572. states.each {|state| graph.add_node(state.to_s)}
  573. @event = StateMachine::Event.new(@machine , :park)
  574. @event.transition :parked => :idling
  575. @event.transition :first_gear => :parked
  576. @event.transition :except_from => :parked, :to => :parked
  577. @edges = @event.draw(graph)
  578. end
  579. def test_should_generate_edges_for_each_transition
  580. assert_equal 4, @edges.size
  581. end
  582. def test_should_use_event_name_for_edge_label
  583. assert_equal 'park', @edges.first['label'].to_s.gsub('"', '')
  584. end
  585. end
  586. rescue LoadError
  587. $stderr.puts 'Skipping GraphViz StateMachine::Event tests. `gem install ruby-graphviz` >= v0.9.0 and try again.'
  588. end