require 'test_helper' class AssociationMatcherTest < ActiveSupport::TestCase # :nodoc: context "belong_to" do setup do @matcher = belong_to(:parent) end should "accept a good association with the default foreign key" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent end assert_accepts @matcher, Child.new end should "reject a nonexistent association" do define_model :child assert_rejects @matcher, Child.new end should "reject an association of the wrong type" do define_model :parent, :child_id => :integer child_class = define_model :child do has_one :parent end assert_rejects @matcher, Child.new end should "reject an association that has a nonexistent foreign key" do define_model :parent define_model :child do belongs_to :parent end assert_rejects @matcher, Child.new end should "accept an association with an existing custom foreign key" do define_model :parent define_model :child, :guardian_id => :integer do belongs_to :parent, :foreign_key => 'guardian_id' end assert_accepts @matcher, Child.new end should "accept a polymorphic association" do define_model :child, :parent_type => :string, :parent_id => :integer do belongs_to :parent, :polymorphic => true end assert_accepts @matcher, Child.new end should "accept an association with a valid :dependent option" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent, :dependent => :destroy end assert_accepts @matcher.dependent(:destroy), Child.new end should "reject an association with a bad :dependent option" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent end assert_rejects @matcher.dependent(:destroy), Child.new end should "ignore other options" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent, :readonly => true end assert_accepts @matcher, Child.new end context "with options" do setup do @matcher = belong_to(:parent).with_options(:readonly => true, :touch => true) end should "accept a good association with the correct options" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent, :readonly => true, :touch => true end assert_accepts @matcher, Child.new end should "reject an association with missing options" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent, :readonly => true end assert_rejects @matcher, Child.new, :message => /missing :touch option/ end should "reject an association with additional options" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent, :readonly => true, :touch => true, :validate => false end assert_rejects @matcher, Child.new, :message => /unexpected :validate option/ end should "reject an association with incorrect option values" do define_model :parent define_model :child, :parent_id => :integer do belongs_to :parent, :readonly => true, :touch => false end assert_rejects @matcher, Child.new, :message => /expected :touch option to be true, but got false/ end end end context "have_many" do setup do @matcher = have_many(:children) end should "accept a valid association without any options" do define_model :child, :parent_id => :integer define_model :parent do has_many :children end assert_accepts @matcher, Parent.new end should "accept a valid association with a :through option" do define_model :child define_model :conception, :child_id => :integer, :parent_id => :integer do belongs_to :child end define_model :parent do has_many :conceptions has_many :children, :through => :conceptions end assert_accepts @matcher, Parent.new end should "accept a valid association with an :as option" do define_model :child, :guardian_type => :string, :guardian_id => :integer define_model :parent do has_many :children, :as => :guardian end assert_accepts @matcher, Parent.new end should "reject an association that has a nonexistent foreign key" do define_model :child define_model :parent do has_many :children end assert_rejects @matcher, Parent.new end should "reject an association with a bad :as option" do define_model :child, :caretaker_type => :string, :caretaker_id => :integer define_model :parent do has_many :children, :as => :guardian end assert_rejects @matcher, Parent.new end should "reject an association that has a bad :through option" do define_model :child, :parent_id => :integer define_model :parent do has_many :children end assert_rejects @matcher.through(:conceptions), Parent.new, :message => /does not have any relationship to conceptions/ end should "reject an association that has the wrong :through option" do define_model :child define_model :conception, :child_id => :integer, :parent_id => :integer do belongs_to :child end define_model :parent do has_many :conceptions has_many :relationships has_many :children, :through => :conceptions end assert_rejects @matcher.through(:relationships), Parent.new, :message => /through relationships, but got it through conceptions/ end should "accept an association with a valid :dependent option" do define_model :child, :parent_id => :integer define_model :parent do has_many :children, :dependent => :destroy end assert_accepts @matcher.dependent(:destroy), Parent.new end should "reject an association with a bad :dependent option" do define_model :child, :parent_id => :integer define_model :parent do has_many :children end assert_rejects @matcher.dependent(:destroy), Parent.new end should "ignore other options" do define_model :child, :parent_id => :integer define_model :parent do has_many :children, :order => "first_name" end assert_accepts @matcher, Parent.new end context "with options" do setup do @matcher = have_many(:children).with_options(:order => "first_name", :limit =>5) end should "accept a good association with the correct options" do define_model :child, :parent_id => :integer define_model :parent do has_many :children, :order => "first_name", :limit =>5 end assert_accepts @matcher, Parent.new end should "reject an association with missing options" do define_model :child, :parent_id => :integer define_model :parent do has_many :children, :order => "first_name" end assert_rejects @matcher, Parent.new, :message => /missing :limit option/ end should "reject an association with additional options" do define_model :child, :parent_id => :integer define_model :parent do has_many :children, :order => "first_name", :limit =>5, :validate => false end assert_rejects @matcher, Parent.new, :message => /unexpected :validate option/ end should "reject an association with incorrect option values" do define_model :child, :parent_id => :integer define_model :parent do has_many :children, :order => "first_name", :limit => 2 end assert_rejects @matcher, Parent.new, :message => /expected :limit option to be 5, but got 2/ end end end context "have_one" do setup do @matcher = have_one(:detail) end should "accept a valid association without any options" do define_model :detail, :person_id => :integer define_model :person do has_one :detail end assert_accepts @matcher, Person.new end should "accept a valid association with an :as option" do define_model :detail, :detailable_id => :integer, :detailable_type => :string define_model :person do has_one :detail, :as => :detailable end assert_accepts @matcher, Person.new end should "reject an association that has a nonexistent foreign key" do define_model :detail define_model :person do has_one :detail end assert_rejects @matcher, Person.new end should "reject an association with a bad :as option" do define_model :detail, :detailable_id => :integer, :detailable_type => :string define_model :person do has_one :detail, :as => :describable end assert_rejects @matcher, Person.new end should "accept an association with a valid :dependent option" do define_model :detail, :person_id => :integer define_model :person do has_one :detail, :dependent => :destroy end assert_accepts @matcher.dependent(:destroy), Person.new end should "reject an association with a bad :dependent option" do define_model :detail, :person_id => :integer define_model :person do has_one :detail end assert_rejects @matcher.dependent(:destroy), Person.new end should "ignore other options" do define_model :detail, :person_id => :integer define_model :person do has_one :detail, :readonly => true end assert_accepts @matcher, Person.new end context "with options" do setup do @matcher = have_one(:detail).with_options(:readonly => true, :autosave => false) end should "accept a good association with the correct options" do define_model :detail, :person_id => :integer define_model :person do has_one :detail, :readonly => true, :autosave => false end assert_accepts @matcher, Person.new end should "reject an association with missing options" do define_model :detail, :person_id => :integer define_model :person do has_one :detail, :readonly => true end assert_rejects @matcher, Person.new, :message => /missing :autosave option/ end should "reject an association with additional options" do define_model :detail, :person_id => :integer define_model :person do has_one :detail, :readonly => true, :autosave => false, :validate => true end assert_rejects @matcher, Person.new, :message => /unexpected :validate option/ end should "reject an association with incorrect option values" do define_model :detail, :person_id => :integer define_model :person do has_one :detail, :readonly => true, :autosave => true end assert_rejects @matcher, Person.new, :message => /expected :autosave option to be false, but got true/ end end end context "have_and_belong_to_many" do setup do @matcher = have_and_belong_to_many(:relatives) end should "accept a valid association" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives end define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_accepts @matcher, Person.new end should "reject a nonexistent association" do define_model :relatives define_model :person define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_rejects @matcher, Person.new end should "reject an association with a nonexistent join table" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives end assert_rejects @matcher, Person.new end should "reject an association of the wrong type" do define_model :relatives, :person_id => :integer define_model :person do has_many :relatives end assert_rejects @matcher, Person.new end should "ignore other options" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives, :order => "surname" end define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_accepts @matcher, Person.new end context "with options" do setup do @matcher = have_and_belong_to_many(:relatives).with_options( :order => "surname", :limit =>5) end should "accept a good association with the correct options" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives, :order => "surname", :limit =>5 end define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_accepts @matcher, Person.new end should "reject an association with missing options" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives, :order => "surname" end define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_rejects @matcher, Person.new, :message => /missing :limit option/ end should "reject an association with additional options" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives, :order => "surname", :limit =>5, :validate => true end define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_rejects @matcher, Person.new, :message => /unexpected :validate option/ end should "reject an association with incorrect option values" do define_model :relatives define_model :person do has_and_belongs_to_many :relatives, :order => "surname", :limit =>2 end define_model :people_relative, :person_id => :integer, :relative_id => :integer assert_rejects @matcher, Person.new, :message => /expected :limit option to be 5, but got 2/ end end end end