PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/test/unit/callback_test.rb

https://github.com/amatsuda/state_machine
Ruby | 728 lines | 576 code | 152 blank | 0 comment | 6 complexity | 3c940872a75355f81f228a2c4efc4bd3 MD5 | raw file
  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. class CallbackTest < Test::Unit::TestCase
  3. def test_should_raise_exception_if_invalid_type_specified
  4. exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:invalid) {} }
  5. assert_equal 'Type must be :before, :after, or :around', exception.message
  6. end
  7. def test_should_not_raise_exception_if_using_before_type
  8. assert_nothing_raised { StateMachine::Callback.new(:before) {} }
  9. end
  10. def test_should_not_raise_exception_if_using_after_type
  11. assert_nothing_raised { StateMachine::Callback.new(:after) {} }
  12. end
  13. def test_should_not_raise_exception_if_using_around_type
  14. assert_nothing_raised { StateMachine::Callback.new(:around) {} }
  15. end
  16. def test_should_raise_exception_if_no_methods_specified
  17. exception = assert_raise(ArgumentError) { StateMachine::Callback.new(:before) }
  18. assert_equal 'Method(s) for callback must be specified', exception.message
  19. end
  20. def test_should_not_raise_exception_if_method_specified_in_do_option
  21. assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run) }
  22. end
  23. def test_should_not_raise_exception_if_method_specified_as_argument
  24. assert_nothing_raised { StateMachine::Callback.new(:before, :run) }
  25. end
  26. def test_should_not_raise_exception_if_method_specified_as_block
  27. assert_nothing_raised { StateMachine::Callback.new(:before, :run) {} }
  28. end
  29. def test_should_not_raise_exception_if_implicit_option_specified
  30. assert_nothing_raised { StateMachine::Callback.new(:before, :do => :run, :invalid => :valid) }
  31. end
  32. def test_should_not_bind_to_objects
  33. assert !StateMachine::Callback.bind_to_object
  34. end
  35. def test_should_not_have_a_terminator
  36. assert_nil StateMachine::Callback.terminator
  37. end
  38. end
  39. class CallbackByDefaultTest < Test::Unit::TestCase
  40. def setup
  41. @callback = StateMachine::Callback.new(:before) {}
  42. end
  43. def test_should_have_type
  44. assert_equal :before, @callback.type
  45. end
  46. def test_should_not_have_a_terminator
  47. assert_nil @callback.terminator
  48. end
  49. def test_should_have_a_guard_with_all_matcher_requirements
  50. assert_equal StateMachine::AllMatcher.instance, @callback.guard.event_requirement
  51. assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:from]
  52. assert_equal StateMachine::AllMatcher.instance, @callback.guard.state_requirements.first[:to]
  53. end
  54. def test_should_not_have_any_known_states
  55. assert_equal [], @callback.known_states
  56. end
  57. end
  58. class CallbackWithMethodArgumentTest < Test::Unit::TestCase
  59. def setup
  60. @callback = StateMachine::Callback.new(:before, lambda {|*args| @args = args})
  61. @object = Object.new
  62. @result = @callback.call(@object)
  63. end
  64. def test_should_be_successful
  65. assert @result
  66. end
  67. def test_should_call_with_empty_context
  68. assert_equal [@object], @args
  69. end
  70. end
  71. class CallbackWithMultipleMethodArgumentsTest < Test::Unit::TestCase
  72. def setup
  73. @callback = StateMachine::Callback.new(:before, :run_1, :run_2)
  74. class << @object = Object.new
  75. attr_accessor :callbacks
  76. def run_1
  77. (@callbacks ||= []) << :run_1
  78. end
  79. def run_2
  80. (@callbacks ||= []) << :run_2
  81. end
  82. end
  83. @result = @callback.call(@object)
  84. end
  85. def test_should_be_successful
  86. assert @result
  87. end
  88. def test_should_call_each_callback_in_order
  89. assert_equal [:run_1, :run_2], @object.callbacks
  90. end
  91. end
  92. class CallbackWithDoMethodTest < Test::Unit::TestCase
  93. def setup
  94. @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
  95. @object = Object.new
  96. @result = @callback.call(@object)
  97. end
  98. def test_should_be_successful
  99. assert @result
  100. end
  101. def test_should_call_with_empty_context
  102. assert_equal [@object], @args
  103. end
  104. end
  105. class CallbackWithMultipleDoMethodsTest < Test::Unit::TestCase
  106. def setup
  107. @callback = StateMachine::Callback.new(:before, :do => [:run_1, :run_2])
  108. class << @object = Object.new
  109. attr_accessor :callbacks
  110. def run_1
  111. (@callbacks ||= []) << :run_1
  112. end
  113. def run_2
  114. (@callbacks ||= []) << :run_2
  115. end
  116. end
  117. @result = @callback.call(@object)
  118. end
  119. def test_should_be_successful
  120. assert @result
  121. end
  122. def test_should_call_each_callback_in_order
  123. assert_equal [:run_1, :run_2], @object.callbacks
  124. end
  125. end
  126. class CallbackWithBlockTest < Test::Unit::TestCase
  127. def setup
  128. @callback = StateMachine::Callback.new(:before) do |*args|
  129. @args = args
  130. end
  131. @object = Object.new
  132. @result = @callback.call(@object)
  133. end
  134. def test_should_be_successful
  135. assert @result
  136. end
  137. def test_should_call_with_empty_context
  138. assert_equal [@object], @args
  139. end
  140. end
  141. class CallbackWithMixedMethodsTest < Test::Unit::TestCase
  142. def setup
  143. @callback = StateMachine::Callback.new(:before, :run_argument, :do => :run_do) do |object|
  144. object.callbacks << :block
  145. end
  146. class << @object = Object.new
  147. attr_accessor :callbacks
  148. def run_argument
  149. (@callbacks ||= []) << :argument
  150. end
  151. def run_do
  152. (@callbacks ||= []) << :do
  153. end
  154. end
  155. @result = @callback.call(@object)
  156. end
  157. def test_should_be_successful
  158. assert @result
  159. end
  160. def test_should_call_each_callback_in_order
  161. assert_equal [:argument, :do, :block], @object.callbacks
  162. end
  163. end
  164. class CallbackWithExplicitRequirementsTest < Test::Unit::TestCase
  165. def setup
  166. @object = Object.new
  167. @callback = StateMachine::Callback.new(:before, :from => :parked, :to => :idling, :on => :ignite, :do => lambda {})
  168. end
  169. def test_should_call_with_empty_context
  170. assert @callback.call(@object, {})
  171. end
  172. def test_should_not_call_if_from_not_included
  173. assert !@callback.call(@object, :from => :idling)
  174. end
  175. def test_should_not_call_if_to_not_included
  176. assert !@callback.call(@object, :to => :parked)
  177. end
  178. def test_should_not_call_if_on_not_included
  179. assert !@callback.call(@object, :on => :park)
  180. end
  181. def test_should_call_if_all_requirements_met
  182. assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
  183. end
  184. def test_should_include_in_known_states
  185. assert_equal [:parked, :idling], @callback.known_states
  186. end
  187. end
  188. class CallbackWithImplicitRequirementsTest < Test::Unit::TestCase
  189. def setup
  190. @object = Object.new
  191. @callback = StateMachine::Callback.new(:before, :parked => :idling, :on => :ignite, :do => lambda {})
  192. end
  193. def test_should_call_with_empty_context
  194. assert @callback.call(@object, {})
  195. end
  196. def test_should_not_call_if_from_not_included
  197. assert !@callback.call(@object, :from => :idling)
  198. end
  199. def test_should_not_call_if_to_not_included
  200. assert !@callback.call(@object, :to => :parked)
  201. end
  202. def test_should_not_call_if_on_not_included
  203. assert !@callback.call(@object, :on => :park)
  204. end
  205. def test_should_call_if_all_requirements_met
  206. assert @callback.call(@object, :from => :parked, :to => :idling, :on => :ignite)
  207. end
  208. def test_should_include_in_known_states
  209. assert_equal [:parked, :idling], @callback.known_states
  210. end
  211. end
  212. class CallbackWithIfConditionTest < Test::Unit::TestCase
  213. def setup
  214. @object = Object.new
  215. end
  216. def test_should_call_if_true
  217. callback = StateMachine::Callback.new(:before, :if => lambda {true}, :do => lambda {})
  218. assert callback.call(@object)
  219. end
  220. def test_should_not_call_if_false
  221. callback = StateMachine::Callback.new(:before, :if => lambda {false}, :do => lambda {})
  222. assert !callback.call(@object)
  223. end
  224. end
  225. class CallbackWithUnlessConditionTest < Test::Unit::TestCase
  226. def setup
  227. @object = Object.new
  228. end
  229. def test_should_call_if_false
  230. callback = StateMachine::Callback.new(:before, :unless => lambda {false}, :do => lambda {})
  231. assert callback.call(@object)
  232. end
  233. def test_should_not_call_if_true
  234. callback = StateMachine::Callback.new(:before, :unless => lambda {true}, :do => lambda {})
  235. assert !callback.call(@object)
  236. end
  237. end
  238. class CallbackWithoutTerminatorTest < Test::Unit::TestCase
  239. def setup
  240. @object = Object.new
  241. end
  242. def test_should_not_halt_if_result_is_false
  243. callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => nil)
  244. assert_nothing_thrown { callback.call(@object) }
  245. end
  246. end
  247. class CallbackWithTerminatorTest < Test::Unit::TestCase
  248. def setup
  249. @object = Object.new
  250. end
  251. def test_should_not_halt_if_terminator_does_not_match
  252. callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == true})
  253. assert_nothing_thrown { callback.call(@object) }
  254. end
  255. def test_should_halt_if_terminator_matches
  256. callback = StateMachine::Callback.new(:before, :do => lambda {false}, :terminator => lambda {|result| result == false})
  257. assert_throws(:halt) { callback.call(@object) }
  258. end
  259. def test_should_halt_if_terminator_matches_any_method
  260. callback = StateMachine::Callback.new(:before, :do => [lambda {true}, lambda {false}], :terminator => lambda {|result| result == false})
  261. assert_throws(:halt) { callback.call(@object) }
  262. end
  263. end
  264. class CallbackWithoutArgumentsTest < Test::Unit::TestCase
  265. def setup
  266. @callback = StateMachine::Callback.new(:before, :do => lambda {|object| @arg = object})
  267. @object = Object.new
  268. @callback.call(@object, {}, 1, 2, 3)
  269. end
  270. def test_should_call_method_with_object_as_argument
  271. assert_equal @object, @arg
  272. end
  273. end
  274. class CallbackWithArgumentsTest < Test::Unit::TestCase
  275. def setup
  276. @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @args = args})
  277. @object = Object.new
  278. @callback.call(@object, {}, 1, 2, 3)
  279. end
  280. def test_should_call_method_with_all_arguments
  281. assert_equal [@object, 1, 2, 3], @args
  282. end
  283. end
  284. class CallbackWithUnboundMethodTest < Test::Unit::TestCase
  285. def setup
  286. @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| @context = args.unshift(self)})
  287. @object = Object.new
  288. @callback.call(@object, {}, 1, 2, 3)
  289. end
  290. def test_should_call_method_outside_the_context_of_the_object
  291. assert_equal [self, @object, 1, 2, 3], @context
  292. end
  293. end
  294. class CallbackWithBoundMethodTest < Test::Unit::TestCase
  295. def setup
  296. @object = Object.new
  297. end
  298. def test_should_call_method_within_the_context_of_the_object_for_block_methods
  299. context = nil
  300. callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = [self] + args}, :bind_to_object => true)
  301. callback.call(@object, {}, 1, 2, 3)
  302. assert_equal [@object, 1, 2, 3], context
  303. end
  304. def test_should_ignore_option_for_symbolic_methods
  305. class << @object
  306. attr_reader :context
  307. def after_ignite(*args)
  308. @context = args
  309. end
  310. end
  311. callback = StateMachine::Callback.new(:before, :do => :after_ignite, :bind_to_object => true)
  312. callback.call(@object)
  313. assert_equal [], @object.context
  314. end
  315. def test_should_ignore_option_for_string_methods
  316. callback = StateMachine::Callback.new(:before, :do => '[1, 2, 3]', :bind_to_object => true)
  317. assert callback.call(@object)
  318. end
  319. end
  320. class CallbackWithMultipleBoundMethodsTest < Test::Unit::TestCase
  321. def setup
  322. @object = Object.new
  323. first_context = nil
  324. second_context = nil
  325. @callback = StateMachine::Callback.new(:before, :do => [lambda {first_context = self}, lambda {second_context = self}], :bind_to_object => true)
  326. @callback.call(@object)
  327. @first_context = first_context
  328. @second_context = second_context
  329. end
  330. def test_should_call_each_method_within_the_context_of_the_object
  331. assert_equal @object, @first_context
  332. assert_equal @object, @second_context
  333. end
  334. end
  335. class CallbackWithApplicationBoundObjectTest < Test::Unit::TestCase
  336. def setup
  337. @original_bind_to_object = StateMachine::Callback.bind_to_object
  338. StateMachine::Callback.bind_to_object = true
  339. context = nil
  340. @callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = self})
  341. @object = Object.new
  342. @callback.call(@object)
  343. @context = context
  344. end
  345. def test_should_call_method_within_the_context_of_the_object
  346. assert_equal @object, @context
  347. end
  348. def teardown
  349. StateMachine::Callback.bind_to_object = @original_bind_to_object
  350. end
  351. end
  352. class CallbackWithBoundMethodAndArgumentsTest < Test::Unit::TestCase
  353. def setup
  354. @object = Object.new
  355. end
  356. def test_should_include_single_argument_if_specified
  357. context = nil
  358. callback = StateMachine::Callback.new(:before, :do => lambda {|arg1| context = [arg1]}, :bind_to_object => true)
  359. callback.call(@object, {}, 1)
  360. assert_equal [1], context
  361. end
  362. def test_should_include_multiple_arguments_if_specified
  363. context = nil
  364. callback = StateMachine::Callback.new(:before, :do => lambda {|arg1, arg2, arg3| context = [arg1, arg2, arg3]}, :bind_to_object => true)
  365. callback.call(@object, {}, 1, 2, 3)
  366. assert_equal [1, 2, 3], context
  367. end
  368. def test_should_include_arguments_if_splat_used
  369. context = nil
  370. callback = StateMachine::Callback.new(:before, :do => lambda {|*args| context = args}, :bind_to_object => true)
  371. callback.call(@object, {}, 1, 2, 3)
  372. assert_equal [1, 2, 3], context
  373. end
  374. end
  375. class CallbackWithApplicationTerminatorTest < Test::Unit::TestCase
  376. def setup
  377. @original_terminator = StateMachine::Callback.bind_to_object
  378. StateMachine::Callback.terminator = lambda {|result| result == false}
  379. @object = Object.new
  380. end
  381. def test_should_not_halt_if_terminator_does_not_match
  382. callback = StateMachine::Callback.new(:before, :do => lambda {true})
  383. assert_nothing_thrown { callback.call(@object) }
  384. end
  385. def test_should_halt_if_terminator_matches
  386. callback = StateMachine::Callback.new(:before, :do => lambda {false})
  387. assert_throws(:halt) { callback.call(@object) }
  388. end
  389. def teardown
  390. StateMachine::Callback.bind_to_object = @original_bind_to_object
  391. end
  392. end
  393. class CallbackWithAroundTypeAndBlockTest < Test::Unit::TestCase
  394. def setup
  395. @object = Object.new
  396. @callbacks = []
  397. end
  398. def test_should_evaluate_before_without_after
  399. callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
  400. assert callback.call(@object)
  401. assert_equal [@object], @args
  402. end
  403. def test_should_evaluate_after_without_before
  404. callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; block.call; @args = args})
  405. assert callback.call(@object)
  406. assert_equal [@object], @args
  407. end
  408. def test_should_halt_if_not_yielded
  409. callback = StateMachine::Callback.new(:around, lambda {|block|})
  410. assert_throws(:halt) { callback.call(@object) }
  411. end
  412. def test_should_call_block_after_before
  413. callback = StateMachine::Callback.new(:around, lambda {|block| @callbacks << :before; block.call})
  414. assert callback.call(@object) { @callbacks << :block }
  415. assert_equal [:before, :block], @callbacks
  416. end
  417. def test_should_call_block_before_after
  418. @callbacks = []
  419. callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
  420. assert callback.call(@object) { @callbacks << :block }
  421. assert_equal [:block, :after], @callbacks
  422. end
  423. def test_should_halt_if_block_halts
  424. callback = StateMachine::Callback.new(:around, lambda {|block| block.call; @callbacks << :after})
  425. assert_throws(:halt) { callback.call(@object) { throw :halt } }
  426. assert_equal [], @callbacks
  427. end
  428. end
  429. class CallbackWithAroundTypeAndMultipleMethodsTest < Test::Unit::TestCase
  430. def setup
  431. @callback = StateMachine::Callback.new(:around, :run_1, :run_2)
  432. class << @object = Object.new
  433. attr_accessor :before_callbacks
  434. attr_accessor :after_callbacks
  435. def run_1
  436. (@before_callbacks ||= []) << :run_1
  437. yield
  438. (@after_callbacks ||= []) << :run_1
  439. end
  440. def run_2
  441. (@before_callbacks ||= []) << :run_2
  442. yield
  443. (@after_callbacks ||= []) << :run_2
  444. end
  445. end
  446. end
  447. def test_should_succeed
  448. assert @callback.call(@object)
  449. end
  450. def test_should_evaluate_before_callbacks_in_order
  451. @callback.call(@object)
  452. assert_equal [:run_1, :run_2], @object.before_callbacks
  453. end
  454. def test_should_evaluate_after_callbacks_in_reverse_order
  455. @callback.call(@object)
  456. assert_equal [:run_2, :run_1], @object.after_callbacks
  457. end
  458. def test_should_call_block_after_before_callbacks
  459. @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
  460. assert_equal [:run_1, :run_2, :block], @object.before_callbacks
  461. end
  462. def test_should_call_block_before_after_callbacks
  463. @callback.call(@object) { (@object.after_callbacks ||= []) << :block }
  464. assert_equal [:block, :run_2, :run_1], @object.after_callbacks
  465. end
  466. def test_should_halt_if_first_doesnt_yield
  467. class << @object
  468. def run_1
  469. (@before_callbacks ||= []) << :run_1
  470. end
  471. end
  472. catch(:halt) do
  473. @callback.call(@object) { (@object.before_callbacks ||= []) << :block }
  474. end
  475. assert_equal [:run_1], @object.before_callbacks
  476. assert_nil @object.after_callbacks
  477. end
  478. def test_should_halt_if_last_doesnt_yield
  479. class << @object
  480. def run_2
  481. (@before_callbacks ||= []) << :run_2
  482. end
  483. end
  484. catch(:halt) { @callback.call(@object) }
  485. assert_equal [:run_1, :run_2], @object.before_callbacks
  486. assert_nil @object.after_callbacks
  487. end
  488. def test_should_not_evaluate_further_methods_if_after_halts
  489. class << @object
  490. def run_2
  491. (@before_callbacks ||= []) << :run_2
  492. yield
  493. (@after_callbacks ||= []) << :run_2
  494. throw :halt
  495. end
  496. end
  497. catch(:halt) { @callback.call(@object) }
  498. assert_equal [:run_1, :run_2], @object.before_callbacks
  499. assert_equal [:run_2], @object.after_callbacks
  500. end
  501. end
  502. class CallbackWithAroundTypeAndArgumentsTest < Test::Unit::TestCase
  503. def setup
  504. @object = Object.new
  505. end
  506. def test_should_include_object_if_specified
  507. callback = StateMachine::Callback.new(:around, lambda {|object, block| @args = [object]; block.call})
  508. callback.call(@object)
  509. assert_equal [@object], @args
  510. end
  511. def test_should_include_arguments_if_specified
  512. callback = StateMachine::Callback.new(:around, lambda {|object, arg1, arg2, arg3, block| @args = [object, arg1, arg2, arg3]; block.call})
  513. callback.call(@object, {}, 1, 2, 3)
  514. assert_equal [@object, 1, 2, 3], @args
  515. end
  516. def test_should_include_arguments_if_splat_used
  517. callback = StateMachine::Callback.new(:around, lambda {|*args| block = args.pop; @args = args; block.call})
  518. callback.call(@object, {}, 1, 2, 3)
  519. assert_equal [@object, 1, 2, 3], @args
  520. end
  521. end
  522. class CallbackWithAroundTypeAndTerminatorTest < Test::Unit::TestCase
  523. def setup
  524. @object = Object.new
  525. end
  526. def test_should_not_halt_if_terminator_does_not_match
  527. callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == true})
  528. assert_nothing_thrown { callback.call(@object) }
  529. end
  530. def test_should_not_halt_if_terminator_matches
  531. callback = StateMachine::Callback.new(:around, :do => lambda {|block| block.call(false); false}, :terminator => lambda {|result| result == false})
  532. assert_nothing_thrown { callback.call(@object) }
  533. end
  534. end
  535. class CallbackWithAroundTypeAndBoundMethodTest < Test::Unit::TestCase
  536. def setup
  537. @object = Object.new
  538. end
  539. def test_should_call_method_within_the_context_of_the_object
  540. context = nil
  541. callback = StateMachine::Callback.new(:around, :do => lambda {|block| context = self; block.call}, :bind_to_object => true)
  542. callback.call(@object, {}, 1, 2, 3)
  543. assert_equal @object, context
  544. end
  545. def test_should_include_arguments_if_specified
  546. context = nil
  547. callback = StateMachine::Callback.new(:around, :do => lambda {|*args| block = args.pop; context = args; block.call}, :bind_to_object => true)
  548. callback.call(@object, {}, 1, 2, 3)
  549. assert_equal [1, 2, 3], context
  550. end
  551. end
  552. class CallbackSuccessMatcherTest < Test::Unit::TestCase
  553. def setup
  554. @object = Object.new
  555. end
  556. def test_should_match_if_not_specified
  557. callback = StateMachine::Callback.new(:before) {}
  558. assert callback.matches_success?(true)
  559. end
  560. def test_should_match_if_true_and_not_including_failures
  561. callback = StateMachine::Callback.new(:before, :include_failures => false) {}
  562. assert callback.matches_success?(true)
  563. end
  564. def test_should_match_if_true_and_including_failures
  565. callback = StateMachine::Callback.new(:before, :include_failures => true) {}
  566. assert callback.matches_success?(true)
  567. end
  568. def test_should_not_match_if_false_and_not_including_failures
  569. callback = StateMachine::Callback.new(:before, :include_failures => false) {}
  570. assert !callback.matches_success?(false)
  571. end
  572. def test_Should_match_if_false_and_including_failures
  573. callback = StateMachine::Callback.new(:before, :include_failures => true) {}
  574. assert callback.matches_success?(false)
  575. end
  576. end