From 6a7436e77b59e1968a80b115a6feda5a20258040 Mon Sep 17 00:00:00 2001 From: OlegKrakenTeam Date: Mon, 4 Mar 2024 05:00:33 +0300 Subject: [PATCH 1/3] Dockerfile with old gems to check build --- Dockerfile | 12 ++++++++++++ state_machine.gemspec | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..bd366e90 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM ruby:1.9.3 + +RUN mkdir /app +COPY . /app +WORKDIR /app + +RUN bundle install +RUN gem install appraisal -v 0.5.2 +RUN bundle exec rake test +#RUN bundle exec rake appraisal:install +#CMD bundle exec rake appraisal test + diff --git a/state_machine.gemspec b/state_machine.gemspec index 1b7614b6..dbce2b39 100644 --- a/state_machine.gemspec +++ b/state_machine.gemspec @@ -15,8 +15,9 @@ Gem::Specification.new do |s| s.test_files = s.files.grep(/^test\//) s.rdoc_options = %w(--line-numbers --inline-source --title state_machine --main README.md) s.extra_rdoc_files = %w(README.md CHANGELOG.md LICENSE) - - s.add_development_dependency("rake") - s.add_development_dependency("simplecov") + + s.add_development_dependency("rake", "<= 10.5.0") + s.add_development_dependency("simplecov", "0.11.1") + s.add_development_dependency("docile", "1.1.5") s.add_development_dependency("appraisal", "~> 0.5.0") end From b5357f91e3f38dbc094ab7cbcbfd32be5f05a6a1 Mon Sep 17 00:00:00 2001 From: OlegKrakenTeam Date: Mon, 4 Mar 2024 05:01:32 +0300 Subject: [PATCH 2/3] Use File.exist instead of File.exists --- .gitignore | 2 + lib/state_machine/integrations/base.rb | 32 +- test/unit/machine_test.rb | 1276 ++++++++++++------------ 3 files changed, 656 insertions(+), 654 deletions(-) diff --git a/.gitignore b/.gitignore index 8294350e..9c5c6725 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ coverage/ /doc/ test/*.log /Gemfile.lock + +.idea/ diff --git a/lib/state_machine/integrations/base.rb b/lib/state_machine/integrations/base.rb index 17802aee..f83dee7c 100644 --- a/lib/state_machine/integrations/base.rb +++ b/lib/state_machine/integrations/base.rb @@ -5,7 +5,7 @@ module Base module ClassMethods # The default options to use for state machines using this integration attr_reader :defaults - + # The name of the integration def integration_name @integration_name ||= begin @@ -16,40 +16,40 @@ def integration_name name.to_sym end end - + # Whether this integration is available for the current library. This # is only true if the ORM that the integration is for is currently # defined. def available? matching_ancestors.any? && Object.const_defined?(matching_ancestors[0].split('::')[0]) end - + # The list of ancestor names that cause this integration to matched. def matching_ancestors [] end - + # Whether the integration should be used for the given class. def matches?(klass) matches_ancestors?(klass.ancestors.map {|ancestor| ancestor.name}) end - + # Whether the integration should be used for the given list of ancestors. def matches_ancestors?(ancestors) (ancestors & matching_ancestors).any? end - + # Tracks the various version overrides for an integration def versions @versions ||= [] end - + # Creates a new version override for an integration. When this # integration is activated, each version that is marked as active will # also extend the integration. - # + # # == Example - # + # # module StateMachine # module Integrations # module ORMLibrary @@ -57,7 +57,7 @@ def versions # def self.active? # ::ORMLibrary::VERSION >= '0.2.0' && ::ORMLibrary::VERSION < '0.4.0' # end - # + # # def invalidate(object, attribute, message, values = []) # # Override here... # end @@ -65,22 +65,22 @@ def versions # end # end # end - # + # # In the above example, a version override is defined for the ORMLibrary # integration when the version is between 0.2.x and 0.3.x. def version(name, &block) versions << mod = Module.new(&block) mod end - + # The path to the locale file containing translations for this # integration. This file will only exist for integrations that actually # support i18n. def locale_path path = "#{File.dirname(__FILE__)}/#{integration_name}/locale.rb" - path if File.exists?(path) + path if File.exist?(path) end - + # Extends the given object with any version overrides that are currently # active def extended(base) @@ -89,9 +89,9 @@ def extended(base) end end end - + extend ClassMethods - + def self.included(base) #:nodoc: base.class_eval { extend ClassMethods } end diff --git a/test/unit/machine_test.rb b/test/unit/machine_test.rb index 066fc1d5..232dbaca 100644 --- a/test/unit/machine_test.rb +++ b/test/unit/machine_test.rb @@ -6,177 +6,177 @@ def setup @machine = StateMachine::Machine.new(@klass) @object = @klass.new end - + def test_should_have_an_owner_class assert_equal @klass, @machine.owner_class end - + def test_should_have_a_name assert_equal :state, @machine.name end - + def test_should_have_an_attribute assert_equal :state, @machine.attribute end - + def test_should_prefix_custom_attributes_with_attribute assert_equal :state_event, @machine.attribute(:event) end - + def test_should_have_an_initial_state assert_not_nil @machine.initial_state(@object) end - + def test_should_have_a_nil_initial_state assert_nil @machine.initial_state(@object).value end - + def test_should_not_have_any_events assert !@machine.events.any? end - + def test_should_not_have_any_before_callbacks assert @machine.callbacks[:before].empty? end - + def test_should_not_have_any_after_callbacks assert @machine.callbacks[:after].empty? end - + def test_should_not_have_any_failure_callbacks assert @machine.callbacks[:failure].empty? end - + def test_should_not_have_an_action assert_nil @machine.action end - + def test_should_use_tranactions assert_equal true, @machine.use_transactions end - + def test_should_not_have_a_namespace assert_nil @machine.namespace end - + def test_should_have_a_nil_state assert_equal [nil], @machine.states.keys end - + def test_should_set_initial_on_nil_state assert @machine.state(nil).initial end - + def test_should_generate_default_messages assert_equal 'is invalid', @machine.generate_message(:invalid) assert_equal 'cannot transition when parked', @machine.generate_message(:invalid_event, [[:state, :parked]]) assert_equal 'cannot transition via "park"', @machine.generate_message(:invalid_transition, [[:event, :park]]) end - + def test_should_not_be_extended_by_the_base_integration assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::Base) end - + def test_should_not_be_extended_by_the_active_model_integration assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveModel) end - + def test_should_not_be_extended_by_the_active_record_integration assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::ActiveRecord) end - + def test_should_not_be_extended_by_the_datamapper_integration assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::DataMapper) end - + def test_should_not_be_extended_by_the_mongo_mapper_integration assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::MongoMapper) end - + def test_should_not_be_extended_by_the_sequel_integration assert !(class << @machine; ancestors; end).include?(StateMachine::Integrations::Sequel) end - + def test_should_define_a_reader_attribute_for_the_attribute assert @object.respond_to?(:state) end - + def test_should_define_a_writer_attribute_for_the_attribute assert @object.respond_to?(:state=) end - + def test_should_define_a_predicate_for_the_attribute assert @object.respond_to?(:state?) end - + def test_should_define_a_name_reader_for_the_attribute assert @object.respond_to?(:state_name) end - + def test_should_define_an_event_reader_for_the_attribute assert @object.respond_to?(:state_events) end - + def test_should_define_a_transition_reader_for_the_attribute assert @object.respond_to?(:state_transitions) end - + def test_should_define_a_path_reader_for_the_attribute assert @object.respond_to?(:state_paths) end - + def test_should_define_an_event_runner_for_the_attribute assert @object.respond_to?(:fire_state_event) end - + def test_should_not_define_an_event_attribute_reader assert !@object.respond_to?(:state_event) end - + def test_should_not_define_an_event_attribute_writer assert !@object.respond_to?(:state_event=) end - + def test_should_not_define_an_event_transition_attribute_reader assert !@object.respond_to?(:state_event_transition) end - + def test_should_not_define_an_event_transition_attribute_writer assert !@object.respond_to?(:state_event_transition=) end - + def test_should_define_a_human_attribute_name_reader_for_the_attribute assert @klass.respond_to?(:human_state_name) end - + def test_should_define_a_human_event_name_reader_for_the_attribute assert @klass.respond_to?(:human_state_event_name) end - + def test_should_not_define_singular_with_scope assert !@klass.respond_to?(:with_state) end - + def test_should_not_define_singular_without_scope assert !@klass.respond_to?(:without_state) end - + def test_should_not_define_plural_with_scope assert !@klass.respond_to?(:with_states) end - + def test_should_not_define_plural_without_scope assert !@klass.respond_to?(:without_states) end - + def test_should_extend_owner_class_with_class_methods assert((class << @klass; ancestors; end).include?(StateMachine::ClassMethods)) end - + def test_should_include_instance_methods_in_owner_class assert @klass.included_modules.include?(StateMachine::InstanceMethods) end - + def test_should_define_state_machines_reader expected = {:state => @machine} assert_equal expected, @klass.state_machines @@ -189,51 +189,51 @@ def setup @machine = StateMachine::Machine.new(@klass, :status) @object = @klass.new end - + def test_should_use_custom_name assert_equal :status, @machine.name end - + def test_should_use_custom_name_for_attribute assert_equal :status, @machine.attribute end - + def test_should_prefix_custom_attributes_with_custom_name assert_equal :status_event, @machine.attribute(:event) end - + def test_should_define_a_reader_attribute_for_the_attribute assert @object.respond_to?(:status) end - + def test_should_define_a_writer_attribute_for_the_attribute assert @object.respond_to?(:status=) end - + def test_should_define_a_predicate_for_the_attribute assert @object.respond_to?(:status?) end - + def test_should_define_a_name_reader_for_the_attribute assert @object.respond_to?(:status_name) end - + def test_should_define_an_event_reader_for_the_attribute assert @object.respond_to?(:status_events) end - + def test_should_define_a_transition_reader_for_the_attribute assert @object.respond_to?(:status_transitions) end - + def test_should_define_an_event_runner_for_the_attribute assert @object.respond_to?(:fire_status_event) end - + def test_should_define_a_human_attribute_name_reader_for_the_attribute assert @klass.respond_to?(:human_status_name) end - + def test_should_define_a_human_event_name_reader_for_the_attribute assert @klass.respond_to?(:human_status_event_name) end @@ -247,15 +247,15 @@ def initialize(attributes = {}) super() end end - + @machine = StateMachine::Machine.new(@klass, :initial => :parked, :initialize => false) end - + def test_should_not_have_an_initial_state object = @klass.new assert_nil object.state end - + def test_should_still_allow_manual_initialization @klass.send(:include, Module.new do def initialize(attributes = {}) @@ -263,7 +263,7 @@ def initialize(attributes = {}) initialize_state_machines end end) - + object = @klass.new assert_equal 'parked', object.state end @@ -274,30 +274,30 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass, :initial => :parked) end - + def test_should_not_have_dynamic_initial_state assert !@machine.dynamic_initial_state? end - + def test_should_have_an_initial_state object = @klass.new assert_equal 'parked', @machine.initial_state(object).value end - + def test_should_write_to_attribute_when_initializing_state object = @klass.allocate @machine.initialize_state(object) assert_equal 'parked', object.state end - + def test_should_set_initial_on_state_object assert @machine.state(:parked).initial end - + def test_should_set_initial_state_on_created_object assert_equal 'parked', @klass.new.state end - + def test_not_set_initial_state_even_if_not_empty @klass.class_eval do def initialize(attributes = {}) @@ -308,21 +308,21 @@ def initialize(attributes = {}) object = @klass.new assert_equal 'idling', object.state end - + def test_should_set_initial_state_prior_to_initialization base = Class.new do attr_accessor :state_on_init - + def initialize self.state_on_init = state end end klass = Class.new(base) StateMachine::Machine.new(klass, :initial => :parked) - + assert_equal 'parked', klass.new.state_on_init end - + def test_should_be_included_in_known_states assert_equal [:parked], @machine.states.keys end @@ -337,30 +337,30 @@ def setup @machine.state :parked, :idling, :default @object = @klass.new end - + def test_should_have_dynamic_initial_state assert @machine.dynamic_initial_state? end - + def test_should_use_the_record_for_determining_the_initial_state @object.initial_state = :parked assert_equal :parked, @machine.initial_state(@object).name - + @object.initial_state = :idling assert_equal :idling, @machine.initial_state(@object).name end - + def test_should_write_to_attribute_when_initializing_state object = @klass.allocate object.initial_state = :parked @machine.initialize_state(object) assert_equal 'parked', object.state end - + def test_should_set_initial_state_on_created_object assert_equal 'default', @object.state end - + def test_should_not_set_initial_state_even_if_not_empty @klass.class_eval do def initialize(attributes = {}) @@ -371,11 +371,11 @@ def initialize(attributes = {}) object = @klass.new assert_equal 'parked', object.state end - + def test_should_set_initial_state_after_initialization base = Class.new do attr_accessor :state_on_init - + def initialize self.state_on_init = state end @@ -383,10 +383,10 @@ def initialize klass = Class.new(base) machine = StateMachine::Machine.new(klass, :initial => lambda {|object| :parked}) machine.state :parked - + assert_nil klass.new.state_on_init end - + def test_should_not_be_included_in_known_states assert_equal [:parked, :idling, :default], @machine.states.map {|state| state.name} end @@ -396,50 +396,50 @@ class MachineStateInitializationTest < Test::Unit::TestCase def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass, :state, :initial => :parked, :initialize => false) - + @object = @klass.new @object.state = nil end - + def test_should_set_states_if_nil @machine.initialize_state(@object) - + assert_equal 'parked', @object.state end - + def test_should_set_states_if_empty @object.state = '' @machine.initialize_state(@object) - + assert_equal 'parked', @object.state end - + def test_should_not_set_states_if_not_empty @object.state = 'idling' @machine.initialize_state(@object) - + assert_equal 'idling', @object.state end - + def test_should_set_states_if_not_empty_and_forced @object.state = 'idling' @machine.initialize_state(@object, :force => true) - + assert_equal 'parked', @object.state end - + def test_should_not_set_state_if_nil_and_nil_is_valid_state @machine.state :initial, :value => nil @machine.initialize_state(@object) - + assert_nil @object.state end - + def test_should_write_to_hash_if_specified @machine.initialize_state(@object, :to => hash = {}) assert_equal({'state' => 'parked'}, hash) end - + def test_should_not_write_to_object_if_writing_to_hash @machine.initialize_state(@object, :to => {}) assert_nil @object.state @@ -450,7 +450,7 @@ class MachineWithCustomActionTest < Test::Unit::TestCase def setup @machine = StateMachine::Machine.new(Class.new, :action => :save) end - + def test_should_use_the_custom_action assert_equal :save, @machine.action end @@ -460,17 +460,17 @@ class MachineWithNilActionTest < Test::Unit::TestCase def setup integration = Module.new do include StateMachine::Integrations::Base - + @defaults = {:action => :save} end StateMachine::Integrations.const_set('Custom', integration) @machine = StateMachine::Machine.new(Class.new, :action => nil, :integration => :custom) end - + def test_should_have_a_nil_action assert_nil @machine.action end - + def teardown StateMachine::Integrations.send(:remove_const, 'Custom') end @@ -482,24 +482,24 @@ def setup @machine = StateMachine::Machine.new(@klass) @object = @klass.new end - + def test_transaction_should_yield @yielded = false @machine.within_transaction(@object) do @yielded = true end - + assert @yielded end - + def test_invalidation_should_do_nothing assert_nil @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']]) end - + def test_reset_should_do_nothing assert_nil @machine.reset(@object) end - + def test_errors_for_should_be_empty assert_equal '', @machine.errors_for(@object) end @@ -509,25 +509,25 @@ class MachineWithCustomIntegrationTest < Test::Unit::TestCase def setup integration = Module.new do include StateMachine::Integrations::Base - + def self.matching_ancestors ['MachineWithCustomIntegrationTest::Vehicle'] end end - + StateMachine::Integrations.const_set('Custom', integration) - + superclass = Class.new self.class.const_set('Vehicle', superclass) - + @klass = Class.new(superclass) end - + def test_should_be_extended_by_the_integration_if_explicit machine = StateMachine::Machine.new(@klass, :integration => :custom) assert((class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)) end - + def test_should_not_be_extended_by_the_integration_if_implicit_but_not_available StateMachine::Integrations::Custom.class_eval do class << self; remove_method :matching_ancestors; end @@ -535,7 +535,7 @@ def self.matching_ancestors [] end end - + machine = StateMachine::Machine.new(@klass) assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)) end @@ -547,7 +547,7 @@ def self.matching_ancestors [] end end - + machine = StateMachine::Machine.new(@klass) assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)) end @@ -561,12 +561,12 @@ def test_should_not_be_extended_by_the_integration_if_nil machine = StateMachine::Machine.new(@klass, :integration => nil) assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)) end - + def test_should_not_be_extended_by_the_integration_if_false machine = StateMachine::Machine.new(@klass, :integration => false) assert(!(class << machine; ancestors; end).include?(StateMachine::Integrations::Custom)) end - + def teardown self.class.send(:remove_const, 'Vehicle') StateMachine::Integrations.send(:remove_const, 'Custom') @@ -575,66 +575,66 @@ def teardown class MachineWithIntegrationTest < Test::Unit::TestCase def setup - StateMachine::Integrations.const_set('Custom', Module.new do + StateMachine::Integrations.const_set('Custom', Module.new do include StateMachine::Integrations::Base - + @defaults = {:action => :save, :use_transactions => false} - + attr_reader :initialized, :with_scopes, :without_scopes, :ran_transaction - + def after_initialize @initialized = true end - + def create_with_scope(name) (@with_scopes ||= []) << name lambda {} end - + def create_without_scope(name) (@without_scopes ||= []) << name lambda {} end - + def transaction(object) @ran_transaction = true yield end end) - + @machine = StateMachine::Machine.new(Class.new, :integration => :custom) end - + def test_should_call_after_initialize_hook assert @machine.initialized end - + def test_should_use_the_default_action assert_equal :save, @machine.action end - + def test_should_use_the_custom_action_if_specified machine = StateMachine::Machine.new(Class.new, :integration => :custom, :action => :save!) assert_equal :save!, machine.action end - + def test_should_use_the_default_use_transactions assert_equal false, @machine.use_transactions end - + def test_should_use_the_custom_use_transactions_if_specified machine = StateMachine::Machine.new(Class.new, :integration => :custom, :use_transactions => true) assert_equal true, machine.use_transactions end - + def test_should_define_a_singular_and_plural_with_scope assert_equal %w(with_state with_states), @machine.with_scopes end - + def test_should_define_a_singular_and_plural_without_scope assert_equal %w(without_state without_states), @machine.without_scopes end - + def teardown StateMachine::Integrations.send(:remove_const, 'Custom') end @@ -646,27 +646,27 @@ def setup @machine = StateMachine::Machine.new(@klass, :action => :save) @object = @klass.new end - + def test_should_define_an_event_attribute_reader assert @object.respond_to?(:state_event) end - + def test_should_define_an_event_attribute_writer assert @object.respond_to?(:state_event=) end - + def test_should_define_an_event_transition_attribute_reader assert @object.respond_to?(:state_event_transition, true) end - + def test_should_define_an_event_transition_attribute_writer assert @object.respond_to?(:state_event_transition=, true) end - + def test_should_not_define_action assert !@object.respond_to?(:save) end - + def test_should_not_mark_action_hook_as_defined assert !@machine.action_hook? end @@ -678,31 +678,31 @@ def setup def save end end - + @machine = StateMachine::Machine.new(@klass, :action => :save) @object = @klass.new end - + def test_should_define_an_event_attribute_reader assert @object.respond_to?(:state_event) end - + def test_should_define_an_event_attribute_writer assert @object.respond_to?(:state_event=) end - + def test_should_define_an_event_transition_attribute_reader assert @object.respond_to?(:state_event_transition, true) end - + def test_should_define_an_event_transition_attribute_writer assert @object.respond_to?(:state_event_transition=, true) end - + def test_should_not_define_action assert !@klass.ancestors.any? {|ancestor| ancestor != @klass && ancestor.method_defined?(:save)} end - + def test_should_not_mark_action_hook_as_defined assert !@machine.action_hook? end @@ -714,39 +714,39 @@ def setup def save end end - + @klass = Class.new do include mod end - + @machine = StateMachine::Machine.new(@klass, :action => :save) @object = @klass.new end - + def test_should_define_an_event_attribute_reader assert @object.respond_to?(:state_event) end - + def test_should_define_an_event_attribute_writer assert @object.respond_to?(:state_event=) end - + def test_should_define_an_event_transition_attribute_reader assert @object.respond_to?(:state_event_transition, true) end - + def test_should_define_an_event_transition_attribute_writer assert @object.respond_to?(:state_event_transition=, true) end - + def test_should_define_action assert @klass.ancestors.any? {|ancestor| ![@klass, @mod].include?(ancestor) && ancestor.method_defined?(:save)} end - + def test_should_keep_action_public assert @klass.public_method_defined?(:save) end - + def test_should_mark_action_hook_as_defined assert @machine.action_hook? end @@ -759,35 +759,35 @@ def save end end @klass = Class.new(@superclass) - + @machine = StateMachine::Machine.new(@klass, :action => :save) @object = @klass.new end - + def test_should_define_an_event_attribute_reader assert @object.respond_to?(:state_event) end - + def test_should_define_an_event_attribute_writer assert @object.respond_to?(:state_event=) end - + def test_should_define_an_event_transition_attribute_reader assert @object.respond_to?(:state_event_transition, true) end - + def test_should_define_an_event_transition_attribute_writer assert @object.respond_to?(:state_event_transition=, true) end - + def test_should_define_action assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)} end - + def test_should_keep_action_public assert @klass.public_method_defined?(:save) end - + def test_should_mark_action_hook_as_defined assert @machine.action_hook? end @@ -801,35 +801,35 @@ def save end end @klass = Class.new(@superclass) - + @machine = StateMachine::Machine.new(@klass, :action => :save) @object = @klass.new end - + def test_should_define_an_event_attribute_reader assert @object.respond_to?(:state_event) end - + def test_should_define_an_event_attribute_writer assert @object.respond_to?(:state_event=) end - + def test_should_define_an_event_transition_attribute_reader assert @object.respond_to?(:state_event_transition, true) end - + def test_should_define_an_event_transition_attribute_writer assert @object.respond_to?(:state_event_transition=, true) end - + def test_should_define_action assert @klass.ancestors.any? {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.private_method_defined?(:save)} end - + def test_should_keep_action_private assert @klass.private_method_defined?(:save) end - + def test_should_mark_action_hook_as_defined assert @machine.action_hook? end @@ -842,16 +842,16 @@ def save end end @klass = Class.new(@superclass) - + StateMachine::Machine.new(@klass, :action => :save) @machine = StateMachine::Machine.new(@klass, :status, :action => :save) @object = @klass.new end - + def test_should_not_redefine_action assert_equal 1, @klass.ancestors.select {|ancestor| ![@klass, @superclass].include?(ancestor) && ancestor.method_defined?(:save)}.length end - + def test_should_mark_action_hook_as_defined assert @machine.action_hook? end @@ -861,45 +861,45 @@ class MachineWithCustomPluralTest < Test::Unit::TestCase def setup @integration = Module.new do include StateMachine::Integrations::Base - + class << self; attr_accessor :with_scopes, :without_scopes; end @with_scopes = [] @without_scopes = [] - + def create_with_scope(name) StateMachine::Integrations::Custom.with_scopes << name lambda {} end - + def create_without_scope(name) StateMachine::Integrations::Custom.without_scopes << name lambda {} end end - + StateMachine::Integrations.const_set('Custom', @integration) end - + def test_should_define_a_singular_and_plural_with_scope StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties') assert_equal %w(with_state with_staties), @integration.with_scopes end - + def test_should_define_a_singular_and_plural_without_scope StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'staties') assert_equal %w(without_state without_staties), @integration.without_scopes end - + def test_should_define_single_with_scope_if_singular_same_as_plural StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'state') assert_equal %w(with_state), @integration.with_scopes end - + def test_should_define_single_without_scope_if_singular_same_as_plural StateMachine::Machine.new(Class.new, :integration => :custom, :plural => 'state') assert_equal %w(without_state), @integration.without_scopes end - + def teardown StateMachine::Integrations.send(:remove_const, 'Custom') end @@ -909,33 +909,33 @@ class MachineWithCustomInvalidationTest < Test::Unit::TestCase def setup @integration = Module.new do include StateMachine::Integrations::Base - + def invalidate(object, attribute, message, values = []) object.error = generate_message(message, values) end end StateMachine::Integrations.const_set('Custom', @integration) - + @klass = Class.new do attr_accessor :error end - + @machine = StateMachine::Machine.new(@klass, :integration => :custom, :messages => {:invalid_transition => 'cannot %s'}) @machine.state :parked - + @object = @klass.new @object.state = 'parked' end - + def test_generate_custom_message assert_equal 'cannot park', @machine.generate_message(:invalid_transition, [[:event, :park]]) end - + def test_use_custom_message @machine.invalidate(@object, :state, :invalid_transition, [[:event, 'park']]) assert_equal 'cannot park', @object.error end - + def teardown StateMachine::Integrations.send(:remove_const, 'Custom') end @@ -945,27 +945,27 @@ class MachineTest < Test::Unit::TestCase def test_should_raise_exception_if_invalid_option_specified assert_raise(ArgumentError) {StateMachine::Machine.new(Class.new, :invalid => true)} end - + def test_should_not_raise_exception_if_custom_messages_specified assert_nothing_raised {StateMachine::Machine.new(Class.new, :messages => {:invalid_transition => 'custom'})} end - + def test_should_evaluate_a_block_during_initialization called = true StateMachine::Machine.new(Class.new) do called = respond_to?(:event) end - + assert called end - + def test_should_provide_matcher_helpers_during_initialization matchers = [] - + StateMachine::Machine.new(Class.new) do matchers = [all, any, same] end - + assert_equal [StateMachine::AllMatcher.instance, StateMachine::AllMatcher.instance, StateMachine::LoopbackMatcher.instance], matchers end end @@ -978,54 +978,54 @@ def setup @machine.after_transition(lambda {}) @machine.around_transition(lambda {}) @machine.after_failure(lambda {}) - + @copied_machine = @machine.clone end - + def test_should_not_have_the_same_collection_of_states assert_not_same @copied_machine.states, @machine.states end - + def test_should_copy_each_state assert_not_same @copied_machine.states[:parked], @machine.states[:parked] end - + def test_should_update_machine_for_each_state assert_equal @copied_machine, @copied_machine.states[:parked].machine end - + def test_should_not_update_machine_for_original_state assert_equal @machine, @machine.states[:parked].machine end - + def test_should_not_have_the_same_collection_of_events assert_not_same @copied_machine.events, @machine.events end - + def test_should_copy_each_event assert_not_same @copied_machine.events[:ignite], @machine.events[:ignite] end - + def test_should_update_machine_for_each_event assert_equal @copied_machine, @copied_machine.events[:ignite].machine end - + def test_should_not_update_machine_for_original_event assert_equal @machine, @machine.events[:ignite].machine end - + def test_should_not_have_the_same_callbacks assert_not_same @copied_machine.callbacks, @machine.callbacks end - + def test_should_not_have_the_same_before_callbacks assert_not_same @copied_machine.callbacks[:before], @machine.callbacks[:before] end - + def test_should_not_have_the_same_after_callbacks assert_not_same @copied_machine.callbacks[:after], @machine.callbacks[:after] end - + def test_should_not_have_the_same_failure_callbacks assert_not_same @copied_machine.callbacks[:failure], @machine.callbacks[:failure] end @@ -1035,26 +1035,26 @@ class MachineAfterChangingOwnerClassTest < Test::Unit::TestCase def setup @original_class = Class.new @machine = StateMachine::Machine.new(@original_class) - + @new_class = Class.new(@original_class) @new_machine = @machine.clone @new_machine.owner_class = @new_class - + @object = @new_class.new end - + def test_should_update_owner_class assert_equal @new_class, @new_machine.owner_class end - + def test_should_not_change_original_owner_class assert_equal @original_class, @machine.owner_class end - + def test_should_change_the_associated_machine_in_the_new_class assert_equal @new_machine, @new_class.state_machines[:state] end - + def test_should_not_change_the_associated_machine_in_the_original_class assert_equal @machine, @original_class.state_machines[:state] end @@ -1065,22 +1065,22 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass, :initial => :parked) @machine.initial_state = :idling - + @object = @klass.new end - + def test_should_change_the_initial_state assert_equal :idling, @machine.initial_state(@object).name end - + def test_should_include_in_known_states assert_equal [:parked, :idling], @machine.states.map {|state| state.name} end - + def test_should_reset_original_initial_state assert !@machine.state(:parked).initial end - + def test_should_set_new_state_to_initial assert @machine.state(:idling).initial end @@ -1092,7 +1092,7 @@ def setup @machine = StateMachine::Machine.new(@klass) @object = @klass.new end - + def test_should_throw_exception_with_invalid_scope assert_raise(RUBY_VERSION < '1.9' ? IndexError : KeyError) { @machine.define_helper(:invalid, :park) {} } end @@ -1104,18 +1104,18 @@ def setup @machine = StateMachine::Machine.new(@klass) @object = @klass.new end - + def test_should_not_redefine_existing_public_methods @klass.class_eval do def park true end end - + @machine.define_helper(:instance, :park) {} assert_equal true, @object.park end - + def test_should_not_redefine_existing_protected_methods @klass.class_eval do protected @@ -1123,11 +1123,11 @@ def park true end end - + @machine.define_helper(:instance, :park) {} assert_equal true, @object.send(:park) end - + def test_should_not_redefine_existing_private_methods @klass.class_eval do private @@ -1135,32 +1135,32 @@ def park true end end - + @machine.define_helper(:instance, :park) {} assert_equal true, @object.send(:park) end - + def test_should_warn_if_defined_in_superclass require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + superclass = Class.new do def park end end klass = Class.new(superclass) machine = StateMachine::Machine.new(klass) - + machine.define_helper(:instance, :park) {} assert_equal "Instance method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_warn_if_defined_in_multiple_superclasses require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + superclass1 = Class.new do def park end @@ -1171,17 +1171,17 @@ def park end klass = Class.new(superclass2) machine = StateMachine::Machine.new(klass) - + machine.define_helper(:instance, :park) {} assert_equal "Instance method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_warn_if_defined_in_module_prior_to_helper_module require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + mod = Module.new do def park end @@ -1190,20 +1190,20 @@ def park include mod end machine = StateMachine::Machine.new(klass) - + machine.define_helper(:instance, :park) {} assert_equal "Instance method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_not_warn_if_defined_in_module_after_helper_module require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + klass = Class.new machine = StateMachine::Machine.new(klass) - + mod = Module.new do def park end @@ -1211,25 +1211,25 @@ def park klass.class_eval do include mod end - + machine.define_helper(:instance, :park) {} assert_equal '', $stderr.string ensure $stderr = @original_stderr end - + def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new StateMachine::Machine.ignore_method_conflicts = true - + superclass = Class.new do def park end end klass = Class.new(superclass) machine = StateMachine::Machine.new(klass) - + machine.define_helper(:instance, :park) {true} assert_equal '', $stderr.string assert_equal true, klass.new.park @@ -1237,24 +1237,24 @@ def park StateMachine::Machine.ignore_method_conflicts = false $stderr = @original_stderr end - + def test_should_define_nonexistent_methods @machine.define_helper(:instance, :park) {false} assert_equal false, @object.park end - + def test_should_warn_if_defined_multiple_times require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + @machine.define_helper(:instance, :park) {} @machine.define_helper(:instance, :park) {} - + assert_equal "Instance method \"park\" is already defined in #{@klass} :state instance helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_pass_context_as_arguments helper_args = nil @machine.define_helper(:instance, :park) {|*args| helper_args = args} @@ -1262,7 +1262,7 @@ def test_should_pass_context_as_arguments assert_equal 2, helper_args.length assert_equal [@machine, @object], helper_args end - + def test_should_pass_method_arguments_through helper_args = nil @machine.define_helper(:instance, :park) {|*args| helper_args = args} @@ -1270,7 +1270,7 @@ def test_should_pass_method_arguments_through assert_equal 5, helper_args.length assert_equal [@machine, @object, 1, 2, 3], helper_args end - + def test_should_allow_string_evaluation @machine.define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1 def park @@ -1286,18 +1286,18 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) end - + def test_should_not_redefine_existing_public_methods class << @klass def states [] end end - + @machine.define_helper(:class, :states) {} assert_equal [], @klass.states end - + def test_should_not_redefine_existing_protected_methods class << @klass protected @@ -1305,11 +1305,11 @@ def states [] end end - + @machine.define_helper(:class, :states) {} assert_equal [], @klass.send(:states) end - + def test_should_not_redefine_existing_private_methods class << @klass private @@ -1317,32 +1317,32 @@ def states [] end end - + @machine.define_helper(:class, :states) {} assert_equal [], @klass.send(:states) end - + def test_should_warn_if_defined_in_superclass require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + superclass = Class.new do def self.park end end klass = Class.new(superclass) machine = StateMachine::Machine.new(klass) - + machine.define_helper(:class, :park) {} assert_equal "Class method \"park\" is already defined in #{superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_warn_if_defined_in_multiple_superclasses require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + superclass1 = Class.new do def self.park end @@ -1353,17 +1353,17 @@ def self.park end klass = Class.new(superclass2) machine = StateMachine::Machine.new(klass) - + machine.define_helper(:class, :park) {} assert_equal "Class method \"park\" is already defined in #{superclass1.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_warn_if_defined_in_module_prior_to_helper_module require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + mod = Module.new do def park end @@ -1372,20 +1372,20 @@ def park extend mod end machine = StateMachine::Machine.new(klass) - + machine.define_helper(:class, :park) {} assert_equal "Class method \"park\" is already defined in #{mod.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_not_warn_if_defined_in_module_after_helper_module require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + klass = Class.new machine = StateMachine::Machine.new(klass) - + mod = Module.new do def park end @@ -1393,25 +1393,25 @@ def park klass.class_eval do extend mod end - + machine.define_helper(:class, :park) {} assert_equal '', $stderr.string ensure $stderr = @original_stderr end - + def test_should_define_if_ignoring_method_conflicts_and_defined_in_superclass require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new StateMachine::Machine.ignore_method_conflicts = true - + superclass = Class.new do def self.park end end klass = Class.new(superclass) machine = StateMachine::Machine.new(klass) - + machine.define_helper(:class, :park) {true} assert_equal '', $stderr.string assert_equal true, klass.park @@ -1419,24 +1419,24 @@ def self.park StateMachine::Machine.ignore_method_conflicts = false $stderr = @original_stderr end - + def test_should_define_nonexistent_methods @machine.define_helper(:class, :states) {[]} assert_equal [], @klass.states end - + def test_should_warn_if_defined_multiple_times require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + @machine.define_helper(:class, :states) {} @machine.define_helper(:class, :states) {} - + assert_equal "Class method \"states\" is already defined in #{@klass} :state class helpers, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n", $stderr.string ensure $stderr = @original_stderr end - + def test_should_pass_context_as_arguments helper_args = nil @machine.define_helper(:class, :states) {|*args| helper_args = args} @@ -1444,7 +1444,7 @@ def test_should_pass_context_as_arguments assert_equal 2, helper_args.length assert_equal [@machine, @klass], helper_args end - + def test_should_pass_method_arguments_through helper_args = nil @machine.define_helper(:class, :states) {|*args| helper_args = args} @@ -1452,7 +1452,7 @@ def test_should_pass_method_arguments_through assert_equal 5, helper_args.length assert_equal [@machine, @klass, 1, 2, 3], helper_args end - + def test_should_allow_string_evaluation @machine.define_helper :class, <<-end_eval, __FILE__, __LINE__ + 1 def states @@ -1467,151 +1467,151 @@ class MachineWithConflictingHelpersBeforeDefinitionTest < Test::Unit::TestCase def setup require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + @superclass = Class.new do def self.with_state :with_state end - + def self.with_states :with_states end - + def self.without_state :without_state end - + def self.without_states :without_states end - + def self.human_state_name :human_state_name end - + def self.human_state_event_name :human_state_event_name end - + attr_accessor :status - + def state 'parked' end - + def state=(value) self.status = value end - + def state? true end - + def state_name :parked end - + def human_state_name 'parked' end - + def state_events [:ignite] end - + def state_transitions [{:parked => :idling}] end - + def state_paths [[{:parked => :idling}]] end - + def fire_state_event true end end @klass = Class.new(@superclass) - + StateMachine::Integrations.const_set('Custom', Module.new do include StateMachine::Integrations::Base - + def create_with_scope(name) lambda {|klass, values| []} end - + def create_without_scope(name) lambda {|klass, values| []} end end) - + @machine = StateMachine::Machine.new(@klass, :integration => :custom) @machine.state :parked, :idling @machine.event :ignite @object = @klass.new end - + def test_should_not_redefine_singular_with_scope assert_equal :with_state, @klass.with_state end - + def test_should_not_redefine_plural_with_scope assert_equal :with_states, @klass.with_states end - + def test_should_not_redefine_singular_without_scope assert_equal :without_state, @klass.without_state end - + def test_should_not_redefine_plural_without_scope assert_equal :without_states, @klass.without_states end - + def test_should_not_redefine_human_attribute_name_reader assert_equal :human_state_name, @klass.human_state_name end - + def test_should_not_redefine_human_event_name_reader assert_equal :human_state_event_name, @klass.human_state_event_name end - + def test_should_not_redefine_attribute_reader assert_equal 'parked', @object.state end - + def test_should_not_redefine_attribute_writer @object.state = 'parked' assert_equal 'parked', @object.status end - + def test_should_not_define_attribute_predicate assert @object.state? end - + def test_should_not_redefine_attribute_name_reader assert_equal :parked, @object.state_name end - + def test_should_not_redefine_attribute_human_name_reader assert_equal 'parked', @object.human_state_name end - + def test_should_not_redefine_attribute_events_reader assert_equal [:ignite], @object.state_events end - + def test_should_not_redefine_attribute_transitions_reader assert_equal [{:parked => :idling}], @object.state_transitions end - + def test_should_not_redefine_attribute_paths_reader assert_equal [[{:parked => :idling}]], @object.state_paths end - + def test_should_not_redefine_event_runner assert_equal true, @object.fire_state_event end - + def test_should_output_warning expected = [ 'Instance method "state_events"', @@ -1627,10 +1627,10 @@ def test_should_output_warning 'Class method "without_state"', 'Class method "without_states"' ].map {|method| "#{method} is already defined in #{@superclass.to_s}, use generic helper instead or set StateMachine::Machine.ignore_method_conflicts = true.\n"}.join - + assert_equal expected, $stderr.string end - + def teardown $stderr = @original_stderr StateMachine::Integrations.send(:remove_const, 'Custom') @@ -1641,222 +1641,222 @@ class MachineWithConflictingHelpersAfterDefinitionTest < Test::Unit::TestCase def setup require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + @klass = Class.new do def self.with_state :with_state end - + def self.with_states :with_states end - + def self.without_state :without_state end - + def self.without_states :without_states end - + def self.human_state_name :human_state_name end - + def self.human_state_event_name :human_state_event_name end - + attr_accessor :status - + def state 'parked' end - + def state=(value) self.status = value end - + def state? true end - + def state_name :parked end - + def human_state_name 'parked' end - + def state_events [:ignite] end - + def state_transitions [{:parked => :idling}] end - + def state_paths [[{:parked => :idling}]] end - + def fire_state_event true end end - + StateMachine::Integrations.const_set('Custom', Module.new do include StateMachine::Integrations::Base - + def create_with_scope(name) lambda {|klass, values| []} end - + def create_without_scope(name) lambda {|klass, values| []} end end) - + @machine = StateMachine::Machine.new(@klass, :integration => :custom) @machine.state :parked, :idling @machine.event :ignite @object = @klass.new end - + def test_should_not_redefine_singular_with_scope assert_equal :with_state, @klass.with_state end - + def test_should_not_redefine_plural_with_scope assert_equal :with_states, @klass.with_states end - + def test_should_not_redefine_singular_without_scope assert_equal :without_state, @klass.without_state end - + def test_should_not_redefine_plural_without_scope assert_equal :without_states, @klass.without_states end - + def test_should_not_redefine_human_attribute_name_reader assert_equal :human_state_name, @klass.human_state_name end - + def test_should_not_redefine_human_event_name_reader assert_equal :human_state_event_name, @klass.human_state_event_name end - + def test_should_not_redefine_attribute_reader assert_equal 'parked', @object.state end - + def test_should_not_redefine_attribute_writer @object.state = 'parked' assert_equal 'parked', @object.status end - + def test_should_not_define_attribute_predicate assert @object.state? end - + def test_should_not_redefine_attribute_name_reader assert_equal :parked, @object.state_name end - + def test_should_not_redefine_attribute_human_name_reader assert_equal 'parked', @object.human_state_name end - + def test_should_not_redefine_attribute_events_reader assert_equal [:ignite], @object.state_events end - + def test_should_not_redefine_attribute_transitions_reader assert_equal [{:parked => :idling}], @object.state_transitions end - + def test_should_not_redefine_attribute_paths_reader assert_equal [[{:parked => :idling}]], @object.state_paths end - + def test_should_not_redefine_event_runner assert_equal true, @object.fire_state_event end - + def test_should_allow_super_chaining @klass.class_eval do def self.with_state(*states) super end - + def self.with_states(*states) super end - + def self.without_state(*states) super end - + def self.without_states(*states) super end - + def self.human_state_name(state) super end - + def self.human_state_event_name(event) super end - + attr_accessor :status - + def state super end - + def state=(value) super end - + def state?(state) super end - + def state_name super end - + def human_state_name super end - + def state_events super end - + def state_transitions super end - + def state_paths super end - + def fire_state_event(event) super end end - + assert_equal [], @klass.with_state assert_equal [], @klass.with_states assert_equal [], @klass.without_state assert_equal [], @klass.without_states assert_equal 'parked', @klass.human_state_name(:parked) assert_equal 'ignite', @klass.human_state_event_name(:ignite) - + assert_equal nil, @object.state @object.state = 'idling' assert_equal 'idling', @object.state @@ -1869,11 +1869,11 @@ def fire_state_event(event) assert_equal [], @object.state_paths assert_equal false, @object.fire_state_event(:ignite) end - + def test_should_not_output_warning assert_equal '', $stderr.string end - + def teardown $stderr = @original_stderr StateMachine::Integrations.send(:remove_const, 'Custom') @@ -1884,31 +1884,31 @@ class MachineWithSuperclassConflictingHelpersAfterDefinitionTest < Test::Unit::T def setup require 'stringio' @original_stderr, $stderr = $stderr, StringIO.new - + @superclass = Class.new @klass = Class.new(@superclass) - + @machine = StateMachine::Machine.new(@klass) @machine.state :parked, :idling @machine.event :ignite - + @superclass.class_eval do def state? true end end - + @object = @klass.new end - + def test_should_call_superclass_attribute_predicate_without_arguments assert @object.state? end - + def test_should_define_attribute_predicate_with_arguments assert !@object.state?(:parked) end - + def teardown $stderr = @original_stderr end @@ -1920,7 +1920,7 @@ def setup @machine = StateMachine::Machine.new(@klass, :initial => :parked) @object = @klass.new end - + def test_should_initialize_state assert_equal 'parked', @object.state end @@ -1935,7 +1935,7 @@ def initialize @machine = StateMachine::Machine.new(@klass, :initial => :parked) @object = @klass.new end - + def test_should_not_initialize_state assert_nil @object.state end @@ -1951,7 +1951,7 @@ def initialize @machine = StateMachine::Machine.new(@klass, :initial => :parked) @object = @klass.new end - + def test_should_initialize_state assert_equal 'parked', @object.state end @@ -1962,7 +1962,7 @@ def setup @superclass = Class.new do attr_reader :args attr_reader :block_given - + def initialize(*args) @args = args @block_given = block_given? @@ -1972,15 +1972,15 @@ def initialize(*args) @machine = StateMachine::Machine.new(@klass, :initial => :parked) @object = @klass.new(1, 2, 3) {} end - + def test_should_initialize_state assert_equal 'parked', @object.state end - + def test_should_preserve_arguments assert_equal [1, 2, 3], @object.args end - + def test_should_preserve_block assert @object.block_given end @@ -1997,11 +1997,11 @@ def initialize(state = nil, options = {}) @machine = StateMachine::Machine.new(@klass, :initial => :parked) @object = @klass.new end - + def test_should_initialize_state assert_equal 'parked', @object.state end - + def test_should_allow_custom_options @machine.state :idling @object = @klass.new('idling', :static => :force) @@ -2017,43 +2017,43 @@ def setup @machine = StateMachine::Machine.new(@klass, :initial => :parked) @object = @klass.new end - + def test_should_allow_reading_state assert_equal 'parked', @machine.read(@object, :state) end - + def test_should_allow_reading_custom_attributes assert_nil @machine.read(@object, :event) - + @object.state_event = 'ignite' assert_equal 'ignite', @machine.read(@object, :event) end - + def test_should_allow_reading_custom_instance_variables @klass.class_eval do attr_writer :state_value end - + @object.state_value = 1 assert_raise(NoMethodError) { @machine.read(@object, :value) } assert_equal 1, @machine.read(@object, :value, true) end - + def test_should_allow_writing_state @machine.write(@object, :state, 'idling') assert_equal 'idling', @object.state end - + def test_should_allow_writing_custom_attributes @machine.write(@object, :event, 'ignite') assert_equal 'ignite', @object.state_event end - + def test_should_allow_writing_custom_instance_variables @klass.class_eval do attr_reader :state_value end - + assert_raise(NoMethodError) { @machine.write(@object, :value, 1) } assert_equal 1, @machine.write(@object, :value, 1, true) assert_equal 1, @object.state_value @@ -2066,49 +2066,49 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) @parked, @idling = @machine.state :parked, :idling - + @object = @klass.new end - + def test_should_have_states assert_equal [nil, :parked, :idling], @machine.states.map {|state| state.name} end - + def test_should_allow_state_lookup_by_name assert_equal @parked, @machine.states[:parked] end - + def test_should_allow_state_lookup_by_value assert_equal @parked, @machine.states['parked', :value] end - + def test_should_allow_human_state_name_lookup assert_equal 'parked', @klass.human_state_name(:parked) end - + def test_should_raise_exception_on_invalid_human_state_name_lookup exception = assert_raise(IndexError) {@klass.human_state_name(:invalid)} assert_equal ':invalid is an invalid name', exception.message end - + def test_should_use_stringified_name_for_value assert_equal 'parked', @parked.value end - + def test_should_not_use_custom_matcher assert_nil @parked.matcher end - + def test_should_raise_exception_if_invalid_option_specified exception = assert_raise(ArgumentError) {@machine.state(:first_gear, :invalid => true)} assert_equal 'Invalid key(s): invalid', exception.message end - + def test_should_raise_exception_if_conflicting_type_used_for_name exception = assert_raise(ArgumentError) { @machine.state 'first_gear' } assert_equal '"first_gear" state defined as String, :parked defined as Symbol; all states must be consistent', exception.message end - + def test_should_not_raise_exception_if_conflicting_type_is_nil_for_name assert_nothing_raised { @machine.state nil } end @@ -2119,15 +2119,15 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) @state = @machine.state :parked, :value => 1 - + @object = @klass.new @object.state = 1 end - + def test_should_use_custom_value assert_equal 1, @state.value end - + def test_should_allow_lookup_by_custom_value assert_equal @state, @machine.states[1, :value] end @@ -2139,11 +2139,11 @@ def setup @machine = StateMachine::Machine.new(@klass) @state = @machine.state :parked, :human_name => 'stopped' end - + def test_should_use_custom_human_name assert_equal 'stopped', @state.human_name end - + def test_should_allow_human_state_name_lookup assert_equal 'stopped', @klass.human_state_name(:parked) end @@ -2155,11 +2155,11 @@ def setup @machine = StateMachine::Machine.new(@klass) @machine.state :parked end - + def test_should_not_evaluate_value_during_definition assert_nothing_raised { @machine.state :parked, :value => lambda {raise ArgumentError} } end - + def test_should_not_evaluate_if_not_initial_state @machine.state :parked, :value => lambda {raise ArgumentError} assert_nothing_raised { @klass.new } @@ -2171,11 +2171,11 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) @state = @machine.state :parked, :if => lambda {|value| !value.nil?} - + @object = @klass.new @object.state = 1 end - + def test_should_use_custom_matcher assert_not_nil @state.matcher assert @state.matches?(1) @@ -2188,14 +2188,14 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass, :initial => :parked) @state = @machine.state :parked, :value => lambda {Object.new}, :cache => true - + @object = @klass.new end - + def test_should_use_evaluated_value assert_instance_of Object, @object.state end - + def test_use_same_value_across_multiple_objects assert_equal @object.state, @klass.new.state end @@ -2205,19 +2205,19 @@ class MachineWithStatesWithBehaviorsTest < Test::Unit::TestCase def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) - + @parked, @idling = @machine.state :parked, :idling do def speed 0 end end end - + def test_should_define_behaviors_for_each_state assert_not_nil @parked.context_methods[:speed] assert_not_nil @idling.context_methods[:speed] end - + def test_should_define_different_behaviors_for_each_state assert_not_equal @parked.context_methods[:speed], @idling.context_methods[:speed] end @@ -2230,19 +2230,19 @@ def setup @state = @machine.state :parked @same_state = @machine.state :parked, :value => 1 end - + def test_should_not_create_a_new_state assert_same @state, @same_state end - + def test_should_update_attributes assert_equal 1, @state.value end - + def test_should_no_longer_be_able_to_look_up_state_by_original_value assert_nil @machine.states['parked', :value] end - + def test_should_be_able_to_look_up_state_by_new_value assert_equal @state, @machine.states[1, :value] end @@ -2253,35 +2253,35 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) end - + def test_should_empty_array_for_all_matcher assert_equal [], @machine.state(StateMachine::AllMatcher.instance) end - + def test_should_return_referenced_states_for_blacklist_matcher assert_instance_of StateMachine::State, @machine.state(StateMachine::BlacklistMatcher.new([:parked])) end - + def test_should_not_allow_configurations exception = assert_raise(ArgumentError) { @machine.state(StateMachine::BlacklistMatcher.new([:parked]), :human_name => 'Parked') } assert_equal 'Cannot configure states when using matchers (using {:human_name=>"Parked"})', exception.message end - + def test_should_track_referenced_states @machine.state(StateMachine::BlacklistMatcher.new([:parked])) assert_equal [nil, :parked], @machine.states.map {|state| state.name} end - + def test_should_eval_context_for_matching_states contexts_run = [] @machine.event(StateMachine::BlacklistMatcher.new([:parked])) { contexts_run << self.name } - + @machine.event :parked assert_equal [], contexts_run - + @machine.event :idling assert_equal [:idling], contexts_run - + @machine.event :first_gear, :second_gear assert_equal [:idling, :first_gear, :second_gear], contexts_run end @@ -2293,15 +2293,15 @@ def setup @machine = StateMachine::Machine.new(@klass, :initial => :parked) @parked, @idling = @machine.other_states(:parked, :idling) end - + def test_should_include_other_states_in_known_states assert_equal [@parked, @idling], @machine.states.to_a end - + def test_should_use_default_value assert_equal 'idling', @idling.value end - + def test_should_not_create_matcher assert_nil @idling.matcher end @@ -2312,45 +2312,45 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) end - + def test_should_return_the_created_event assert_instance_of StateMachine::Event, @machine.event(:ignite) end - + def test_should_create_event_with_given_name event = @machine.event(:ignite) {} assert_equal :ignite, event.name end - + def test_should_evaluate_block_within_event_context responded = false @machine.event :ignite do responded = respond_to?(:transition) end - + assert responded end - + def test_should_be_aliased_as_on event = @machine.on(:ignite) {} assert_equal :ignite, event.name end - + def test_should_have_events event = @machine.event(:ignite) assert_equal [event], @machine.events.to_a end - + def test_should_allow_human_state_name_lookup @machine.event(:ignite) assert_equal 'ignite', @klass.human_state_event_name(:ignite) end - + def test_should_raise_exception_on_invalid_human_state_event_name_lookup exception = assert_raise(IndexError) {@klass.human_state_event_name(:invalid)} assert_equal ':invalid is an invalid name', exception.message end - + def test_should_raise_exception_if_conflicting_type_used_for_name @machine.event :park exception = assert_raise(ArgumentError) { @machine.event 'ignite' } @@ -2364,11 +2364,11 @@ def setup @event = @machine.event(:ignite) @same_event = @machine.event(:ignite) end - + def test_should_not_create_new_event assert_same @event, @same_event end - + def test_should_allow_accessing_event_without_block assert_equal @event, @machine.event(:ignite) end @@ -2380,11 +2380,11 @@ def setup @machine = StateMachine::Machine.new(@klass) @event = @machine.event(:ignite, :human_name => 'start') end - + def test_should_use_custom_human_name assert_equal 'start', @event.human_name end - + def test_should_allow_human_state_name_lookup assert_equal 'start', @klass.human_state_event_name(:ignite) end @@ -2395,35 +2395,35 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass) end - + def test_should_empty_array_for_all_matcher assert_equal [], @machine.event(StateMachine::AllMatcher.instance) end - + def test_should_return_referenced_events_for_blacklist_matcher assert_instance_of StateMachine::Event, @machine.event(StateMachine::BlacklistMatcher.new([:park])) end - + def test_should_not_allow_configurations exception = assert_raise(ArgumentError) { @machine.event(StateMachine::BlacklistMatcher.new([:park]), :human_name => 'Park') } assert_equal 'Cannot configure events when using matchers (using {:human_name=>"Park"})', exception.message end - + def test_should_track_referenced_events @machine.event(StateMachine::BlacklistMatcher.new([:park])) assert_equal [:park], @machine.events.map {|event| event.name} end - + def test_should_eval_context_for_matching_events contexts_run = [] @machine.event(StateMachine::BlacklistMatcher.new([:park])) { contexts_run << self.name } - + @machine.event :park assert_equal [], contexts_run - + @machine.event :ignite assert_equal [:ignite], contexts_run - + @machine.event :shift_up, :shift_down assert_equal [:ignite, :shift_up, :shift_down], contexts_run end @@ -2438,28 +2438,28 @@ def setup transition :stalled => :idling end end - + def test_should_have_events assert_equal [@event], @machine.events.to_a end - + def test_should_track_states_defined_in_event_transitions assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name} end - + def test_should_not_duplicate_states_defined_in_multiple_event_transitions @machine.event :park do transition :idling => :parked end - + assert_equal [:parked, :idling, :stalled], @machine.states.map {|state| state.name} end - + def test_should_track_state_from_new_events @machine.event :shift_up do transition :idling => :first_gear end - + assert_equal [:parked, :idling, :stalled, :first_gear], @machine.states.map {|state| state.name} end end @@ -2472,21 +2472,21 @@ def setup transition :first_gear => :parked end end - + def test_should_have_events assert_equal [@park, @shift_down], @machine.events.to_a end - + def test_should_define_transitions_for_each_event [@park, @shift_down].each {|event| assert_equal 1, event.branches.size} end - + def test_should_transition_the_same_for_each_event object = @klass.new object.state = 'first_gear' object.park assert_equal 'parked', object.state - + object = @klass.new object.state = 'first_gear' object.shift_down @@ -2499,40 +2499,40 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass, :initial => :parked) end - + def test_should_require_on_event exception = assert_raise(ArgumentError) { @machine.transition(:parked => :idling) } assert_equal 'Must specify :on event', exception.message end - + def test_should_not_allow_except_on_option exception = assert_raise(ArgumentError) {@machine.transition(:except_on => :ignite, :on => :ignite)} assert_equal 'Invalid key(s): except_on', exception.message end - + def test_should_allow_transitioning_without_a_to_state assert_nothing_raised {@machine.transition(:from => :parked, :on => :ignite)} end - + def test_should_allow_transitioning_without_a_from_state assert_nothing_raised {@machine.transition(:to => :idling, :on => :ignite)} end - + def test_should_allow_except_from_option assert_nothing_raised {@machine.transition(:except_from => :idling, :on => :ignite)} end - + def test_should_allow_except_to_option assert_nothing_raised {@machine.transition(:except_to => :parked, :on => :ignite)} end - + def test_should_allow_implicit_options branch = @machine.transition(:first_gear => :second_gear, :on => :shift_up) assert_instance_of StateMachine::Branch, branch - + state_requirements = branch.state_requirements assert_equal 1, state_requirements.length - + assert_instance_of StateMachine::WhitelistMatcher, state_requirements[0][:from] assert_equal [:first_gear], state_requirements[0][:from].values assert_instance_of StateMachine::WhitelistMatcher, state_requirements[0][:to] @@ -2540,42 +2540,42 @@ def test_should_allow_implicit_options assert_instance_of StateMachine::WhitelistMatcher, branch.event_requirement assert_equal [:shift_up], branch.event_requirement.values end - + def test_should_allow_multiple_implicit_options branch = @machine.transition(:first_gear => :second_gear, :second_gear => :third_gear, :on => :shift_up) - + state_requirements = branch.state_requirements assert_equal 2, state_requirements.length end - + def test_should_allow_verbose_options branch = @machine.transition(:from => :parked, :to => :idling, :on => :ignite) assert_instance_of StateMachine::Branch, branch end - + def test_should_include_all_transition_states_in_machine_states @machine.transition(:parked => :idling, :on => :ignite) - + assert_equal [:parked, :idling], @machine.states.map {|state| state.name} end - + def test_should_include_all_transition_events_in_machine_events @machine.transition(:parked => :idling, :on => :ignite) - + assert_equal [:ignite], @machine.events.map {|event| event.name} end - + def test_should_allow_multiple_events branches = @machine.transition(:parked => :ignite, :on => [:ignite, :shift_up]) - + assert_equal 2, branches.length assert_equal [:ignite, :shift_up], @machine.events.map {|event| event.name} end - + def test_should_not_modify_options options = {:parked => :idling, :on => :ignite} @machine.transition(options) - + assert_equal options, {:parked => :idling, :on => :ignite} end end @@ -2585,34 +2585,34 @@ def setup @klass = Class.new do attr_accessor :callbacks end - + @machine = StateMachine::Machine.new(@klass, :initial => :parked) @event = @machine.event :ignite do transition :parked => :idling end - + @object = @klass.new @object.callbacks = [] end - + def test_should_not_raise_exception_if_implicit_option_specified assert_nothing_raised {@machine.before_transition :invalid => :valid, :do => lambda {}} end - + def test_should_raise_exception_if_method_not_specified exception = assert_raise(ArgumentError) {@machine.before_transition :to => :idling} assert_equal 'Method(s) for callback must be specified', exception.message end - + def test_should_invoke_callbacks_during_transition @machine.before_transition lambda {|object| object.callbacks << 'before'} @machine.after_transition lambda {|object| object.callbacks << 'after'} @machine.around_transition lambda {|object, transition, block| object.callbacks << 'before_around'; block.call; object.callbacks << 'after_around'} - + @event.fire(@object) assert_equal %w(before before_around after_around after), @object.callbacks end - + def test_should_allow_multiple_callbacks @machine.before_transition lambda {|object| object.callbacks << 'before1'}, lambda {|object| object.callbacks << 'before2'} @machine.after_transition lambda {|object| object.callbacks << 'after1'}, lambda {|object| object.callbacks << 'after2'} @@ -2620,11 +2620,11 @@ def test_should_allow_multiple_callbacks lambda {|object, transition, block| object.callbacks << 'before_around1'; block.call; object.callbacks << 'after_around1'}, lambda {|object, transition, block| object.callbacks << 'before_around2'; block.call; object.callbacks << 'after_around2'} ) - + @event.fire(@object) assert_equal %w(before1 before2 before_around1 before_around2 after_around2 after_around1 after1 after2), @object.callbacks end - + def test_should_allow_multiple_callbacks_with_requirements @machine.before_transition lambda {|object| object.callbacks << 'before_parked1'}, lambda {|object| object.callbacks << 'before_parked2'}, :from => :parked @machine.before_transition lambda {|object| object.callbacks << 'before_idling1'}, lambda {|object| object.callbacks << 'before_idling2'}, :from => :idling @@ -2640,84 +2640,84 @@ def test_should_allow_multiple_callbacks_with_requirements lambda {|object, transition, block| object.callbacks << 'before_around_idling2'; block.call; object.callbacks << 'after_around_idling2'}, :from => :idling ) - + @event.fire(@object) assert_equal %w(before_parked1 before_parked2 before_around_parked1 before_around_parked2 after_around_parked2 after_around_parked1 after_parked1 after_parked2), @object.callbacks end - + def test_should_support_from_requirement @machine.before_transition :from => :parked, :do => lambda {|object| object.callbacks << :parked} @machine.before_transition :from => :idling, :do => lambda {|object| object.callbacks << :idling} - + @event.fire(@object) assert_equal [:parked], @object.callbacks end - + def test_should_support_except_from_requirement @machine.before_transition :except_from => :parked, :do => lambda {|object| object.callbacks << :parked} @machine.before_transition :except_from => :idling, :do => lambda {|object| object.callbacks << :idling} - + @event.fire(@object) assert_equal [:idling], @object.callbacks end - + def test_should_support_to_requirement @machine.before_transition :to => :parked, :do => lambda {|object| object.callbacks << :parked} @machine.before_transition :to => :idling, :do => lambda {|object| object.callbacks << :idling} - + @event.fire(@object) assert_equal [:idling], @object.callbacks end - + def test_should_support_except_to_requirement @machine.before_transition :except_to => :parked, :do => lambda {|object| object.callbacks << :parked} @machine.before_transition :except_to => :idling, :do => lambda {|object| object.callbacks << :idling} - + @event.fire(@object) assert_equal [:parked], @object.callbacks end - + def test_should_support_on_requirement @machine.before_transition :on => :park, :do => lambda {|object| object.callbacks << :park} @machine.before_transition :on => :ignite, :do => lambda {|object| object.callbacks << :ignite} - + @event.fire(@object) assert_equal [:ignite], @object.callbacks end - + def test_should_support_except_on_requirement @machine.before_transition :except_on => :park, :do => lambda {|object| object.callbacks << :park} @machine.before_transition :except_on => :ignite, :do => lambda {|object| object.callbacks << :ignite} - + @event.fire(@object) assert_equal [:park], @object.callbacks end - + def test_should_support_implicit_requirement @machine.before_transition :parked => :idling, :do => lambda {|object| object.callbacks << :parked} @machine.before_transition :idling => :parked, :do => lambda {|object| object.callbacks << :idling} - + @event.fire(@object) assert_equal [:parked], @object.callbacks end - + def test_should_track_states_defined_in_transition_callbacks @machine.before_transition :parked => :idling, :do => lambda {} @machine.after_transition :first_gear => :second_gear, :do => lambda {} @machine.around_transition :third_gear => :fourth_gear, :do => lambda {} - + assert_equal [:parked, :idling, :first_gear, :second_gear, :third_gear, :fourth_gear], @machine.states.map {|state| state.name} end - + def test_should_not_duplicate_states_defined_in_multiple_event_transitions @machine.before_transition :parked => :idling, :do => lambda {} @machine.after_transition :first_gear => :second_gear, :do => lambda {} @machine.after_transition :parked => :idling, :do => lambda {} @machine.around_transition :parked => :idling, :do => lambda {} - + assert_equal [:parked, :idling, :first_gear, :second_gear], @machine.states.map {|state| state.name} end - + def test_should_define_predicates_for_each_state [:parked?, :idling?].each {|predicate| assert @object.respond_to?(predicate)} end @@ -2728,42 +2728,42 @@ def setup @klass = Class.new do attr_accessor :callbacks end - + @machine = StateMachine::Machine.new(@klass, :initial => :parked) @event = @machine.event :ignite - + @object = @klass.new @object.callbacks = [] end - + def test_should_raise_exception_if_implicit_option_specified exception = assert_raise(ArgumentError) {@machine.after_failure :invalid => :valid, :do => lambda {}} assert_equal 'Invalid key(s): invalid', exception.message end - + def test_should_raise_exception_if_method_not_specified exception = assert_raise(ArgumentError) {@machine.after_failure :on => :ignite} assert_equal 'Method(s) for callback must be specified', exception.message end - + def test_should_invoke_callbacks_during_failed_transition @machine.after_failure lambda {|object| object.callbacks << 'failure'} - + @event.fire(@object) assert_equal %w(failure), @object.callbacks end - + def test_should_allow_multiple_callbacks @machine.after_failure lambda {|object| object.callbacks << 'failure1'}, lambda {|object| object.callbacks << 'failure2'} - + @event.fire(@object) assert_equal %w(failure1 failure2), @object.callbacks end - + def test_should_allow_multiple_callbacks_with_requirements @machine.after_failure lambda {|object| object.callbacks << 'failure_ignite1'}, lambda {|object| object.callbacks << 'failure_ignite2'}, :on => :ignite @machine.after_failure lambda {|object| object.callbacks << 'failure_park1'}, lambda {|object| object.callbacks << 'failure_park2'}, :on => :park - + @event.fire(@object) assert_equal %w(failure_ignite1 failure_ignite2), @object.callbacks end @@ -2779,15 +2779,15 @@ def setup @machine.event :shift_up do transition :first_gear => :second_gear end - + @object = @klass.new @object.state = 'parked' end - + def test_should_have_paths assert_equal [[StateMachine::Transition.new(@object, @machine, :ignite, :parked, :idling)]], @machine.paths_for(@object) end - + def test_should_allow_requirement_configuration assert_equal [[StateMachine::Transition.new(@object, @machine, :shift_up, :first_gear, :second_gear)]], @machine.paths_for(@object, :from => :first_gear) end @@ -2799,11 +2799,11 @@ def setup @machine = StateMachine::Machine.new(@klass) @subclass = Class.new(@klass) end - + def test_should_have_a_different_collection_of_state_machines assert_not_same @klass.state_machines, @subclass.state_machines end - + def test_should_have_the_same_attribute_associated_state_machines assert_equal @klass.state_machines, @subclass.state_machines end @@ -2816,12 +2816,12 @@ def setup @second_machine = StateMachine::Machine.new(@klass, :status, :initial => :idling) @object = @klass.new end - + def test_should_track_each_state_machine expected = {:state => @machine, :status => @second_machine} assert_equal expected, @klass.state_machines end - + def test_should_initialize_state_for_both_machines assert_equal 'parked', @object.state assert_equal 'idling', @object.status @@ -2835,63 +2835,63 @@ def setup @second_machine = StateMachine::Machine.new(@klass, :public_state, :initial => :idling, :attribute => :state) @object = @klass.new end - + def test_should_track_each_state_machine expected = {:state => @machine, :public_state => @second_machine} assert_equal expected, @klass.state_machines end - + def test_should_write_to_state_only_once @klass.class_eval do attr_reader :write_count - + def state=(value) @write_count ||= 0 @write_count += 1 end end object = @klass.new - + assert_equal 1, object.write_count end - + def test_should_initialize_based_on_first_machine assert_equal 'parked', @object.state end - + def test_should_not_allow_second_machine_to_initialize_state @object.state = nil @second_machine.initialize_state(@object) assert_nil @object.state end - + def test_should_allow_transitions_on_both_machines @machine.event :ignite do transition :parked => :idling end - + @second_machine.event :park do transition :idling => :parked end - + @object.ignite assert_equal 'idling', @object.state - + @object.park assert_equal 'parked', @object.state end - + def test_should_copy_new_states_to_sibling_machines @first_gear = @machine.state :first_gear assert_equal @first_gear, @second_machine.state(:first_gear) - + @second_gear = @second_machine.state :second_gear assert_equal @second_gear, @machine.state(:second_gear) end - + def test_should_copy_all_existing_states_to_new_machines third_machine = StateMachine::Machine.new(@klass, :protected_state, :attribute => :state) - + assert_equal @machine.state(:parked), third_machine.state(:parked) assert_equal @machine.state(:idling), third_machine.state(:idling) end @@ -2902,26 +2902,26 @@ def setup @klass = Class.new @machine = StateMachine::Machine.new(@klass, :initial => :parked) @second_machine = StateMachine::Machine.new(@klass, :public_state, :initial => :idling, :attribute => :state) - + @subclass = Class.new(@klass) @object = @subclass.new end - + def test_should_not_copy_sibling_machines_to_subclass_after_initialization @subclass.state_machine(:state) {} assert_equal @klass.state_machine(:public_state), @subclass.state_machine(:public_state) end - + def test_should_copy_sibling_machines_to_subclass_after_new_state subclass_machine = @subclass.state_machine(:state) {} subclass_machine.state :first_gear assert_not_equal @klass.state_machine(:public_state), @subclass.state_machine(:public_state) end - + def test_should_copy_new_states_to_sibling_machines subclass_machine = @subclass.state_machine(:state) {} @first_gear = subclass_machine.state :first_gear - + second_subclass_machine = @subclass.state_machine(:public_state) assert_equal @first_gear, second_subclass_machine.state(:first_gear) end @@ -2934,38 +2934,38 @@ def setup event :enable do transition :off => :active end - + event :disable do transition :active => :off end end @object = @klass.new end - + def test_should_namespace_state_predicates [:alarm_active?, :alarm_off?].each do |name| assert @object.respond_to?(name) end end - + def test_should_namespace_event_checks [:can_enable_alarm?, :can_disable_alarm?].each do |name| assert @object.respond_to?(name) end end - + def test_should_namespace_event_transition_readers [:enable_alarm_transition, :disable_alarm_transition].each do |name| assert @object.respond_to?(name) end end - + def test_should_namespace_events [:enable_alarm, :disable_alarm].each do |name| assert @object.respond_to?(name) end end - + def test_should_namespace_bang_events [:enable_alarm!, :disable_alarm!].each do |name| assert @object.respond_to?(name) @@ -2975,20 +2975,20 @@ def test_should_namespace_bang_events class MachineWithCustomAttributeTest < Test::Unit::TestCase def setup - StateMachine::Integrations.const_set('Custom', Module.new do + StateMachine::Integrations.const_set('Custom', Module.new do include StateMachine::Integrations::Base - + @defaults = {:action => :save, :use_transactions => false} - + def create_with_scope(name) lambda {} end - + def create_without_scope(name) lambda {} end end) - + @klass = Class.new @machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id, :initial => :active, :integration => :custom) do event :ignite do @@ -2997,72 +2997,72 @@ def create_without_scope(name) end @object = @klass.new end - + def test_should_define_a_reader_attribute_for_the_attribute assert @object.respond_to?(:state_id) end - + def test_should_define_a_writer_attribute_for_the_attribute assert @object.respond_to?(:state_id=) end - + def test_should_define_a_predicate_for_the_attribute assert @object.respond_to?(:state?) end - + def test_should_define_a_name_reader_for_the_attribute assert @object.respond_to?(:state_name) end - + def test_should_define_a_human_name_reader_for_the_attribute assert @object.respond_to?(:state_name) end - + def test_should_define_an_event_reader_for_the_attribute assert @object.respond_to?(:state_events) end - + def test_should_define_a_transition_reader_for_the_attribute assert @object.respond_to?(:state_transitions) end - + def test_should_define_a_path_reader_for_the_attribute assert @object.respond_to?(:state_paths) end - + def test_should_define_an_event_runner_for_the_attribute assert @object.respond_to?(:fire_state_event) end - + def test_should_define_a_human_attribute_name_reader assert @klass.respond_to?(:human_state_name) end - + def test_should_define_a_human_event_name_reader assert @klass.respond_to?(:human_state_event_name) end - + def test_should_define_singular_with_scope assert @klass.respond_to?(:with_state) end - + def test_should_define_singular_without_scope assert @klass.respond_to?(:without_state) end - + def test_should_define_plural_with_scope assert @klass.respond_to?(:with_states) end - + def test_should_define_plural_without_scope assert @klass.respond_to?(:without_states) end - + def test_should_define_state_machines_reader expected = {:state => @machine} assert_equal expected, @klass.state_machines end - + def teardown StateMachine::Integrations.send(:remove_const, 'Custom') end @@ -3073,20 +3073,20 @@ def setup @klass = Class.new @machine = StateMachine::Machine.find_or_create(@klass) end - + def test_should_accept_a_block called = false StateMachine::Machine.find_or_create(Class.new) do called = respond_to?(:event) end - + assert called end - + def test_should_create_a_new_machine assert_not_nil @machine end - + def test_should_use_default_state assert_equal :state, @machine.attribute end @@ -3098,16 +3098,16 @@ def setup @existing_machine = StateMachine::Machine.new(@klass) @machine = StateMachine::Machine.find_or_create(@klass) end - + def test_should_accept_a_block called = false StateMachine::Machine.find_or_create(@klass) do called = respond_to?(:event) end - + assert called end - + def test_should_not_create_a_new_machine assert_same @machine, @existing_machine end @@ -3117,76 +3117,76 @@ class MachineFinderWithExistingMachineOnSuperclassTest < Test::Unit::TestCase def setup integration = Module.new do include StateMachine::Integrations::Base - + def self.matches?(klass) false end end StateMachine::Integrations.const_set('Custom', integration) - + @base_class = Class.new @base_machine = StateMachine::Machine.new(@base_class, :status, :action => :save, :integration => :custom) @base_machine.event(:ignite) {} @base_machine.before_transition(lambda {}) @base_machine.after_transition(lambda {}) @base_machine.around_transition(lambda {}) - + @klass = Class.new(@base_class) @machine = StateMachine::Machine.find_or_create(@klass, :status) {} end - + def test_should_accept_a_block called = false StateMachine::Machine.find_or_create(Class.new(@base_class)) do called = respond_to?(:event) end - + assert called end - + def test_should_not_create_a_new_machine_if_no_block_or_options machine = StateMachine::Machine.find_or_create(Class.new(@base_class), :status) - + assert_same machine, @base_machine end - + def test_should_create_a_new_machine_if_given_options machine = StateMachine::Machine.find_or_create(@klass, :status, :initial => :parked) - + assert_not_nil machine assert_not_same machine, @base_machine end - + def test_should_create_a_new_machine_if_given_block assert_not_nil @machine assert_not_same @machine, @base_machine end - + def test_should_copy_the_base_attribute assert_equal :status, @machine.attribute end - + def test_should_copy_the_base_configuration assert_equal :save, @machine.action end - + def test_should_copy_events # Can't assert equal arrays since their machines change assert_equal 1, @machine.events.length end - + def test_should_copy_before_callbacks assert_equal @base_machine.callbacks[:before], @machine.callbacks[:before] end - + def test_should_copy_after_transitions assert_equal @base_machine.callbacks[:after], @machine.callbacks[:after] end - + def test_should_use_the_same_integration assert((class << @machine; ancestors; end).include?(StateMachine::Integrations::Custom)) end - + def teardown StateMachine::Integrations.send(:remove_const, 'Custom') end @@ -3198,11 +3198,11 @@ def setup @machine = StateMachine::Machine.find_or_create(@klass, :status, :initial => :parked) @object = @klass.new end - + def test_should_use_custom_attribute assert_equal :status, @machine.attribute end - + def test_should_set_custom_initial_state assert_equal :parked, @machine.initial_state(@object).name end @@ -3211,7 +3211,7 @@ def test_should_set_custom_initial_state begin # Load library require 'graphviz' - + class MachineDrawingTest < Test::Unit::TestCase def setup @klass = Class.new do @@ -3222,65 +3222,65 @@ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end transition :parked => :idling end end - + def test_should_raise_exception_if_invalid_option_specified assert_raise(ArgumentError) {@machine.draw(:invalid => true)} end - + def test_should_save_file_with_class_name_by_default @machine.draw - assert File.exists?("./#{@klass.name}_state.png") + assert File.exist?("./#{@klass.name}_state.png") end - + def test_should_allow_base_name_to_be_customized name = "machine_#{rand(1000000)}" @machine.draw(:name => name) @path = "./#{name}.png" - assert File.exists?(@path) + assert File.exist?(@path) end - + def test_should_allow_format_to_be_customized @machine.draw(:format => 'jpg') @path = "./#{@klass.name}_state.jpg" - assert File.exists?(@path) + assert File.exist?(@path) end - + def test_should_allow_path_to_be_customized @machine.draw(:path => "#{File.dirname(__FILE__)}/") @path = "#{File.dirname(__FILE__)}/#{@klass.name}_state.png" - assert File.exists?(@path) + assert File.exist?(@path) end - + def test_should_allow_orientation_to_be_landscape graph = @machine.draw(:orientation => 'landscape') assert_equal 'LR', graph['rankdir'].to_s.gsub('"', '') end - + def test_should_allow_orientation_to_be_portrait graph = @machine.draw(:orientation => 'portrait') assert_equal 'TB', graph['rankdir'].to_s.gsub('"', '') end - + if Constants::RGV_VERSION != '0.9.0' def test_should_allow_human_names_to_be_displayed @machine.event :ignite, :human_name => 'Ignite' @machine.state :parked, :human_name => 'Parked' @machine.state :idling, :human_name => 'Idling' graph = @machine.draw(:human_names => true) - + parked_node = graph.get_node('parked') assert_equal 'Parked', parked_node['label'].to_s.gsub('"', '') - + idling_node = graph.get_node('idling') assert_equal 'Idling', idling_node['label'].to_s.gsub('"', '') end end - + def teardown FileUtils.rm Dir[@path || "./#{@klass.name}_state.png"] end end - + class MachineDrawingWithIntegerStatesTest < Test::Unit::TestCase def setup @klass = Class.new do @@ -3294,24 +3294,24 @@ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end @machine.state :idling, :value => 2 @graph = @machine.draw end - + def test_should_draw_all_states assert_equal 3, @graph.node_count end - + def test_should_draw_all_events assert_equal 2, @graph.edge_count end - + def test_should_draw_machine assert File.exist?("./#{@klass.name}_state_id.png") end - + def teardown FileUtils.rm Dir["./#{@klass.name}_state_id.png"] end end - + class MachineDrawingWithNilStatesTest < Test::Unit::TestCase def setup @klass = Class.new do @@ -3324,24 +3324,24 @@ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end @machine.state :parked, :value => nil @graph = @machine.draw end - + def test_should_draw_all_states assert_equal 3, @graph.node_count end - + def test_should_draw_all_events assert_equal 2, @graph.edge_count end - + def test_should_draw_machine assert File.exist?("./#{@klass.name}_state.png") end - + def teardown FileUtils.rm Dir["./#{@klass.name}_state.png"] end end - + class MachineDrawingWithDynamicStatesTest < Test::Unit::TestCase def setup @klass = Class.new do @@ -3354,24 +3354,24 @@ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end @machine.state :idling, :value => lambda {Time.now} @graph = @machine.draw end - + def test_should_draw_all_states assert_equal 3, @graph.node_count end - + def test_should_draw_all_events assert_equal 2, @graph.edge_count end - + def test_should_draw_machine assert File.exist?("./#{@klass.name}_state.png") end - + def teardown FileUtils.rm Dir["./#{@klass.name}_state.png"] end end - + class MachineClassDrawingTest < Test::Unit::TestCase def setup @klass = Class.new do @@ -3382,22 +3382,22 @@ def self.name; @name ||= "Vehicle_#{rand(1000000)}"; end transition :parked => :idling end end - + def test_should_raise_exception_if_no_class_names_specified exception = assert_raise(ArgumentError) {StateMachine::Machine.draw(nil)} assert_equal 'At least one class must be specified', exception.message end - + def test_should_load_files StateMachine::Machine.draw('Switch', :file => File.expand_path("#{File.dirname(__FILE__)}/../files/switch.rb")) assert defined?(::Switch) end - + def test_should_allow_path_and_format_to_be_customized StateMachine::Machine.draw('Switch', :file => File.expand_path("#{File.dirname(__FILE__)}/../files/switch.rb"), :path => "#{File.dirname(__FILE__)}/", :format => 'jpg') assert File.exist?("#{File.dirname(__FILE__)}/#{Switch.name}_state.jpg") end - + def teardown FileUtils.rm Dir["{.,#{File.dirname(__FILE__)}}/#{Switch.name}_state.{jpg,png}"] end From 9a37a5bd5ed5533b65fbe3d396a436d7f35aa756 Mon Sep 17 00:00:00 2001 From: OlegKrakenTeam Date: Mon, 4 Mar 2024 05:18:05 +0300 Subject: [PATCH 3/3] Ruby 3.2 support --- CHANGELOG.md | 4 +++ Dockerfile | 1 + Gemfile | 1 + lib/state_machine/version.rb | 2 +- state_machine.gemspec | 8 +++--- test/unit/eval_helpers_test.rb | 52 ++++++++++++++++++---------------- 6 files changed, 38 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a224a3..e3349791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ * Fix target state being indeterminate for transitions that use blacklists * Allow super to be called within state-driven behaviors +## 2.0.0 - 2025-03-04 + +* Added Ruby 3.2 support for legacy projects, a very few changes such as `File.exists` and `Object#taint` fixes + ## 1.2.0 / 2013-03-30 * Allow multiple whitelisted / blacklisted :to states when definining transitions diff --git a/Dockerfile b/Dockerfile index bd366e90..3b444769 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# This file is used to compare changes with "original" version of this gem. FROM ruby:1.9.3 RUN mkdir /app diff --git a/Gemfile b/Gemfile index e8e34715..0c2f279d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,4 @@ source "http://www.rubygems.org" +gem 'test-unit' gemspec diff --git a/lib/state_machine/version.rb b/lib/state_machine/version.rb index a141e7ec..9ffe6859 100644 --- a/lib/state_machine/version.rb +++ b/lib/state_machine/version.rb @@ -1,3 +1,3 @@ module StateMachine - VERSION = '1.2.0' + VERSION = '2.0.0' end diff --git a/state_machine.gemspec b/state_machine.gemspec index dbce2b39..e34061ab 100644 --- a/state_machine.gemspec +++ b/state_machine.gemspec @@ -16,8 +16,8 @@ Gem::Specification.new do |s| s.rdoc_options = %w(--line-numbers --inline-source --title state_machine --main README.md) s.extra_rdoc_files = %w(README.md CHANGELOG.md LICENSE) - s.add_development_dependency("rake", "<= 10.5.0") - s.add_development_dependency("simplecov", "0.11.1") - s.add_development_dependency("docile", "1.1.5") - s.add_development_dependency("appraisal", "~> 0.5.0") + s.add_development_dependency("rake", "~> 13.1.0") + s.add_development_dependency("simplecov") + s.add_development_dependency("docile", "~> 1.4.0") + s.add_development_dependency("appraisal", "~> 2.5.0") end diff --git a/test/unit/eval_helpers_test.rb b/test/unit/eval_helpers_test.rb index a86391bd..9262bc71 100644 --- a/test/unit/eval_helpers_test.rb +++ b/test/unit/eval_helpers_test.rb @@ -2,7 +2,7 @@ class EvalHelpersBaseTest < Test::Unit::TestCase include StateMachine::EvalHelpers - + def default_test end end @@ -11,7 +11,7 @@ class EvalHelpersTest < EvalHelpersBaseTest def setup @object = Object.new end - + def test_should_raise_exception_if_method_is_not_symbol_string_or_proc exception = assert_raise(ArgumentError) { evaluate_method(@object, 1) } assert_match(/Methods must/, exception.message) @@ -26,7 +26,7 @@ def callback end end end - + def test_should_call_method_on_object_with_no_arguments assert_equal true, evaluate_method(@object, :callback, 1, 2, 3) end @@ -41,7 +41,7 @@ def callback end end end - + def test_should_call_method_on_object_with_no_arguments assert_equal true, evaluate_method(@object, :callback, 1, 2, 3) end @@ -56,7 +56,7 @@ def callback end end end - + def test_should_call_method_on_object_with_no_arguments assert_equal true, evaluate_method(@object, :callback, 1, 2, 3) end @@ -70,7 +70,7 @@ def callback(*args) end end end - + def test_should_call_method_with_all_arguments assert_equal [1, 2, 3], evaluate_method(@object, :callback, 1, 2, 3) end @@ -84,7 +84,7 @@ def callback end end end - + def test_should_call_method_on_object_with_block assert_equal true, evaluate_method(@object, :callback) { true } end @@ -98,7 +98,7 @@ def callback(*args) end end end - + def test_should_call_method_on_object_with_all_arguments_and_block assert_equal [1, 2, 3, true], evaluate_method(@object, :callback, 1, 2, 3) { true } end @@ -110,11 +110,13 @@ class << (@object = Object.new) def callback true end - - taint + + # taint + # https://blog.saeloun.com/2020/02/18/ruby-2-7-access-and-setting-of-safe-warned-will-become-global-variable/#ruby-27 + self end end - + def test_should_not_raise_security_error assert_nothing_raised { evaluate_method(@object, :callback, 1, 2, 3) } end @@ -126,13 +128,13 @@ class << (@object = Object.new) def method_missing(symbol, *args) send("method_missing_#{symbol}", *args) end - + def method_missing_callback(*args) args end end end - + def test_should_call_dynamic_method_with_all_arguments assert_equal [1, 2, 3], evaluate_method(@object, :callback, 1, 2, 3) end @@ -142,16 +144,16 @@ class EvalHelpersStringTest < EvalHelpersBaseTest def setup @object = Object.new end - + def test_should_evaluate_string assert_equal 1, evaluate_method(@object, '1') end - + def test_should_evaluate_string_within_object_context @object.instance_variable_set('@value', 1) assert_equal 1, evaluate_method(@object, '@value') end - + def test_should_ignore_additional_arguments assert_equal 1, evaluate_method(@object, '1', 2, 3, 4) end @@ -161,7 +163,7 @@ class EvalHelpersStringWithBlockTest < EvalHelpersBaseTest def setup @object = Object.new end - + def test_should_call_method_on_object_with_block assert_equal 1, evaluate_method(@object, 'yield') { 1 } end @@ -172,7 +174,7 @@ def setup @object = Object.new @proc = lambda {|obj| obj} end - + def test_should_call_proc_with_object_as_argument assert_equal @object, evaluate_method(@object, @proc, 1, 2, 3) end @@ -188,7 +190,7 @@ def arity end end end - + def test_should_call_proc_with_no_arguments assert_equal [], evaluate_method(@object, @proc, 1, 2, 3) end @@ -199,7 +201,7 @@ def setup @object = Object.new @proc = lambda {|*args| args} end - + def test_should_call_method_with_all_arguments assert_equal [@object, 1, 2, 3], evaluate_method(@object, @proc, 1, 2, 3) end @@ -210,7 +212,7 @@ def setup @object = Object.new @proc = lambda {|obj, block| block.call} end - + def test_should_call_method_on_object_with_block assert_equal true, evaluate_method(@object, @proc, 1, 2, 3) { true } end @@ -226,7 +228,7 @@ def arity end end end - + def test_should_call_proc_without_arguments block = lambda { true } assert_equal [], evaluate_method(@object, @proc, 1, 2, 3, &block) @@ -238,7 +240,7 @@ def setup @object = Object.new @proc = lambda {|block| [block]} end - + def test_should_call_proc_with_block_only block = lambda { true } assert_equal [block], evaluate_method(@object, @proc, 1, 2, 3, &block) @@ -250,7 +252,7 @@ def setup @object = Object.new @proc = lambda {|*args| args} end - + def test_should_call_method_on_object_with_all_arguments_and_block block = lambda { true } assert_equal [@object, 1, 2, 3, block], evaluate_method(@object, @proc, 1, 2, 3, &block) @@ -262,7 +264,7 @@ def setup @object = Object.new @proc = lambda {|object, arg1, arg2, arg3, block| [object, arg1, arg2, arg3, block]} end - + def test_should_call_method_on_object_with_all_arguments_and_block block = lambda { true } assert_equal [@object, 1, 2, 3, block], evaluate_method(@object, @proc, 1, 2, 3, &block)