Reject associations when class is not defined
This commit is contained in:
parent
fcbb5c485e
commit
f835cf439e
3
NEWS.md
3
NEWS.md
|
@ -1,5 +1,8 @@
|
|||
# HEAD
|
||||
|
||||
* Association matchers now test that the model being referred to (either
|
||||
implicitly or explicitly, using `:class_name`) actually exists.
|
||||
|
||||
# v 2.5.0
|
||||
|
||||
* Fix Rails/Test::Unit integration to ensure that the test case classes we are
|
||||
|
|
|
@ -160,6 +160,7 @@ module Shoulda # :nodoc:
|
|||
@subject = subject
|
||||
association_exists? &&
|
||||
macro_correct? &&
|
||||
class_exists? &&
|
||||
foreign_key_exists? &&
|
||||
class_name_correct? &&
|
||||
conditions_correct? &&
|
||||
|
@ -257,6 +258,14 @@ module Shoulda # :nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
def class_exists?
|
||||
associated_class
|
||||
true
|
||||
rescue NameError
|
||||
@missing = "#{reflection.class_name} does not exist"
|
||||
false
|
||||
end
|
||||
|
||||
def conditions_correct?
|
||||
if options.key?(:conditions)
|
||||
if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions])
|
||||
|
|
|
@ -30,6 +30,7 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
end
|
||||
|
||||
it 'accepts a polymorphic association' do
|
||||
define_model :parent
|
||||
define_model :child, parent_type: :string, parent_id: :integer do
|
||||
belongs_to :parent, polymorphic: true
|
||||
end
|
||||
|
@ -100,6 +101,21 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
belonging_to_parent.should_not belong_to(:parent).class_name('TreeChild')
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent implicit class name' do
|
||||
belonging_to_non_existent_class(:child, :parent).should_not belong_to(:parent)
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent explicit class name' do
|
||||
belonging_to_non_existent_class(:child, :parent, :class_name => 'Parent').should_not belong_to(:parent)
|
||||
end
|
||||
|
||||
it 'adds error message when rejecting an association with non-existent class' do
|
||||
message = 'Expected Child to have a belongs_to association called parent (Parent2 does not exist)'
|
||||
expect {
|
||||
belonging_to_non_existent_class(:child, :parent, :class_name => 'Parent2').should belong_to(:parent)
|
||||
}.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
|
||||
|
@ -194,6 +210,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
belongs_to :parent, options
|
||||
end.new
|
||||
end
|
||||
|
||||
def belonging_to_non_existent_class(model_name, assoc_name, options = {})
|
||||
define_model model_name, "#{assoc_name}_id" => :integer do
|
||||
belongs_to assoc_name, options
|
||||
end.new
|
||||
end
|
||||
end
|
||||
|
||||
context 'have_many' do
|
||||
|
@ -343,6 +365,21 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
having_many_children.should_not have_many(:children).class_name('Node')
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent implicit class name' do
|
||||
having_many_non_existent_class(:parent, :children).should_not have_many(:children)
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent explicit class name' do
|
||||
having_many_non_existent_class(:parent, :children, :class_name => 'Child').should_not have_many(:children)
|
||||
end
|
||||
|
||||
it 'adds error message when rejecting an association with non-existent class' do
|
||||
message = 'Expected Parent to have a has_many association called children (Child2 does not exist)'
|
||||
expect {
|
||||
having_many_non_existent_class(:parent, :children, :class_name => 'Child2').should have_many(:children)
|
||||
}.to fail_with_message(message)
|
||||
end
|
||||
|
||||
context 'validate' do
|
||||
it 'accepts when the :validate option matches' do
|
||||
having_many_children(validate: false).should have_many(:children).validate(false)
|
||||
|
@ -396,6 +433,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
end
|
||||
end.new
|
||||
end
|
||||
|
||||
def having_many_non_existent_class(model_name, assoc_name, options = {})
|
||||
define_model model_name do
|
||||
has_many assoc_name, options
|
||||
end.new
|
||||
end
|
||||
end
|
||||
|
||||
context 'have_one' do
|
||||
|
@ -500,6 +543,21 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
having_one_detail.should_not have_one(:detail).class_name('NotSet')
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent implicit class name' do
|
||||
having_one_non_existent(:pserson, :detail).should_not have_one(:detail)
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent explicit class name' do
|
||||
having_one_non_existent(:person, :detail, :class_name => 'Detail').should_not have_one(:detail)
|
||||
end
|
||||
|
||||
it 'adds error message when rejecting an association with non-existent class' do
|
||||
message = 'Expected Person to have a has_one association called detail (Detail2 does not exist)'
|
||||
expect {
|
||||
having_one_non_existent(:person, :detail, :class_name => 'Detail2').should have_one(:detail)
|
||||
}.to fail_with_message(message)
|
||||
end
|
||||
|
||||
it 'accepts an association with a through' do
|
||||
define_model :detail
|
||||
|
||||
|
@ -551,6 +609,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
end
|
||||
end.new
|
||||
end
|
||||
|
||||
def having_one_non_existent(model_name, assoc_name, options = {})
|
||||
define_model model_name do
|
||||
has_one assoc_name, options
|
||||
end.new
|
||||
end
|
||||
end
|
||||
|
||||
context 'have_and_belong_to_many' do
|
||||
|
@ -630,6 +694,24 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
should_not have_and_belong_to_many(:relatives).class_name('PersonRelatives')
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent implicit class name' do
|
||||
having_and_belonging_to_many_non_existent_class(:person, :relatives).
|
||||
should_not have_and_belong_to_many(:relatives)
|
||||
end
|
||||
|
||||
it 'rejects an association with non-existent explicit class name' do
|
||||
having_and_belonging_to_many_non_existent_class(:person, :relatives, :class_name => 'Relative')
|
||||
.should_not have_and_belong_to_many(:relatives)
|
||||
end
|
||||
|
||||
it 'adds error message when rejecting an association with non-existent class' do
|
||||
message = 'Expected Person to have a has_and_belongs_to_many association called relatives (Relative2 does not exist)'
|
||||
expect {
|
||||
having_and_belonging_to_many_non_existent_class(:person, :relatives, :class_name => 'Relative2').
|
||||
should have_and_belong_to_many(:relatives)
|
||||
}.to fail_with_message(message)
|
||||
end
|
||||
|
||||
context 'validate' do
|
||||
it 'accepts when the :validate option matches' do
|
||||
having_and_belonging_to_many_relatives(validate: false).
|
||||
|
@ -660,6 +742,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|||
has_and_belongs_to_many :relatives
|
||||
end.new
|
||||
end
|
||||
|
||||
def having_and_belonging_to_many_non_existent_class(model_name, assoc_name, options = {})
|
||||
define_model model_name do
|
||||
has_and_belongs_to_many assoc_name, options
|
||||
end.new
|
||||
end
|
||||
end
|
||||
|
||||
def define_association_with_conditions(model, macro, name, conditions, other_options={})
|
||||
|
|
Loading…
Reference in New Issue