diff --git a/NEWS.md b/NEWS.md index b8b9f96a..cf554860 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,8 @@ * Association matchers now test that the model being referred to (either implicitly or explicitly, using `:class_name`) actually exists. +* Add ability to test `:autosave` option on associations. + # v 2.5.0 * Fix Rails/Test::Unit integration to ensure that the test case classes we are diff --git a/lib/shoulda/matchers/active_record/association_matcher.rb b/lib/shoulda/matchers/active_record/association_matcher.rb index 94ad6963..39235cae 100644 --- a/lib/shoulda/matchers/active_record/association_matcher.rb +++ b/lib/shoulda/matchers/active_record/association_matcher.rb @@ -28,6 +28,8 @@ module Shoulda # :nodoc: # * dependent - tests that the association makes use of the # dependent option. # * :class_name - tests that the association resoves to class_name. + # * :autosave - tests that the association makes use of the + # autosave option. # * :validate - tests that the association makes use of the validate # option. # @@ -48,6 +50,8 @@ module Shoulda # :nodoc: # * :dependent - tests that the association makes use of the # dependent option. # * :class_name - tests that the association resolves to class_name. + # * :autosave - tests that the association makes use of the + # autosave option. # * :validate - tests that the association makes use of the validate # option. # @@ -120,6 +124,11 @@ module Shoulda # :nodoc: self end + def autosave(autosave) + @options[:autosave] = autosave + self + end + def class_name(class_name) @options[:class_name] = class_name self @@ -163,6 +172,7 @@ module Shoulda # :nodoc: class_exists? && foreign_key_exists? && class_name_correct? && + autosave_correct? && conditions_correct? && join_table_exists? && validate_correct? && @@ -266,6 +276,19 @@ module Shoulda # :nodoc: false end + def autosave_correct? + if options.key?(:autosave) + if option_verifier.correct_for_boolean?(:autosave, options[:autosave]) + true + else + @missing = "#{name} should have autosave set to #{options[:autosave]}" + false + end + else + true + end + end + def conditions_correct? if options.key?(:conditions) if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions]) diff --git a/spec/shoulda/matchers/active_record/association_matcher_spec.rb b/spec/shoulda/matchers/active_record/association_matcher_spec.rb index bc89187c..253b9a19 100644 --- a/spec/shoulda/matchers/active_record/association_matcher_spec.rb +++ b/spec/shoulda/matchers/active_record/association_matcher_spec.rb @@ -116,6 +116,26 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do }.to fail_with_message(message) end + it 'accepts an association with a matching :autosave option' do + define_model :parent, :adopter => :boolean + define_model :child, :parent_id => :integer do + belongs_to :parent, :autosave => true + end + expect(Child.new).to belong_to(:parent).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :parent, :adopter => :boolean + define_model :child, :parent_id => :integer do + belongs_to :parent, :autosave => false + end + + message = 'Expected Child to have a belongs_to association called parent (parent should have autosave set to true)' + expect { + expect(Child.new).to belong_to(:parent).autosave(true) + }.to fail_with_message(message) + end + context 'an association with a :validate option' do [false, true].each do |validate_value| context "when the model has validate: #{validate_value}" do @@ -380,6 +400,26 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do }.to fail_with_message(message) end + it 'accepts an association with a matching :autosave option' do + define_model :child, :parent_id => :integer + define_model :parent do + has_many :children, :autosave => true + end + expect(Parent.new).to have_many(:children).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :child, :parent_id => :integer + define_model :parent do + has_many :children, :autosave => false + end + + message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)' + expect { + expect(Parent.new).to have_many(:children).autosave(true) + }.to fail_with_message(message) + end + context 'validate' do it 'accepts when the :validate option matches' do expect(having_many_children(validate: false)).to have_many(:children).validate(false) @@ -530,6 +570,26 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do expect(having_one_detail).to have_one(:detail).class_name('Detail') end + it 'accepts an association with a matching :autosave option' do + define_model :detail, :person_id => :integer, :disabled => :boolean + define_model :person do + has_one :detail, :autosave => true + end + expect(Person.new).to have_one(:detail).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :detail, :person_id => :integer, :disabled => :boolean + define_model :person do + has_one :detail, :autosave => false + end + + message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)' + expect { + expect(Person.new).to have_one(:detail).autosave(true) + }.to fail_with_message(message) + end + it 'accepts an association with a valid :class_name option' do define_model :person_detail, person_id: :integer define_model :person do @@ -712,6 +772,30 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do }.to fail_with_message(message) end + it 'accepts an association with a matching :autosave option' do + define_model :relatives, :adopted => :boolean + define_model :person do + has_and_belongs_to_many :relatives, :autosave => true + end + define_model :people_relative, :person_id => :integer, + :relative_id => :integer + expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :relatives, :adopted => :boolean + define_model :person do + has_and_belongs_to_many :relatives + end + define_model :people_relative, :person_id => :integer, + :relative_id => :integer + + message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)' + expect { + expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true) + }.to fail_with_message(message) + end + context 'validate' do it 'accepts when the :validate option matches' do expect(having_and_belonging_to_many_relatives(validate: false)).