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
|
# HEAD
|
||||||
|
|
||||||
|
* Association matchers now test that the model being referred to (either
|
||||||
|
implicitly or explicitly, using `:class_name`) actually exists.
|
||||||
|
|
||||||
# v 2.5.0
|
# v 2.5.0
|
||||||
|
|
||||||
* Fix Rails/Test::Unit integration to ensure that the test case classes we are
|
* Fix Rails/Test::Unit integration to ensure that the test case classes we are
|
||||||
|
|
|
@ -160,6 +160,7 @@ module Shoulda # :nodoc:
|
||||||
@subject = subject
|
@subject = subject
|
||||||
association_exists? &&
|
association_exists? &&
|
||||||
macro_correct? &&
|
macro_correct? &&
|
||||||
|
class_exists? &&
|
||||||
foreign_key_exists? &&
|
foreign_key_exists? &&
|
||||||
class_name_correct? &&
|
class_name_correct? &&
|
||||||
conditions_correct? &&
|
conditions_correct? &&
|
||||||
|
@ -257,6 +258,14 @@ module Shoulda # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def class_exists?
|
||||||
|
associated_class
|
||||||
|
true
|
||||||
|
rescue NameError
|
||||||
|
@missing = "#{reflection.class_name} does not exist"
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
def conditions_correct?
|
def conditions_correct?
|
||||||
if options.key?(:conditions)
|
if options.key?(:conditions)
|
||||||
if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions])
|
if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions])
|
||||||
|
|
|
@ -30,6 +30,7 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accepts a polymorphic association' do
|
it 'accepts a polymorphic association' do
|
||||||
|
define_model :parent
|
||||||
define_model :child, parent_type: :string, parent_id: :integer do
|
define_model :child, parent_type: :string, parent_id: :integer do
|
||||||
belongs_to :parent, polymorphic: true
|
belongs_to :parent, polymorphic: true
|
||||||
end
|
end
|
||||||
|
@ -100,6 +101,21 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
belonging_to_parent.should_not belong_to(:parent).class_name('TreeChild')
|
belonging_to_parent.should_not belong_to(:parent).class_name('TreeChild')
|
||||||
end
|
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
|
context 'an association with a :validate option' do
|
||||||
[false, true].each do |validate_value|
|
[false, true].each do |validate_value|
|
||||||
context "when the model has validate: #{validate_value}" do
|
context "when the model has validate: #{validate_value}" do
|
||||||
|
@ -194,6 +210,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
belongs_to :parent, options
|
belongs_to :parent, options
|
||||||
end.new
|
end.new
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
context 'have_many' do
|
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')
|
having_many_children.should_not have_many(:children).class_name('Node')
|
||||||
end
|
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
|
context 'validate' do
|
||||||
it 'accepts when the :validate option matches' do
|
it 'accepts when the :validate option matches' do
|
||||||
having_many_children(validate: false).should have_many(:children).validate(false)
|
having_many_children(validate: false).should have_many(:children).validate(false)
|
||||||
|
@ -396,6 +433,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
end
|
end
|
||||||
end.new
|
end.new
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
context 'have_one' do
|
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')
|
having_one_detail.should_not have_one(:detail).class_name('NotSet')
|
||||||
end
|
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
|
it 'accepts an association with a through' do
|
||||||
define_model :detail
|
define_model :detail
|
||||||
|
|
||||||
|
@ -551,6 +609,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
end
|
end
|
||||||
end.new
|
end.new
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
context 'have_and_belong_to_many' do
|
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')
|
should_not have_and_belong_to_many(:relatives).class_name('PersonRelatives')
|
||||||
end
|
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
|
context 'validate' do
|
||||||
it 'accepts when the :validate option matches' do
|
it 'accepts when the :validate option matches' do
|
||||||
having_and_belonging_to_many_relatives(validate: false).
|
having_and_belonging_to_many_relatives(validate: false).
|
||||||
|
@ -660,6 +742,12 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
has_and_belongs_to_many :relatives
|
has_and_belongs_to_many :relatives
|
||||||
end.new
|
end.new
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
def define_association_with_conditions(model, macro, name, conditions, other_options={})
|
def define_association_with_conditions(model, macro, name, conditions, other_options={})
|
||||||
|
|
Loading…
Reference in New Issue