PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/test/unit/machine_test.rb

https://github.com/jbwiv/state_machine
Ruby | 1648 lines | 1319 code | 327 blank | 2 comment | 7 complexity | bf72f1f58a87021003db53129b852b78 MD5 | raw 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_an_attribute
  12. assert_equal :state, @machine.attribute
  13. end
  14. def test_should_have_an_initial_state
  15. assert_not_nil @machine.initial_state(@object)
  16. end
  17. def test_should_have_a_nil_initial_state
  18. assert_nil @machine.initial_state(@object).value
  19. end
  20. def test_should_not_have_any_events
  21. assert !@machine.events.any?
  22. end
  23. def test_should_not_have_any_before_callbacks
  24. assert @machine.callbacks[:before].empty?
  25. end
  26. def test_should_not_have_any_after_callbacks
  27. assert @machine.callbacks[:after].empty?
  28. end
  29. def test_should_not_have_an_action
  30. assert_nil @machine.action
  31. end
  32. def test_should_not_have_a_namespace
  33. assert_nil @machine.namespace
  34. end
  35. def test_should_have_a_nil_state
  36. assert_equal [nil], @machine.states.keys
  37. end
  38. def test_should_set_initial_on_nil_state
  39. assert @machine.state(nil).initial
  40. end
  41. def test_should_not_be_extended_by_the_active_record_integration
  42. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveRecord)
  43. end
  44. def test_should_not_be_extended_by_the_datamapper_integration
  45. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::DataMapper)
  46. end
  47. def test_should_not_be_extended_by_the_sequel_integration
  48. assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::Sequel)
  49. end
  50. def test_should_define_a_reader_attribute_for_the_attribute
  51. assert @object.respond_to?(:state)
  52. end
  53. def test_should_define_a_writer_attribute_for_the_attribute
  54. assert @object.respond_to?(:state=)
  55. end
  56. def test_should_define_a_predicate_for_the_attribute
  57. assert @object.respond_to?(:state?)
  58. end
  59. def test_should_define_a_name_reader_for_the_attribute
  60. assert @object.respond_to?(:state_name)
  61. end
  62. def test_should_not_define_singular_with_scope
  63. assert !@klass.respond_to?(:with_state)
  64. end
  65. def test_should_not_define_singular_without_scope
  66. assert !@klass.respond_to?(:without_state)
  67. end
  68. def test_should_not_define_plural_with_scope
  69. assert !@klass.respond_to?(:with_states)
  70. end
  71. def test_should_not_define_plural_without_scope
  72. assert !@klass.respond_to?(:without_states)
  73. end
  74. def test_should_extend_owner_class_with_class_methods
  75. assert (class << @klass; ancestors; end).include?(StateMachine::ClassMethods)
  76. end
  77. def test_should_include_instance_methods_in_owner_class
  78. assert @klass.included_modules.include?(StateMachine::InstanceMethods)
  79. end
  80. def test_should_define_state_machines_reader
  81. expected = {:state => @machine}
  82. assert_equal expected, @klass.state_machines
  83. end
  84. end
  85. class MachineWithCustomAttributeTest < Test::Unit::TestCase
  86. def setup
  87. @klass = Class.new
  88. @machine = StateMachine::Machine.new(@klass, :status)
  89. @object = @klass.new
  90. end
  91. def test_should_use_custom_attribute
  92. assert_equal :status, @machine.attribute
  93. end
  94. def test_should_define_a_reader_attribute_for_the_attribute
  95. assert @object.respond_to?(:status)
  96. end
  97. def test_should_define_a_writer_attribute_for_the_attribute
  98. assert @object.respond_to?(:status=)
  99. end
  100. def test_should_define_a_predicate_for_the_attribute
  101. assert @object.respond_to?(:status?)
  102. end
  103. def test_should_define_a_name_reader_for_the_attribute
  104. assert @object.respond_to?(:status_name)
  105. end
  106. end
  107. class MachineWithStaticInitialStateTest < Test::Unit::TestCase
  108. def setup
  109. @klass = Class.new do
  110. def initialize(attributes = {})
  111. attributes.each {|attr, value| send("#{attr}=", value)}
  112. super()
  113. end
  114. end
  115. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  116. end
  117. def test_should_have_an_initial_state
  118. object = @klass.new
  119. assert_equal 'parked', @machine.initial_state(object).value
  120. end
  121. def test_should_set_initial_on_state_object
  122. assert @machine.state(:parked).initial
  123. end
  124. def test_should_set_initial_state_if_existing_is_nil
  125. object = @klass.new(:state => nil)
  126. assert_equal 'parked', object.state
  127. end
  128. def test_should_set_initial_state_if_existing_is_empty
  129. object = @klass.new(:state => '')
  130. assert_equal 'parked', object.state
  131. end
  132. def test_should_not_set_initial_state_if_existing_is_not_empty
  133. object = @klass.new(:state => 'idling')
  134. assert_equal 'idling', object.state
  135. end
  136. def test_should_be_included_in_known_states
  137. assert_equal [:parked], @machine.states.keys
  138. end
  139. end
  140. class MachineWithDynamicInitialStateTest < Test::Unit::TestCase
  141. def setup
  142. @klass = Class.new do
  143. attr_accessor :initial_state
  144. end
  145. @machine = StateMachine::Machine.new(@klass, :initial => lambda {|object| object.initial_state || :default})
  146. @machine.state :parked, :idling, :default
  147. @object = @klass.new
  148. end
  149. def test_should_use_the_record_for_determining_the_initial_state
  150. @object.initial_state = :parked
  151. assert_equal :parked, @machine.initial_state(@object).name
  152. @object.initial_state = :idling
  153. assert_equal :idling, @machine.initial_state(@object).name
  154. end
  155. def test_should_set_initial_state_on_created_object
  156. assert_equal 'default', @object.state
  157. end
  158. def test_should_not_be_included_in_known_states
  159. assert_equal [:parked, :idling, :default], @machine.states.map {|state| state.name}
  160. end
  161. end
  162. class MachineWithCustomActionTest < Test::Unit::TestCase
  163. def setup
  164. @machine = StateMachine::Machine.new(Class.new, :action => :save)
  165. end
  166. def test_should_use_the_custom_action
  167. assert_equal :save, @machine.action
  168. end
  169. end
  170. class MachineWithNilActionTest < Test::Unit::TestCase
  171. def setup
  172. integration = Module.new do
  173. def default_action
  174. :save
  175. end
  176. end
  177. StateMachine::Integrations.const_set('Custom', integration)
  178. @machine = StateMachine::Machine.new(Class.new, :action => nil, :integration => :custom)
  179. end
  180. def test_should_have_a_nil_action
  181. assert_nil @machine.action
  182. end
  183. def teardown
  184. StateMachine::Integrations.send(:remove_const, 'Custom')
  185. end
  186. end
  187. class MachineWithoutIntegrationTest < Test::Unit::TestCase
  188. def setup
  189. @klass = Class.new
  190. @machine = StateMachine::Machine.new(@klass)
  191. @object = @klass.new
  192. end
  193. def test_transaction_should_yield
  194. @yielded = false
  195. @machine.within_transaction(@object) do
  196. @yielded = true
  197. end
  198. assert @yielded
  199. end
  200. def test_invalidation_should_do_nothing
  201. assert_nil @machine.invalidate(@object, StateMachine::Event.new(@machine, :park))
  202. end
  203. def test_reset_should_do_nothing
  204. assert_nil @machine.reset(@object)
  205. end
  206. end
  207. class MachineWithCustomIntegrationTest < Test::Unit::TestCase
  208. def setup
  209. StateMachine::Integrations.const_set('Custom', Module.new)
  210. @machine = StateMachine::Machine.new(Class.new, :integration => :custom)
  211. end
  212. def test_should_be_extended_by_the_integration
  213. assert (class << @machine; ancestors; end).include?(StateMachine::Integrations::Custom)
  214. end
  215. def teardown
  216. StateMachine::Integrations.send(:remove_const, 'Custom')
  217. end
  218. end
  219. class MachineWithIntegrationTest < Test::Unit::TestCase
  220. def setup
  221. @integration = Module.new do
  222. class << self; attr_accessor :initialized, :with_scopes, :without_scopes; end
  223. @initialized = false
  224. @with_scopes = []
  225. @without_scopes = []
  226. def after_initialize
  227. StateMachine::Integrations::Custom.initialized = true
  228. end
  229. def default_action
  230. :save
  231. end
  232. def create_with_scope(name)
  233. StateMachine::Integrations::Custom.with_scopes << name
  234. lambda {}
  235. end
  236. def create_without_scope(name)
  237. StateMachine::Integrations::Custom.without_scopes << name
  238. lambda {}
  239. end
  240. end
  241. StateMachine::Integrations.const_set('Custom', @integration)
  242. @machine = StateMachine::Machine.new(Class.new, :integration => :custom)
  243. end
  244. def test_should_call_after_initialize_hook
  245. assert @integration.initialized
  246. end
  247. def test_should_use_the_default_action
  248. assert_equal :save, @machine.action
  249. end
  250. def test_should_use_the_custom_action_if_specified
  251. machine = StateMachine::Machine.new(Class.new, :integration => :custom, :action => :save!)
  252. assert_equal :save!, machine.action
  253. end
  254. def test_should_define_a_singular_and_plural_with_scope
  255. assert_equal %w(with_state with_states), @integration.with_scopes
  256. end
  257. def test_should_define_a_singular_and_plural_without_scope
  258. assert_equal %w(without_state without_states), @integration.without_scopes
  259. end
  260. def teardown
  261. StateMachine::Integrations.send(:remove_const, 'Custom')
  262. end
  263. end
  264. class MachineWithCustomPluralTest < Test::Unit::TestCase
  265. def setup
  266. @integration = Module.new do
  267. class << self; attr_accessor :with_scopes, :without_scopes; end
  268. @with_scopes = []
  269. @without_scopes = []
  270. def create_with_scope(name)
  271. StateMachine::Integrations::Custom.with_scopes << name
  272. lambda {}
  273. end
  274. def create_without_scope(name)
  275. StateMachine::Integrations::Custom.without_scopes << name
  276. lambda {}
  277. end
  278. end
  279. StateMachine::Integrations.const_set('Custom', @integration)
  280. @machine = StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties')
  281. end
  282. def test_should_define_a_singular_and_plural_with_scope
  283. assert_equal %w(with_state with_staties), @integration.with_scopes
  284. end
  285. def test_should_define_a_singular_and_plural_without_scope
  286. assert_equal %w(without_state without_staties), @integration.without_scopes
  287. end
  288. def teardown
  289. StateMachine::Integrations.send(:remove_const, 'Custom')
  290. end
  291. end
  292. class MachineWithCustomInvalidationTest < Test::Unit::TestCase
  293. def setup
  294. @integration = Module.new do
  295. def invalidate(object, event)
  296. object.error = invalid_message(object, event)
  297. end
  298. end
  299. StateMachine::Integrations.const_set('Custom', @integration)
  300. @klass = Class.new do
  301. attr_accessor :error
  302. end
  303. @machine = StateMachine::Machine.new(@klass, :integration => :custom, :invalid_message => 'cannot %s when %s')
  304. @machine.state :parked
  305. @object = @klass.new
  306. @object.state = 'parked'
  307. end
  308. def test_use_custom_message
  309. @machine.invalidate(@object, StateMachine::Event.new(@machine, :park))
  310. assert_equal 'cannot park when parked', @object.error
  311. end
  312. def teardown
  313. StateMachine::Integrations.send(:remove_const, 'Custom')
  314. end
  315. end
  316. class MachineTest < Test::Unit::TestCase
  317. def test_should_raise_exception_if_invalid_option_specified
  318. assert_raise(ArgumentError) {StateMachine::Machine.new(Class.new, :invalid => true)}
  319. end
  320. def test_should_not_raise_exception_if_custom_invalid_message_specified
  321. assert_nothing_raised {StateMachine::Machine.new(Class.new, :invalid_message => 'custom')}
  322. end
  323. def test_should_evaluate_a_block_during_initialization
  324. called = true
  325. StateMachine::Machine.new(Class.new) do
  326. called = respond_to?(:event)
  327. end
  328. assert called
  329. end
  330. def test_should_provide_matcher_helpers_during_initialization
  331. matchers = []
  332. StateMachine::Machine.new(Class.new) do
  333. matchers = [all, any, same]
  334. end
  335. assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers
  336. end
  337. end
  338. class MachineAfterBeingCopiedTest < Test::Unit::TestCase
  339. def setup
  340. @machine = StateMachine::Machine.new(Class.new, :state, :initial => :parked)
  341. @machine.event(:ignite) {}
  342. @machine.before_transition(lambda {})
  343. @machine.after_transition(lambda {})
  344. @copied_machine = @machine.clone
  345. end
  346. def test_should_not_have_the_same_collection_of_states
  347. assert_not_same @copied_machine.states, @machine.states
  348. end
  349. def test_should_copy_each_state
  350. assert_not_same @copied_machine.states[:parked], @machine.states[:parked]
  351. end
  352. def test_should_update_machine_for_each_state
  353. assert_equal @copied_machine, @copied_machine.states[:parked].machine
  354. end
  355. def test_should_not_update_machine_for_original_state
  356. assert_equal @machine, @machine.states[:parked].machine
  357. end
  358. def test_should_not_have_the_same_collection_of_events
  359. assert_not_same @copied_machine.events, @machine.events
  360. end
  361. def test_should_copy_each_event
  362. assert_not_same @copied_machine.events[:ignite], @machine.events[:ignite]
  363. end
  364. def test_should_update_machine_for_each_event
  365. assert_equal @copied_machine, @copied_machine.events[:ignite].machine
  366. end
  367. def test_should_not_update_machine_for_original_event
  368. assert_equal @machine, @machine.events[:ignite].machine
  369. end
  370. def test_should_not_have_the_same_callbacks
  371. assert_not_same @copied_machine.callbacks, @machine.callbacks
  372. end
  373. def test_should_not_have_the_same_before_callbacks
  374. assert_not_same @copied_machine.callbacks[:before], @machine.callbacks[:before]
  375. end
  376. def test_should_not_have_the_same_after_callbacks
  377. assert_not_same @copied_machine.callbacks[:after], @machine.callbacks[:after]
  378. end
  379. end
  380. class MachineAfterChangingOwnerClassTest < Test::Unit::TestCase
  381. def setup
  382. @original_class = Class.new
  383. @machine = StateMachine::Machine.new(@original_class)
  384. @new_class = Class.new(@original_class)
  385. @new_machine = @machine.clone
  386. @new_machine.owner_class = @new_class
  387. @object = @new_class.new
  388. end
  389. def test_should_update_owner_class
  390. assert_equal @new_class, @new_machine.owner_class
  391. end
  392. def test_should_not_change_original_owner_class
  393. assert_equal @original_class, @machine.owner_class
  394. end
  395. def test_should_change_the_associated_machine_in_the_new_class
  396. assert_equal @new_machine, @new_class.state_machines[:state]
  397. end
  398. def test_should_not_change_the_associated_machine_in_the_original_class
  399. assert_equal @machine, @original_class.state_machines[:state]
  400. end
  401. end
  402. class MachineAfterChangingInitialState < Test::Unit::TestCase
  403. def setup
  404. @klass = Class.new
  405. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  406. @machine.initial_state = :idling
  407. @object = @klass.new
  408. end
  409. def test_should_change_the_initial_state
  410. assert_equal :idling, @machine.initial_state(@object).name
  411. end
  412. def test_should_include_in_known_states
  413. assert_equal [:parked, :idling], @machine.states.map {|state| state.name}
  414. end
  415. def test_should_reset_original_initial_state
  416. assert !@machine.state(:parked).initial
  417. end
  418. def test_should_set_new_state_to_initial
  419. assert @machine.state(:idling).initial
  420. end
  421. end
  422. class MachineWithInstanceHelpersTest < Test::Unit::TestCase
  423. def setup
  424. @klass = Class.new
  425. @machine = StateMachine::Machine.new(@klass)
  426. @object = @klass.new
  427. end
  428. def test_should_not_redefine_existing_public_methods
  429. @klass.class_eval do
  430. def state
  431. 'parked'
  432. end
  433. end
  434. @machine.define_instance_method(:state) {}
  435. assert_equal 'parked', @object.state
  436. end
  437. def test_should_not_redefine_existing_protected_methods
  438. @klass.class_eval do
  439. protected
  440. def state
  441. 'parked'
  442. end
  443. end
  444. @machine.define_instance_method(:state) {}
  445. assert_equal 'parked', @object.send(:state)
  446. end
  447. def test_should_not_redefine_existing_private_methods
  448. @klass.class_eval do
  449. private
  450. def state
  451. 'parked'
  452. end
  453. end
  454. @machine.define_instance_method(:state) {}
  455. assert_equal 'parked', @object.send(:state)
  456. end
  457. def test_should_define_nonexistent_methods
  458. @machine.define_instance_method(:state) {'parked'}
  459. assert_equal 'parked', @object.state
  460. end
  461. end
  462. class MachineWithClassHelpersTest < Test::Unit::TestCase
  463. def setup
  464. @klass = Class.new
  465. @machine = StateMachine::Machine.new(@klass)
  466. end
  467. def test_should_not_redefine_existing_public_methods
  468. class << @klass
  469. def states
  470. []
  471. end
  472. end
  473. @machine.define_class_method(:states) {}
  474. assert_equal [], @klass.states
  475. end
  476. def test_should_not_redefine_existing_protected_methods
  477. class << @klass
  478. protected
  479. def states
  480. []
  481. end
  482. end
  483. @machine.define_class_method(:states) {}
  484. assert_equal [], @klass.send(:states)
  485. end
  486. def test_should_not_redefine_existing_private_methods
  487. class << @klass
  488. private
  489. def states
  490. []
  491. end
  492. end
  493. @machine.define_class_method(:states) {}
  494. assert_equal [], @klass.send(:states)
  495. end
  496. def test_should_define_nonexistent_methods
  497. @machine.define_class_method(:states) {[]}
  498. assert_equal [], @klass.states
  499. end
  500. end
  501. class MachineWithConflictingHelpersTest < Test::Unit::TestCase
  502. def setup
  503. @klass = Class.new do
  504. def self.with_state
  505. :with_state
  506. end
  507. def self.with_states
  508. :with_states
  509. end
  510. def self.without_state
  511. :without_state
  512. end
  513. def self.without_states
  514. :without_states
  515. end
  516. attr_accessor :status
  517. def state
  518. 'parked'
  519. end
  520. def state=(value)
  521. self.status = value
  522. end
  523. def state?
  524. true
  525. end
  526. def state_name
  527. :parked
  528. end
  529. end
  530. StateMachine::Integrations.const_set('Custom', Module.new do
  531. def create_with_scope(name)
  532. lambda {|klass, values| []}
  533. end
  534. def create_without_scope(name)
  535. lambda {|klass, values| []}
  536. end
  537. end)
  538. @machine = StateMachine::Machine.new(@klass, :integration => :custom)
  539. @machine.state :parked, :idling
  540. @object = @klass.new
  541. end
  542. def test_should_not_redefine_singular_with_scope
  543. assert_equal :with_state, @klass.with_state
  544. end
  545. def test_should_not_redefine_plural_with_scope
  546. assert_equal :with_states, @klass.with_states
  547. end
  548. def test_should_not_redefine_singular_without_scope
  549. assert_equal :without_state, @klass.without_state
  550. end
  551. def test_should_not_redefine_plural_without_scope
  552. assert_equal :without_states, @klass.without_states
  553. end
  554. def test_should_not_redefine_attribute_writer
  555. assert_equal 'parked', @object.state
  556. end
  557. def test_should_not_redefine_attribute_writer
  558. @object.state = 'parked'
  559. assert_equal 'parked', @object.status
  560. end
  561. def test_should_not_define_attribute_predicate
  562. assert @object.state?
  563. end
  564. def test_should_not_redefine_attribute_name_reader
  565. assert_equal :parked, @object.state_name
  566. end
  567. def test_should_allow_super_chaining
  568. @klass.class_eval do
  569. def self.with_state(*states)
  570. super == []
  571. end
  572. def self.with_states(*states)
  573. super == []
  574. end
  575. def self.without_state(*states)
  576. super == []
  577. end
  578. def self.without_states(*states)
  579. super == []
  580. end
  581. attr_accessor :status
  582. def state
  583. super || 'parked'
  584. end
  585. def state=(value)
  586. super
  587. self.status = value
  588. end
  589. def state?(state)
  590. super ? 1 : 0
  591. end
  592. def state_name
  593. super == :parked ? 1 : 0
  594. end
  595. end
  596. assert_equal true, @klass.with_state
  597. assert_equal true, @klass.with_states
  598. assert_equal true, @klass.without_state
  599. assert_equal true, @klass.without_states
  600. assert_equal 'parked', @object.state
  601. @object.state = 'idling'
  602. assert_equal 'idling', @object.status
  603. assert_equal 0, @object.state?(:parked)
  604. assert_equal 0, @object.state_name
  605. end
  606. def teardown
  607. StateMachine::Integrations.send(:remove_const, 'Custom')
  608. end
  609. end
  610. class MachineWithoutInitializeTest < Test::Unit::TestCase
  611. def setup
  612. @klass = Class.new
  613. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  614. @object = @klass.new
  615. end
  616. def test_should_initialize_state
  617. assert_equal 'parked', @object.state
  618. end
  619. end
  620. class MachineWithInitializeWithoutSuperTest < Test::Unit::TestCase
  621. def setup
  622. @klass = Class.new do
  623. def initialize
  624. end
  625. end
  626. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  627. @object = @klass.new
  628. end
  629. def test_should_not_initialize_state
  630. assert_nil @object.state
  631. end
  632. end
  633. class MachineWithInitializeAndSuperTest < Test::Unit::TestCase
  634. def setup
  635. @klass = Class.new do
  636. def initialize
  637. super()
  638. end
  639. end
  640. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  641. @object = @klass.new
  642. end
  643. def test_should_initialize_state
  644. assert_equal 'parked', @object.state
  645. end
  646. end
  647. class MachineWithInitializeArgumentsAndBlockTest < Test::Unit::TestCase
  648. def setup
  649. @superclass = Class.new do
  650. attr_reader :args
  651. attr_reader :block_given
  652. def initialize(*args)
  653. @args = args
  654. @block_given = block_given?
  655. end
  656. end
  657. @klass = Class.new(@superclass)
  658. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  659. @object = @klass.new(1, 2, 3) {}
  660. end
  661. def test_should_initialize_state
  662. assert_equal 'parked', @object.state
  663. end
  664. def test_should_preserve_arguments
  665. assert_equal [1, 2, 3], @object.args
  666. end
  667. def test_should_preserve_block
  668. assert @object.block_given
  669. end
  670. end
  671. class MachineWithCustomInitializeTest < Test::Unit::TestCase
  672. def setup
  673. @klass = Class.new do
  674. def initialize
  675. initialize_state_machines
  676. end
  677. end
  678. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  679. @object = @klass.new
  680. end
  681. def test_should_initialize_state
  682. assert_equal 'parked', @object.state
  683. end
  684. end
  685. class MachineWithStatesTest < Test::Unit::TestCase
  686. def setup
  687. @klass = Class.new
  688. @machine = StateMachine::Machine.new(@klass)
  689. @parked, @idling = @machine.state :parked, :idling
  690. @object = @klass.new
  691. end
  692. def test_should_have_states
  693. assert_equal [nil, :parked, :idling], @machine.states.map {|state| state.name}
  694. end
  695. def test_should_allow_state_lookup_by_name
  696. assert_equal @parked, @machine.states[:parked]
  697. end
  698. def test_should_allow_state_lookup_by_value
  699. assert_equal @parked, @machine.states['parked', :value]
  700. end
  701. def test_should_use_stringified_name_for_value
  702. assert_equal 'parked', @parked.value
  703. end
  704. def test_should_not_use_custom_matcher
  705. assert_nil @parked.matcher
  706. end
  707. def test_should_raise_exception_if_invalid_option_specified
  708. exception = assert_raise(ArgumentError) {@machine.state(:first_gear, :invalid => true)}
  709. assert_equal 'Invalid key(s): invalid', exception.message
  710. end
  711. def test_should_not_be_in_state_if_value_does_not_match
  712. assert !@machine.state?(@object, :parked)
  713. assert !@machine.state?(@object, :idling)
  714. end
  715. def test_should_be_in_state_if_value_matches
  716. assert @machine.state?(@object, nil)
  717. end
  718. def test_raise_exception_if_checking_invalid_state
  719. assert_raise(ArgumentError) { @machine.state?(@object, :invalid) }
  720. end
  721. def test_should_find_state_for_object_if_value_is_known
  722. @object.state = 'parked'
  723. assert_equal @parked, @machine.state_for(@object)
  724. end
  725. def test_should_raise_exception_if_finding_state_for_object_with_unknown_value
  726. @object.state = 'invalid'
  727. exception = assert_raise(ArgumentError) { @machine.state_for(@object) }
  728. assert_equal '"invalid" is not a known state value', exception.message
  729. end
  730. end
  731. class MachineWithStatesWithCustomValuesTest < Test::Unit::TestCase
  732. def setup
  733. @klass = Class.new
  734. @machine = StateMachine::Machine.new(@klass)
  735. @state = @machine.state :parked, :value => 1
  736. @object = @klass.new
  737. @object.state = 1
  738. end
  739. def test_should_use_custom_value
  740. assert_equal 1, @state.value
  741. end
  742. def test_should_allow_lookup_by_custom_value
  743. assert_equal @state, @machine.states[1, :value]
  744. end
  745. def test_should_be_in_state_if_value_matches
  746. assert @machine.state?(@object, :parked)
  747. end
  748. def test_should_not_be_in_state_if_value_does_not_match
  749. @object.state = 2
  750. assert !@machine.state?(@object, :parked)
  751. end
  752. def test_should_find_state_for_object_if_value_is_known
  753. assert_equal @state, @machine.state_for(@object)
  754. end
  755. end
  756. class MachineWithStateWithMatchersTest < Test::Unit::TestCase
  757. def setup
  758. @klass = Class.new
  759. @machine = StateMachine::Machine.new(@klass)
  760. @state = @machine.state :parked, :if => lambda {|value| !value.nil?}
  761. @object = @klass.new
  762. @object.state = 1
  763. end
  764. def test_should_use_custom_matcher
  765. assert_not_nil @state.matcher
  766. assert @state.matches?(1)
  767. assert !@state.matches?(nil)
  768. end
  769. def test_should_be_in_state_if_value_matches
  770. assert @machine.state?(@object, :parked)
  771. end
  772. def test_should_not_be_in_state_if_value_does_not_match
  773. @object.state = nil
  774. assert !@machine.state?(@object, :parked)
  775. end
  776. def test_should_find_state_for_object_if_value_is_known
  777. assert_equal @state, @machine.state_for(@object)
  778. end
  779. end
  780. class MachineWithStatesWithBehaviorsTest < Test::Unit::TestCase
  781. def setup
  782. @klass = Class.new
  783. @machine = StateMachine::Machine.new(@klass)
  784. @parked, @idling = @machine.state :parked, :idling do
  785. def speed
  786. 0
  787. end
  788. end
  789. end
  790. def test_should_define_behaviors_for_each_state
  791. assert_not_nil @parked.methods[:speed]
  792. assert_not_nil @idling.methods[:speed]
  793. end
  794. def test_should_define_different_behaviors_for_each_state
  795. assert_not_equal @parked.methods[:speed], @idling.methods[:speed]
  796. end
  797. end
  798. class MachineWithExistingStateTest < Test::Unit::TestCase
  799. def setup
  800. @klass = Class.new
  801. @machine = StateMachine::Machine.new(@klass)
  802. @state = @machine.state :parked
  803. @same_state = @machine.state :parked, :value => 1
  804. end
  805. def test_should_not_create_a_new_state
  806. assert_same @state, @same_state
  807. end
  808. def test_should_update_attributes
  809. assert_equal 1, @state.value
  810. end
  811. def test_should_no_longer_be_able_to_look_up_state_by_original_value
  812. assert_nil @machine.states['parked', :value]
  813. end
  814. def test_should_be_able_to_look_up_state_by_new_value
  815. assert_equal @state, @machine.states[1, :value]
  816. end
  817. end
  818. class MachineWithOtherStates < Test::Unit::TestCase
  819. def setup
  820. @klass = Class.new
  821. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  822. @parked, @idling = @machine.other_states(:parked, :idling)
  823. end
  824. def test_should_include_other_states_in_known_states
  825. assert_equal [@parked, @idling], @machine.states.to_a
  826. end
  827. def test_should_use_default_value
  828. assert_equal 'idling', @idling.value
  829. end
  830. def test_should_not_create_matcher
  831. assert_nil @idling.matcher
  832. end
  833. end
  834. class MachineWithEventsTest < Test::Unit::TestCase
  835. def setup
  836. @machine = StateMachine::Machine.new(Class.new)
  837. end
  838. def test_should_return_the_created_event
  839. assert_instance_of StateMachine::Event, @machine.event(:ignite)
  840. end
  841. def test_should_create_event_with_given_name
  842. event = @machine.event(:ignite) {}
  843. assert_equal :ignite, event.name
  844. end
  845. def test_should_evaluate_block_within_event_context
  846. responded = false
  847. @machine.event :ignite do
  848. responded = respond_to?(:transition)
  849. end
  850. assert responded
  851. end
  852. def test_should_be_aliased_as_on
  853. event = @machine.on(:ignite) {}
  854. assert_equal :ignite, event.name
  855. end
  856. def test_should_have_events
  857. event = @machine.event(:ignite)
  858. assert_equal [event], @machine.events.to_a
  859. end
  860. end
  861. class MachineWithExistingEventTest < Test::Unit::TestCase
  862. def setup
  863. @machine = StateMachine::Machine.new(Class.new)
  864. @event = @machine.event(:ignite)
  865. @same_event = @machine.event(:ignite)
  866. end
  867. def test_should_not_create_new_event
  868. assert_same @event, @same_event
  869. end
  870. def test_should_allow_accessing_event_without_block
  871. assert_equal @event, @machine.event(:ignite)
  872. end
  873. end
  874. class MachineWithEventsWithTransitionsTest < Test::Unit::TestCase
  875. def setup
  876. @klass = Class.new
  877. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  878. @event = @machine.event(:ignite) do
  879. transition :parked => :idling
  880. transition :stalled => :idling
  881. end
  882. end
  883. def test_should_have_events
  884. assert_equal [@event], @machine.events.to_a
  885. end
  886. def test_should_track_states_defined_in_event_transitions
  887. assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
  888. end
  889. def test_should_not_duplicate_states_defined_in_multiple_event_transitions
  890. @machine.event :park do
  891. transition :idling => :parked
  892. end
  893. assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name}
  894. end
  895. def test_should_track_state_from_new_events
  896. @machine.event :shift_up do
  897. transition :idling => :first_gear
  898. end
  899. assert_equal [:parked, :idling, :stalled, :first_gear], @machine.states.map {|state| state.name}
  900. end
  901. end
  902. class MachineWithMultipleEventsTest < Test::Unit::TestCase
  903. def setup
  904. @klass = Class.new
  905. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  906. @park, @shift_down = @machine.event(:park, :shift_down) do
  907. transition :first_gear => :parked
  908. end
  909. end
  910. def test_should_have_events
  911. assert_equal [@park, @shift_down], @machine.events.to_a
  912. end
  913. def test_should_define_transitions_for_each_event
  914. [@park, @shift_down].each {|event| assert_equal 1, event.guards.size}
  915. end
  916. def test_should_transition_the_same_for_each_event
  917. object = @klass.new
  918. object.state = 'first_gear'
  919. object.park
  920. assert_equal 'parked', object.state
  921. object = @klass.new
  922. object.state = 'first_gear'
  923. object.shift_down
  924. assert_equal 'parked', object.state
  925. end
  926. end
  927. class MachineWithTransitionCallbacksTest < Test::Unit::TestCase
  928. def setup
  929. @klass = Class.new do
  930. attr_accessor :callbacks
  931. end
  932. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  933. @event = @machine.event :ignite do
  934. transition :parked => :idling
  935. end
  936. @object = @klass.new
  937. @object.callbacks = []
  938. end
  939. def test_should_not_raise_exception_if_implicit_option_specified
  940. assert_nothing_raised {@machine.before_transition :invalid => true, :do => lambda {}}
  941. end
  942. def test_should_raise_exception_if_do_option_not_specified
  943. exception = assert_raise(ArgumentError) {@machine.before_transition :to => :idling}
  944. assert_equal ':do callback must be specified', exception.message
  945. end
  946. def test_should_invoke_callbacks_during_transition
  947. @machine.before_transition lambda {|object| object.callbacks << 'before'}
  948. @machine.after_transition lambda {|object| object.callbacks << 'after'}
  949. @event.fire(@object)
  950. assert_equal %w(before after), @object.callbacks
  951. end
  952. def test_should_support_from_requirement
  953. @machine.before_transition :from => :parked, :do => lambda {|object| object.callbacks << :parked}
  954. @machine.before_transition :from => :idling, :do => lambda {|object| object.callbacks << :idling}
  955. @event.fire(@object)
  956. assert_equal [:parked], @object.callbacks
  957. end
  958. def test_should_support_except_from_requirement
  959. @machine.before_transition :except_from => :parked, :do => lambda {|object| object.callbacks << :parked}
  960. @machine.before_transition :except_from => :idling, :do => lambda {|object| object.callbacks << :idling}
  961. @event.fire(@object)
  962. assert_equal [:idling], @object.callbacks
  963. end
  964. def test_should_support_to_requirement
  965. @machine.before_transition :to => :parked, :do => lambda {|object| object.callbacks << :parked}
  966. @machine.before_transition :to => :idling, :do => lambda {|object| object.callbacks << :idling}
  967. @event.fire(@object)
  968. assert_equal [:idling], @object.callbacks
  969. end
  970. def test_should_support_except_to_requirement
  971. @machine.before_transition :except_to => :parked, :do => lambda {|object| object.callbacks << :parked}
  972. @machine.before_transition :except_to => :idling, :do => lambda {|object| object.callbacks << :idling}
  973. @event.fire(@object)
  974. assert_equal [:parked], @object.callbacks
  975. end
  976. def test_should_support_on_requirement
  977. @machine.before_transition :on => :park, :do => lambda {|object| object.callbacks << :park}
  978. @machine.before_transition :on => :ignite, :do => lambda {|object| object.callbacks << :ignite}
  979. @event.fire(@object)
  980. assert_equal [:ignite], @object.callbacks
  981. end
  982. def test_should_support_except_on_requirement
  983. @machine.before_transition :except_on => :park, :do => lambda {|object| object.callbacks << :park}
  984. @machine.before_transition :except_on => :ignite, :do => lambda {|object| object.callbacks << :ignite}
  985. @event.fire(@object)
  986. assert_equal [:park], @object.callbacks
  987. end
  988. def test_should_support_implicit_requirement
  989. @machine.before_transition :parked => :idling, :do => lambda {|object| object.callbacks << :parked}
  990. @machine.before_transition :idling => :parked, :do => lambda {|object| object.callbacks << :idling}
  991. @event.fire(@object)
  992. assert_equal [:parked], @object.callbacks
  993. end
  994. def test_should_track_states_defined_in_transition_callbacks
  995. @machine.before_transition :parked => :idling, :do => lambda {}
  996. @machine.after_transition :first_gear => :second_gear, :do => lambda {}
  997. assert_equal [:parked, :idling, :first_gear, :second_gear], @machine.states.map {|state| state.name}
  998. end
  999. def test_should_not_duplicate_states_defined_in_multiple_event_transitions
  1000. @machine.before_transition :parked => :idling, :do => lambda {}
  1001. @machine.after_transition :first_gear => :second_gear, :do => lambda {}
  1002. @machine.after_transition :parked => :idling, :do => lambda {}
  1003. assert_equal [:parked, :idling, :first_gear, :second_gear], @machine.states.map {|state| state.name}
  1004. end
  1005. def test_should_define_predicates_for_each_state
  1006. [:parked?, :idling?].each {|predicate| assert @object.respond_to?(predicate)}
  1007. end
  1008. end
  1009. class MachineWithOwnerSubclassTest < Test::Unit::TestCase
  1010. def setup
  1011. @klass = Class.new
  1012. @machine = StateMachine::Machine.new(@klass)
  1013. @subclass = Class.new(@klass)
  1014. end
  1015. def test_should_have_a_different_collection_of_state_machines
  1016. assert_not_same @klass.state_machines, @subclass.state_machines
  1017. end
  1018. def test_should_have_the_same_attribute_associated_state_machines
  1019. assert_equal @klass.state_machines, @subclass.state_machines
  1020. end
  1021. end
  1022. class MachineWithExistingMachinesOnOwnerClassTest < Test::Unit::TestCase
  1023. def setup
  1024. @klass = Class.new
  1025. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1026. @second_machine = StateMachine::Machine.new(@klass, :status, :initial => :idling)
  1027. @object = @klass.new
  1028. end
  1029. def test_should_track_each_state_machine
  1030. expected = {:state => @machine, :status => @second_machine}
  1031. assert_equal expected, @klass.state_machines
  1032. end
  1033. def test_should_initialize_state_for_both_machines
  1034. assert_equal 'parked', @object.state
  1035. assert_equal 'idling', @object.status
  1036. end
  1037. end
  1038. class MachineWithNamespaceTest < Test::Unit::TestCase
  1039. def setup
  1040. @klass = Class.new
  1041. @machine = StateMachine::Machine.new(@klass, :namespace => 'car', :initial => :parked) do
  1042. event :ignite do
  1043. transition :parked => :idling
  1044. end
  1045. event :park do
  1046. transition :idling => :parked
  1047. end
  1048. end
  1049. @object = @klass.new
  1050. end
  1051. def test_should_namespace_state_predicates
  1052. [:car_parked?, :car_idling?].each do |name|
  1053. assert @object.respond_to?(name)
  1054. end
  1055. end
  1056. def test_should_namespace_event_checks
  1057. [:can_ignite_car?, :can_park_car?].each do |name|
  1058. assert @object.respond_to?(name)
  1059. end
  1060. end
  1061. def test_should_namespace_event_transition_readers
  1062. [:next_ignite_car_transition, :next_park_car_transition].each do |name|
  1063. assert @object.respond_to?(name)
  1064. end
  1065. end
  1066. def test_should_namespace_events
  1067. [:ignite_car, :park_car].each do |name|
  1068. assert @object.respond_to?(name)
  1069. end
  1070. end
  1071. def test_should_namespace_bang_events
  1072. [:ignite_car!, :park_car!].each do |name|
  1073. assert @object.respond_to?(name)
  1074. end
  1075. end
  1076. end
  1077. class MachineFinderWithoutExistingMachineTest < Test::Unit::TestCase
  1078. def setup
  1079. @klass = Class.new
  1080. @machine = StateMachine::Machine.find_or_create(@klass)
  1081. end
  1082. def test_should_accept_a_block
  1083. called = false
  1084. StateMachine::Machine.find_or_create(Class.new) do
  1085. called = respond_to?(:event)
  1086. end
  1087. assert called
  1088. end
  1089. def test_should_create_a_new_machine
  1090. assert_not_nil @machine
  1091. end
  1092. def test_should_use_default_state
  1093. assert_equal :state, @machine.attribute
  1094. end
  1095. end
  1096. class MachineFinderWithExistingOnSameClassTest < Test::Unit::TestCase
  1097. def setup
  1098. @klass = Class.new
  1099. @existing_machine = StateMachine::Machine.new(@klass)
  1100. @machine = StateMachine::Machine.find_or_create(@klass)
  1101. end
  1102. def test_should_accept_a_block
  1103. called = false
  1104. StateMachine::Machine.find_or_create(@klass) do
  1105. called = respond_to?(:event)
  1106. end
  1107. assert called
  1108. end
  1109. def test_should_not_create_a_new_machine
  1110. assert_same @machine, @existing_machine
  1111. end
  1112. end
  1113. class MachineFinderWithExistingMachineOnSuperclassTest < Test::Unit::TestCase
  1114. def setup
  1115. integration = Module.new do
  1116. def self.matches?(klass)
  1117. false
  1118. end
  1119. end
  1120. StateMachine::Integrations.const_set('Custom', integration)
  1121. @base_class = Class.new
  1122. @base_machine = StateMachine::Machine.new(@base_class, :status, :action => :save, :integration => :custom)
  1123. @base_machine.event(:ignite) {}
  1124. @base_machine.before_transition(lambda {})
  1125. @base_machine.after_transition(lambda {})
  1126. @klass = Class.new(@base_class)
  1127. @machine = StateMachine::Machine.find_or_create(@klass, :status)
  1128. end
  1129. def test_should_accept_a_block
  1130. called = false
  1131. StateMachine::Machine.find_or_create(Class.new(@base_class)) do
  1132. called = respond_to?(:event)
  1133. end
  1134. assert called
  1135. end
  1136. def test_should_create_a_new_machine
  1137. assert_not_nil @machine
  1138. assert_not_same @machine, @base_machine
  1139. end
  1140. def test_should_copy_the_base_attribute
  1141. assert_equal :status, @machine.attribute
  1142. end
  1143. def test_should_copy_the_base_configuration
  1144. assert_equal :save, @machine.action
  1145. end
  1146. def test_should_copy_events
  1147. # Can't assert equal arrays since their machines change
  1148. assert_equal 1, @machine.events.length
  1149. end
  1150. def test_should_copy_before_callbacks
  1151. assert_equal @base_machine.callbacks[:before], @machine.callbacks[:before]
  1152. end
  1153. def test_should_copy_after_transitions
  1154. assert_equal @base_machine.callbacks[:after], @machine.callbacks[:after]
  1155. end
  1156. def test_should_use_the_same_integration
  1157. assert (class << @machine; ancestors; end).include?(StateMachine::Integrations::Custom)
  1158. end
  1159. def teardown
  1160. StateMachine::Integrations.send(:remove_const, 'Custom')
  1161. end
  1162. end
  1163. class MachineFinderCustomOptionsTest < Test::Unit::TestCase
  1164. def setup
  1165. @klass = Class.new
  1166. @machine = StateMachine::Machine.find_or_create(@klass, :status, :initial => :parked)
  1167. @object = @klass.new
  1168. end
  1169. def test_should_use_custom_attribute
  1170. assert_equal :status, @machine.attribute
  1171. end
  1172. def test_should_set_custom_initial_state
  1173. assert_equal :parked, @machine.initial_state(@object).name
  1174. end
  1175. end
  1176. begin
  1177. # Load library
  1178. require 'rubygems'
  1179. require 'graphviz'
  1180. class MachineDrawingTest < Test::Unit::TestCase
  1181. def setup
  1182. @klass = Class.new do
  1183. def self.name; 'Vehicle'; end
  1184. end
  1185. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1186. @machine.event :ignite do
  1187. transition :parked => :idling
  1188. end
  1189. end
  1190. def test_should_raise_exception_if_invalid_option_specified
  1191. assert_raise(ArgumentError) {@machine.draw(:invalid => true)}
  1192. end
  1193. def test_should_save_file_with_class_name_by_default
  1194. graph = @machine.draw(:output => false)
  1195. assert_equal './Vehicle_state.png', graph.instance_variable_get('@filename')
  1196. end
  1197. def test_should_allow_base_name_to_be_customized
  1198. graph = @machine.draw(:name => 'machine', :output => false)
  1199. assert_equal './machine.png', graph.instance_variable_get('@filename')
  1200. end
  1201. def test_should_allow_format_to_be_customized
  1202. graph = @machine.draw(:format => 'jpg', :output => false)
  1203. assert_equal './Vehicle_state.jpg', graph.instance_variable_get('@filename')
  1204. assert_equal 'jpg', graph.instance_variable_get('@format')
  1205. end
  1206. def test_should_allow_path_to_be_customized
  1207. graph = @machine.draw(:path => "#{File.dirname(__FILE__)}/", :output => false)
  1208. assert_equal "#{File.dirname(__FILE__)}/Vehicle_state.png", graph.instance_variable_get('@filename')
  1209. end
  1210. def test_should_allow_orientation_to_be_landscape
  1211. graph = @machine.draw(:orientation => 'landscape', :output => false)
  1212. assert_equal 'LR', graph['rankdir']
  1213. end
  1214. def test_should_allow_orientation_to_be_portrait
  1215. graph = @machine.draw(:orientation => 'portrait', :output => false)
  1216. assert_equal 'TB', graph['rankdir']
  1217. end
  1218. end
  1219. class MachineDrawingWithIntegerStatesTest < Test::Unit::TestCase
  1220. def setup
  1221. @klass = Class.new do
  1222. def self.name; 'Vehicle'; end
  1223. end
  1224. @machine = StateMachine::Machine.new(@klass, :state_id, :initial => :parked)
  1225. @machine.event :ignite do
  1226. transition :parked => :idling
  1227. end
  1228. @machine.state :parked, :value => 1
  1229. @machine.state :idling, :value => 2
  1230. @graph = @machine.draw
  1231. end
  1232. def test_should_draw_all_states
  1233. assert_equal 3, @graph.node_count
  1234. end
  1235. def test_should_draw_all_events
  1236. assert_equal 2, @graph.edge_count
  1237. end
  1238. def test_should_draw_machine
  1239. assert File.exist?('./Vehicle_state_id.png')
  1240. ensure
  1241. FileUtils.rm('./Vehicle_state_id.png')
  1242. end
  1243. end
  1244. class MachineDrawingWithNilStatesTest < Test::Unit::TestCase
  1245. def setup
  1246. @klass = Class.new do
  1247. def self.name; 'Vehicle'; end
  1248. end
  1249. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1250. @machine.event :ignite do
  1251. transition :parked => :idling
  1252. end
  1253. @machine.state :parked, :value => nil
  1254. @graph = @machine.draw
  1255. end
  1256. def test_should_draw_all_states
  1257. assert_equal 3, @graph.node_count
  1258. end
  1259. def test_should_draw_all_events
  1260. assert_equal 2, @graph.edge_count
  1261. end
  1262. def test_should_draw_machine
  1263. assert File.exist?('./Vehicle_state.png')
  1264. ensure
  1265. FileUtils.rm('./Vehicle_state.png')
  1266. end
  1267. end
  1268. class MachineDrawingWithDynamicStatesTest < Test::Unit::TestCase
  1269. def setup
  1270. @klass = Class.new do
  1271. def self.name; 'Vehicle'; end
  1272. end
  1273. @machine = StateMachine::Machine.new(@klass, :initial => :parked)
  1274. @machine.event :activate do
  1275. transition :parked => :idling
  1276. end
  1277. @machine.state :idling, :value => lambda {Time.now}
  1278. @graph = @machine.draw
  1279. end
  1280. def test_should_draw_all_states
  1281. assert_equal 3, @graph.node_count
  1282. end
  1283. def test_should_draw_all_events
  1284. assert_equal 2, @graph.edge_count
  1285. end
  1286. def test_should_draw_machine
  1287. assert File.exist?('./Vehicle_state.png')
  1288. ensure
  1289. FileUtils.rm('./Vehicle_state.png')
  1290. end
  1291. end
  1292. class MachineClassDrawingTest < Test::Unit::TestCase
  1293. def setup
  1294. @klass = Class.new do
  1295. def self.name; 'Vehicle'; end
  1296. end
  1297. @machine = StateMachine::Machine.new(@klass)
  1298. @machine.event :ignite do
  1299. transition :parked => :idling
  1300. end
  1301. end
  1302. def test_should_raise_exception_if_no_class_names_specified
  1303. exception = assert_raise(ArgumentError) {StateMachine::Machine.draw(nil)}
  1304. assert_equal 'At least one class must be specified', exception.message
  1305. end
  1306. def test_should_load_files
  1307. StateMachine::Machine.draw('Switch', :file => "#{File.dirname(__FILE__)}/../classes/switch.rb")
  1308. assert defined?(::Switch)
  1309. ensure
  1310. FileUtils.rm('./Switch_state.png')
  1311. end
  1312. def test_should_allow_path_and_format_to_be_customized
  1313. StateMachine::Machine.draw('Switch', :file => "#{File.dirname(__FILE__)}/../classes/switch.rb", :path => "#{File.dirname(__FILE__)}/", :format => 'jpg')
  1314. assert File.exist?("#{File.dirname(__FILE__)}/Switch_state.jpg")
  1315. ensure
  1316. FileUtils.rm("#{File.dirname(__FILE__)}/Switch_state.jpg")
  1317. end
  1318. end
  1319. rescue LoadError
  1320. $stderr.puts 'Skipping GraphViz StateMachine::Machine tests. `gem install ruby-graphviz` and try again.'
  1321. end