diff options
Diffstat (limited to 'activerecord/test')
11 files changed, 574 insertions, 21 deletions
diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index 62ffde558f..eb3f8143e7 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -102,7 +102,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase end # Test that MySQL allows multiple results for stored procedures - if Mysql.const_defined?(:CLIENT_MULTI_RESULTS) + if defined?(Mysql) && Mysql.const_defined?(:CLIENT_MULTI_RESULTS) def test_multi_results rows = ActiveRecord::Base.connection.select_rows('CALL ten();') assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}" diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb index fb59f63f91..d75791cab9 100644 --- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -27,6 +27,7 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging ) assert_nil post.tagging + ActiveRecord::IdentityMap.clear ActiveRecord::Base.store_full_sti_class = true post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging ) assert_instance_of Tagging, post.tagging diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 42dd612083..650bb15b55 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -185,7 +185,7 @@ class EagerAssociationTest < ActiveRecord::TestCase author = authors(:david) post = author.post_about_thinking_with_last_comment last_comment = post.last_comment - author = assert_queries(3) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments + author = assert_queries(2) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments assert_no_queries do assert_equal post, author.post_about_thinking_with_last_comment assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment @@ -196,7 +196,7 @@ class EagerAssociationTest < ActiveRecord::TestCase post = posts(:welcome) author = post.author author_address = author.author_address - post = assert_queries(3) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address + post = assert_queries(2) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address assert_no_queries do assert_equal author, post.author_with_address assert_equal author_address, post.author_with_address.author_address @@ -817,18 +817,18 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal [posts(:welcome)], posts assert_equal authors(:david), assert_no_queries { posts[0].author} - posts = assert_queries(2) do + posts = assert_queries(1) do Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id') end assert_equal [posts(:welcome)], posts assert_equal authors(:david), assert_no_queries { posts[0].author} - posts = assert_queries(2) do + posts = assert_queries(1) do Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'", :order => 'posts.id') end assert_equal posts(:welcome, :thinking), posts - posts = assert_queries(2) do + posts = assert_queries(1) do Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2", :order => 'posts.id') end assert_equal posts(:welcome, :thinking), posts @@ -842,7 +842,7 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal [posts(:welcome)], posts assert_equal authors(:david), assert_no_queries { posts[0].author} - posts = assert_queries(2) do + posts = assert_queries(1) do Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id') end assert_equal [posts(:welcome)], posts @@ -931,7 +931,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_preloading_empty_belongs_to_polymorphic t = Tagging.create!(:taggable_type => 'Post', :taggable_id => Post.maximum(:id) + 1, :tag => tags(:general)) - tagging = assert_queries(2) { Tagging.preload(:taggable).find(t.id) } + tagging = assert_queries(1) { Tagging.preload(:taggable).find(t.id) } assert_no_queries { assert_nil tagging.taggable } end diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb index 91d3025468..fc1db4e34b 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -88,12 +88,12 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase # conditions on the through table assert_equal clubs(:moustache_club), Member.find(@member.id, :include => :favourite_club).favourite_club memberships(:membership_of_favourite_club).update_attribute(:favourite, false) - assert_equal nil, Member.find(@member.id, :include => :favourite_club).favourite_club + assert_equal nil, Member.find(@member.id, :include => :favourite_club).favourite_club.reload # conditions on the source table assert_equal clubs(:moustache_club), Member.find(@member.id, :include => :hairy_club).hairy_club clubs(:moustache_club).update_attribute(:name, "Association of Clean-Shaven Persons") - assert_equal nil, Member.find(@member.id, :include => :hairy_club).hairy_club + assert_equal nil, Member.find(@member.id, :include => :hairy_club).hairy_club.reload end def test_has_one_through_polymorphic_with_source_type diff --git a/activerecord/test/cases/associations/identity_map_test.rb b/activerecord/test/cases/associations/identity_map_test.rb new file mode 100644 index 0000000000..3d3ae0594b --- /dev/null +++ b/activerecord/test/cases/associations/identity_map_test.rb @@ -0,0 +1,135 @@ +require "cases/helper" +require 'models/author' +require 'models/post' + +class InverseHasManyIdentityMapTest < ActiveRecord::TestCase + fixtures :authors, :posts + + def test_parent_instance_should_be_shared_with_every_child_on_find + m = Author.first + is = m.posts + is.each do |i| + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to child-owned instance" + end + end + + def test_parent_instance_should_be_shared_with_eager_loaded_children + m = Author.find(:first, :include => :posts) + is = m.posts + is.each do |i| + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to child-owned instance" + end + + m = Author.find(:first, :include => :posts, :order => 'posts.id') + is = m.posts + is.each do |i| + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to child-owned instance" + end + end + + def test_parent_instance_should_be_shared_with_newly_built_child + m = Author.first + i = m.posts.build(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum') + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to just-built-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_newly_block_style_built_child + m = Author.first + i = m.posts.build {|ii| ii.title = 'Industrial Revolution Re-enactment'; ii.body = 'Lorem ipsum'} + assert_not_nil i.title, "Child attributes supplied to build via blocks should be populated" + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to just-built-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_newly_created_child + m = Author.first + i = m.posts.create(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum') + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_newly_created_via_bang_method_child + m = Author.first + i = m.posts.create!(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum') + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_newly_block_style_created_child + m = Author.first + i = m.posts.create {|ii| ii.title = 'Industrial Revolution Re-enactment'; ii.body = 'Lorem ipsum'} + assert_not_nil i.title, "Child attributes supplied to create via blocks should be populated" + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_poked_in_child + m = Author.first + i = Post.create(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum') + m.posts << i + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to newly-created-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_replaced_via_accessor_children + m = Author.first + i = Post.new(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum') + m.posts = [i] + assert_same m, i.author.target + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to replaced-child-owned instance" + end + + def test_parent_instance_should_be_shared_with_replaced_via_method_children + m = Author.first + i = Post.new(:title => 'Industrial Revolution Re-enactment', :body => 'Lorem ipsum') + m.posts.replace([i]) + assert_not_nil i.author + assert_equal m.name, i.author.name, "Name of man should be the same before changes to parent instance" + m.name = 'Bongo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to parent instance" + i.author.name = 'Mungo' + assert_equal m.name, i.author.name, "Name of man should be the same after changes to replaced-child-owned instance" + end +end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index c50fcd3f33..34f57d3155 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -88,7 +88,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first - tag.author_id + assert_nothing_raised(NoMethodError) { tag.author_id } end def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index dd2ce786aa..8035cd2c6f 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -585,7 +585,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase @pirate.ship.mark_for_destruction assert !@pirate.reload.marked_for_destruction? - assert !@pirate.ship.marked_for_destruction? + assert !@pirate.ship.reload.marked_for_destruction? end # has_one @@ -1311,6 +1311,7 @@ class TestAutosaveAssociationValidationsOnAHasOneAssociation < ActiveRecord::Tes def setup @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") @pirate.create_ship(:name => 'titanic') + super end test "should automatically validate associations with :validate => true" do @@ -1319,7 +1320,7 @@ class TestAutosaveAssociationValidationsOnAHasOneAssociation < ActiveRecord::Tes assert !@pirate.valid? end - test "should not automatically validate associations without :validate => true" do + test "should not automatically asd validate associations without :validate => true" do assert @pirate.valid? @pirate.non_validated_ship.name = '' assert @pirate.valid? diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index be508e46f8..ad0430a92f 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -11,7 +11,14 @@ require 'mocha' require 'active_record' require 'active_support/dependencies' -require 'connection' +begin + require 'connection' +rescue LoadError + # If we cannot load connection we assume that driver was not loaded for this test case, so we load sqlite3 as default one. + # This allows for running separate test cases by simply running test file. + connection_type = defined?(JRUBY_VERSION) ? 'jdbc' : 'native' + require "test/connections/#{connection_type}_sqlite3/connection" +end # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true @@ -19,6 +26,9 @@ ActiveSupport::Deprecation.debug = true # Quote "type" if it's a reserved word for the current connection. QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') +# Enable Identity Map for testing +ActiveRecord::IdentityMap.enabled = true + def current_adapter?(*types) types.any? do |type| ActiveRecord::ConnectionAdapters.const_defined?(type) && diff --git a/activerecord/test/cases/identity_map_test.rb b/activerecord/test/cases/identity_map_test.rb new file mode 100644 index 0000000000..74d4cb0bfb --- /dev/null +++ b/activerecord/test/cases/identity_map_test.rb @@ -0,0 +1,400 @@ +require "cases/helper" +require 'models/developer' +require 'models/project' +require 'models/company' +require 'models/topic' +require 'models/reply' +require 'models/computer' +require 'models/customer' +require 'models/order' +require 'models/post' +require 'models/author' +require 'models/tag' +require 'models/tagging' +require 'models/comment' +require 'models/sponsor' +require 'models/member' +require 'models/essay' +require 'models/subscriber' +require "models/pirate" +require "models/bird" +require "models/parrot" + +class IdentityMapTest < ActiveRecord::TestCase + fixtures :accounts, :companies, :developers, :projects, :topics, + :developers_projects, :computers, :authors, :author_addresses, + :posts, :tags, :taggings, :comments, :subscribers + + ############################################################################## + # Basic tests checking if IM is functioning properly on basic find operations# + ############################################################################## + + def test_find_id + assert_same(Client.find(3), Client.find(3)) + end + + def test_find_id_without_identity_map + ActiveRecord::IdentityMap.without do + assert_not_same(Client.find(3), Client.find(3)) + end + end + + def test_find_id_use_identity_map + ActiveRecord::IdentityMap.enabled = false + ActiveRecord::IdentityMap.use do + assert_same(Client.find(3), Client.find(3)) + end + ActiveRecord::IdentityMap.enabled = true + end + + def test_find_pkey + assert_same( + Subscriber.find('swistak'), + Subscriber.find('swistak') + ) + end + + def test_find_by_id + assert_same( + Client.find_by_id(3), + Client.find_by_id(3) + ) + end + + def test_find_by_string_and_numeric_id + assert_same( + Client.find_by_id("3"), + Client.find_by_id(3) + ) + end + + def test_find_by_pkey + assert_same( + Subscriber.find_by_nick('swistak'), + Subscriber.find_by_nick('swistak') + ) + end + + def test_find_first_id + assert_same( + Client.find(:first, :conditions => {:id => 1}), + Client.find(:first, :conditions => {:id => 1}) + ) + end + + def test_find_first_pkey + assert_same( + Subscriber.find(:first, :conditions => {:nick => 'swistak'}), + Subscriber.find(:first, :conditions => {:nick => 'swistak'}) + ) + end + + ############################################################################## + # Tests checking if IM is functioning properly on more advanced finds # + # and associations # + ############################################################################## + + def test_owner_object_is_associated_from_identity_map + post = Post.find(1) + comment = post.comments.first + + assert_no_queries do + comment.post + end + assert_same post, comment.post.target + end + + def test_associated_object_are_assigned_from_identity_map + post = Post.find(1) + + post.comments.each do |comment| + assert_same post, comment.post.target + assert_equal post.object_id, comment.post.target.object_id + end + end + + def test_creation + t1 = Topic.create("title" => "t1") + t2 = Topic.find(t1.id) + assert_same(t1, t2) + end + + ############################################################################## + # Tests checking dirty attribute behaviour with IM # + ############################################################################## + + def test_loading_new_instance_should_not_update_dirty_attributes + swistak = Subscriber.find(:first, :conditions => {:nick => 'swistak'}) + swistak.name = "Swistak Sreberkowiec" + assert_equal(["name"], swistak.changed) + assert_equal({"name" => ["Marcin Raczkowski", "Swistak Sreberkowiec"]}, swistak.changes) + + s = Subscriber.find('swistak') + + assert swistak.name_changed? + assert_equal("Swistak Sreberkowiec", swistak.name) + end + + def test_loading_new_instance_should_change_dirty_attribute_original_value + swistak = Subscriber.find(:first, :conditions => {:nick => 'swistak'}) + swistak.name = "Swistak Sreberkowiec" + + Subscriber.update_all({:name => "Raczkowski Marcin"}, {:name => "Marcin Raczkowski"}) + + s = Subscriber.find('swistak') + + assert_equal({'name' => ["Raczkowski Marcin", "Swistak Sreberkowiec"]}, swistak.changes) + assert_equal("Swistak Sreberkowiec", swistak.name) + end + + def test_loading_new_instance_should_remove_dirt + swistak = Subscriber.find(:first, :conditions => {:nick => 'swistak'}) + swistak.name = "Swistak Sreberkowiec" + + assert_equal({"name" => ["Marcin Raczkowski", "Swistak Sreberkowiec"]}, swistak.changes) + + Subscriber.update_all({:name => "Swistak Sreberkowiec"}, {:name => "Marcin Raczkowski"}) + + s = Subscriber.find('swistak') + + assert_equal("Swistak Sreberkowiec", swistak.name) + assert_equal({}, swistak.changes) + assert !swistak.name_changed? + end + + def test_has_many_associations + pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") + pirate.birds.create!(:name => 'Posideons Killer') + pirate.birds.create!(:name => 'Killer bandita Dionne') + + posideons, killer = pirate.birds + + pirate.reload + + pirate.birds_attributes = [{ :id => posideons.id, :name => 'Grace OMalley' }] + assert_equal 'Grace OMalley', pirate.birds.send(:load_target).find { |r| r.id == posideons.id }.name + end + + def test_changing_associations + post1 = Post.create("title" => "One post", "body" => "Posting...") + post2 = Post.create("title" => "Another post", "body" => "Posting... Again...") + comment = Comment.new("body" => "comment") + + comment.post = post1 + assert comment.save + + assert_same(post1.comments.first, comment) + + comment.post = post2 + assert comment.save + + assert_same(post2.comments.first, comment) + assert_equal(0, post1.comments.size) + end + + def test_im_with_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins + tag = posts(:welcome).tags.first + tag_with_joins_and_select = posts(:welcome).tags.add_joins_and_select.first + assert_same(tag, tag_with_joins_and_select) + assert_nothing_raised(NoMethodError, "Joins/select was not loaded") { tag.author_id } + end + + ############################################################################## + # Tests checking Identity Map behaviour with preloaded associations, joins, # + # includes etc. # + ############################################################################## + + def test_find_with_preloaded_associations + assert_queries(2) do + posts = Post.preload(:comments) + assert posts.first.comments.first + end + + # With IM we'll retrieve post object from previous query, it'll have comments + # already preloaded from first call + assert_queries(1) do + posts = Post.preload(:comments).to_a + assert posts.first.comments.first + end + + assert_queries(2) do + posts = Post.preload(:author) + assert posts.first.author + end + + # With IM we'll retrieve post object from previous query, it'll have comments + # already preloaded from first call + assert_queries(1) do + posts = Post.preload(:author).to_a + assert posts.first.author + end + + assert_queries(1) do + posts = Post.preload(:author, :comments).to_a + assert posts.first.author + assert posts.first.comments.first + end + end + + def test_find_with_included_associations + assert_queries(2) do + posts = Post.includes(:comments) + assert posts.first.comments.first + end + + assert_queries(1) do + posts = Post.scoped.includes(:comments) + assert posts.first.comments.first + end + + assert_queries(2) do + posts = Post.includes(:author) + assert posts.first.author + end + + assert_queries(1) do + posts = Post.includes(:author, :comments).to_a + assert posts.first.author + assert posts.first.comments.first + end + end + + def test_eager_loading_with_conditions_on_joined_table_preloads + posts = Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id') + assert_equal [posts(:welcome)], posts + assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_same posts.first.author.target, Author.first + + posts = Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id') + assert_equal [posts(:welcome)], posts + assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_same posts.first.author.target, Author.first + + posts = Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'", :order => 'posts.id') + assert_equal posts(:welcome, :thinking), posts + assert_same posts.first.author.target, Author.first + + posts = Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2", :order => 'posts.id') + assert_equal posts(:welcome, :thinking), posts + assert_same posts.first.author.target, Author.first + end + + def test_eager_loading_with_conditions_on_string_joined_table_preloads + posts = assert_queries(2) do + Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :conditions => "comments.body like 'Thank you%'", :order => 'posts.id') + end + assert_equal [posts(:welcome)], posts + assert_equal authors(:david), assert_no_queries { posts[0].author} + + posts = assert_queries(1) do + Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id') + end + assert_equal [posts(:welcome)], posts + assert_equal authors(:david), assert_no_queries { posts[0].author} + end + + ############################################################################## + # Behaviour releated to saving failures + ############################################################################## + + def test_reload_object_if_save_failed + developer = Developer.first + developer.salary = 0 + + assert !developer.save + + same_developer = Developer.first + + assert_not_same developer, same_developer + assert_not_equal 0, same_developer.salary + assert_not_equal developer.salary, same_developer.salary + end + + def test_reload_object_if_forced_save_failed + developer = Developer.first + developer.salary = 0 + + assert_raise(ActiveRecord::RecordInvalid) { developer.save! } + + same_developer = Developer.first + + assert_not_same developer, same_developer + assert_not_equal 0, same_developer.salary + assert_not_equal developer.salary, same_developer.salary + end + + def test_reload_object_if_update_attributes_fails + developer = Developer.first + developer.salary = 0 + + assert !developer.update_attributes(:salary => 0) + + same_developer = Developer.first + + assert_not_same developer, same_developer + assert_not_equal 0, same_developer.salary + assert_not_equal developer.salary, same_developer.salary + end + + ############################################################################## + # Behaviour of readonly, forzen, destroyed + ############################################################################## + + def test_find_using_identity_map_respects_readonly_when_loading_associated_object_first + author = Author.first + readonly_comment = author.readonly_comments.first + + comment = Comment.first + assert !comment.readonly? + + assert readonly_comment.readonly? + + assert_raise(ActiveRecord::ReadOnlyRecord) {readonly_comment.save} + assert comment.save + end + + def test_find_using_identity_map_respects_readonly + comment = Comment.first + assert !comment.readonly? + + author = Author.first + readonly_comment = author.readonly_comments.first + + assert readonly_comment.readonly? + + assert_raise(ActiveRecord::ReadOnlyRecord) {readonly_comment.save} + assert comment.save + end + + def test_find_using_select_and_identity_map + author_id, author = Author.select('id').first, Author.first + + assert_equal author_id, author + assert_same author_id, author + assert_not_nil author.name + + post, post_id = Post.first, Post.select('id').first + + assert_equal post_id, post + assert_same post_id, post + assert_not_nil post.title + end + +# Currently AR is not allowing changing primary key (see Persistence#update) +# So we ignore it. If this changes, this test needs to be uncommented. +# def test_updating_of_pkey +# assert client = Client.find(3), +# client.update_attribute(:id, 666) +# +# assert Client.find(666) +# assert_same(client, Client.find(666)) +# +# s = Subscriber.find_by_nick('swistak') +# assert s.update_attribute(:nick, 'swistakTheJester') +# assert_equal('swistakTheJester', s.nick) +# +# assert stj = Subscriber.find_by_nick('swistakTheJester') +# assert_same(s, stj) +# end + +end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 184e7a2b9e..109cb2c6bc 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -285,7 +285,7 @@ class RelationTest < ActiveRecord::TestCase assert posts.first.comments.first end - assert_queries(2) do + assert_queries(1) do posts = Post.preload(:comments).to_a assert posts.first.comments.first end @@ -295,12 +295,12 @@ class RelationTest < ActiveRecord::TestCase assert posts.first.author end - assert_queries(2) do + assert_queries(1) do posts = Post.preload(:author).to_a assert posts.first.author end - assert_queries(3) do + assert_queries(1) do posts = Post.preload(:author, :comments).to_a assert posts.first.author assert posts.first.comments.first @@ -313,7 +313,7 @@ class RelationTest < ActiveRecord::TestCase assert posts.first.comments.first end - assert_queries(2) do + assert_queries(1) do posts = Post.scoped.includes(:comments) assert posts.first.comments.first end @@ -323,7 +323,7 @@ class RelationTest < ActiveRecord::TestCase assert posts.first.author end - assert_queries(3) do + assert_queries(1) do posts = Post.includes(:author, :comments).to_a assert posts.first.author assert posts.first.comments.first @@ -569,8 +569,10 @@ class RelationTest < ActiveRecord::TestCase end def test_relation_merging_with_preload - [Post.scoped.merge(Post.preload(:author)), Post.preload(:author).merge(Post.scoped)].each do |posts| - assert_queries(2) { assert posts.first.author } + ActiveRecord::IdentityMap.without do + [Post.scoped.merge(Post.preload(:author)), Post.preload(:author).merge(Post.scoped)].each do |posts| + assert_queries(2) { assert posts.first.author } + end end end diff --git a/activerecord/test/fixtures/subscribers.yml b/activerecord/test/fixtures/subscribers.yml index 9ffb4a156f..c6a8c2fa24 100644 --- a/activerecord/test/fixtures/subscribers.yml +++ b/activerecord/test/fixtures/subscribers.yml @@ -5,3 +5,7 @@ first: second: nick: webster132 name: David Heinemeier Hansson + +thrid: + nick: swistak + name: Marcin Raczkowski
\ No newline at end of file |