aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r--activerecord/test/cases/adapters/mysql/connection_test.rb2
-rw-r--r--activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb1
-rw-r--r--activerecord/test/cases/associations/eager_test.rb12
-rw-r--r--activerecord/test/cases/associations/identity_map_test.rb135
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb2
-rw-r--r--activerecord/test/cases/autosave_association_test.rb3
-rw-r--r--activerecord/test/cases/helper.rb12
-rw-r--r--activerecord/test/cases/identity_map_test.rb400
-rw-r--r--activerecord/test/cases/relations_test.rb12
9 files changed, 564 insertions, 15 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 d5262b1ee4..c064731859 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -184,7 +184,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
@@ -195,7 +195,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
@@ -803,18 +803,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
@@ -828,7 +828,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
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 0a57c7883f..d6e772e989 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -94,7 +94,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 27aee400f9..0fd1e62134 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -1207,6 +1207,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
@@ -1215,7 +1216,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 f9bbc5299b..942a5c048e 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 20bfafbc5e..b3d4305f7c 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -279,7 +279,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
@@ -289,12 +289,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
@@ -307,7 +307,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
@@ -317,7 +317,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
@@ -563,9 +563,11 @@ class RelationTest < ActiveRecord::TestCase
end
def test_relation_merging_with_preload
+ ActiveRecord::IdentityMap.without do
[Post.scoped & Post.preload(:author), Post.preload(:author) & Post.scoped].each do |posts|
assert_queries(2) { assert posts.first.author }
end
+ end
end
def test_relation_merging_with_joins