PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/test/unit/integrations/mongo_mapper_test.rb

http://github.com/pluginaweek/state_machine
Ruby | 2026 lines | 1584 code | 436 blank | 6 comment | 28 complexity | d514888b5b625d43f04aee8757d392e9 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. require 'mongo_mapper'
  3. # Establish database connection
  4. MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new("#{File.dirname(__FILE__)}/../../mongo_mapper.log"), :slave_ok => true})
  5. MongoMapper.database = 'test'
  6. module MongoMapperTest
  7. class BaseTestCase < Test::Unit::TestCase
  8. def default_test
  9. end
  10. def teardown
  11. if @table_names
  12. MongoMapper.database.collections.each {|c| c.drop if @table_names.include?(c.name)}
  13. end
  14. end
  15. protected
  16. # Creates a new MongoMapper model (and the associated table)
  17. def new_model(name = :foo, &block)
  18. table_name = "#{name}_#{rand(1000000)}"
  19. @table_names ||= []
  20. @table_names << table_name
  21. model = Class.new do
  22. (class << self; self; end).class_eval do
  23. define_method(:name) { "MongoMapperTest::#{name.to_s.capitalize}" }
  24. define_method(:to_s) { self.name }
  25. end
  26. end
  27. model.class_eval do
  28. include MongoMapper::Document
  29. set_collection_name(table_name)
  30. key :state, String
  31. end
  32. model.class_eval(&block) if block_given?
  33. model
  34. end
  35. end
  36. class IntegrationTest < BaseTestCase
  37. def test_should_have_an_integration_name
  38. assert_equal :mongo_mapper, StateMachine::Integrations::MongoMapper.integration_name
  39. end
  40. def test_should_be_available
  41. assert StateMachine::Integrations::MongoMapper.available?
  42. end
  43. def test_should_match_if_class_includes_mongo_mapper
  44. assert StateMachine::Integrations::MongoMapper.matches?(new_model)
  45. end
  46. def test_should_not_match_if_class_does_not_include_mongo_mapper
  47. assert !StateMachine::Integrations::MongoMapper.matches?(Class.new)
  48. end
  49. def test_should_have_defaults
  50. assert_equal({:action => :save}, StateMachine::Integrations::MongoMapper.defaults)
  51. end
  52. def test_should_have_a_locale_path
  53. assert_not_nil StateMachine::Integrations::MongoMapper.locale_path
  54. end
  55. end
  56. class MachineWithoutDatabaseTest < BaseTestCase
  57. def setup
  58. @model = new_model do
  59. # Simulate the database not being available entirely
  60. def self.connection
  61. raise Mongo::ConnectionFailure
  62. end
  63. end
  64. end
  65. def test_should_allow_machine_creation
  66. assert_nothing_raised { StateMachine::Machine.new(@model) }
  67. end
  68. end
  69. class MachineWithoutKeyTest < BaseTestCase
  70. def setup
  71. @model = new_model
  72. StateMachine::Machine.new(@model, :status)
  73. end
  74. def test_should_define_field_with_string_type
  75. key = @model.keys['status']
  76. assert_not_nil key
  77. assert_equal String, key.type
  78. end
  79. end
  80. class MachineWithKeyTest < BaseTestCase
  81. def setup
  82. @model = new_model do
  83. key :status, Integer
  84. end
  85. StateMachine::Machine.new(@model, :status)
  86. end
  87. def test_should_not_redefine_field
  88. key = @model.keys['status']
  89. assert_not_nil key
  90. assert_equal Integer, key.type
  91. end
  92. end
  93. class MachineByDefaultTest < BaseTestCase
  94. def setup
  95. @model = new_model
  96. @machine = StateMachine::Machine.new(@model)
  97. end
  98. def test_should_use_save_as_action
  99. assert_equal :save, @machine.action
  100. end
  101. def test_should_not_have_any_before_callbacks
  102. assert_equal 0, @machine.callbacks[:before].size
  103. end
  104. def test_should_not_have_any_after_callbacks
  105. assert_equal 0, @machine.callbacks[:after].size
  106. end
  107. end
  108. class MachineWithStatesTest < BaseTestCase
  109. def setup
  110. @model = new_model
  111. @machine = StateMachine::Machine.new(@model)
  112. @machine.state :first_gear
  113. end
  114. def test_should_humanize_name
  115. assert_equal 'first gear', @machine.state(:first_gear).human_name
  116. end
  117. end
  118. class MachineWithStaticInitialStateTest < BaseTestCase
  119. def setup
  120. @model = new_model(:vehicle) do
  121. attr_accessor :value
  122. end
  123. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  124. end
  125. def test_should_set_initial_state_on_created_object
  126. record = @model.new
  127. assert_equal 'parked', record.state
  128. end
  129. def test_should_set_initial_state_with_nil_attributes
  130. record = @model.new(nil)
  131. assert_equal 'parked', record.state
  132. end
  133. def test_should_still_set_attributes
  134. record = @model.new(:value => 1)
  135. assert_equal 1, record.value
  136. end
  137. def test_should_not_allow_initialize_blocks
  138. block_args = nil
  139. @model.new do |*args|
  140. block_args = args
  141. end
  142. assert_nil block_args
  143. end
  144. def test_should_set_initial_state_before_setting_attributes
  145. @model.class_eval do
  146. attr_accessor :state_during_setter
  147. remove_method :value=
  148. define_method(:value=) do |value|
  149. self.state_during_setter = state
  150. end
  151. end
  152. record = @model.new(:value => 1)
  153. assert_equal 'parked', record.state_during_setter
  154. end
  155. def test_should_not_set_initial_state_after_already_initialized
  156. record = @model.new(:value => 1)
  157. assert_equal 'parked', record.state
  158. record.state = 'idling'
  159. record.attributes = {}
  160. assert_equal 'idling', record.state
  161. end
  162. def test_should_persist_initial_state
  163. record = @model.new
  164. record.save
  165. record = @model.find(record.id)
  166. assert_equal 'parked', record.state
  167. end
  168. def test_should_persist_initial_state_on_dup
  169. record = @model.create.dup
  170. record.save
  171. record = @model.find(record.id)
  172. assert_equal 'parked', record.state
  173. end
  174. def test_should_use_stored_values_when_loading_from_database
  175. @machine.state :idling
  176. record = @model.find(@model.create(:state => 'idling').id)
  177. assert_equal 'idling', record.state
  178. end
  179. def test_should_use_stored_values_when_loading_from_database_with_nil_state
  180. @machine.state nil
  181. record = @model.find(@model.create(:state => nil).id)
  182. assert_nil record.state
  183. end
  184. if defined?(MongoMapper::Version) && MongoMapper::Version !~ /^0\.[5-8]\./
  185. def test_should_use_stored_values_when_loading_for_many_association
  186. @machine.state :idling
  187. @model.belongs_to :owner, :class_name => 'MongoMapperTest::Owner'
  188. MongoMapperTest.const_set('Vehicle', @model)
  189. owner_model = new_model(:owner) do
  190. many :vehicles, :class_name => 'MongoMapperTest::Vehicle'
  191. end
  192. MongoMapperTest.const_set('Owner', owner_model)
  193. owner = owner_model.create
  194. record = @model.create(:state => 'idling', :owner_id => owner.id)
  195. assert_equal 'idling', owner.vehicles[0].state
  196. end
  197. def test_should_use_stored_values_when_loading_for_one_association
  198. @machine.state :idling
  199. @model.belongs_to :owner, :class_name => 'MongoMapperTest::Owner'
  200. MongoMapperTest.const_set('Vehicle', @model)
  201. owner_model = new_model(:owner) do
  202. one :vehicle, :class_name => 'MongoMapperTest::Vehicle'
  203. end
  204. MongoMapperTest.const_set('Owner', owner_model)
  205. owner = owner_model.create
  206. record = @model.create(:state => 'idling', :owner_id => owner.id)
  207. owner.reload
  208. assert_equal 'idling', owner.vehicle.state
  209. end
  210. def test_should_use_stored_values_when_loading_for_belongs_to_association
  211. @machine.state :idling
  212. MongoMapperTest.const_set('Vehicle', @model)
  213. driver_model = new_model(:driver) do
  214. belongs_to :vehicle, :class_name => 'MongoMapperTest::Vehicle'
  215. end
  216. MongoMapperTest.const_set('Driver', driver_model)
  217. record = @model.create(:state => 'idling')
  218. driver = driver_model.create(:vehicle_id => record.id)
  219. assert_equal 'idling', driver.vehicle.state
  220. end
  221. end
  222. def teardown
  223. MongoMapperTest.class_eval do
  224. remove_const('Vehicle') if defined?(MongoMapperTest::Vehicle)
  225. remove_const('Owner') if defined?(MongoMapperTest::Owner)
  226. remove_const('Driver') if defined?(MongoMapperTest::Driver)
  227. end
  228. super
  229. end
  230. end
  231. class MachineWithDynamicInitialStateTest < BaseTestCase
  232. def setup
  233. @model = new_model do
  234. attr_accessor :value
  235. end
  236. @machine = StateMachine::Machine.new(@model, :initial => lambda {|object| :parked})
  237. @machine.state :parked
  238. end
  239. def test_should_set_initial_state_on_created_object
  240. record = @model.new
  241. assert_equal 'parked', record.state
  242. end
  243. def test_should_still_set_attributes
  244. record = @model.new(:value => 1)
  245. assert_equal 1, record.value
  246. end
  247. def test_should_not_allow_initialize_blocks
  248. block_args = nil
  249. @model.new do |*args|
  250. block_args = args
  251. end
  252. assert_nil block_args
  253. end
  254. def test_should_set_initial_state_after_setting_attributes
  255. @model.class_eval do
  256. attr_accessor :state_during_setter
  257. remove_method :value=
  258. define_method(:value=) do |value|
  259. self.state_during_setter = state || 'nil'
  260. end
  261. end
  262. record = @model.new(:value => 1)
  263. assert_equal 'nil', record.state_during_setter
  264. end
  265. def test_should_not_set_initial_state_after_already_initialized
  266. record = @model.new(:value => 1)
  267. assert_equal 'parked', record.state
  268. record.state = 'idling'
  269. record.attributes = {}
  270. assert_equal 'idling', record.state
  271. end
  272. def test_should_persist_initial_state
  273. record = @model.new
  274. record.save
  275. record = @model.find(record.id)
  276. assert_equal 'parked', record.state
  277. end
  278. def test_should_persist_initial_state_on_dup
  279. record = @model.create.dup
  280. record.save
  281. record = @model.find(record.id)
  282. assert_equal 'parked', record.state
  283. end
  284. def test_should_use_stored_values_when_loading_from_database
  285. @machine.state :idling
  286. record = @model.find(@model.create(:state => 'idling').id)
  287. assert_equal 'idling', record.state
  288. end
  289. def test_should_use_stored_values_when_loading_from_database_with_nil_state
  290. @machine.state nil
  291. record = @model.find(@model.create(:state => nil).id)
  292. assert_nil record.state
  293. end
  294. end
  295. class MachineWithEventsTest < BaseTestCase
  296. def setup
  297. @model = new_model
  298. @machine = StateMachine::Machine.new(@model)
  299. @machine.event :shift_up
  300. end
  301. def test_should_humanize_name
  302. assert_equal 'shift up', @machine.event(:shift_up).human_name
  303. end
  304. end
  305. class MachineWithSameColumnDefaultTest < BaseTestCase
  306. def setup
  307. @original_stderr, $stderr = $stderr, StringIO.new
  308. @model = new_model do
  309. key :status, String, :default => 'parked'
  310. end
  311. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  312. @record = @model.new
  313. end
  314. def test_should_use_machine_default
  315. assert_equal 'parked', @record.status
  316. end
  317. def test_should_not_generate_a_warning
  318. assert_no_match(/have defined a different default/, $stderr.string)
  319. end
  320. def teardown
  321. $stderr = @original_stderr
  322. end
  323. end
  324. class MachineWithDifferentColumnDefaultTest < BaseTestCase
  325. def setup
  326. @original_stderr, $stderr = $stderr, StringIO.new
  327. @model = new_model do
  328. key :status, String, :default => 'idling'
  329. end
  330. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  331. @record = @model.new
  332. end
  333. def test_should_use_machine_default
  334. assert_equal 'parked', @record.status
  335. end
  336. def test_should_generate_a_warning
  337. assert_match(/Both MongoMapperTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
  338. end
  339. def teardown
  340. $stderr = @original_stderr
  341. end
  342. end
  343. class MachineWithDifferentIntegerColumnDefaultTest < BaseTestCase
  344. def setup
  345. @original_stderr, $stderr = $stderr, StringIO.new
  346. @model = new_model do
  347. key :status, Integer, :default => 0
  348. end
  349. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  350. @machine.state :parked, :value => 1
  351. @record = @model.new
  352. end
  353. def test_should_use_machine_default
  354. assert_equal 1, @record.status
  355. end
  356. def test_should_generate_a_warning
  357. assert_match(/Both MongoMapperTest::Foo and its :status machine have defined a different default for "status". Use only one or the other for defining defaults to avoid unexpected behaviors\./, $stderr.string)
  358. end
  359. def teardown
  360. $stderr = @original_stderr
  361. end
  362. end
  363. class MachineWithConflictingPredicateTest < BaseTestCase
  364. def setup
  365. @model = new_model do
  366. def state?(*args)
  367. true
  368. end
  369. end
  370. @machine = StateMachine::Machine.new(@model)
  371. @record = @model.new
  372. end
  373. def test_should_not_define_attribute_predicate
  374. assert @record.state?
  375. end
  376. end
  377. class MachineWithConflictingStateNameTest < BaseTestCase
  378. def setup
  379. require 'stringio'
  380. @original_stderr, $stderr = $stderr, StringIO.new
  381. @model = new_model
  382. end
  383. def test_should_output_warning_with_same_machine_name
  384. @machine = StateMachine::Machine.new(@model)
  385. @machine.state :state
  386. assert_match(/^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string)
  387. end
  388. def test_should_output_warning_with_same_machine_attribute
  389. @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
  390. @machine.state :state
  391. assert_match(/^Instance method "state\?" is already defined in .*, use generic helper instead.*\n$/, $stderr.string)
  392. end
  393. def teardown
  394. $stderr = @original_stderr
  395. end
  396. end
  397. class MachineWithColumnStateAttributeTest < BaseTestCase
  398. def setup
  399. @model = new_model
  400. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  401. @machine.other_states(:idling)
  402. @record = @model.new
  403. end
  404. def test_should_not_override_the_column_reader
  405. @record[:state] = 'parked'
  406. assert_equal 'parked', @record.state
  407. end
  408. def test_should_not_override_the_column_writer
  409. @record.state = 'parked'
  410. assert_equal 'parked', @record[:state]
  411. end
  412. def test_should_have_an_attribute_predicate
  413. assert @record.respond_to?(:state?)
  414. end
  415. def test_should_test_for_existence_on_predicate_without_parameters
  416. assert @record.state?
  417. @record.state = nil
  418. assert !@record.state?
  419. end
  420. def test_should_return_false_for_predicate_if_does_not_match_current_value
  421. assert !@record.state?(:idling)
  422. end
  423. def test_should_return_true_for_predicate_if_matches_current_value
  424. assert @record.state?(:parked)
  425. end
  426. def test_should_raise_exception_for_predicate_if_invalid_state_specified
  427. assert_raise(IndexError) { @record.state?(:invalid) }
  428. end
  429. end
  430. class MachineWithNonColumnStateAttributeUndefinedTest < BaseTestCase
  431. def setup
  432. @model = new_model do
  433. def initialize
  434. # Skip attribute initialization
  435. @initialized_state_machines = true
  436. super
  437. end
  438. end
  439. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  440. @machine.other_states(:idling)
  441. @record = @model.new
  442. end
  443. def test_should_define_a_new_key_for_the_attribute
  444. assert_not_nil @model.keys['status']
  445. end
  446. def test_should_define_a_reader_attribute_for_the_attribute
  447. assert @record.respond_to?(:status)
  448. end
  449. def test_should_define_a_writer_attribute_for_the_attribute
  450. assert @record.respond_to?(:status=)
  451. end
  452. def test_should_define_an_attribute_predicate
  453. assert @record.respond_to?(:status?)
  454. end
  455. end
  456. class MachineWithNonColumnStateAttributeDefinedTest < BaseTestCase
  457. def setup
  458. @model = new_model do
  459. attr_accessor :status
  460. end
  461. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  462. @machine.other_states(:idling)
  463. @record = @model.new
  464. end
  465. def test_should_return_false_for_predicate_if_does_not_match_current_value
  466. assert !@record.status?(:idling)
  467. end
  468. def test_should_return_true_for_predicate_if_matches_current_value
  469. assert @record.status?(:parked)
  470. end
  471. def test_should_raise_exception_for_predicate_if_invalid_state_specified
  472. assert_raise(IndexError) { @record.status?(:invalid) }
  473. end
  474. def test_should_set_initial_state_on_created_object
  475. assert_equal 'parked', @record.status
  476. end
  477. end
  478. if !defined?(MongoMapper::Version) || MongoMapper::Version =~ /^0\.[5-8]\./
  479. class MachineWithAliasedAttributeTest < BaseTestCase
  480. def setup
  481. @model = new_model do
  482. alias_attribute :vehicle_status, :state
  483. end
  484. @machine = StateMachine::Machine.new(@model, :status, :attribute => :vehicle_status)
  485. @machine.state :parked
  486. @record = @model.new
  487. end
  488. def test_should_check_custom_attribute_for_predicate
  489. @record.vehicle_status = nil
  490. assert !@record.status?(:parked)
  491. @record.vehicle_status = 'parked'
  492. assert @record.status?(:parked)
  493. end
  494. end
  495. end
  496. class MachineWithCustomAttributeTest < BaseTestCase
  497. def setup
  498. require 'stringio'
  499. @original_stderr, $stderr = $stderr, StringIO.new
  500. @model = new_model
  501. @machine = StateMachine::Machine.new(@model, :public_state, :attribute => :state)
  502. @record = @model.new
  503. end
  504. def test_should_not_delegate_attribute_predicate_with_different_attribute
  505. assert_raise(ArgumentError) { @record.public_state? }
  506. end
  507. def teardown
  508. $stderr = @original_stderr
  509. end
  510. end
  511. class MachineWithInitializedStateTest < BaseTestCase
  512. def setup
  513. @model = new_model
  514. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  515. @machine.state :idling
  516. end
  517. def test_should_allow_nil_initial_state_when_static
  518. @machine.state nil
  519. record = @model.new(:state => nil)
  520. assert_nil record.state
  521. end
  522. def test_should_allow_nil_initial_state_when_dynamic
  523. @machine.state nil
  524. @machine.initial_state = lambda {:parked}
  525. record = @model.new(:state => nil)
  526. assert_nil record.state
  527. end
  528. def test_should_allow_different_initial_state_when_static
  529. record = @model.new(:state => 'idling')
  530. assert_equal 'idling', record.state
  531. end
  532. def test_should_allow_different_initial_state_when_dynamic
  533. @machine.initial_state = lambda {:parked}
  534. record = @model.new(:state => 'idling')
  535. assert_equal 'idling', record.state
  536. end
  537. if defined?(MongoMapper::Plugins::Protected)
  538. def test_should_use_default_state_if_protected
  539. @model.class_eval do
  540. attr_protected :state
  541. end
  542. record = @model.new(:state => 'idling')
  543. assert_equal 'parked', record.state
  544. end
  545. end
  546. end
  547. class MachineMultipleTest < BaseTestCase
  548. def setup
  549. @model = new_model do
  550. key :status, String
  551. end
  552. @state_machine = StateMachine::Machine.new(@model, :initial => :parked)
  553. @status_machine = StateMachine::Machine.new(@model, :status, :initial => :idling)
  554. end
  555. def test_should_should_initialize_each_state
  556. record = @model.new
  557. assert_equal 'parked', record.state
  558. assert_equal 'idling', record.status
  559. end
  560. end
  561. class MachineWithLoopbackTest < BaseTestCase
  562. def setup
  563. @model = new_model do
  564. key :updated_at, Time
  565. before_update do |record|
  566. record.updated_at = Time.now
  567. end
  568. end
  569. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  570. @machine.event :park
  571. @record = @model.create(:updated_at => Time.now - 1)
  572. @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
  573. @timestamp = @record.updated_at
  574. @transition.perform
  575. end
  576. def test_should_update_record
  577. assert_not_equal @timestamp, @record.updated_at
  578. end
  579. end
  580. class MachineWithDirtyAttributesTest < BaseTestCase
  581. def setup
  582. @model = new_model
  583. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  584. @machine.event :ignite
  585. @machine.state :idling
  586. @record = @model.create
  587. @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
  588. @transition.perform(false)
  589. end
  590. def test_should_include_state_in_changed_attributes
  591. assert_equal %w(state), @record.changed
  592. end
  593. def test_should_track_attribute_change
  594. assert_equal %w(parked idling), @record.changes['state']
  595. end
  596. def test_should_not_reset_changes_on_multiple_transitions
  597. transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
  598. transition.perform(false)
  599. assert_equal %w(parked idling), @record.changes['state']
  600. end
  601. def test_should_not_have_changes_when_loaded_from_database
  602. record = @model.find(@record.id)
  603. assert !record.changed?
  604. end
  605. end
  606. class MachineWithDirtyAttributesDuringLoopbackTest < BaseTestCase
  607. def setup
  608. @model = new_model
  609. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  610. @machine.event :park
  611. @record = @model.create
  612. @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
  613. @transition.perform(false)
  614. end
  615. def test_should_not_include_state_in_changed_attributes
  616. assert_equal [], @record.changed
  617. end
  618. def test_should_not_track_attribute_changes
  619. assert_equal nil, @record.changes['state']
  620. end
  621. end
  622. class MachineWithDirtyAttributesAndCustomAttributeTest < BaseTestCase
  623. def setup
  624. @model = new_model do
  625. key :status, String
  626. end
  627. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  628. @machine.event :ignite
  629. @machine.state :idling
  630. @record = @model.create
  631. @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
  632. @transition.perform(false)
  633. end
  634. def test_should_include_state_in_changed_attributes
  635. assert_equal %w(status), @record.changed
  636. end
  637. def test_should_track_attribute_change
  638. assert_equal %w(parked idling), @record.changes['status']
  639. end
  640. def test_should_not_reset_changes_on_multiple_transitions
  641. transition = StateMachine::Transition.new(@record, @machine, :ignite, :idling, :idling)
  642. transition.perform(false)
  643. assert_equal %w(parked idling), @record.changes['status']
  644. end
  645. end
  646. class MachineWithDirtyAttributeAndCustomAttributesDuringLoopbackTest < BaseTestCase
  647. def setup
  648. @model = new_model do
  649. key :status, String
  650. end
  651. @machine = StateMachine::Machine.new(@model, :status, :initial => :parked)
  652. @machine.event :park
  653. @record = @model.create
  654. @transition = StateMachine::Transition.new(@record, @machine, :park, :parked, :parked)
  655. @transition.perform(false)
  656. end
  657. def test_should_not_include_state_in_changed_attributes
  658. assert_equal [], @record.changed
  659. end
  660. def test_should_not_track_attribute_changes
  661. assert_equal nil, @record.changes['status']
  662. end
  663. end
  664. class MachineWithDirtyAttributeAndStateEventsTest < BaseTestCase
  665. def setup
  666. @model = new_model
  667. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  668. @machine.event :ignite
  669. @record = @model.create
  670. @record.state_event = 'ignite'
  671. end
  672. def test_should_not_include_state_in_changed_attributes
  673. assert_equal [], @record.changed
  674. end
  675. def test_should_not_track_attribute_change
  676. assert_equal nil, @record.changes['state']
  677. end
  678. end
  679. class MachineWithCallbacksTest < BaseTestCase
  680. def setup
  681. @model = new_model
  682. @machine = StateMachine::Machine.new(@model, :initial => :parked)
  683. @machine.other_states :idling
  684. @machine.event :ignite
  685. @record = @model.new(:state => 'parked')
  686. @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
  687. end
  688. def test_should_run_before_callbacks
  689. called = false
  690. @machine.before_transition {called = true}
  691. @transition.perform
  692. assert called
  693. end
  694. def test_should_pass_record_to_before_callbacks_with_one_argument
  695. record = nil
  696. @machine.before_transition {|arg| record = arg}
  697. @transition.perform
  698. assert_equal @record, record
  699. end
  700. def test_should_pass_record_and_transition_to_before_callbacks_with_multiple_arguments
  701. callback_args = nil
  702. @machine.before_transition {|*args| callback_args = args}
  703. @transition.perform
  704. assert_equal [@record, @transition], callback_args
  705. end
  706. def test_should_run_before_callbacks_outside_the_context_of_the_record
  707. context = nil
  708. @machine.before_transition {context = self}
  709. @transition.perform
  710. assert_equal self, context
  711. end
  712. def test_should_run_after_callbacks
  713. called = false
  714. @machine.after_transition {called = true}
  715. @transition.perform
  716. assert called
  717. end
  718. def test_should_pass_record_to_after_callbacks_with_one_argument
  719. record = nil
  720. @machine.after_transition {|arg| record = arg}
  721. @transition.perform
  722. assert_equal @record, record
  723. end
  724. def test_should_pass_record_and_transition_to_after_callbacks_with_multiple_arguments
  725. callback_args = nil
  726. @machine.after_transition {|*args| callback_args = args}
  727. @transition.perform
  728. assert_equal [@record, @transition], callback_args
  729. end
  730. def test_should_run_after_callbacks_outside_the_context_of_the_record
  731. context = nil
  732. @machine.after_transition {context = self}
  733. @transition.perform
  734. assert_equal self, context
  735. end
  736. def test_should_run_after_callbacks_if_model_callback_added_prior_to_state_machine_definition
  737. model = new_model do
  738. after_save { nil }
  739. end
  740. machine = StateMachine::Machine.new(model, :initial => :parked)
  741. machine.other_states :idling
  742. machine.event :ignite
  743. after_called = false
  744. machine.after_transition {after_called = true}
  745. record = model.new(:state => 'parked')
  746. transition = StateMachine::Transition.new(record, machine, :ignite, :parked, :idling)
  747. transition.perform
  748. assert_equal true, after_called
  749. end
  750. def test_should_run_around_callbacks
  751. before_called = false
  752. after_called = false
  753. ensure_called = 0
  754. @machine.around_transition do |block|
  755. before_called = true
  756. begin
  757. block.call
  758. ensure
  759. ensure_called += 1
  760. end
  761. after_called = true
  762. end
  763. @transition.perform
  764. assert before_called
  765. assert after_called
  766. assert_equal ensure_called, 1
  767. end
  768. def test_should_include_transition_states_in_known_states
  769. @machine.before_transition :to => :first_gear, :do => lambda {}
  770. assert_equal [:parked, :idling, :first_gear], @machine.states.map {|state| state.name}
  771. end
  772. def test_should_allow_symbolic_callbacks
  773. callback_args = nil
  774. klass = class << @record; self; end
  775. klass.send(:define_method, :after_ignite) do |*args|
  776. callback_args = args
  777. end
  778. @machine.before_transition(:after_ignite)
  779. @transition.perform
  780. assert_equal [@transition], callback_args
  781. end
  782. def test_should_allow_string_callbacks
  783. class << @record
  784. attr_reader :callback_result
  785. end
  786. @machine.before_transition('@callback_result = [1, 2, 3]')
  787. @transition.perform
  788. assert_equal [1, 2, 3], @record.callback_result
  789. end
  790. def test_should_run_in_expected_order
  791. expected = [
  792. :before_transition, :before_validation, :after_validation,
  793. :before_save, :before_create, :after_create, :after_save,
  794. :after_transition
  795. ]
  796. callbacks = []
  797. @model.before_validation { callbacks << :before_validation }
  798. @model.after_validation { callbacks << :after_validation }
  799. @model.before_save { callbacks << :before_save }
  800. @model.before_create { callbacks << :before_create }
  801. @model.after_create { callbacks << :after_create }
  802. @model.after_save { callbacks << :after_save }
  803. @machine.before_transition { callbacks << :before_transition }
  804. @machine.after_transition { callbacks << :after_transition }
  805. @transition.perform
  806. assert_equal expected, callbacks
  807. end
  808. end
  809. class MachineWithFailedBeforeCallbacksTest < BaseTestCase
  810. def setup
  811. @callbacks = []
  812. @model = new_model
  813. @machine = StateMachine::Machine.new(@model)
  814. @machine.state :parked, :idling
  815. @machine.event :ignite
  816. @machine.before_transition {@callbacks << :before_1; false}
  817. @machine.before_transition {@callbacks << :before_2}
  818. @machine.after_transition {@callbacks << :after}
  819. @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
  820. @record = @model.new(:state => 'parked')
  821. @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
  822. @result = @transition.perform
  823. end
  824. if !defined?(MongoMapper::Version) || MongoMapper::Version =~ /^0\.[5-8]\./
  825. def test_should_be_successful
  826. assert @result
  827. end
  828. def test_should_change_current_state
  829. assert_equal 'idling', @record.state
  830. end
  831. def test_should_run_action
  832. assert !@record.new_record?
  833. end
  834. def test_should_run_further_callbacks
  835. assert_equal [:before_1, :before_2, :around_before, :around_after, :after], @callbacks
  836. end
  837. else
  838. def test_should_not_be_successful
  839. assert !@result
  840. end
  841. def test_should_not_change_current_state
  842. assert_equal 'parked', @record.state
  843. end
  844. def test_should_not_run_action
  845. assert @record.new_record?
  846. end
  847. def test_should_not_run_further_callbacks
  848. assert_equal [:before_1], @callbacks
  849. end
  850. end
  851. end
  852. class MachineNestedActionTest < BaseTestCase
  853. def setup
  854. @callbacks = []
  855. @model = new_model
  856. @machine = StateMachine::Machine.new(@model)
  857. @machine.event :ignite do
  858. transition :parked => :idling
  859. end
  860. @record = @model.new(:state => 'parked')
  861. end
  862. def test_should_allow_transition_prior_to_creation_if_skipping_action
  863. record = @record
  864. @model.before_create { record.ignite(false) }
  865. result = @record.save
  866. assert_equal true, result
  867. assert_equal "idling", @record.state
  868. @record = @model.find(@record.id)
  869. assert_equal "idling", @record.state
  870. end
  871. def test_should_allow_transition_after_creation
  872. record = @record
  873. @model.after_create { record.ignite }
  874. result = @record.save
  875. assert_equal true, result
  876. assert_equal "idling", @record.state
  877. @record = @model.find(@record.id)
  878. assert_equal "idling", @record.state
  879. end
  880. end
  881. class MachineWithFailedActionTest < BaseTestCase
  882. def setup
  883. @model = new_model do
  884. validates_numericality_of :state
  885. end
  886. @machine = StateMachine::Machine.new(@model)
  887. @machine.state :parked, :idling
  888. @machine.event :ignite
  889. @callbacks = []
  890. @machine.before_transition {@callbacks << :before}
  891. @machine.after_transition {@callbacks << :after}
  892. @machine.after_failure {@callbacks << :after_failure}
  893. @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
  894. @record = @model.new(:state => 'parked')
  895. @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
  896. @result = @transition.perform
  897. end
  898. def test_should_not_be_successful
  899. assert !@result
  900. end
  901. def test_should_not_change_current_state
  902. assert_equal 'parked', @record.state
  903. end
  904. def test_should_not_save_record
  905. assert @record.new_record?
  906. end
  907. def test_should_run_before_callbacks_and_after_callbacks_with_failures
  908. assert_equal [:before, :around_before, :after_failure], @callbacks
  909. end
  910. end
  911. class MachineWithFailedAfterCallbacksTest < BaseTestCase
  912. def setup
  913. @callbacks = []
  914. @model = new_model
  915. @machine = StateMachine::Machine.new(@model)
  916. @machine.state :parked, :idling
  917. @machine.event :ignite
  918. @machine.after_transition {@callbacks << :after_1; false}
  919. @machine.after_transition {@callbacks << :after_2}
  920. @machine.around_transition {|block| @callbacks << :around_before; block.call; @callbacks << :around_after}
  921. @record = @model.new(:state => 'parked')
  922. @transition = StateMachine::Transition.new(@record, @machine, :ignite, :parked, :idling)
  923. @result = @transition.perform
  924. end
  925. def test_should_be_successful
  926. assert @result
  927. end
  928. def test_should_change_current_state
  929. assert_equal 'idling', @record.state
  930. end
  931. def test_should_save_record
  932. assert !@record.new_record?
  933. end
  934. if !defined?(MongoMapper::Version) || MongoMapper::Version =~ /^0\.[5-8]\./
  935. def test_should_still_run_further_after_callbacks
  936. assert_equal [:around_before, :around_after, :after_1, :after_2], @callbacks
  937. end
  938. else
  939. def test_should_not_run_further_after_callbacks
  940. assert_equal [:around_before, :around_after, :after_1], @callbacks
  941. end
  942. end
  943. end
  944. class MachineWithValidationsTest < BaseTestCase
  945. def setup
  946. @model = new_model
  947. @machine = StateMachine::Machine.new(@model)
  948. @machine.state :parked
  949. @record = @model.new
  950. end
  951. def test_should_invalidate_using_errors
  952. I18n.backend = I18n::Backend::Simple.new if Object.const_defined?(:ActiveModel)
  953. @record.state = 'parked'
  954. @machine.invalidate(@record, :state, :invalid_transition, [[:event, 'park']])
  955. assert_equal ['State cannot transition via "park"'], @record.errors.full_messages
  956. end
  957. def test_should_auto_prefix_custom_attributes_on_invalidation
  958. @machine.invalidate(@record, :event, :invalid)
  959. assert_equal ['State event is invalid'], @record.errors.full_messages
  960. end
  961. def test_should_clear_errors_on_reset
  962. @record.state = 'parked'
  963. @record.errors.add(:state, 'is invalid')
  964. @machine.reset(@record)
  965. assert_equal [], @record.errors.full_messages
  966. end
  967. def test_should_be_valid_if_state_is_known
  968. @record.state = 'parked'
  969. assert @record.valid?
  970. end
  971. def test_should_not_be_valid_if_state_is_unknown
  972. @record.state = 'invalid'
  973. assert !@record.valid?
  974. assert_equal ['State is invalid'], @record.errors.full_messages
  975. end
  976. end
  977. class MachineWithValidationsAndCustomAttributeTest < BaseTestCase
  978. def setup
  979. @model = new_model
  980. @machine = StateMachine::Machine.new(@model, :status, :attribute => :state)
  981. @machine.state :parked
  982. @record = @model.new
  983. end
  984. def test_should_add_validation_errors_to_custom_attribute
  985. @record.state = 'invalid'
  986. assert !@record.valid?
  987. assert_equal ['State is invalid'], @record.errors.full_messages
  988. @record.state = 'parked'
  989. assert @record.valid?
  990. end
  991. end
  992. class MachineErrorsTest < BaseTestCase
  993. def setup
  994. @model = new_model
  995. @machine = StateMachine::Machine.new(@model)
  996. @record = @model.new
  997. end
  998. def test_should_be_able_to_describe_current_errors
  999. @record.errors.add(:id, 'cannot be blank')
  1000. @record.errors.add(:state, 'is invalid')
  1001. assert_equal ['Id cannot be blank', 'State is invalid'], @machine.errors_for(@record).split(', ').sort
  1002. end
  1003. def test_should_describe_as_halted_with_no_errors
  1004. assert_equal 'Transition halted', @machine.errors_for(@record)
  1005. end
  1006. end
  1007. class MachineWithStateDrivenValidationsTest < BaseTestCase
  1008. def setup
  1009. @model = new_model do
  1010. attr_accessor :seatbealt
  1011. end
  1012. @machine = StateMachine::Machine.new(@model)
  1013. @machine.state :first_gear do
  1014. validates_presence_of :seatbelt, :key => :first_gear
  1015. end
  1016. @machine.state :second_gear do
  1017. validates_presence_of :seatbelt, :key => :second_gear
  1018. end
  1019. @machine.other_states :parked
  1020. end
  1021. def test_should_be_valid_if_validation_fails_outside_state_scope
  1022. record = @model.new(:state => 'parked', :seatbelt => nil)
  1023. assert record.valid?
  1024. end
  1025. def test_should_be_invalid_if_validation_fails_within_state_scope
  1026. record = @model.new(:state => 'first_gear', :seatbelt => nil)
  1027. assert !record.valid?
  1028. end
  1029. def test_should_be_valid_if_validation_succeeds_within_state_scope
  1030. record = @model.new(:state => 'second_gear', :seatbelt => true)
  1031. assert record.valid?
  1032. end
  1033. end
  1034. class MachineWithEventAttributesOnValidationTest < BaseTestCase
  1035. def setup
  1036. @model = new_model
  1037. @machine = StateMachine::Machine.new(@model)
  1038. @machine.event :ignite do
  1039. transition :parked => :idling
  1040. end
  1041. @record = @model.new
  1042. @record.state = 'parked'
  1043. @record.state_event = 'ignite'
  1044. end
  1045. def test_should_fail_if_event_is_invalid
  1046. @record.state_event = 'invalid'
  1047. assert !@record.valid?
  1048. assert_equal ['State event is invalid'], @record.errors.full_messages
  1049. end
  1050. def test_should_fail_if_event_has_no_transition
  1051. @record.state = 'idling'
  1052. assert !@record.valid?
  1053. assert_equal ['State event cannot transition when idling'], @record.errors.full_messages
  1054. end
  1055. def test_should_be_successful_if_event_has_transition
  1056. assert @record.valid?
  1057. end
  1058. def test_should_run_before_callbacks
  1059. ran_callback = false
  1060. @machine.before_transition { ran_callback = true }
  1061. @record.valid?
  1062. assert ran_callback
  1063. end
  1064. def test_should_run_around_callbacks_before_yield
  1065. ran_callback = false
  1066. @machine.around_transition {|block| ran_callback = true; block.call }
  1067. begin
  1068. @record.valid?
  1069. rescue ArgumentError
  1070. raise if StateMachine::Transition.pause_supported?
  1071. end
  1072. assert ran_callback
  1073. end
  1074. def test_should_persist_new_state
  1075. @record.valid?
  1076. assert_equal 'idling', @record.state
  1077. end
  1078. def test_should_not_run_after_callbacks
  1079. ran_callback = false
  1080. @machine.after_transition { ran_callback = true }
  1081. @record.valid?
  1082. assert !ran_callback
  1083. end
  1084. def test_should_not_run_after_callbacks_with_failures_disabled_if_validation_fails
  1085. @model.class_eval do
  1086. attr_accessor :seatbelt
  1087. validates_presence_of :seatbelt
  1088. end
  1089. ran_callback = false
  1090. @machine.after_transition { ran_callback = true }
  1091. @record.valid?
  1092. assert !ran_callback
  1093. end
  1094. def test_should_not_run_around_callbacks_after_yield
  1095. ran_callback = false
  1096. @machine.around_transition {|block| block.call; ran_callback = true }
  1097. begin
  1098. @record.valid?
  1099. rescue ArgumentError
  1100. raise if StateMachine::Transition.pause_supported?
  1101. end
  1102. assert !ran_callback
  1103. end
  1104. def test_should_not_run_around_callbacks_after_yield_with_failures_disabled_if_validation_fails
  1105. @model.class_eval do
  1106. attr_accessor :seatbelt
  1107. validates_presence_of :seatbelt
  1108. end
  1109. ran_callback = false
  1110. @machine.around_transition {|block| block.call; ran_callback = true }
  1111. @record.valid?
  1112. assert !ran_callback
  1113. end
  1114. def test_should_run_failure_callbacks_if_validation_fails
  1115. @model.class_eval do
  1116. attr_accessor :seatbelt
  1117. validates_presence_of :seatbelt
  1118. end
  1119. ran_callback = false
  1120. @machine.after_failure { ran_callback = true }
  1121. @record.valid?
  1122. assert ran_callback
  1123. end
  1124. end
  1125. class MachineWithEventAttributesOnSaveTest < BaseTestCase
  1126. def setup
  1127. @model = new_model
  1128. @machine = StateMachine::Machine.new(@model)
  1129. @machine.event :ignite do
  1130. transition :parked => :idling
  1131. end
  1132. @record = @model.new
  1133. @record.state = 'parked'
  1134. @record.state_event = 'ignite'
  1135. end
  1136. def test_should_fail_if_event_is_invalid
  1137. @record.state_event = 'invalid'
  1138. assert_equal false, @record.save
  1139. end
  1140. def test_should_fail_if_event_has_no_transition
  1141. @record.state = 'idling'
  1142. assert_equal false, @record.save
  1143. end
  1144. def test_should_be_successful_if_event_has_transition
  1145. assert_equal true, @record.save
  1146. end
  1147. def test_should_run_before_callbacks
  1148. ran_callback = false
  1149. @machine.before_transition { ran_callback = true }
  1150. @record.save
  1151. assert ran_callback
  1152. end
  1153. def test_should_run_before_callbacks_once
  1154. before_count = 0
  1155. @machine.before_transition { before_count += 1 }
  1156. @record.save
  1157. assert_equal 1, before_count
  1158. end
  1159. def test_should_run_around_callbacks_before_yield
  1160. ran_callback = false
  1161. @machine.around_transition {|block| ran_callback = true; block.call }
  1162. @record.save
  1163. assert ran_callback
  1164. end
  1165. def test_should_run_around_callbacks_before_yield_once
  1166. around_before_count = 0
  1167. @machine.around_transition {|block| around_before_count += 1; block.call }
  1168. @record.save
  1169. assert_equal 1, around_before_count
  1170. end
  1171. def test_should_persist_new_state
  1172. @record.save
  1173. assert_equal 'idling', @record.state
  1174. end
  1175. def test_should_run_after_callbacks
  1176. ran_callback = false
  1177. @machine.after_transition { ran_callback = true }
  1178. @record.save
  1179. assert ran_callback
  1180. end
  1181. def test_should_not_run_after_callbacks_with_failures_disabled_if_fails
  1182. @model.class_eval do
  1183. validates_numericality_of :state
  1184. end
  1185. ran_callback = false
  1186. @machine.after_transition { ran_callback = true }
  1187. begin; @record.save; rescue; end
  1188. assert !ran_callback
  1189. end
  1190. def test_should_run_failure_callbacks__if_fails
  1191. @model.class_eval do
  1192. validates_numericality_of :state
  1193. end
  1194. ran_callback = false
  1195. @machine.after_failure { ran_callback = true }
  1196. begin; @record.save; rescue; end
  1197. assert ran_callback
  1198. end
  1199. def test_should_not_run_around_callbacks_with_failures_disabled_if_fails
  1200. @model.class_eval do
  1201. validates_numericality_of :state
  1202. end
  1203. ran_callback = false
  1204. @machine.around_transition {|block| block.call; ran_callback = true }
  1205. begin; @record.save; rescue; end
  1206. assert !ran_callback
  1207. end
  1208. def test_should_run_around_callbacks_after_yield
  1209. ran_callback = false
  1210. @machine.around_transition {|block| block.call; ran_callback = true }
  1211. @record.save
  1212. assert ran_callback
  1213. end
  1214. def test_should_allow_additional_transitions_to_new_state_in_after_transitions
  1215. @machine.event :park do
  1216. transition :idling => :parked
  1217. end
  1218. @machine.after_transition(:on => :ignite) { @record.park }
  1219. @record.save
  1220. assert_equal 'parked', @record.state
  1221. @record = @model.find(@record.id)
  1222. assert_equal 'parked', @record.state
  1223. end
  1224. def test_should_allow_additional_transitions_to_previous_state_in_after_transitions
  1225. @machine.event :shift_up do
  1226. transition :idling => :first_gear
  1227. end
  1228. @machine.after_transition(:on => :ignite) { @record.shift_up }
  1229. @record.save
  1230. assert_equal 'first_gear', @record.state
  1231. @record = @model.find(@record.id)
  1232. assert_equal 'first_gear', @record.state
  1233. end
  1234. end
  1235. if defined?(MongoMapper::Version) && MongoMapper::Version !~ /^0\.[5-8]\./
  1236. class MachineWithEventAttributesOnAutosaveTest < BaseTestCase
  1237. def setup
  1238. @vehicle_model = new_model(:vehicle) do
  1239. belongs_to :owner, :class_name => 'MongoMapperTest::Owner'
  1240. end
  1241. MongoMapperTest.const_set('Vehicle', @vehicle_model)
  1242. @owner_model = new_model(:owner)
  1243. MongoMapperTest.const_set('Owner', @owner_model)
  1244. machine = StateMachine::Machine.new(@vehicle_model)
  1245. machine.event :ignite do
  1246. transition :parked => :idling
  1247. end
  1248. @owner = @owner_model.create
  1249. @vehicle = @vehicle_model.create(:state => 'parked', :owner_id => @owner.id)
  1250. end
  1251. def test_should_persist_many_association
  1252. @owner_model.many :vehicles, :class_name => 'MongoMapperTest::Vehicle', :autosave => true
  1253. @owner.vehicles[0].state_event = 'ignite'
  1254. @owner.save
  1255. @vehicle.reload
  1256. assert_equal 'idling', @vehicle.state
  1257. end
  1258. def teardown
  1259. MongoMapperTest.class_eval do
  1260. remove_const('Vehicle')
  1261. remove_const('Owner')
  1262. end
  1263. super
  1264. end
  1265. end
  1266. end
  1267. class MachineWithEventAttributesOnSaveBangTest < BaseTestCase
  1268. def setup
  1269. @model = new_model
  1270. @machine = StateMachine::Machine.new(@model)
  1271. @machine.event :ignite do
  1272. transition :parked => :idling
  1273. end
  1274. @record = @model.new
  1275. @record.state = 'parked'
  1276. @record.state_event = 'ignite'
  1277. end
  1278. def test_should_fail_if_event_is_invalid
  1279. @record.state_event = 'invalid'
  1280. assert_raise(MongoMapper::DocumentNotValid) { @record.save! }
  1281. end
  1282. def test_should_fail_if_event_has_no_transition
  1283. @record.state = 'idling'
  1284. assert_raise(MongoMapper::DocumentNotValid) { @record.save! }
  1285. end
  1286. def test_should_be_successful_if_event_has_transition
  1287. assert_equal true, @record.save!
  1288. end
  1289. def test_should_run_before_callbacks
  1290. ran_callback = false
  1291. @machine.before_transition { ran_callback = true }
  1292. @record.save!
  1293. assert ran_callback
  1294. end
  1295. def test_should_run_before_callbacks_once
  1296. before_count = 0
  1297. @machine.before_transition { before_count += 1 }
  1298. @record.save!
  1299. assert_equal 1, before_count
  1300. end
  1301. def test_should_run_around_callbacks_before_yield
  1302. ran_callback = false
  1303. @machine.around_transition {|block| ran_callback = true; block.call }
  1304. @record.save!
  1305. assert ran_callback
  1306. end
  1307. def test_should_run_around_callbacks_before_yield_once
  1308. around_before_count = 0
  1309. @machine.around_transition {|block| around_before_count += 1; block.call }
  1310. @record.save!
  1311. assert_equal 1, around_before_count
  1312. end
  1313. def test_should_persist_new_state
  1314. @record.save!
  1315. assert_equal 'idling', @record.state
  1316. end
  1317. def test_should_run_after_callbacks
  1318. ran_callback = false
  1319. @machine.after_transition { ran_callback = true }
  1320. @record.save!
  1321. assert ran_callback
  1322. end
  1323. def test_should_run_around_callbacks_after_yield
  1324. ran_callback = false
  1325. @machine.around_transition {|block| block.call; ran_callback = true }
  1326. @record.save!
  1327. assert ran_callback
  1328. end
  1329. end
  1330. class MachineWithEventAttributesOnCustomActionTest < BaseTestCase
  1331. def setup
  1332. @superclass = new_model do
  1333. def persist
  1334. create_or_update
  1335. end
  1336. end
  1337. @model = Class.new(@superclass)
  1338. @machine = StateMachine::Machine.new(@model, :action => :persist)
  1339. @machine.event :ignite do
  1340. transition :parked => :idling
  1341. end
  1342. @record = @model.new
  1343. @record.state = 'parked'
  1344. @record.state_event = 'ignite'
  1345. end
  1346. def test_should_not_transition_on_valid?
  1347. @record.valid?
  1348. assert_equal 'parked', @record.state
  1349. end
  1350. def test_should_not_transition_on_save
  1351. @record.save
  1352. assert_equal 'parked', @record.state
  1353. end
  1354. def test_should_not_transition_on_save!
  1355. @record.save!
  1356. assert_equal 'parked', @record.state
  1357. end
  1358. def test_should_transition_on_custom_action
  1359. @record.persist
  1360. assert_equal 'idling', @record.state
  1361. end
  1362. end
  1363. class MachineWithScopesTest

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