From 5ad04a89e239df85773dc32ceb5b24b631a6d8d4 Mon Sep 17 00:00:00 2001 From: Panupan Sriautharawong Date: Tue, 9 Apr 2013 22:46:32 -0400 Subject: [PATCH] Add touch option to belongs_to matcher. * Also fixes validate failing when specified on model but not on matcher. --- NEWS.md | 1 + .../active_record/association_matcher.rb | 33 ++++++++++-- .../active_record/association_matcher_spec.rb | 52 ++++++++++++++++++- 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index 97ff1337..8f6f827e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # HEAD +* Add `:touch` option to the association matcher. * Ruby 2.0.0 is now officially supported. * Fixes the issue where using %{attribute} or %{model} in I18n translations raised exceptions diff --git a/lib/shoulda/matchers/active_record/association_matcher.rb b/lib/shoulda/matchers/active_record/association_matcher.rb index 7ff0bcf5..e372ce09 100644 --- a/lib/shoulda/matchers/active_record/association_matcher.rb +++ b/lib/shoulda/matchers/active_record/association_matcher.rb @@ -7,6 +7,8 @@ module Shoulda # :nodoc: # * :class_name - tests that the association resolves to class_name. # * :validate - tests that the association makes use of the validate # option. + # * :touch - tests that the association makes use of the touch + # option. # # Example: # it { should belong_to(:parent) } @@ -107,7 +109,12 @@ module Shoulda # :nodoc: end def validate(validate = true) - @validate = validate + @options[:validate] = validate + self + end + + def touch(touch = true) + @options[:touch] = touch self end @@ -122,7 +129,8 @@ module Shoulda # :nodoc: order_correct? && conditions_correct? && join_table_exists? && - validate_correct? + validate_correct? && + touch_correct? end def failure_message_for_should @@ -258,14 +266,31 @@ module Shoulda # :nodoc: end def validate_correct? - if !@validate && !reflection.options[:validate] || @validate == reflection.options[:validate] + if option_correct?(:validate) true else - @missing = "#{@name} should have :validate => #{@validate}" + @missing = "#{@name} should have :validate => #{@options[:validate]}" false end end + def touch_correct? + if option_correct?(:touch) + true + else + @missing = "#{@name} should have :touch => #{@options[:touch]}" + false + end + end + + def option_correct?(key) + !@options.key?(key) || reflection_set_properly_for?(key) + end + + def reflection_set_properly_for?(key) + @options[key] == !!reflection.options[key] + end + def class_has_foreign_key?(klass) if @options.key?(:foreign_key) reflection.options[:foreign_key] == @options[:foreign_key] diff --git a/spec/shoulda/matchers/active_record/association_matcher_spec.rb b/spec/shoulda/matchers/active_record/association_matcher_spec.rb index 2a84896e..8ea9f056 100644 --- a/spec/shoulda/matchers/active_record/association_matcher_spec.rb +++ b/spec/shoulda/matchers/active_record/association_matcher_spec.rb @@ -81,9 +81,9 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do belonging_to_parent.should_not belong_to(:parent).class_name('TreeChild') end - context 'validate' do + context 'an association with a :validate option' do [false, true].each do |validate_value| - context 'when the model has :validate => #{validate_value}' do + context "when the model has :validate => #{validate_value}" do it 'accepts a matching validate option' do belonging_to_parent(:validate => validate_value). should belong_to(:parent).validate(validate_value) @@ -103,6 +103,10 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do should_not belong_to(:parent).validate end end + + it 'will not break matcher when validate option is unspecified' do + belonging_to_parent(:validate => validate_value).should belong_to(:parent) + end end end end @@ -121,6 +125,50 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do end end + context 'an association with a :touch option' do + [false, true].each do |touch_value| + context "when the model has :touch => #{touch_value}" do + it 'accepts a matching touch option' do + belonging_to_parent(:touch => touch_value). + should belong_to(:parent).touch(touch_value) + end + + it 'rejects a non-matching touch option' do + belonging_to_parent(:touch => touch_value). + should_not belong_to(:parent).touch(!touch_value) + end + + it 'defaults to touch(true)' do + if touch_value + belonging_to_parent(:touch => touch_value). + should belong_to(:parent).touch + else + belonging_to_parent(:touch => touch_value). + should_not belong_to(:parent).touch + end + end + + it 'will not break matcher when touch option is unspecified' do + belonging_to_parent(:touch => touch_value).should belong_to(:parent) + end + end + end + end + + context 'an association without a :touch option' do + it 'accepts touch(false)' do + belonging_to_parent.should belong_to(:parent).touch(false) + end + + it 'rejects touch(true)' do + belonging_to_parent.should_not belong_to(:parent).touch(true) + end + + it 'rejects touch()' do + belonging_to_parent.should_not belong_to(:parent).touch + end + end + def belonging_to_parent(options = {}) define_model :parent define_model :child, :parent_id => :integer do