Association matchers now support :source option

This commit is contained in:
Luciano Sousa 2013-11-27 15:18:46 -03:00 committed by Elliot Winkler
parent 5c86571182
commit 803c06b0b0
6 changed files with 69 additions and 1 deletions

View File

@ -13,11 +13,14 @@
* The `ensure_inclusion_of` matcher now works with a decimal column.
* Fix association matchers on Rails 3 so they work when used in conjunction with
a submatcher such as #order and an association that has :include on it.
a submatcher such as #order and an association that has `:include` on it.
* Fix a bug where `validate_uniqueness_of` would fail if the attribute under
test had a limit of fewer than 16 characters.
* You can now test that your `has_many :through` or `has_one :through`
associations are defined with a `:source` option.
# v 2.4.0
* Fix a bug with the `validate_numericality_of` matcher that would not allow the

View File

@ -618,6 +618,7 @@ The `have_many` matcher tests your `has_many` and `has_many :through` associatio
class Person < ActiveRecord::Base
has_many :friends
has_many :acquaintances, through: :friends
has_many :job_offers, through: :friends, source: :opportunities
has_many :coins, -> { where(condition: 'mint') }
has_many :shirts, -> { order('color') }
has_many :hopes, class_name: 'Dream'
@ -632,6 +633,7 @@ end
describe Person do
it { should have_many(:friends) }
it { should have_many(:acquaintances).through(:friends) }
it { should have_many(:job_offers).through(:friends).source(:opportunities) }
it { should have_many(:coins).conditions(condition: 'mint') }
it { should have_many(:shirts).order('color') }
it { should have_many(:hopes).class_name('Dream') }
@ -646,6 +648,7 @@ end
class PersonTest < ActiveSupport::TestCase
should have_many(:friends)
should have_many(:acquaintances).through(:friends)
should have_many(:job_offers).through(:friends).source(:opportunities)
should have_many(:coins).conditions(condition: 'mint')
should have_many(:shirts).order('color')
should have_many(:hopes).class_name('Dream')
@ -665,6 +668,7 @@ The `have_one` matcher tests your `has_one` and `has_one :through` associations.
class Person < ActiveRecord::Base
has_one :partner
has_one :life, through: :partner
has_one :car, through: :partner, source: :vehicle
has_one :pet, -> { where('weight < 80') }
has_one :focus, -> { order('priority desc') }
has_one :chance, class_name: 'Opportunity'
@ -677,6 +681,7 @@ end
describe Person do
it { should have_one(:partner) }
it { should have_one(:life).through(:partner) }
it { should have_one(:car).through(:partner).source(:vehicle) }
it { should have_one(:pet).conditions('weight < 80') }
it { should have_one(:focus).order('priority desc') }
it { should have_one(:chance).class_name('Opportunity') }

View File

@ -3,6 +3,7 @@ require 'shoulda/matchers/active_record/association_matchers/counter_cache_match
require 'shoulda/matchers/active_record/association_matchers/order_matcher'
require 'shoulda/matchers/active_record/association_matchers/through_matcher'
require 'shoulda/matchers/active_record/association_matchers/dependent_matcher'
require 'shoulda/matchers/active_record/association_matchers/source_matcher'
require 'shoulda/matchers/active_record/association_matchers/model_reflector'
require 'shoulda/matchers/active_record/association_matchers/model_reflection'
require 'shoulda/matchers/active_record/association_matchers/option_verifier'

View File

@ -109,6 +109,12 @@ module Shoulda # :nodoc:
self
end
def source(source)
source_matcher = AssociationMatchers::SourceMatcher.new(source, name)
add_submatcher(source_matcher)
self
end
def conditions(conditions)
@options[:conditions] = conditions
self

View File

@ -0,0 +1,40 @@
module Shoulda # :nodoc:
module Matchers
module ActiveRecord # :nodoc:
module AssociationMatchers
class SourceMatcher
attr_accessor :missing_option
def initialize(source, name)
@source = source
@name = name
@missing_option = ''
end
def description
"source => #{source}"
end
def matches?(subject)
self.subject = ModelReflector.new(subject, name)
if option_verifier.correct_for_string?(:source, source)
true
else
self.missing_option = "#{name} should have #{source} as source option"
false
end
end
private
attr_accessor :subject, :source, :name
def option_verifier
@option_verifier ||= OptionVerifier.new(subject)
end
end
end
end
end
end

View File

@ -282,6 +282,19 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
matcher.failure_message_for_should.should =~ /children should have destroy dependency/
end
it 'accepts an association with a valid :source option' do
having_many_children(:source => :user).
should have_many(:children).source(:user)
end
it 'rejects an association with a bad :source option' do
matcher = have_many(:children).source(:user)
having_many_children.should_not matcher
matcher.failure_message_for_should.should =~ /children should have user as source option/
end
it 'accepts an association with a valid :order option' do
having_many_children(:order => :id).
should have_many(:children).order(:id)