PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/plugins/state_machine/test/functional/state_machine_test.rb

https://bitbucket.org/systech3/boxyroom
Ruby | 941 lines | 729 code | 203 blank | 9 comment | 3 complexity | 439c89b6c91405a4ab129172dca53353 MD5 | raw file
Possible License(s): JSON, MIT
  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. class AutoShop
  3. attr_accessor :num_customers
  4. def initialize
  5. @num_customers = 0
  6. super
  7. end
  8. state_machine :initial => :available do
  9. after_transition :available => any, :do => :increment_customers
  10. after_transition :busy => any, :do => :decrement_customers
  11. event :tow_vehicle do
  12. transition :available => :busy
  13. end
  14. event :fix_vehicle do
  15. transition :busy => :available
  16. end
  17. end
  18. # Increments the number of customers in service
  19. def increment_customers
  20. self.num_customers += 1
  21. end
  22. # Decrements the number of customers in service
  23. def decrement_customers
  24. self.num_customers -= 1
  25. end
  26. end
  27. class ModelBase
  28. def save
  29. @saved = true
  30. self
  31. end
  32. end
  33. class Vehicle < ModelBase
  34. attr_accessor :auto_shop, :seatbelt_on, :insurance_premium, :force_idle, :callbacks, :saved
  35. def initialize(attributes = {})
  36. attributes = {
  37. :auto_shop => AutoShop.new,
  38. :seatbelt_on => false,
  39. :insurance_premium => 50,
  40. :force_idle => false,
  41. :callbacks => [],
  42. :saved => false
  43. }.merge(attributes)
  44. attributes.each {|attr, value| send("#{attr}=", value)}
  45. super()
  46. end
  47. # Defines the state machine for the state of the vehicled
  48. state_machine :initial => lambda {|vehicle| vehicle.force_idle ? :idling : :parked}, :action => :save do
  49. before_transition :parked => any, :do => :put_on_seatbelt
  50. before_transition any => :stalled, :do => :increase_insurance_premium
  51. after_transition any => :parked, :do => lambda {|vehicle| vehicle.seatbelt_on = false}
  52. after_transition :on => :crash, :do => :tow
  53. after_transition :on => :repair, :do => :fix
  54. # Callback tracking for initial state callbacks
  55. after_transition any => :parked, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_parked'}
  56. before_transition any => :idling, :do => lambda {|vehicle| vehicle.callbacks << 'before_enter_idling'}
  57. event :park do
  58. transition [:idling, :first_gear] => :parked
  59. end
  60. event :ignite do
  61. transition :stalled => :stalled
  62. transition :parked => :idling
  63. end
  64. event :idle do
  65. transition :first_gear => :idling
  66. end
  67. event :shift_up do
  68. transition :idling => :first_gear, :first_gear => :second_gear, :second_gear => :third_gear
  69. end
  70. event :shift_down do
  71. transition :third_gear => :second_gear
  72. transition :second_gear => :first_gear
  73. end
  74. event :crash do
  75. transition [:first_gear, :second_gear, :third_gear] => :stalled, :if => lambda {|vehicle| vehicle.auto_shop.available?}
  76. end
  77. event :repair do
  78. transition :stalled => :parked, :if => :auto_shop_busy?
  79. end
  80. end
  81. state_machine :insurance_state, :initial => :inactive, :namespace => 'insurance' do
  82. event :buy do
  83. transition :inactive => :active
  84. end
  85. event :cancel do
  86. transition :active => :inactive
  87. end
  88. end
  89. def save
  90. super
  91. end
  92. def new_record?
  93. @saved == false
  94. end
  95. def park
  96. super
  97. end
  98. # Tows the vehicle to the auto shop
  99. def tow
  100. auto_shop.tow_vehicle
  101. end
  102. # Fixes the vehicle; it will no longer be in the auto shop
  103. def fix
  104. auto_shop.fix_vehicle
  105. end
  106. private
  107. # Safety first! Puts on our seatbelt
  108. def put_on_seatbelt
  109. self.seatbelt_on = true
  110. end
  111. # We crashed! Increase the insurance premium on the vehicle
  112. def increase_insurance_premium
  113. self.insurance_premium += 100
  114. end
  115. # Is the auto shop currently servicing another customer?
  116. def auto_shop_busy?
  117. auto_shop.busy?
  118. end
  119. end
  120. class Car < Vehicle
  121. state_machine do
  122. event :reverse do
  123. transition [:parked, :idling, :first_gear] => :backing_up
  124. end
  125. event :park do
  126. transition :backing_up => :parked
  127. end
  128. event :idle do
  129. transition :backing_up => :idling
  130. end
  131. event :shift_up do
  132. transition :backing_up => :first_gear
  133. end
  134. end
  135. end
  136. class Motorcycle < Vehicle
  137. state_machine :initial => :idling
  138. end
  139. class TrafficLight
  140. state_machine :initial => :stop do
  141. event :cycle do
  142. transition :stop => :proceed, :proceed=> :caution, :caution => :stop
  143. end
  144. state :stop do
  145. def color(transform)
  146. value = 'red'
  147. if block_given?
  148. yield value
  149. else
  150. value.send(transform)
  151. end
  152. value
  153. end
  154. end
  155. state :proceed do
  156. def color(transform)
  157. 'green'
  158. end
  159. end
  160. state :caution do
  161. def color(transform)
  162. 'yellow'
  163. end
  164. end
  165. end
  166. def color(transform = :to_s)
  167. super
  168. end
  169. end
  170. class VehicleTest < Test::Unit::TestCase
  171. def setup
  172. @vehicle = Vehicle.new
  173. end
  174. def test_should_not_allow_access_to_subclass_events
  175. assert !@vehicle.respond_to?(:reverse)
  176. end
  177. end
  178. class VehicleUnsavedTest < Test::Unit::TestCase
  179. def setup
  180. @vehicle = Vehicle.new
  181. end
  182. def test_should_be_in_parked_state
  183. assert_equal 'parked', @vehicle.state
  184. end
  185. def test_should_raise_exception_if_checking_invalid_state
  186. assert_raise(IndexError) { @vehicle.state?(:invalid) }
  187. end
  188. def test_should_raise_exception_if_getting_name_of_invalid_state
  189. @vehicle.state = 'invalid'
  190. assert_raise(ArgumentError) { @vehicle.state_name }
  191. end
  192. def test_should_be_parked
  193. assert @vehicle.parked?
  194. assert @vehicle.state?(:parked)
  195. assert_equal :parked, @vehicle.state_name
  196. end
  197. def test_should_not_be_idling
  198. assert !@vehicle.idling?
  199. end
  200. def test_should_not_be_first_gear
  201. assert !@vehicle.first_gear?
  202. end
  203. def test_should_not_be_second_gear
  204. assert !@vehicle.second_gear?
  205. end
  206. def test_should_not_be_stalled
  207. assert !@vehicle.stalled?
  208. end
  209. def test_should_not_be_able_to_park
  210. assert !@vehicle.can_park?
  211. end
  212. def test_should_not_have_a_transition_for_park
  213. assert_nil @vehicle.park_transition
  214. end
  215. def test_should_not_allow_park
  216. assert !@vehicle.park
  217. end
  218. def test_should_be_able_to_ignite
  219. assert @vehicle.can_ignite?
  220. end
  221. def test_should_have_a_transition_for_ignite
  222. transition = @vehicle.ignite_transition
  223. assert_not_nil transition
  224. assert_equal 'parked', transition.from
  225. assert_equal 'idling', transition.to
  226. assert_equal :ignite, transition.event
  227. assert_equal :state, transition.attribute
  228. assert_equal @vehicle, transition.object
  229. end
  230. def test_should_have_a_list_of_possible_events
  231. assert_equal [:ignite], @vehicle.state_events
  232. end
  233. def test_should_have_a_list_of_possible_transitions
  234. assert_equal [{:object => @vehicle, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}], @vehicle.state_transitions.map {|transition| transition.attributes}
  235. end
  236. def test_should_allow_ignite
  237. assert @vehicle.ignite
  238. assert_equal 'idling', @vehicle.state
  239. end
  240. def test_should_allow_ignite_with_skipped_action
  241. assert @vehicle.ignite(false)
  242. assert @vehicle.new_record?
  243. end
  244. def test_should_allow_ignite_bang
  245. assert @vehicle.ignite!
  246. end
  247. def test_should_allow_ignite_bang_with_skipped_action
  248. assert @vehicle.ignite!(false)
  249. assert @vehicle.new_record?
  250. end
  251. def test_should_be_saved_after_successful_event
  252. @vehicle.ignite
  253. assert !@vehicle.new_record?
  254. end
  255. def test_should_not_allow_idle
  256. assert !@vehicle.idle
  257. end
  258. def test_should_not_allow_shift_up
  259. assert !@vehicle.shift_up
  260. end
  261. def test_should_not_allow_shift_down
  262. assert !@vehicle.shift_down
  263. end
  264. def test_should_not_allow_crash
  265. assert !@vehicle.crash
  266. end
  267. def test_should_not_allow_repair
  268. assert !@vehicle.repair
  269. end
  270. def test_should_be_insurance_inactive
  271. assert @vehicle.insurance_inactive?
  272. end
  273. def test_should_be_able_to_buy
  274. assert @vehicle.can_buy_insurance?
  275. end
  276. def test_should_allow_buying_insurance
  277. assert @vehicle.buy_insurance
  278. end
  279. def test_should_allow_buying_insurance_bang
  280. assert @vehicle.buy_insurance!
  281. end
  282. def test_should_allow_ignite_buying_insurance_with_skipped_action
  283. assert @vehicle.buy_insurance!(false)
  284. assert @vehicle.new_record?
  285. end
  286. def test_should_not_be_insurance_active
  287. assert !@vehicle.insurance_active?
  288. end
  289. def test_should_not_be_able_to_cancel
  290. assert !@vehicle.can_cancel_insurance?
  291. end
  292. def test_should_not_allow_cancelling_insurance
  293. assert !@vehicle.cancel_insurance
  294. end
  295. end
  296. class VehicleParkedTest < Test::Unit::TestCase
  297. def setup
  298. @vehicle = Vehicle.new
  299. end
  300. def test_should_be_in_parked_state
  301. assert_equal 'parked', @vehicle.state
  302. end
  303. def test_should_not_have_the_seatbelt_on
  304. assert !@vehicle.seatbelt_on
  305. end
  306. def test_should_not_allow_park
  307. assert !@vehicle.park
  308. end
  309. def test_should_allow_ignite
  310. assert @vehicle.ignite
  311. assert_equal 'idling', @vehicle.state
  312. end
  313. def test_should_not_allow_idle
  314. assert !@vehicle.idle
  315. end
  316. def test_should_not_allow_shift_up
  317. assert !@vehicle.shift_up
  318. end
  319. def test_should_not_allow_shift_down
  320. assert !@vehicle.shift_down
  321. end
  322. def test_should_not_allow_crash
  323. assert !@vehicle.crash
  324. end
  325. def test_should_not_allow_repair
  326. assert !@vehicle.repair
  327. end
  328. def test_should_raise_exception_if_repair_not_allowed!
  329. assert_raise(StateMachine::InvalidTransition) {@vehicle.repair!}
  330. end
  331. end
  332. class VehicleIdlingTest < Test::Unit::TestCase
  333. def setup
  334. @vehicle = Vehicle.new
  335. @vehicle.ignite
  336. end
  337. def test_should_be_in_idling_state
  338. assert_equal 'idling', @vehicle.state
  339. end
  340. def test_should_be_idling
  341. assert @vehicle.idling?
  342. end
  343. def test_should_have_seatbelt_on
  344. assert @vehicle.seatbelt_on
  345. end
  346. def test_should_allow_park
  347. assert @vehicle.park
  348. end
  349. def test_should_call_park_with_bang_action
  350. class << @vehicle
  351. def park
  352. super && 1
  353. end
  354. end
  355. assert_equal 1, @vehicle.park!
  356. end
  357. def test_should_not_allow_idle
  358. assert !@vehicle.idle
  359. end
  360. def test_should_allow_shift_up
  361. assert @vehicle.shift_up
  362. end
  363. def test_should_not_allow_shift_down
  364. assert !@vehicle.shift_down
  365. end
  366. def test_should_not_allow_crash
  367. assert !@vehicle.crash
  368. end
  369. def test_should_not_allow_repair
  370. assert !@vehicle.repair
  371. end
  372. end
  373. class VehicleFirstGearTest < Test::Unit::TestCase
  374. def setup
  375. @vehicle = Vehicle.new
  376. @vehicle.ignite
  377. @vehicle.shift_up
  378. end
  379. def test_should_be_in_first_gear_state
  380. assert_equal 'first_gear', @vehicle.state
  381. end
  382. def test_should_be_first_gear
  383. assert @vehicle.first_gear?
  384. end
  385. def test_should_allow_park
  386. assert @vehicle.park
  387. end
  388. def test_should_allow_idle
  389. assert @vehicle.idle
  390. end
  391. def test_should_allow_shift_up
  392. assert @vehicle.shift_up
  393. end
  394. def test_should_not_allow_shift_down
  395. assert !@vehicle.shift_down
  396. end
  397. def test_should_allow_crash
  398. assert @vehicle.crash
  399. end
  400. def test_should_not_allow_repair
  401. assert !@vehicle.repair
  402. end
  403. end
  404. class VehicleSecondGearTest < Test::Unit::TestCase
  405. def setup
  406. @vehicle = Vehicle.new
  407. @vehicle.ignite
  408. 2.times {@vehicle.shift_up}
  409. end
  410. def test_should_be_in_second_gear_state
  411. assert_equal 'second_gear', @vehicle.state
  412. end
  413. def test_should_be_second_gear
  414. assert @vehicle.second_gear?
  415. end
  416. def test_should_not_allow_park
  417. assert !@vehicle.park
  418. end
  419. def test_should_not_allow_idle
  420. assert !@vehicle.idle
  421. end
  422. def test_should_allow_shift_up
  423. assert @vehicle.shift_up
  424. end
  425. def test_should_allow_shift_down
  426. assert @vehicle.shift_down
  427. end
  428. def test_should_allow_crash
  429. assert @vehicle.crash
  430. end
  431. def test_should_not_allow_repair
  432. assert !@vehicle.repair
  433. end
  434. end
  435. class VehicleThirdGearTest < Test::Unit::TestCase
  436. def setup
  437. @vehicle = Vehicle.new
  438. @vehicle.ignite
  439. 3.times {@vehicle.shift_up}
  440. end
  441. def test_should_be_in_third_gear_state
  442. assert_equal 'third_gear', @vehicle.state
  443. end
  444. def test_should_be_third_gear
  445. assert @vehicle.third_gear?
  446. end
  447. def test_should_not_allow_park
  448. assert !@vehicle.park
  449. end
  450. def test_should_not_allow_idle
  451. assert !@vehicle.idle
  452. end
  453. def test_should_not_allow_shift_up
  454. assert !@vehicle.shift_up
  455. end
  456. def test_should_allow_shift_down
  457. assert @vehicle.shift_down
  458. end
  459. def test_should_allow_crash
  460. assert @vehicle.crash
  461. end
  462. def test_should_not_allow_repair
  463. assert !@vehicle.repair
  464. end
  465. end
  466. class VehicleStalledTest < Test::Unit::TestCase
  467. def setup
  468. @vehicle = Vehicle.new
  469. @vehicle.ignite
  470. @vehicle.shift_up
  471. @vehicle.crash
  472. end
  473. def test_should_be_in_stalled_state
  474. assert_equal 'stalled', @vehicle.state
  475. end
  476. def test_should_be_stalled
  477. assert @vehicle.stalled?
  478. end
  479. def test_should_be_towed
  480. assert @vehicle.auto_shop.busy?
  481. assert_equal 1, @vehicle.auto_shop.num_customers
  482. end
  483. def test_should_have_an_increased_insurance_premium
  484. assert_equal 150, @vehicle.insurance_premium
  485. end
  486. def test_should_not_allow_park
  487. assert !@vehicle.park
  488. end
  489. def test_should_allow_ignite
  490. assert @vehicle.ignite
  491. end
  492. def test_should_not_change_state_when_ignited
  493. assert_equal 'stalled', @vehicle.state
  494. end
  495. def test_should_not_allow_idle
  496. assert !@vehicle.idle
  497. end
  498. def test_should_now_allow_shift_up
  499. assert !@vehicle.shift_up
  500. end
  501. def test_should_not_allow_shift_down
  502. assert !@vehicle.shift_down
  503. end
  504. def test_should_not_allow_crash
  505. assert !@vehicle.crash
  506. end
  507. def test_should_allow_repair_if_auto_shop_is_busy
  508. assert @vehicle.repair
  509. end
  510. def test_should_not_allow_repair_if_auto_shop_is_available
  511. @vehicle.auto_shop.fix_vehicle
  512. assert !@vehicle.repair
  513. end
  514. end
  515. class VehicleRepairedTest < Test::Unit::TestCase
  516. def setup
  517. @vehicle = Vehicle.new
  518. @vehicle.ignite
  519. @vehicle.shift_up
  520. @vehicle.crash
  521. @vehicle.repair
  522. end
  523. def test_should_be_in_parked_state
  524. assert_equal 'parked', @vehicle.state
  525. end
  526. def test_should_not_have_a_busy_auto_shop
  527. assert @vehicle.auto_shop.available?
  528. end
  529. end
  530. class VehicleWithParallelEventsTest < Test::Unit::TestCase
  531. def setup
  532. @vehicle = Vehicle.new
  533. end
  534. def test_should_fail_if_any_event_cannot_transition
  535. assert !@vehicle.fire_events(:ignite, :cancel_insurance)
  536. end
  537. def test_should_be_successful_if_all_events_transition
  538. assert @vehicle.fire_events(:ignite, :buy_insurance)
  539. end
  540. def test_should_not_save_if_skipping_action
  541. assert @vehicle.fire_events(:ignite, :buy_insurance, false)
  542. assert !@vehicle.saved
  543. end
  544. def test_should_raise_exception_if_any_event_cannot_transition_on_bang
  545. assert_raise(StateMachine::InvalidTransition) { @vehicle.fire_events!(:ignite, :cancel_insurance) }
  546. end
  547. def test_should_not_raise_exception_if_all_events_transition_on_bang
  548. assert @vehicle.fire_events!(:ignite, :buy_insurance)
  549. end
  550. def test_should_not_save_if_skipping_action_on_bang
  551. assert @vehicle.fire_events!(:ignite, :buy_insurance, false)
  552. assert !@vehicle.saved
  553. end
  554. end
  555. class VehicleWithEventAttributesTest < Test::Unit::TestCase
  556. def setup
  557. @vehicle = Vehicle.new
  558. @vehicle.state_event = 'ignite'
  559. end
  560. def test_should_fail_if_event_is_invalid
  561. @vehicle.state_event = 'invalid'
  562. assert !@vehicle.save
  563. assert_equal 'parked', @vehicle.state
  564. end
  565. def test_should_fail_if_event_has_no_transition
  566. @vehicle.state_event = 'park'
  567. assert !@vehicle.save
  568. assert_equal 'parked', @vehicle.state
  569. end
  570. def test_should_return_original_action_value_on_success
  571. assert_equal @vehicle, @vehicle.save
  572. end
  573. def test_should_transition_state_on_success
  574. @vehicle.save
  575. assert_equal 'idling', @vehicle.state
  576. end
  577. end
  578. class MotorcycleTest < Test::Unit::TestCase
  579. def setup
  580. @motorcycle = Motorcycle.new
  581. end
  582. def test_should_be_in_idling_state
  583. assert_equal 'idling', @motorcycle.state
  584. end
  585. def test_should_allow_park
  586. assert @motorcycle.park
  587. end
  588. def test_should_not_allow_ignite
  589. assert !@motorcycle.ignite
  590. end
  591. def test_should_allow_shift_up
  592. assert @motorcycle.shift_up
  593. end
  594. def test_should_not_allow_shift_down
  595. assert !@motorcycle.shift_down
  596. end
  597. def test_should_not_allow_crash
  598. assert !@motorcycle.crash
  599. end
  600. def test_should_not_allow_repair
  601. assert !@motorcycle.repair
  602. end
  603. end
  604. class CarTest < Test::Unit::TestCase
  605. def setup
  606. @car = Car.new
  607. end
  608. def test_should_be_in_parked_state
  609. assert_equal 'parked', @car.state
  610. end
  611. def test_should_not_have_the_seatbelt_on
  612. assert !@car.seatbelt_on
  613. end
  614. def test_should_not_allow_park
  615. assert !@car.park
  616. end
  617. def test_should_allow_ignite
  618. assert @car.ignite
  619. assert_equal 'idling', @car.state
  620. end
  621. def test_should_not_allow_idle
  622. assert !@car.idle
  623. end
  624. def test_should_not_allow_shift_up
  625. assert !@car.shift_up
  626. end
  627. def test_should_not_allow_shift_down
  628. assert !@car.shift_down
  629. end
  630. def test_should_not_allow_crash
  631. assert !@car.crash
  632. end
  633. def test_should_not_allow_repair
  634. assert !@car.repair
  635. end
  636. def test_should_allow_reverse
  637. assert @car.reverse
  638. end
  639. end
  640. class CarBackingUpTest < Test::Unit::TestCase
  641. def setup
  642. @car = Car.new
  643. @car.reverse
  644. end
  645. def test_should_be_in_backing_up_state
  646. assert_equal 'backing_up', @car.state
  647. end
  648. def test_should_allow_park
  649. assert @car.park
  650. end
  651. def test_should_not_allow_ignite
  652. assert !@car.ignite
  653. end
  654. def test_should_allow_idle
  655. assert @car.idle
  656. end
  657. def test_should_allow_shift_up
  658. assert @car.shift_up
  659. end
  660. def test_should_not_allow_shift_down
  661. assert !@car.shift_down
  662. end
  663. def test_should_not_allow_crash
  664. assert !@car.crash
  665. end
  666. def test_should_not_allow_repair
  667. assert !@car.repair
  668. end
  669. def test_should_not_allow_reverse
  670. assert !@car.reverse
  671. end
  672. end
  673. class AutoShopAvailableTest < Test::Unit::TestCase
  674. def setup
  675. @auto_shop = AutoShop.new
  676. end
  677. def test_should_be_in_available_state
  678. assert_equal 'available', @auto_shop.state
  679. end
  680. def test_should_allow_tow_vehicle
  681. assert @auto_shop.tow_vehicle
  682. end
  683. def test_should_not_allow_fix_vehicle
  684. assert !@auto_shop.fix_vehicle
  685. end
  686. end
  687. class AutoShopBusyTest < Test::Unit::TestCase
  688. def setup
  689. @auto_shop = AutoShop.new
  690. @auto_shop.tow_vehicle
  691. end
  692. def test_should_be_in_busy_state
  693. assert_equal 'busy', @auto_shop.state
  694. end
  695. def test_should_have_incremented_number_of_customers
  696. assert_equal 1, @auto_shop.num_customers
  697. end
  698. def test_should_not_allow_tow_vehicle
  699. assert !@auto_shop.tow_vehicle
  700. end
  701. def test_should_allow_fix_vehicle
  702. assert @auto_shop.fix_vehicle
  703. end
  704. end
  705. class TrafficLightStopTest < Test::Unit::TestCase
  706. def setup
  707. @light = TrafficLight.new
  708. @light.state = 'stop'
  709. end
  710. def test_should_use_stop_color
  711. assert_equal 'red', @light.color
  712. end
  713. def test_should_pass_arguments_through
  714. assert_equal 'RED', @light.color(:upcase!)
  715. end
  716. def test_should_pass_block_through
  717. color = @light.color {|value| value.upcase!}
  718. assert_equal 'RED', color
  719. end
  720. end
  721. class TrafficLightProceedTest < Test::Unit::TestCase
  722. def setup
  723. @light = TrafficLight.new
  724. @light.state = 'proceed'
  725. end
  726. def test_should_use_proceed_color
  727. assert_equal 'green', @light.color
  728. end
  729. end
  730. class TrafficLightCautionTest < Test::Unit::TestCase
  731. def setup
  732. @light = TrafficLight.new
  733. @light.state = 'caution'
  734. end
  735. def test_should_use_caution_color
  736. assert_equal 'yellow', @light.color
  737. end
  738. end