PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/test/unit/machine_test.rb

https://github.com/amatsuda/state_machine
Ruby | 2349 lines | 1870 code | 477 blank | 2 comment | 18 complexity | a0df4d1be679dcfdfd7b6c71a17a82d8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. class MachineByDefaultTest < Test::Unit::TestCase
  3. def setup
  4. @klass = Class.new
  5. @machine = StateMachine::Machine.new(@klass)
  6. @object = @klass.new
  7. end
  8. def test_should_have_an_owner_class
  9. assert_equal @klass, @machine.owner_class
  10. end
  11. def test_should_have_a_name
  12. assert_equal :state, @machine.name
  13. end
  14. def test_should_have_an_attribute
  15. assert_equal :state, @machine.attribute
  16. end
  17. def test_should_prefix_custom_attributes_with_attribute
  18. assert_equal :state_event, @machine.attribute(:event)
  19. end
  20. def test_should_have_an_initial_state
  21. assert_not_nil @machine.initial_state(@object)
  22. end
  23. def test_should_have_a_nil_initial_state
  24. assert_nil @machine.initial_state(@object).value
  25. end
  26. def test_should_not_have_any_events
  27. assert !@machine.events.any?
  28. end
  29. def test_should_not_have_any_before_callbacks
  30. assert @machine.callbacks[:before].empty?
  31. end
  32. def test_should_not_have_any_after_callbacks
  33. assert @machine.callbacks[:after].empty?
  34. end
  35. def test_should_not_have_an_action
  36. assert_nil @machine.action
  37. end
  38. def test_should_use_tranactions
  39. assert_equal true, @machine.use_transactions
  40. end
  41. def test_should_not_have_a_namespace
  42. assert_nil @machine.namespace
  43. end
  44. def test_should_have_a_nil_state
  45. assert_equal [nil], @machine.states.keys
  46. end
  47. def test_should_set_initial_on_nil_state
  48. assert @machine.state(nil).initial
  49. end
  50. def test_should_generate_default_messages
  51. assert_equal 'is invalid', @machine.generate_message(:invalid)
  52. assert_equal 'cannot transition when parked', @machine.generate_message(:invalid_event, [[:state, :parked]])
  53. assert_equal 'cannot transition via "park"', @machine.generate_message(:invalid_transition, [[:event, :park]])
  54. end
  55. def test_should_not_be_extended_by_the_active_model_integration
  56. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveModel)
  57. end
  58. def test_should_not_be_extended_by_the_active_record_integration
  59. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveRecord)
  60. end
  61. def test_should_not_be_extended_by_the_datamapper_integration
  62. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::DataMapper)
  63. end
  64. def test_should_not_be_extended_by_the_mongo_mapper_integration
  65. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::MongoMapper)
  66. end
  67. def test_should_not_be_extended_by_the_sequel_integration
  68. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::Sequel)
  69. end
  70. def test_should_define_a_reader_attribute_for_the_attribute
  71. assert @object.respond_to?(:state)
  72. end
  73. def test_should_define_a_writer_attribute_for_the_attribute
  74. assert @object.respond_to?(:state=)
  75. end
  76. def test_should_define_a_predicate_for_the_attribute
  77. assert @object.respond_to?(:state?)
  78. end
  79. def test_should_define_a_name_reader_for_the_attribute
  80. assert @object.respond_to?(:state_name)
  81. end
  82. def test_should_define_an_event_reader_for_the_attribute
  83. assert @object.respond_to?(:state_events)
  84. end
  85. def test_should_define_a_transition_reader_for_the_attribute
  86. assert @object.respond_to?(:state_transitions)
  87. end
  88. def test_should_not_define_an_event_attribute_reader
  89. assert !@object.respond_to?(:state_event)
  90. end
  91. def test_should_not_define_an_event_attribute_writer
  92. assert !@object.respond_to?(:state_event=)
  93. end
  94. def test_should_not_define_an_event_transition_attribute_reader
  95. assert !@object.respond_to?(:state_event_transition)
  96. end
  97. def test_should_not_define_an_event_transition_attribute_writer
  98. assert !@object.respond_to?(:state_event_transition=)
  99. end
  100. def test_should_define_a_human_attribute_name_reader_for_the_attribute
  101. assert @klass.respond_to?(:human_state_name)
  102. end
  103. def test_should_define_a_human_event_name_reader_for_the_attribute
  104. assert @klass.respond_to?(:human_state_event_name)
  105. end
  106. def test_should_not_define_singular_with_scope
  107. assert !@klass.respond_to?(:with_state)
  108. end
  109. def test_should_not_define_singular_without_scope
  110. assert !@klass.respond_to?(:without_state)
  111. end
  112. def test_should_not_define_plural_with_scope
  113. assert !@klass.respond_to?(:with_states)
  114. end
  115. def test_should_not_define_plural_without_scope
  116. assert !@klass.respond_to?(:without_states)
  117. end
  118. def test_should_extend_owner_class_with_class_methods
  119. assert (class << @klass; ancestors; end).include?(StateMachine::ClassMethods)
  120. end
  121. def test_should_include_instance_methods_in_owner_class
  122. assert @klass.included_modules.include?(StateMachine::InstanceMethods)
  123. end
  124. def test_should_define_state_machines_reader
  125. expected = {:state => @machine}
  126. assert_equal expected, @klass.state_machines
  127. end
  128. end
  129. class MachineWithCustomNameTest < Test::Unit::TestCase
  130. def setup
  131. @klass = Class.new
  132. @machine = StateMachine::Machine.new(@klass, :status)
  133. @object = @klass.new
  134. end
  135. def test_should_use_custom_name
  136. assert_equal :status, @machine.name
  137. end
  138. def test_should_use_custom_name_for_attribute
  139. assert_equal :status, @machine.attribute
  140. end
  141. def test_should_prefix_custom_attributes_with_custom_name
  142. assert_equal :status_event, @machine.attribute(:event)
  143. end
  144. def test_should_define_a_reader_attribute_for_the_attribute
  145. assert @object.respond_to?(:status)
  146. end
  147. def test_should_define_a_writer_attribute_for_the_attribute
  148. assert @object.respond_to?(:status=)
  149. end
  150. def test_should_define_a_predicate_for_the_attribute
  151. assert @object.respond_to?(:status?)
  152. end
  153. def test_should_define_a_name_reader_for_the_attribute
  154. assert @object.respond_to?(:status_name)
  155. end
  156. def test_should_define_an_event_reader_for_the_attribute
  157. assert @object.respond_to?(:status_events)
  158. end
  159. def test_should_define_a_transition_reader_for_the_attribute
  160. assert @object.respond_to?(:status_transitions)
  161. end
  162. def test_should_define_a_human_attribute_name_reader_for_the_attribute
  163. assert @klass.respond_to?(:human_status_name)
  164. end
  165. def test_should_define_a_human_event_name_reader_for_the_attribute
  166. assert @klass.respond_to?(:human_status_event_name)
  167. end
  168. end
  169. class MachineWithStaticInitialStateTest < Test::Unit::TestCase
  170. def setup
  171. @klass = Class.new do
  172. def initialize(attributes = {})
  173. attributes.each {|attr, value| send("#{attr}=", value)}
  174. super()
  175. end
  176. end
  177. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  178. end
  179. def test_should_not_have_dynamic_initial_state
  180. assert !@machine.dynamic_initial_state?
  181. end
  182. def test_should_have_an_initial_state
  183. object = @klass.new
  184. assert_equal 'parked', @machine.initial_state(object).value
  185. end
  186. def test_should_write_to_attribute_when_initializing_state
  187. object = @klass.allocate
  188. @machine.initialize_state(object)
  189. assert_equal 'parked', object.state
  190. end
  191. def test_should_set_initial_on_state_object
  192. assert @machine.state(:parked).initial
  193. end
  194. def test_should_set_initial_state_if_existing_is_nil
  195. object = @klass.new(:state => nil)
  196. assert_equal 'parked', object.state
  197. end
  198. def test_should_set_initial_state_if_existing_is_empty
  199. object = @klass.new(:state => '')
  200. assert_equal 'parked', object.state
  201. end
  202. def test_should_not_set_initial_state_if_existing_is_not_empty
  203. object = @klass.new(:state => 'idling')
  204. assert_equal 'idling', object.state
  205. end
  206. def test_should_set_initial_state_prior_to_initialization
  207. base = Class.new do
  208. attr_accessor :state_on_init
  209. def initialize
  210. self.state_on_init = state
  211. end
  212. end
  213. klass = Class.new(base)
  214. machine = StateMachine::Machine.new(klass, :initial => :parked)
  215. assert_equal 'parked', klass.new.state_on_init
  216. end
  217. def test_should_be_included_in_known_states
  218. assert_equal [:parked], @machine.states.keys
  219. end
  220. end
  221. class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
  222. def setup
  223. @klass = Class.new do
  224. attr_accessor :initial_state
  225. end
  226. @machine = StateMachine::Machine.new(@klass, :initial => lambda {|object| object.initial_state || :default})
  227. @machine.state :parked, :idling, :default
  228. @object = @klass.new
  229. end
  230. def test_should_have_dynamic_initial_state
  231. assert @machine.dynamic_initial_state?
  232. end
  233. def test_should_use_the_record_for_determining_the_initial_state
  234. @object.initial_state = :parked
  235. assert_equal :parked, @machine.initial_state(@object).name
  236. @object.initial_state = :idling
  237. assert_equal :idling, @machine.initial_state(@object).name
  238. end
  239. def test_should_write_to_attribute_when_initializing_state
  240. object = @klass.allocate
  241. object.initial_state = :parked
  242. @machine.initialize_state(object)
  243. assert_equal 'parked', object.state
  244. end
  245. def test_should_set_initial_state_on_created_object
  246. assert_equal 'default', @object.state
  247. end
  248. def test_should_set_initial_state_after_initialization
  249. base = Class.new do
  250. attr_accessor :state_on_init
  251. def initialize
  252. self.state_on_init = state
  253. end
  254. end
  255. klass = Class.new(base)
  256. machine = StateMachine::Machine.new(klass, :initial => lambda {|object| :parked})
  257. machine.state :parked
  258. assert_nil klass.new.state_on_init
  259. end
  260. def test_should_not_be_included_in_known_states
  261. assert_equal [:parked, :idling, :default], @machine.states.map {|state| state.name}
  262. end
  263. end
  264. class MachineWithCustomActionTest < Test::Unit::TestCase
  265. def setup
  266. @machine = StateMachine::Machine.new(Class.new, :action => :save)
  267. end
  268. def test_should_use_the_custom_action
  269. assert_equal :save, @machine.action
  270. end
  271. end
  272. class MachineWithNilActionTest < Test::Unit::TestCase
  273. def setup
  274. integration = Module.new do
  275. class << self; attr_reader :defaults; end
  276. @defaults = {:action => :save}
  277. end
  278. StateMachine::Integrations.const_set('Custom', integration)
  279. @machine = StateMachine::Machine.new(Class.new, :action => nil, :integration => :custom)
  280. end
  281. def test_should_have_a_nil_action
  282. assert_nil @machine.action
  283. end
  284. def teardown
  285. StateMachine::Integrations.send(:remove_const, 'Custom')
  286. end
  287. end
  288. class MachineWithoutIntegrationTest < Test::Unit::TestCase
  289. def setup
  290. @klass = Class.new
  291. @machine = StateMachine::Machine.new(@klass)
  292. @object = @klass.new
  293. end
  294. def test_transaction_should_yield
  295. @yielded = false
  296. @machine.within_transaction(@object) do
  297. @yielded = true
  298. end
  299. assert @yielded
  300. end
  301. def test_invalidation_should_do_nothing
  302. assert_nil @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']])
  303. end
  304. def test_reset_should_do_nothing
  305. assert_nil @machine.reset(@object)
  306. end
  307. end
  308. class MachineWithCustomIntegrationTest < Test::Unit::TestCase
  309. def setup
  310. integration = Module.new do
  311. def self.matches?(klass)
  312. true
  313. end
  314. end
  315. StateMachine::Integrations.const_set('Custom', integration)
  316. end
  317. def test_should_be_extended_by_the_integration_if_explicit
  318. machine = StateMachine::Machine.new(Class.new, :integration => :custom)
  319. assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
  320. end
  321. def test_should_be_extended_by_the_integration_if_implicit
  322. machine = StateMachine::Machine.new(Class.new)
  323. assert (class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
  324. end
  325. def test_should_not_be_extended_by_the_integration_if_nil
  326. machine = StateMachine::Machine.new(Class.new, :integration => nil)
  327. assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
  328. end
  329. def test_should_not_be_extended_by_the_integration_if_false
  330. machine = StateMachine::Machine.new(Class.new, :integration => false)
  331. assert !(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)
  332. end
  333. def teardown
  334. StateMachine::Integrations.send(:remove_const, 'Custom')
  335. end
  336. end
  337. class MachineWithIntegrationTest < Test::Unit::TestCase
  338. def setup
  339. StateMachine::Integrations.const_set('Custom', Module.new do
  340. class << self; attr_reader :defaults; end
  341. @defaults = {:action => :save, :use_transactions => false}
  342. attr_reader :initialized, :with_scopes, :without_scopes, :ran_transaction
  343. def after_initialize
  344. @initialized = true
  345. end
  346. def create_with_scope(name)
  347. (@with_scopes ||= []) << name
  348. lambda {}
  349. end
  350. def create_without_scope(name)
  351. (@without_scopes ||= []) << name
  352. lambda {}
  353. end
  354. def transaction(object)
  355. @ran_transaction = true
  356. yield
  357. end
  358. end)
  359. @machine = StateMachine::Machine.new(Class.new, :integration => :custom)
  360. end
  361. def test_should_call_after_initialize_hook
  362. assert @machine.initialized
  363. end
  364. def test_should_use_the_default_action
  365. assert_equal :save, @machine.action
  366. end
  367. def test_should_use_the_custom_action_if_specified
  368. machine = StateMachine::Machine.new(Class.new, :integration => :custom, :action => :save!)
  369. assert_equal :save!, machine.action
  370. end
  371. def test_should_use_the_default_use_transactions
  372. assert_equal false, @machine.use_transactions
  373. end
  374. def test_should_use_the_custom_use_transactions_if_specified
  375. machine = StateMachine::Machine.new(Class.new, :integration => :custom, :use_transactions => true)
  376. assert_equal true, machine.use_transactions
  377. end
  378. def test_should_define_a_singular_and_plural_with_scope
  379. assert_equal %w(with_state with_states), @machine.with_scopes
  380. end
  381. def test_should_define_a_singular_and_plural_without_scope
  382. assert_equal %w(without_state without_states), @machine.without_scopes
  383. end
  384. def teardown
  385. StateMachine::Integrations.send(:remove_const, 'Custom')
  386. end
  387. end
  388. class MachineWithActionUndefinedTest < Test::Unit::TestCase
  389. def setup
  390. @klass = Class.new
  391. @machine = StateMachine::Machine.new(@klass, :action => :save)
  392. @object = @klass.new
  393. end
  394. def test_should_define_an_event_attribute_reader
  395. assert @object.respond_to?(:state_event)
  396. end
  397. def test_should_define_an_event_attribute_writer
  398. assert @object.respond_to?(:state_event=)
  399. end
  400. def test_should_define_an_event_transition_attribute_reader
  401. assert @object.respond_to?(:state_event_transition)
  402. end
  403. def test_should_define_an_event_transition_attribute_writer
  404. assert @object.respond_to?(:state_event_transition=)
  405. end
  406. def test_should_not_define_action
  407. assert !@object.respond_to?(:save)
  408. end
  409. def test_should_not_mark_action_helper_as_defined
  410. assert !@machine.action_helper_defined?
  411. end
  412. end
  413. class MachineWithActionDefinedInClassTest < Test::Unit::TestCase
  414. def setup
  415. @klass = Class.new do
  416. def save
  417. end
  418. end
  419. @machine = StateMachine::Machine.new(@klass, :action => :save)
  420. @object = @klass.new
  421. end
  422. def test_should_define_an_event_attribute_reader
  423. assert @object.respond_to?(:state_event)
  424. end
  425. def test_should_define_an_event_attribute_writer
  426. assert @object.respond_to?(:state_event=)
  427. end
  428. def test_should_define_an_event_transition_attribute_reader
  429. assert @object.respond_to?(:state_event_transition)
  430. end
  431. def test_should_define_an_event_transition_attribute_writer
  432. assert @object.respond_to?(:state_event_transition=)
  433. end
  434. def test_should_not_define_action
  435. assert !@klass.ancestors.any? {|ancestor| ancestor != @klass && ancestor.method_defined?(:save)}
  436. end
  437. def test_should_not_mark_action_helper_as_defined
  438. assert !@machine.action_helper_defined?
  439. end
  440. end
  441. class MachineWithActionDefinedInIncludedModuleTest < Test::Unit::TestCase
  442. def setup
  443. @mod = mod = Module.new do
  444. def save
  445. end
  446. end
  447. @klass = Class.new do
  448. include mod
  449. end
  450. @machine = StateMachine::Machine.new(@klass, :action => :save)
  451. @object = @klass.new
  452. end
  453. def test_should_define_an_event_attribute_reader
  454. assert @object.respond_to?(:state_event)
  455. end
  456. def test_should_define_an_event_attribute_writer
  457. assert @object.respond_to?(:state_event=)
  458. end
  459. def test_should_define_an_event_transition_attribute_reader
  460. assert @object.respond_to?(:state_event_transition)
  461. end
  462. def test_should_define_an_event_transition_attribute_writer
  463. assert @object.respond_to?(:state_event_transition=)
  464. end
  465. def test_should_define_action
  466. assert @klass.ancestors.any? {|ancestor| ![@klass, @mod].include?(ancestor) && ancestor.method_defined?(:save)}
  467. end
  468. def test_should_keep_action_public
  469. assert @klass.public_method_defined?(:save)
  470. end
  471. def test_should_mark_action_helper_as_defined
  472. assert @machine.action_helper_defined?
  473. end
  474. end
  475. class MachineWithActionDefinedInSuperclassTest < Test::Unit::TestCase
  476. def setup
  477. @superclass = Class.new do
  478. def save
  479. end
  480. end
  481. @klass = Class.new(@superclass)
  482. @machine = StateMachine::Machine.new(@klass, :action => :save)
  483. @object = @klass.new
  484. end
  485. def test_should_define_an_event_attribute_reader
  486. assert @object.respond_to?(:state_event)
  487. end
  488. def test_should_define_an_event_attribute_writer
  489. assert @object.respond_to?(:state_event=)
  490. end
  491. def test_should_define_an_event_transition_attribute_reader
  492. assert @object.respond_to?(:state_event_transition)
  493. end
  494. def test_should_define_an_event_transition_attribute_writer
  495. assert @object.respond_to?(:state_event_transition=)
  496. end
  497. def test_should_define_action
  498. assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}
  499. end
  500. def test_should_keep_action_public
  501. assert @klass.public_method_defined?(:save)
  502. end
  503. def test_should_mark_action_helper_as_defined
  504. assert @machine.action_helper_defined?
  505. end
  506. end
  507. class MachineWithPrivateActionTest < Test::Unit::TestCase
  508. def setup
  509. @superclass = Class.new do
  510. private
  511. def save
  512. end
  513. end
  514. @klass = Class.new(@superclass)
  515. @machine = StateMachine::Machine.new(@klass, :action => :save)
  516. @object = @klass.new
  517. end
  518. def test_should_define_an_event_attribute_reader
  519. assert @object.respond_to?(:state_event)
  520. end
  521. def test_should_define_an_event_attribute_writer
  522. assert @object.respond_to?(:state_event=)
  523. end
  524. def test_should_define_an_event_transition_attribute_reader
  525. assert @object.respond_to?(:state_event_transition)
  526. end
  527. def test_should_define_an_event_transition_attribute_writer
  528. assert @object.respond_to?(:state_event_transition=)
  529. end
  530. def test_should_define_action
  531. assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.private_method_defined?(:save)}
  532. end
  533. def test_should_keep_action_private
  534. assert @klass.private_method_defined?(:save)
  535. end
  536. def test_should_mark_action_helper_as_defined
  537. assert @machine.action_helper_defined?
  538. end
  539. end
  540. class MachineWithActionAlreadyOverriddenTest < Test::Unit::TestCase
  541. def setup
  542. @superclass = Class.new do
  543. def save
  544. end
  545. end
  546. @klass = Class.new(@superclass)
  547. StateMachine::Machine.new(@klass, :action => :save)
  548. @machine = StateMachine::Machine.new(@klass, :status, :action => :save)
  549. @object = @klass.new
  550. end
  551. def test_should_not_redefine_action
  552. assert_equal 1, @klass.ancestors.select {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}.length
  553. end
  554. def test_should_mark_action_helper_as_defined
  555. assert @machine.action_helper_defined?
  556. end
  557. end
  558. class MachineWithCustomPluralTest < Test::Unit::TestCase
  559. def setup
  560. @integration = Module.new do
  561. class << self; attr_accessor :with_scopes, :without_scopes; end
  562. @with_scopes = []
  563. @without_scopes = []
  564. def create_with_scope(name)
  565. StateMachine::Integrations::Custom.with_scopes << name
  566. lambda {}
  567. end
  568. def create_without_scope(name)
  569. StateMachine::Integrations::Custom.without_scopes << name
  570. lambda {}
  571. end
  572. end
  573. StateMachine::Integrations.const_set('Custom', @integration)
  574. @machine = StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
  575. end
  576. def test_should_define_a_singular_and_plural_with_scope
  577. assert_equal %w(with_state with_staties), @integration.with_scopes
  578. end
  579. def test_should_define_a_singular_and_plural_without_scope
  580. assert_equal %w(without_state without_staties), @integration.without_scopes
  581. end
  582. def teardown
  583. StateMachine::Integrations.send(:remove_const, 'Custom')
  584. end
  585. end
  586. class MachineWithCustomInvalidationTest < Test::Unit::TestCase
  587. def setup
  588. @integration = Module.new do
  589. def invalidate(object, attribute, message, values = [])
  590. object.error = generate_message(message, values)
  591. end
  592. end
  593. StateMachine::Integrations.const_set('Custom', @integration)
  594. @klass = Class.new do
  595. attr_accessor :error
  596. end
  597. @machine = StateMachine::Machine.new(@klass, :integration => :custom, :messages => {:invalid_transition => 'cannot %s'})
  598. @machine.state :parked
  599. @object = @klass.new
  600. @object.state = 'parked'
  601. end
  602. def test_generate_custom_message
  603. assert_equal 'cannot park', @machine.generate_message(:invalid_transition, [[:event, :park]])
  604. end
  605. def test_use_custom_message
  606. @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']])
  607. assert_equal 'cannot park', @object.error
  608. end
  609. def teardown
  610. StateMachine::Integrations.send(:remove_const, 'Custom')
  611. end
  612. end
  613. class MachineTest < Test::Unit::TestCase
  614. def test_should_raise_exception_if_invalid_option_specified
  615. assert_raise(ArgumentError) {StateMachine::Machine.new(Class.new, :invalid => true)}
  616. end
  617. def test_should_not_raise_exception_if_custom_messages_specified
  618. assert_nothing_raised {StateMachine::Machine.new(Class.new, :messages => {:invalid_transition => 'custom'})}
  619. end
  620. def test_should_evaluate_a_block_during_initialization
  621. called = true
  622. StateMachine::Machine.new(Class.new) do
  623. called = respond_to?(:event)
  624. end
  625. assert called
  626. end
  627. def test_should_provide_matcher_helpers_during_initialization
  628. matchers = []
  629. StateMachine::Machine.new(Class.new) do
  630. matchers = [all, any, same]
  631. end
  632. assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
  633. end
  634. end
  635. class MachineAfterBeingCopiedTest < Test::Unit::TestCase
  636. def setup
  637. @machine = StateMachine::Machine.new(Class.new, :state, :initial => :parked)
  638. @machine.event(:ignite) {}
  639. @machine.before_transition(lambda {})
  640. @machine.after_transition(lambda {})
  641. @machine.around_transition(lambda {})
  642. @copied_machine = @machine.clone
  643. end
  644. def test_should_not_have_the_same_collection_of_states
  645. assert_not_same @copied_machine.states, @machine.states
  646. end
  647. def test_should_copy_each_state
  648. assert_not_same @copied_machine.states[:parked], @machine.states[:parked]
  649. end
  650. def test_should_update_machine_for_each_state
  651. assert_equal @copied_machine, @copied_machine.states[:parked].machine
  652. end
  653. def test_should_not_update_machine_for_original_state
  654. assert_equal @machine, @machine.states[:parked].machine
  655. end
  656. def test_should_not_have_the_same_collection_of_events
  657. assert_not_same @copied_machine.events, @machine.events
  658. end
  659. def test_should_copy_each_event
  660. assert_not_same @copied_machine.events[:ignite], @machine.events[:ignite]
  661. end
  662. def test_should_update_machine_for_each_event
  663. assert_equal @copied_machine, @copied_machine.events[:ignite].machine
  664. end
  665. def test_should_not_update_machine_for_original_event
  666. assert_equal @machine, @machine.events[:ignite].machine
  667. end
  668. def test_should_not_have_the_same_callbacks
  669. assert_not_same @copied_machine.callbacks, @machine.callbacks
  670. end
  671. def test_should_not_have_the_same_before_callbacks
  672. assert_not_same @copied_machine.callbacks[:before], @machine.callbacks[:before]
  673. end
  674. def test_should_not_have_the_same_after_callbacks
  675. assert_not_same @copied_machine.callbacks[:after], @machine.callbacks[:after]
  676. end
  677. end
  678. class MachineAfterChangingOwnerClassTest < Test::Unit::TestCase
  679. def setup
  680. @original_class = Class.new
  681. @machine = StateMachine::Machine.new(@original_class)
  682. @new_class = Class.new(@original_class)
  683. @new_machine = @machine.clone
  684. @new_machine.owner_class = @new_class
  685. @object = @new_class.new
  686. end
  687. def test_should_update_owner_class
  688. assert_equal @new_class, @new_machine.owner_class
  689. end
  690. def test_should_not_change_original_owner_class
  691. assert_equal @original_class, @machine.owner_class
  692. end
  693. def test_should_change_the_associated_machine_in_the_new_class
  694. assert_equal @new_machine, @new_class.state_machines[:state]
  695. end
  696. def test_should_not_change_the_associated_machine_in_the_original_class
  697. assert_equal @machine, @original_class.state_machines[:state]
  698. end
  699. end
  700. class MachineAfterChangingInitialState < Test::Unit::TestCase
  701. def setup
  702. @klass = Class.new
  703. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  704. @machine.initial_state = :idling
  705. @object = @klass.new
  706. end
  707. def test_should_change_the_initial_state
  708. assert_equal :idling, @machine.initial_state(@object).name
  709. end
  710. def test_should_include_in_known_states
  711. assert_equal [:parked, :idling], @machine.states.map {|state| state.name}
  712. end
  713. def test_should_reset_original_initial_state
  714. assert !@machine.state(:parked).initial
  715. end
  716. def test_should_set_new_state_to_initial
  717. assert @machine.state(:idling).initial
  718. end
  719. end
  720. class MachineWithInstanceHelpersTest < Test::Unit::TestCase
  721. def setup
  722. @klass = Class.new
  723. @machine = StateMachine::Machine.new(@klass)
  724. @object = @klass.new
  725. end
  726. def test_should_not_redefine_existing_public_methods
  727. @klass.class_eval do
  728. def state
  729. 'parked'
  730. end
  731. end
  732. @machine.define_instance_method(:state) {}
  733. assert_equal 'parked', @object.state
  734. end
  735. def test_should_not_redefine_existing_protected_methods
  736. @klass.class_eval do
  737. protected
  738. def state
  739. 'parked'
  740. end
  741. end
  742. @machine.define_instance_method(:state) {}
  743. assert_equal 'parked', @object.send(:state)
  744. end
  745. def test_should_not_redefine_existing_private_methods
  746. @klass.class_eval do
  747. private
  748. def state
  749. 'parked'
  750. end
  751. end
  752. @machine.define_instance_method(:state) {}
  753. assert_equal 'parked', @object.send(:state)
  754. end
  755. def test_should_define_nonexistent_methods
  756. @machine.define_instance_method(:state) {'parked'}
  757. assert_equal 'parked', @object.state
  758. end
  759. end
  760. class MachineWithClassHelpersTest < Test::Unit::TestCase
  761. def setup
  762. @klass = Class.new
  763. @machine = StateMachine::Machine.new(@klass)
  764. end
  765. def test_should_not_redefine_existing_public_methods
  766. class << @klass
  767. def states
  768. []
  769. end
  770. end
  771. @machine.define_class_method(:states) {}
  772. assert_equal [], @klass.states
  773. end
  774. def test_should_not_redefine_existing_protected_methods
  775. class << @klass
  776. protected
  777. def states
  778. []
  779. end
  780. end
  781. @machine.define_class_method(:states) {}
  782. assert_equal [], @klass.send(:states)
  783. end
  784. def test_should_not_redefine_existing_private_methods
  785. class << @klass
  786. private
  787. def states
  788. []
  789. end
  790. end
  791. @machine.define_class_method(:states) {}
  792. assert_equal [], @klass.send(:states)
  793. end
  794. def test_should_define_nonexistent_methods
  795. @machine.define_class_method(:states) {[]}
  796. assert_equal [], @klass.states
  797. end
  798. end
  799. class MachineWithConflictingHelpersTest < Test::Unit::TestCase
  800. def setup
  801. @klass = Class.new do
  802. def self.with_state
  803. :with_state
  804. end
  805. def self.with_states
  806. :with_states
  807. end
  808. def self.without_state
  809. :without_state
  810. end
  811. def self.without_states
  812. :without_states
  813. end
  814. def self.human_state_name
  815. :human_state_name
  816. end
  817. def self.human_state_event_name
  818. :human_state_event_name
  819. end
  820. attr_accessor :status
  821. def state
  822. 'parked'
  823. end
  824. def state=(value)
  825. self.status = value
  826. end
  827. def state?
  828. true
  829. end
  830. def state_name
  831. :parked
  832. end
  833. def human_state_name
  834. 'parked'
  835. end
  836. def state_events
  837. [:ignite]
  838. end
  839. def state_transitions
  840. [{:parked => :idling}]
  841. end
  842. end
  843. StateMachine::Integrations.const_set('Custom', Module.new do
  844. def create_with_scope(name)
  845. lambda {|klass, values| []}
  846. end
  847. def create_without_scope(name)
  848. lambda {|klass, values| []}
  849. end
  850. end)
  851. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  852. @machine.state :parked, :idling
  853. @machine.event :ignite
  854. @object = @klass.new
  855. end
  856. def test_should_not_redefine_singular_with_scope
  857. assert_equal :with_state, @klass.with_state
  858. end
  859. def test_should_not_redefine_plural_with_scope
  860. assert_equal :with_states, @klass.with_states
  861. end
  862. def test_should_not_redefine_singular_without_scope
  863. assert_equal :without_state, @klass.without_state
  864. end
  865. def test_should_not_redefine_plural_without_scope
  866. assert_equal :without_states, @klass.without_states
  867. end
  868. def test_should_not_redefine_human_attribute_name_reader
  869. assert_equal :human_state_name, @klass.human_state_name
  870. end
  871. def test_should_not_redefine_human_event_name_reader
  872. assert_equal :human_state_event_name, @klass.human_state_event_name
  873. end
  874. def test_should_not_redefine_attribute_writer
  875. assert_equal 'parked', @object.state
  876. end
  877. def test_should_not_redefine_attribute_writer
  878. @object.state = 'parked'
  879. assert_equal 'parked', @object.status
  880. end
  881. def test_should_not_define_attribute_predicate
  882. assert @object.state?
  883. end
  884. def test_should_not_redefine_attribute_name_reader
  885. assert_equal :parked, @object.state_name
  886. end
  887. def test_should_not_redefine_attribute_human_name_reader
  888. assert_equal 'parked', @object.human_state_name
  889. end
  890. def test_should_not_redefine_attribute_events_reader
  891. assert_equal [:ignite], @object.state_events
  892. end
  893. def test_should_not_redefine_attribute_transitions_reader
  894. assert_equal [{:parked => :idling}], @object.state_transitions
  895. end
  896. def test_should_allow_super_chaining
  897. @klass.class_eval do
  898. def self.with_state(*states)
  899. super == []
  900. end
  901. def self.with_states(*states)
  902. super == []
  903. end
  904. def self.without_state(*states)
  905. super == []
  906. end
  907. def self.without_states(*states)
  908. super == []
  909. end
  910. def self.human_state_name(state)
  911. super == 'parked'
  912. end
  913. def self.human_state_event_name(event)
  914. super == 'ignite'
  915. end
  916. attr_accessor :status
  917. def state
  918. super || 'parked'
  919. end
  920. def state=(value)
  921. super
  922. self.status = value
  923. end
  924. def state?(state)
  925. super ? 1 : 0
  926. end
  927. def state_name
  928. super == :parked ? 1 : 0
  929. end
  930. def human_state_name
  931. super == 'parked' ? 1 : 0
  932. end
  933. def state_events
  934. super == []
  935. end
  936. def state_transitions
  937. super == []
  938. end
  939. end
  940. assert_equal true, @klass.with_state
  941. assert_equal true, @klass.with_states
  942. assert_equal true, @klass.without_state
  943. assert_equal true, @klass.without_states
  944. assert_equal true, @klass.human_state_name(:parked)
  945. assert_equal true, @klass.human_state_event_name(:ignite)
  946. assert_equal 'parked', @object.state
  947. @object.state = 'idling'
  948. assert_equal 'idling', @object.status
  949. assert_equal 0, @object.state?(:parked)
  950. assert_equal 0, @object.state_name
  951. assert_equal 0, @object.human_state_name
  952. assert_equal true, @object.state_events
  953. assert_equal true, @object.state_transitions
  954. end
  955. def teardown
  956. StateMachine::Integrations.send(:remove_const, 'Custom')
  957. end
  958. end
  959. class MachineWithoutInitializeTest < Test::Unit::TestCase
  960. def setup
  961. @klass = Class.new
  962. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  963. @object = @klass.new
  964. end
  965. def test_should_initialize_state
  966. assert_equal 'parked', @object.state
  967. end
  968. end
  969. class MachineWithInitializeWithoutSuperTest < Test::Unit::TestCase
  970. def setup
  971. @klass = Class.new do
  972. def initialize
  973. end
  974. end
  975. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  976. @object = @klass.new
  977. end
  978. def test_should_not_initialize_state
  979. assert_nil @object.state
  980. end
  981. end
  982. class MachineWithInitializeAndSuperTest < Test::Unit::TestCase
  983. def setup
  984. @klass = Class.new do
  985. def initialize
  986. super()
  987. end
  988. end
  989. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  990. @object = @klass.new
  991. end
  992. def test_should_initialize_state
  993. assert_equal 'parked', @object.state
  994. end
  995. end
  996. class MachineWithInitializeArgumentsAndBlockTest < Test::Unit::TestCase
  997. def setup
  998. @superclass = Class.new do
  999. attr_reader :args
  1000. attr_reader :block_given
  1001. def initialize(*args)
  1002. @args = args
  1003. @block_given = block_given?
  1004. end
  1005. end
  1006. @klass = Class.new(@superclass)
  1007. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1008. @object = @klass.new(1, 2, 3) {}
  1009. end
  1010. def test_should_initialize_state
  1011. assert_equal 'parked', @object.state
  1012. end
  1013. def test_should_preserve_arguments
  1014. assert_equal [1, 2, 3], @object.args
  1015. end
  1016. def test_should_preserve_block
  1017. assert @object.block_given
  1018. end
  1019. end
  1020. class MachineWithCustomInitializeTest < Test::Unit::TestCase
  1021. def setup
  1022. @klass = Class.new do
  1023. def initialize
  1024. initialize_state_machines
  1025. end
  1026. end
  1027. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1028. @object = @klass.new
  1029. end
  1030. def test_should_initialize_state
  1031. assert_equal 'parked', @object.state
  1032. end
  1033. end
  1034. class MachinePersistenceTest < Test::Unit::TestCase
  1035. def setup
  1036. @klass = Class.new do
  1037. attr_accessor :state_event
  1038. end
  1039. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1040. @object = @klass.new
  1041. end
  1042. def test_should_allow_reading_state
  1043. assert_equal 'parked', @machine.read(@object, :state)
  1044. end
  1045. def test_should_allow_reading_custom_attributes
  1046. assert_nil @machine.read(@object, :event)
  1047. @object.state_event = 'ignite'
  1048. assert_equal 'ignite', @machine.read(@object, :event)
  1049. end
  1050. def test_should_allow_reading_custom_instance_variables
  1051. @klass.class_eval do
  1052. attr_writer :state_value
  1053. end
  1054. @object.state_value = 1
  1055. assert_raise(NoMethodError) { @machine.read(@object, :value) }
  1056. assert_equal 1, @machine.read(@object, :value, true)
  1057. end
  1058. def test_should_allow_writing_state
  1059. @machine.write(@object, :state, 'idling')
  1060. assert_equal 'idling', @object.state
  1061. end
  1062. def test_should_allow_writing_custom_attributes
  1063. @machine.write(@object, :event, 'ignite')
  1064. assert_equal 'ignite', @object.state_event
  1065. end
  1066. end
  1067. class MachineWithStatesTest < Test::Unit::TestCase
  1068. def setup
  1069. @klass = Class.new
  1070. @machine = StateMachine::Machine.new(@klass)
  1071. @parked, @idling = @machine.state :parked, :idling
  1072. @object = @klass.new
  1073. end
  1074. def test_should_have_states
  1075. assert_equal [nil, :parked, :idling], @machine.states.map {|state| state.name}
  1076. end
  1077. def test_should_allow_state_lookup_by_name
  1078. assert_equal @parked, @machine.states[:parked]
  1079. end
  1080. def test_should_allow_state_lookup_by_value
  1081. assert_equal @parked, @machine.states['parked', :value]
  1082. end
  1083. def test_should_allow_human_state_name_lookup
  1084. assert_equal 'parked', @klass.human_state_name(:parked)
  1085. end
  1086. def test_should_raise_exception_on_invalid_human_state_name_lookup
  1087. exception = assert_raise(IndexError) {@klass.human_state_name(:invalid)}
  1088. assert_equal ':invalid is an invalid name', exception.message
  1089. end
  1090. def test_should_use_stringified_name_for_value
  1091. assert_equal 'parked', @parked.value
  1092. end
  1093. def test_should_not_use_custom_matcher
  1094. assert_nil @parked.matcher
  1095. end
  1096. def test_should_raise_exception_if_invalid_option_specified
  1097. exception = assert_raise(ArgumentError) {@machine.state(:first_gear, :invalid => true)}
  1098. assert_equal 'Invalid key(s): invalid', exception.message
  1099. end
  1100. end
  1101. class MachineWithStatesWithCustomValuesTest < Test::Unit::TestCase
  1102. def setup
  1103. @klass = Class.new
  1104. @machine = StateMachine::Machine.new(@klass)
  1105. @state = @machine.state :parked, :value => 1
  1106. @object = @klass.new
  1107. @object.state = 1
  1108. end
  1109. def test_should_use_custom_value
  1110. assert_equal 1, @state.value
  1111. end
  1112. def test_should_allow_lookup_by_custom_value
  1113. assert_equal @state, @machine.states[1, :value]
  1114. end
  1115. end
  1116. class MachineWithStatesWithCustomHumanNamesTest < Test::Unit::TestCase
  1117. def setup
  1118. @klass = Class.new
  1119. @machine = StateMachine::Machine.new(@klass)
  1120. @state = @machine.state :parked, :human_name => 'stopped'
  1121. end
  1122. def test_should_use_custom_human_name
  1123. assert_equal 'stopped', @state.human_name
  1124. end
  1125. def test_should_allow_human_state_name_lookup
  1126. assert_equal 'stopped', @klass.human_state_name(:parked)
  1127. end
  1128. end
  1129. class MachineWithStatesWithRuntimeDependenciesTest < Test::Unit::TestCase
  1130. def setup
  1131. @klass = Class.new
  1132. @machine = StateMachine::Machine.new(@klass)
  1133. @machine.state :parked
  1134. end
  1135. def test_should_not_evaluate_value_during_definition
  1136. assert_nothing_raised { @machine.state :parked, :value => lambda {raise ArgumentError} }
  1137. end
  1138. def test_should_not_evaluate_if_not_initial_state
  1139. @machine.state :parked, :value => lambda {raise ArgumentError}
  1140. assert_nothing_raised { @klass.new }
  1141. end
  1142. end
  1143. class MachineWithStateWithMatchersTest < Test::Unit::TestCase
  1144. def setup
  1145. @klass = Class.new
  1146. @machine = StateMachine::Machine.new(@klass)
  1147. @state = @machine.state :parked, :if => lambda {|value| !value.nil?}
  1148. @object = @klass.new
  1149. @object.state = 1
  1150. end
  1151. def test_should_use_custom_matcher
  1152. assert_not_nil @state.matcher
  1153. assert @state.matches?(1)
  1154. assert !@state.matches?(nil)
  1155. end
  1156. end
  1157. class MachineWithCachedStateTest < Test::Unit::TestCase
  1158. def setup
  1159. @klass = Class.new
  1160. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1161. @state = @machine.state :parked, :value => lambda {Object.new}, :cache => true
  1162. @object = @klass.new
  1163. end
  1164. def test_should_use_evaluated_value
  1165. assert_instance_of Object, @object.state
  1166. end
  1167. def test_use_same_value_across_multiple_objects
  1168. assert_equal @object.state, @klass.new.state
  1169. end
  1170. end
  1171. class MachineWithStatesWithBehaviorsTest < Test::Unit::TestCase
  1172. def setup
  1173. @klass = Class.new
  1174. @machine = StateMachine::Machine.new(@klass)
  1175. @parked, @idling = @machine.state :parked, :idling do
  1176. def speed
  1177. 0
  1178. end
  1179. end
  1180. end
  1181. def test_should_define_behaviors_for_each_state
  1182. assert_not_nil @parked.methods[:speed]
  1183. assert_not_nil @idling.methods[:speed]
  1184. end
  1185. def test_should_define_different_behaviors_for_each_state
  1186. assert_not_equal @parked.methods[:speed], @idling.methods[:speed]
  1187. end
  1188. end
  1189. class MachineWithExistingStateTest < Test::Unit::TestCase
  1190. def setup
  1191. @klass = Class.new
  1192. @machine = StateMachine::Machine.new(@klass)
  1193. @state = @machine.state :parked
  1194. @same_state = @machine.state :parked, :value => 1
  1195. end
  1196. def test_should_not_create_a_new_state
  1197. assert_same @state, @same_state
  1198. end
  1199. def test_should_update_attributes
  1200. assert_equal 1, @state.value
  1201. end
  1202. def test_should_no_longer_be_able_to_look_up_state_by_original_value
  1203. assert_nil @machine.states['parked', :value]
  1204. end
  1205. def test_should_be_able_to_look_up_state_by_new_value
  1206. assert_equal @state, @machine.states[1, :value]
  1207. end
  1208. end
  1209. class MachineWithOtherStates < Test::Unit::TestCase
  1210. def setup
  1211. @klass = Class.new
  1212. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1213. @parked, @idling = @machine.other_states(:parked, :idling)
  1214. end
  1215. def test_should_include_other_states_in_known_states
  1216. assert_equal [@parked, @idling], @machine.states.to_a
  1217. end
  1218. def test_should_use_default_value
  1219. assert_equal 'idling', @idling.value
  1220. end
  1221. def test_should_not_create_matcher
  1222. assert_nil @idling.matcher
  1223. end
  1224. end
  1225. class MachineWithEventsTest < Test::Unit::TestCase
  1226. def setup
  1227. @klass = Class.new
  1228. @machine = StateMachine::Machine.new(@klass)
  1229. end
  1230. def test_should_return_the_created_event
  1231. assert_instance_of StateMachine::Event, @machine.event(:ignite)
  1232. end
  1233. def test_should_create_event_with_given_name
  1234. event = @machine.event(:ignite) {}
  1235. assert_equal :ignite, event.name
  1236. end
  1237. def test_should_evaluate_block_within_event_context
  1238. responded = false
  1239. @machine.event :ignite do
  1240. responded = respond_to?(:transition)
  1241. end
  1242. assert responded
  1243. end
  1244. def test_should_be_aliased_as_on
  1245. event = @machine.on(:ignite) {}
  1246. assert_equal :ignite, event.name
  1247. end
  1248. def test_should_have_events
  1249. event = @machine.event(:ignite)
  1250. assert_equal [event], @machine.events.to_a
  1251. end
  1252. def test_should_allow_human_state_name_lookup
  1253. @machine.event(:ignite)
  1254. assert_equal 'ignite', @klass.human_state_event_name(:ignite)
  1255. end
  1256. def test_should_raise_exception_on_invalid_human_state_event_name_lookup
  1257. exception = assert_raise(IndexError) {@klass.human_state_event_name(:invalid)}
  1258. assert_equal ':invalid is an invalid name', exception.message
  1259. end
  1260. end
  1261. class MachineWithExistingEventTest < Test::Unit::TestCase
  1262. def setup
  1263. @machine = StateMachine::Machine.new(Class.new)
  1264. @event = @machine.event(:ignite)
  1265. @same_event = @machine.event(:ignite)
  1266. end
  1267. def test_should_not_create_new_event
  1268. assert_same @event, @same_event
  1269. end
  1270. def test_should_allow_accessing_event_without_block
  1271. assert_equal @event, @machine.event(:ignite)
  1272. end
  1273. end
  1274. class MachineWithEventsWithCustomHumanNamesTest < Test::Unit::TestCase
  1275. def setup
  1276. @klass = Class.new
  1277. @machine = StateMachine::Machine.new(@klass)
  1278. @event = @machine.event(:ignite, :human_name => 'start')
  1279. end
  1280. def test_should_use_custom_human_name
  1281. assert_equal 'start', @event.human_name
  1282. end
  1283. def test_should_allow_human_state_name_lookup
  1284. assert_equal 'start', @klass.human_state_event_name(:ignite)
  1285. end
  1286. end
  1287. class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
  1288. def setup
  1289. @klass = Class.new
  1290. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1291. @event = @machine.event(:ignite) do
  1292. transition :parked => :idling
  1293. transition :stalled => :idling
  1294. end
  1295. end
  1296. def test_should_have_events
  1297. assert_equal [@event], @machine.events.to_a
  1298. end
  1299. def test_should_track_states_defined_in_event_transitions
  1300. assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
  1301. end
  1302. def test_should_not_duplicate_states_defined_in_multiple_event_transitions
  1303. @machine.event :park do
  1304. transition :idling => :parked
  1305. end
  1306. assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
  1307. end
  1308. def test_should_track_state_from_new_events
  1309. @machine.event :shift_up do
  1310. transition :idling => :first_gear
  1311. end
  1312. assert_equal [:parked, :idling, :stalled, :first_gear], @machine.states.map {|state| state.name}
  1313. end
  1314. end
  1315. class MachineWithMultipleEventsTest < Test::Unit::TestCase
  1316. def setup
  1317. @klass = Class.new
  1318. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1319. @park, @shift_down = @machine.event(:park, :shift_down) do
  1320. transition :first_gear => :parked
  1321. end
  1322. end
  1323. def test_should_have_events
  1324. assert_equal [@park, @shift_down], @machine.events.to_a
  1325. end
  1326. def test_should_define_transitions_for_each_event
  1327. [@park, @shift_down].each {|event| assert_equal 1, event.guards.size}
  1328. end
  1329. def test_should_transition_the_same_for_each_event
  1330. object = @klass.new
  1331. object.state = 'first_gear'
  1332. object.park
  1333. assert_equal 'parked', object.state
  1334. object = @klass.new
  1335. object.state = 'first_gear'
  1336. object.shift_down
  1337. assert_equal 'parked', object.state
  1338. end
  1339. end
  1340. class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
  1341. def setup
  1342. @klass = Class.new do
  1343. attr_accessor :callbacks
  1344. end
  1345. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1346. @event = @machine.event :ignite do
  1347. transition :parked => :idling
  1348. end
  1349. @object = @klass.new
  1350. @object.callbacks = []
  1351. end
  1352. def test_should_not_raise_exception_if_implicit_option_specified
  1353. assert_nothing_raised {@machine.before_transition :invalid => :valid, :do => lambda {}}
  1354. end
  1355. def test_should_raise_exception_if_method_not_specified
  1356. exception = assert_raise(ArgumentError) {@machine.before_transition :to => :idling}
  1357. assert_equal 'Method(s) for callback must be specified', exception.message
  1358. end
  1359. def test_should_invoke_callbacks_during_transition
  1360. @machine.before_transition lambda {|object| object.callbacks << 'before'}
  1361. @machine.after_transition lambda {|object| object.callbacks << 'after'}
  1362. @machine.around_transition lambda {|object, transition, block| object.callbacks << 'before_around'; block.call; object.callbacks << 'after_around'}
  1363. @event.fire(@object)
  1364. assert_equal %w(before before_around after_around after), @object.callbacks
  1365. end
  1366. def test_should_allow_multiple_callbacks
  1367. @machine.before_transition lambda {|object| object.callbacks << 'before1'}, lambda {|object| object.callbacks << 'before2'}
  1368. @machine.after_transition lambda {|object| object.callbacks << 'after1'}, lambda {|object| object.callbacks << 'after2'}
  1369. @machine.around_transition(
  1370. lambda {|object, transition, block| object.callbacks << 'before_around1'; block.call; object.callbacks << 'after_around1'},
  1371. lambda {|object, transition, block| object.callbacks << 'before_around2'; block.call; object.callbacks << 'after_around2'}
  1372. )
  1373. @event.fire(@object)
  1374. assert_equal %w(before1 before2 before_around1 before_around2 after_around2 after_around1 after1 after2), @object.callbacks
  1375. end
  1376. def test_should_allow_multiple_callbacks_with_requirements
  1377. @machine.before_transition lambda {|object| object.callbacks << 'before_parked1'}, lambda {|object| object.callbacks << 'before_parked2'}, :from => :parked
  1378. @machine.before_transition lambda {|object| object.callbacks << 'before_idling1'}, lambda {|object| object.callbacks << 'before_idling2'}, :from => :idling
  1379. @machine.after_transition lambda {|object| object.callbacks << 'after_parked1'}, lambda {|object| object.callbacks << 'after_parked2'}, :from => :parked
  1380. @machine.after_transition lambda {|object| object.callbacks << 'after_idling1'}, lambda {|object| object.callbacks << 'after_idling2'}, :from => :idling
  1381. @machine.around_transition(
  1382. lambda {|object, transition, block| object.callbacks << 'before_around_parked1'; block.call; object.callbacks << 'after_around_parked1'},
  1383. lambda {|object, transition, block| object.callbacks << 'before_around_parked2'; block.call; object.callbacks << 'after_around_parked2'},
  1384. :from => :parked
  1385. )
  1386. @machine.around_transition(
  1387. lambda {|object, transition, block| object.callbacks << 'before_around_idling1'; block.call; object.callbacks << 'after_around_idling1'},
  1388. lambda {|object, transition, block| object.callbacks << 'before_around_idling2'; block.call; object.callbacks << 'after_around_idling2'},
  1389. :from => :idling
  1390. )
  1391. @event.fire(@object)
  1392. assert_equal %w(before_parked1 before_parked2 before_around_parked1 before_around_parked2 after_around_parked2 after_around_parked1 after_parked1 after_parked2), @object.callbacks
  1393. end
  1394. def test_should_support_from_requirement
  1395. @machine.before_transition :from => :parked, :do => lambda {|object| object.callbacks << :parked}
  1396. @machine.before_transition :from => :idling, :do => lambda {|object| object.callbacks << :idling}
  1397. @event.fire(@object)
  1398. assert_equal [:parked], @object.callbacks
  1399. end
  1400. def test_should_support_except_from_requirement
  1401. @machine.before_transition :except_from => :parked, :do => lambda {|object| object.callbacks << :parked}
  1402. @machine.before_transition :except_from => :idling, :do => lambda {|object| object.callbacks << :idling}
  1403. @event.fire(@object)
  1404. assert_equal [:idling], @object.callbacks
  1405. end
  1406. def test_should_support_to_requirement
  1407. @machine.before_transition :to => :parked, :do => lambda {|object| object.callbacks << :parked}
  1408. @machine.before_transition :to => :idling, :do => lambda {

Large files files are truncated, but you can click here to view the full file