Permalink
Browse files

Reject associations when class is not defined

  • Loading branch information...
1 parent fcbb5c4 commit f835cf439e97f87ce9d998c5c9b9989f1758f827 @chulkilee chulkilee committed with mcmire Jan 10, 2014
View
@@ -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 @@ def matches?(subject)
@subject = subject
association_exists? &&
macro_correct? &&
+ class_exists? &&
foreign_key_exists? &&
class_name_correct? &&
conditions_correct? &&
@@ -257,6 +258,14 @@ def class_name_correct?
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 @@
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 @@
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 @@ def belonging_to_parent(options = {})
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 @@ def belonging_to_parent(options = {})
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 @@ def having_many_children(options = {})
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 @@ def having_many_children(options = {})
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 @@ def having_one_detail(options = {})
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 @@ def having_one_detail(options = {})
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 @@ def having_and_belonging_to_many_relatives(options = {})
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={})

0 comments on commit f835cf4

Please sign in to comment.