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

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

https://github.com/Calamitous/spree
Ruby | 633 lines | 502 code | 131 blank | 0 comment | 1 complexity | 25a93d269058e2b7034e6bdaabe4e015 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. class TransitionTest < Test::Unit::TestCase
  3. def setup
  4. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  5. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  6. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on')
  7. end
  8. def test_should_have_an_event
  9. assert_not_nil @transition.event
  10. end
  11. def test_should_have_options
  12. assert_not_nil @transition.options
  13. end
  14. def test_should_match_any_from_state
  15. assert @transition.matches?('off')
  16. assert @transition.matches?('on')
  17. end
  18. def test_should_match_empty_query
  19. assert @transition.matches?('off', {})
  20. end
  21. def test_should_match_if_from_state_included
  22. assert @transition.matches?('off', :from => 'off')
  23. end
  24. def test_should_not_match_if_from_state_not_included
  25. assert !@transition.matches?('off', :from => 'on')
  26. end
  27. def test_should_allow_matching_of_multiple_from_states
  28. assert @transition.matches?('off', :from => %w(on off))
  29. end
  30. def test_should_match_if_except_from_state_not_included
  31. assert @transition.matches?('off', :except_from => 'on')
  32. end
  33. def test_should_not_match_if_except_from_state_included
  34. assert !@transition.matches?('off', :except_from => 'off')
  35. end
  36. def test_should_allow_matching_of_multiple_except_from_states
  37. assert @transition.matches?('off', :except_from => %w(on maybe))
  38. end
  39. def test_should_match_if_to_state_included
  40. assert @transition.matches?('off', :to => 'on')
  41. end
  42. def test_should_not_match_if_to_state_not_included
  43. assert !@transition.matches?('off', :to => 'off')
  44. end
  45. def test_should_allow_matching_of_multiple_to_states
  46. assert @transition.matches?('off', :to => %w(on off))
  47. end
  48. def test_should_match_if_except_to_state_not_included
  49. assert @transition.matches?('off', :except_to => 'off')
  50. end
  51. def test_should_not_match_if_except_to_state_included
  52. assert !@transition.matches?('off', :except_to => 'on')
  53. end
  54. def test_should_allow_matching_of_multiple_except_to_states
  55. assert @transition.matches?('off', :except_to => %w(off maybe))
  56. end
  57. def test_should_match_if_on_event_included
  58. assert @transition.matches?('off', :on => 'turn_on')
  59. end
  60. def test_should_not_match_if_on_event_not_included
  61. assert !@transition.matches?('off', :on => 'turn_off')
  62. end
  63. def test_should_allow_matching_of_multiple_on_events
  64. assert @transition.matches?('off', :on => %w(turn_off turn_on))
  65. end
  66. def test_should_match_if_except_on_event_not_included
  67. assert @transition.matches?('off', :except_on => 'turn_off')
  68. end
  69. def test_should_not_match_if_except_on_event_included
  70. assert !@transition.matches?('off', :except_on => 'turn_on')
  71. end
  72. def test_should_allow_matching_of_multiple_except_on_events
  73. assert @transition.matches?('off', :except_on => %w(turn_off not_sure))
  74. end
  75. def test_should_match_if_from_state_and_to_state_match
  76. assert @transition.matches?('off', :from => 'off', :to => 'on')
  77. end
  78. def test_should_not_match_if_from_state_matches_but_not_to_state
  79. assert !@transition.matches?('off', :from => 'off', :to => 'off')
  80. end
  81. def test_should_not_match_if_to_state_matches_but_not_from_state
  82. assert !@transition.matches?('off', :from => 'on', :to => 'on')
  83. end
  84. def test_should_match_if_from_state_to_state_and_on_event_match
  85. assert @transition.matches?('off', :from => 'off', :to => 'on', :on => 'turn_on')
  86. end
  87. def test_should_not_match_if_from_state_and_to_state_match_but_not_on_event
  88. assert !@transition.matches?('off', :from => 'off', :to => 'on', :on => 'turn_off')
  89. end
  90. def test_should_be_able_to_perform_on_all_states
  91. record = new_switch(:state => 'off')
  92. assert @transition.can_perform?(record)
  93. record = new_switch(:state => 'on')
  94. assert @transition.can_perform?(record)
  95. end
  96. def test_should_perform_for_all_states
  97. record = new_switch(:state => 'off')
  98. assert @transition.perform(record)
  99. record = new_switch(:state => 'on')
  100. assert @transition.perform(record)
  101. end
  102. def test_should_not_raise_exception_if_not_valid_during_perform
  103. record = new_switch(:state => 'off')
  104. record.fail_validation = true
  105. assert !@transition.perform(record)
  106. end
  107. def test_should_raise_exception_if_not_valid_during_perform!
  108. record = new_switch(:state => 'off')
  109. record.fail_validation = true
  110. assert_raise(ActiveRecord::RecordInvalid) {@transition.perform!(record)}
  111. end
  112. def test_should_not_raise_exception_if_not_saved_during_perform
  113. record = new_switch(:state => 'off')
  114. record.fail_save = true
  115. assert !@transition.perform(record)
  116. end
  117. def test_should_raise_exception_if_not_saved_during_perform!
  118. record = new_switch(:state => 'off')
  119. record.fail_save = true
  120. assert_raise(ActiveRecord::RecordNotSaved) {@transition.perform!(record)}
  121. end
  122. def test_should_raise_exception_if_invalid_option_specified
  123. assert_raise(ArgumentError) {PluginAWeek::StateMachine::Transition.new(@event, :invalid => true)}
  124. end
  125. def test_should_raise_exception_if_to_option_not_specified
  126. assert_raise(ArgumentError) {PluginAWeek::StateMachine::Transition.new(@event, :from => 'off')}
  127. end
  128. end
  129. class TransitionWithConditionalTest < Test::Unit::TestCase
  130. def setup
  131. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  132. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  133. @switch = create_switch(:state => 'off')
  134. end
  135. def test_should_be_able_to_perform_if_if_is_true
  136. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => lambda {true})
  137. assert transition.can_perform?(@switch)
  138. end
  139. def test_should_not_be_able_to_perform_if_if_is_false
  140. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => lambda {false})
  141. assert !transition.can_perform?(@switch)
  142. end
  143. def test_should_be_able_to_perform_if_unless_is_false
  144. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :unless => lambda {false})
  145. assert transition.can_perform?(@switch)
  146. end
  147. def test_should_not_be_able_to_perform_if_unless_is_true
  148. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :unless => lambda {true})
  149. assert !transition.can_perform?(@switch)
  150. end
  151. def test_should_pass_in_record_as_argument
  152. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => lambda {|record| !record.nil?})
  153. assert transition.can_perform?(@switch)
  154. end
  155. def test_should_be_able_to_perform_if_method_evaluates_to_true
  156. @switch.data = true
  157. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => :data)
  158. assert transition.can_perform?(@switch)
  159. end
  160. def test_should_not_be_able_to_perform_if_method_evaluates_to_false
  161. @switch.data = false
  162. transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :if => :data)
  163. assert !transition.can_perform?(@switch)
  164. end
  165. end
  166. class TransitionWithLoopbackTest < Test::Unit::TestCase
  167. def setup
  168. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  169. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  170. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'on')
  171. end
  172. def test_should_be_able_to_perform
  173. record = new_switch(:state => 'on')
  174. assert @transition.can_perform?(record)
  175. end
  176. def test_should_perform_for_valid_from_state
  177. record = new_switch(:state => 'on')
  178. assert @transition.perform(record)
  179. end
  180. end
  181. class TransitionWithFromStateTest < Test::Unit::TestCase
  182. def setup
  183. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  184. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  185. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
  186. end
  187. def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
  188. record = new_switch(:state => 'on')
  189. assert !@transition.can_perform?(record)
  190. end
  191. def test_should_be_able_to_perform_if_record_state_is_from_state
  192. record = new_switch(:state => 'off')
  193. assert @transition.can_perform?(record)
  194. end
  195. def test_should_perform_for_valid_from_state
  196. record = new_switch(:state => 'off')
  197. assert @transition.perform(record)
  198. end
  199. end
  200. class TransitionWithMultipleFromStatesTest < Test::Unit::TestCase
  201. def setup
  202. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  203. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  204. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => %w(off on))
  205. end
  206. def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
  207. record = new_switch(:state => 'unknown')
  208. assert !@transition.can_perform?(record)
  209. end
  210. def test_should_be_able_to_perform_if_record_state_is_any_from_state
  211. record = new_switch(:state => 'off')
  212. assert @transition.can_perform?(record)
  213. record = new_switch(:state => 'on')
  214. assert @transition.can_perform?(record)
  215. end
  216. def test_should_perform_for_any_valid_from_state
  217. record = new_switch(:state => 'off')
  218. assert @transition.perform(record)
  219. record = new_switch(:state => 'on')
  220. assert @transition.perform(record)
  221. end
  222. end
  223. class TransitionWithMismatchedFromStatesRequiredTest < Test::Unit::TestCase
  224. def setup
  225. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  226. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  227. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :except_from => 'on')
  228. end
  229. def test_should_be_able_to_perform_if_record_state_is_not_from_state
  230. record = new_switch(:state => 'off')
  231. assert @transition.can_perform?(record)
  232. end
  233. def test_should_not_be_able_to_perform_if_record_state_is_from_state
  234. record = new_switch(:state => 'on')
  235. assert !@transition.can_perform?(record)
  236. end
  237. def test_should_perform_for_valid_from_state
  238. record = new_switch(:state => 'off')
  239. assert @transition.perform(record)
  240. end
  241. def test_should_not_perform_for_invalid_from_state
  242. record = new_switch(:state => 'on')
  243. assert !@transition.can_perform?(record)
  244. end
  245. end
  246. class TransitionAfterBeingPerformedTest < Test::Unit::TestCase
  247. def setup
  248. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  249. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  250. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
  251. @record = create_switch(:state => 'off')
  252. @transition.perform(@record)
  253. @record.reload
  254. end
  255. def test_should_update_the_state_to_the_to_state
  256. assert_equal 'on', @record.state
  257. end
  258. def test_should_no_longer_be_able_to_perform_on_the_record
  259. assert !@transition.can_perform?(@record)
  260. end
  261. end
  262. class TransitionWithLoopbackAfterBeingPerformedTest < Test::Unit::TestCase
  263. def setup
  264. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  265. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  266. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'on')
  267. @record = create_switch(:state => 'on')
  268. @record.kind = 'light'
  269. @transition.perform(@record)
  270. @record.reload
  271. end
  272. def test_should_have_the_same_attribute
  273. assert_equal 'on', @record.state
  274. end
  275. def test_should_save_the_record
  276. assert_equal 'light', @record.kind
  277. end
  278. def test_should_still_be_able_to_perform_on_the_record
  279. assert @transition.can_perform?(@record)
  280. end
  281. end
  282. class TransitionWithCallbacksTest < Test::Unit::TestCase
  283. def setup
  284. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  285. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  286. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
  287. @record = create_switch(:state => 'off')
  288. Switch.define_callbacks :before_transition_state, :after_transition_state
  289. end
  290. def test_should_include_record_in_callback
  291. Switch.before_transition_state lambda {|record| record == @record}
  292. assert @transition.perform(@record)
  293. end
  294. def test_should_not_perform_if_before_callback_fails
  295. Switch.before_transition_state lambda {|record| false}
  296. Switch.after_transition_state lambda {|record| record.callbacks << 'after'; true}
  297. assert !@transition.perform(@record)
  298. assert_equal [], @record.callbacks
  299. end
  300. def test_should_raise_exception_if_before_callback_fails_during_perform!
  301. Switch.before_transition_state lambda {|record| false}
  302. assert_raise(PluginAWeek::StateMachine::InvalidTransition) {@transition.perform!(@record)}
  303. end
  304. def test_should_perform_if_after_callback_fails
  305. Switch.before_transition_state lambda {|record| record.callbacks << 'before'; true}
  306. Switch.after_transition_state lambda {|record| false}
  307. assert @transition.perform(@record)
  308. assert_equal %w(before), @record.callbacks
  309. end
  310. def test_should_not_raise_exception_if_after_callback_fails_during_perform!
  311. Switch.before_transition_state lambda {|record| record.callbacks << 'before'; true}
  312. Switch.after_transition_state lambda {|record| false}
  313. assert @transition.perform!(@record)
  314. end
  315. def test_should_perform_if_all_callbacks_are_successful
  316. Switch.before_transition_state lambda {|record| record.callbacks << 'before'; true}
  317. Switch.after_transition_state lambda {|record| record.callbacks << 'after'; true}
  318. assert @transition.perform(@record)
  319. assert_equal %w(before after), @record.callbacks
  320. end
  321. def test_should_stop_before_callbacks_if_any_fail
  322. Switch.before_transition_state lambda {|record| false}
  323. Switch.before_transition_state lambda {|record| record.callbacks << 'before_2'; true}
  324. assert !@transition.perform(@record)
  325. assert_equal [], @record.callbacks
  326. end
  327. def test_should_stop_after_callbacks_if_any_fail
  328. Switch.after_transition_state lambda {|record| false}
  329. Switch.after_transition_state lambda {|record| record.callbacks << 'after_2'; true}
  330. assert @transition.perform(@record)
  331. assert_equal [], @record.callbacks
  332. end
  333. def teardown
  334. Switch.class_eval do
  335. @before_transition_state_callbacks = nil
  336. @after_transition_state_callbacks = nil
  337. end
  338. end
  339. end
  340. class TransitionWithCallbackConditionalsTest < Test::Unit::TestCase
  341. def setup
  342. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  343. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  344. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
  345. @record = create_switch(:state => 'off')
  346. @invoked = false
  347. Switch.define_callbacks :before_transition_state, :after_transition_state
  348. end
  349. def test_should_invoke_callback_if_if_is_true
  350. Switch.before_transition_state lambda {|record| @invoked = true}, :if => lambda {true}
  351. @transition.perform(@record)
  352. assert @invoked
  353. end
  354. def test_should_not_invoke_callback_if_if_is_false
  355. Switch.before_transition_state lambda {|record| @invoked = true}, :if => lambda {false}
  356. @transition.perform(@record)
  357. assert !@invoked
  358. end
  359. def test_should_invoke_callback_if_unless_is_false
  360. Switch.before_transition_state lambda {|record| @invoked = true}, :unless => lambda {false}
  361. @transition.perform(@record)
  362. assert @invoked
  363. end
  364. def test_should_not_invoke_callback_if_unless_is_true
  365. Switch.before_transition_state lambda {|record| @invoked = true}, :unless => lambda {true}
  366. @transition.perform(@record)
  367. assert !@invoked
  368. end
  369. def teardown
  370. Switch.class_eval do
  371. @before_transition_state_callbacks = nil
  372. @after_transition_state_callbacks = nil
  373. end
  374. end
  375. end
  376. class TransitionWithCallbackQueryTest < Test::Unit::TestCase
  377. def setup
  378. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  379. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  380. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
  381. @record = create_switch(:state => 'off')
  382. Switch.define_callbacks :before_transition_state, :after_transition_state
  383. end
  384. def test_should_invoke_callback_if_from_state_included
  385. Switch.before_transition_state lambda {|record| @invoked = true}, :from => 'off'
  386. @transition.perform(@record)
  387. assert @invoked
  388. end
  389. def test_should_not_invoke_callback_if_from_state_not_included
  390. Switch.before_transition_state lambda {|record| @invoked = true}, :from => 'on'
  391. @transition.perform(@record)
  392. assert !@invoked
  393. end
  394. def test_should_invoke_callback_if_except_from_state_not_included
  395. Switch.before_transition_state lambda {|record| @invoked = true}, :except_from => 'on'
  396. @transition.perform(@record)
  397. assert @invoked
  398. end
  399. def test_should_not_invoke_callback_if_except_from_state_included
  400. Switch.before_transition_state lambda {|record| @invoked = true}, :except_from => 'off'
  401. @transition.perform(@record)
  402. assert !@invoked
  403. end
  404. def test_should_invoke_callback_if_to_state_included
  405. Switch.before_transition_state lambda {|record| @invoked = true}, :to => 'on'
  406. @transition.perform(@record)
  407. assert @invoked
  408. end
  409. def test_should_not_invoke_callback_if_to_state_not_included
  410. Switch.before_transition_state lambda {|record| @invoked = true}, :to => 'off'
  411. @transition.perform(@record)
  412. assert !@invoked
  413. end
  414. def test_should_invoke_callback_if_except_to_state_not_included
  415. Switch.before_transition_state lambda {|record| @invoked = true}, :except_to => 'off'
  416. @transition.perform(@record)
  417. assert @invoked
  418. end
  419. def test_should_not_invoke_callback_if_except_to_state_included
  420. Switch.before_transition_state lambda {|record| @invoked = true}, :except_to => 'on'
  421. @transition.perform(@record)
  422. assert !@invoked
  423. end
  424. def test_should_invoke_callback_if_on_event_included
  425. Switch.before_transition_state lambda {|record| @invoked = true}, :on => 'turn_on'
  426. @transition.perform(@record)
  427. assert @invoked
  428. end
  429. def test_should_not_invoke_callback_if_on_event_not_included
  430. Switch.before_transition_state lambda {|record| @invoked = true}, :on => 'turn_off'
  431. @transition.perform(@record)
  432. assert !@invoked
  433. end
  434. def test_should_invoke_callback_if_except_on_event_not_included
  435. Switch.before_transition_state lambda {|record| @invoked = true}, :except_on => 'turn_off'
  436. @transition.perform(@record)
  437. assert @invoked
  438. end
  439. def test_should_not_invoke_callback_if_except_on_event_included
  440. Switch.before_transition_state lambda {|record| @invoked = true}, :except_on => 'turn_on'
  441. @transition.perform(@record)
  442. assert !@invoked
  443. end
  444. def test_should_skip_callbacks_that_do_not_match
  445. Switch.before_transition_state lambda {|record| false}, :from => 'on'
  446. Switch.before_transition_state lambda {|record| @invoked = true}, :from => 'off'
  447. @transition.perform(@record)
  448. assert @invoked
  449. end
  450. def teardown
  451. Switch.class_eval do
  452. @before_transition_state_callbacks = nil
  453. @after_transition_state_callbacks = nil
  454. end
  455. end
  456. end
  457. class TransitionWithObserversTest < Test::Unit::TestCase
  458. def setup
  459. @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state')
  460. @event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
  461. @transition = PluginAWeek::StateMachine::Transition.new(@event, :to => 'on', :from => 'off')
  462. @record = create_switch(:state => 'off')
  463. Switch.define_callbacks :before_transition_state, :after_transition_state
  464. SwitchObserver.notifications = []
  465. end
  466. def test_should_notify_all_callbacks_if_successful
  467. @transition.perform(@record)
  468. expected = [
  469. ['before_turn_on', @record, 'off', 'on'],
  470. ['before_transition', @record, 'state', 'turn_on', 'off', 'on'],
  471. ['after_turn_on', @record, 'off', 'on'],
  472. ['after_transition', @record, 'state', 'turn_on', 'off', 'on']
  473. ]
  474. assert_equal expected, SwitchObserver.notifications
  475. end
  476. def test_should_notify_before_callbacks_if_before_callback_fails
  477. Switch.before_transition_state lambda {|record| false}
  478. @transition.perform(@record)
  479. expected = [
  480. ['before_turn_on', @record, 'off', 'on'],
  481. ['before_transition', @record, 'state', 'turn_on', 'off', 'on']
  482. ]
  483. assert_equal expected, SwitchObserver.notifications
  484. end
  485. def test_should_notify_before_and_after_callbacks_if_after_callback_fails
  486. Switch.after_transition_state lambda {|record| false}
  487. @transition.perform(@record)
  488. expected = [
  489. ['before_turn_on', @record, 'off', 'on'],
  490. ['before_transition', @record, 'state', 'turn_on', 'off', 'on'],
  491. ['after_turn_on', @record, 'off', 'on'],
  492. ['after_transition', @record, 'state', 'turn_on', 'off', 'on']
  493. ]
  494. assert_equal expected, SwitchObserver.notifications
  495. end
  496. def teardown
  497. Switch.class_eval do
  498. @before_transition_state_callbacks = nil
  499. @after_transition_state_callbacks = nil
  500. end
  501. end
  502. end