spec/integration/constraints_spec.rb in dm-constraints-0.9.9 vs spec/integration/constraints_spec.rb in dm-constraints-0.9.10

- old
+ new

@@ -3,33 +3,37 @@ ADAPTERS.each do |adapter| describe 'DataMapper::Constraints' do + # load_models_for_metaphor :stable, :farmer, :cow + before do DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[adapter] - class Stable + class ::Stable include DataMapper::Resource + include DataMapper::Constraints property :id, Serial property :location, String property :size, Integer has n, :cows end - class Farmer + class ::Farmer include DataMapper::Resource + include DataMapper::Constraints property :first_name, String, :key => true property :last_name, String, :key => true has n, :cows end - class Cow + class ::Cow include DataMapper::Resource include DataMapper::Constraints property :id, Serial property :name, String @@ -59,7 +63,171 @@ it "should not be able to create related objects with a failing foreign key constraint" do s = Stable.create lambda { @c1 = Cow.create(:name => "Bea", :stable_id => s.id + 1) }.should raise_error end - end -end + # :constraint associations + # value | on deletion of parent... + # --------------------------------- + # :protect | raises exception if there are child records + # :destroy | deletes children + # :destroy! | deletes children directly without instantiating the resource, bypassing any hooks + # :set_nil | sets parent id to nil in child associations + # :skip | does not do anything with children (they'll become orphan records) + + describe "constraint options" do + describe "when no constraint options are given" do + + it "should destroy the parent if there are no children in the association" do + @f1 = Farmer.create(:first_name => "John", :last_name => "Doe") + @f2 = Farmer.create(:first_name => "Some", :last_name => "Body") + @c1 = Cow.create(:name => "Bea", :farmer => @f2) + @f1.destroy.should == true + end + + it "should not destroy the parent if there are children in the association" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c1 = Cow.create(:name => "Bea", :farmer => @f) + @f.destroy.should == false + end + + end + + describe "when :constraint => :protect is given" do + before do + class ::Farmer + has n, :cows, :constraint => :protect + end + class ::Cow + belongs_to :farmer + end + end + + it "should destroy the parent if there are no children in the association" do + @f1 = Farmer.create(:first_name => "John", :last_name => "Doe") + @f2 = Farmer.create(:first_name => "Some", :last_name => "Body") + @c1 = Cow.create(:name => "Bea", :farmer => @f2) + @f1.destroy.should == true + end + + it "should not destroy the parent if there are children in the association" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c1 = Cow.create(:name => "Bea", :farmer => @f) + @f.destroy.should == false + end + + it "the child should be destroyable" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c = Cow.create(:name => "Bea", :farmer => @f) + @c.destroy.should == true + end + + end + + describe "when :constraint => :destroy is given" do + before do + class ::Farmer + has n, :cows, :constraint => :destroy + end + class ::Cow + belongs_to :farmer + end + DataMapper.auto_migrate! + end + + it "should destroy the parent and the children, too" do + #NOTE: the repository wrapper is needed in order for + # the identity map to work (otherwise @c1 in the below two calls + # would refer to different instances) + repository do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c1 = Cow.create(:name => "Bea", :farmer => @f) + @c2 = Cow.create(:name => "Riksa", :farmer => @f) + @f.destroy.should == true + @f.should be_new_record + @c1.should be_new_record + @c2.should be_new_record + end + end + + it "the child should be destroyable" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c = Cow.create(:name => "Bea", :farmer => @f) + @c.destroy.should == true + end + + end + + describe "when :constraint => :set_nil is given" do + before do + class ::Farmer + has n, :cows, :constraint => :set_nil + end + class ::Cow + belongs_to :farmer + end + DataMapper.auto_migrate! + end + + it "destroying the parent should set children foreign keys to nil" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c1 = Cow.create(:name => "Bea", :farmer => @f) + @c2 = Cow.create(:name => "Riksa", :farmer => @f) + cows = @f.cows + @f.destroy.should == true + cows.all? { |cow| cow.farmer.should be_nil } + end + + it "the child should be destroyable" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c = Cow.create(:name => "Bea", :farmer => @f) + @c.destroy.should == true + end + + end # describe + + describe "when :constraint => :skip is given" do + before do + class ::Farmer + has n, :cows, :constraint => :skip + end + class ::Cow + belongs_to :farmer + end + DataMapper.auto_migrate! + end + + it "destroying the parent should be allowed, children should become orphan records" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c1 = Cow.create(:name => "Bea", :farmer => @f) + @c2 = Cow.create(:name => "Riksa", :farmer => @f) + @f.destroy.should == true + @c1.farmer.should be_new_record + @c2.farmer.should be_new_record + end + + it "the child should be destroyable" do + @f = Farmer.create(:first_name => "John", :last_name => "Doe") + @c = Cow.create(:name => "Bea", :farmer => @f) + @c.destroy.should == true + end + + end # describe + + describe "when an invalid option is given" do + before do + end + + it "should raise an error" do + lambda do + class ::Farmer + has n, :cows, :constraint => :chocolate + end + end.should raise_error(ArgumentError) + end + + end + + end # describe 'constraint options' + + end # DataMapper::Constraints +end # ADAPTERS.each