diff options
author | rick <technoweenie@gmail.com> | 2008-09-20 13:00:20 -0700 |
---|---|---|
committer | rick <technoweenie@gmail.com> | 2008-09-20 13:00:20 -0700 |
commit | 22e830f883af0b56de81186c184751b6398d0141 (patch) | |
tree | 0de20fad9f3a7ce2e49d660d1243b5b02a32e290 /activerecord/test/cases | |
parent | 0aef9d1a2651fa0acd2adcd2de308eeb0ec8cdd2 (diff) | |
parent | a3b7fa78bfdc33e45e39c095b67e02d50a2c7bea (diff) | |
download | rails-22e830f883af0b56de81186c184751b6398d0141.tar.gz rails-22e830f883af0b56de81186c184751b6398d0141.tar.bz2 rails-22e830f883af0b56de81186c184751b6398d0141.zip |
Merge branch 'master' of git@github.com:rails/rails
Diffstat (limited to 'activerecord/test/cases')
28 files changed, 716 insertions, 249 deletions
diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index 75d1f27e07..4e0e1c7f15 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -107,6 +107,45 @@ class AggregationsTest < ActiveRecord::TestCase customers(:david).gps_location = nil assert_equal nil, customers(:david).gps_location end + + def test_custom_constructor + assert_equal 'Barney GUMBLE', customers(:barney).fullname.to_s + assert_kind_of Fullname, customers(:barney).fullname + end + + def test_custom_converter + customers(:barney).fullname = 'Barnoit Gumbleau' + assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s + assert_kind_of Fullname, customers(:barney).fullname + end +end + +class DeprecatedAggregationsTest < ActiveRecord::TestCase + class Person < ActiveRecord::Base; end + + def test_conversion_block_is_deprecated + assert_deprecated 'conversion block has been deprecated' do + Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money } + end + end + + def test_conversion_block_used_when_converter_option_is_nil + assert_deprecated 'conversion block has been deprecated' do + Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money } + end + assert_raise(NoMethodError) { Person.new.balance = 5 } + end + + def test_converter_option_overrides_conversion_block + assert_deprecated 'conversion block has been deprecated' do + Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| Money.new(balance) }) { |balance| balance.to_money } + end + + person = Person.new + assert_nothing_raised { person.balance = 5 } + assert_equal 5, person.balance.amount + assert_kind_of Money, person.balance + end end class OverridingAggregationsTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 9c718c4fef..37b6836a89 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -47,6 +47,19 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal apple.id, citibank.firm_id end + def test_foreign_key_assignment + # Test using an existing record + signals37 = accounts(:signals37) + assert_equal companies(:first_firm), signals37.firm + signals37.firm_id = companies(:another_firm).id + assert_equal companies(:another_firm), signals37.firm + + # Test using a new record + account = Account.new + account.firm_id = companies(:another_firm).id + assert_equal companies(:another_firm), account.firm + end + def test_no_unexpected_aliasing first_firm = companies(:first_firm) another_firm = companies(:another_firm) diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 0572418e3b..9981f4c5d5 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -223,10 +223,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase devel = Developer.find(1) proj = assert_no_queries { devel.projects.build("name" => "Projekt") } assert !devel.projects.loaded? - + assert_equal devel.projects.last, proj assert devel.projects.loaded? - + assert proj.new_record? devel.save assert !proj.new_record? @@ -251,10 +251,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase devel = Developer.find(1) proj = devel.projects.create("name" => "Projekt") assert !devel.projects.loaded? - + assert_equal devel.projects.last, proj assert devel.projects.loaded? - + assert !proj.new_record? assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated end @@ -274,10 +274,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_creation_respects_hash_condition post = categories(:general).post_with_conditions.build(:body => '') - + assert post.save assert_equal 'Yet Another Testing Title', post.title - + another_post = categories(:general).post_with_conditions.create(:body => '') assert !another_post.new_record? @@ -288,7 +288,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase dev = developers(:jamis) dev.projects << projects(:active_record) dev.projects << projects(:active_record) - + assert_equal 3, dev.projects.size assert_equal 1, dev.projects.uniq.size end @@ -415,13 +415,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase project.developers.class # force load target developer = project.developers.first - + assert_no_queries do assert project.developers.loaded? assert project.developers.include?(developer) end end - + def test_include_checks_if_record_exists_if_target_not_loaded project = projects(:active_record) developer = project.developers.first @@ -636,11 +636,39 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size end + def test_find_grouped + all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories) + grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories) + assert_equal 4, all_posts_from_category1.size + assert_equal 1, grouped_posts_of_category1.size + end + + def test_find_scoped_grouped + assert_equal 4, categories(:general).posts_gruoped_by_title.size + assert_equal 1, categories(:technology).posts_gruoped_by_title.size + end + def test_get_ids assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort assert_equal [projects(:active_record).id], developers(:jamis).project_ids end + def test_get_ids_for_loaded_associations + developer = developers(:david) + developer.projects(true) + assert_queries(0) do + developer.project_ids + developer.project_ids + end + end + + def test_get_ids_for_unloaded_associations_does_not_load_them + developer = developers(:david) + assert !developer.projects.loaded? + assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort + assert !developer.projects.loaded? + end + def test_assign_ids developer = Developer.new("name" => "Joe") developer.project_ids = projects(:active_record, :action_controller).map(&:id) @@ -703,4 +731,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase # due to Unknown column 'authors.id' assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog') end + + def test_counting_on_habtm_association_and_not_array + david = Developer.find(1) + # Extra parameter just to make sure we aren't falling back to + # Array#count in Ruby >=1.8.7, which would raise an ArgumentError + assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') } + end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index da3c8fb28e..ba750b266c 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -48,6 +48,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, Firm.find(:first).plain_clients.count(:name) end + def test_counting_with_association_limit + firm = companies(:first_firm) + assert_equal firm.limited_clients.length, firm.limited_clients.size + assert_equal firm.limited_clients.length, firm.limited_clients.count + end + def test_finding assert_equal 2, Firm.find(:first).clients.length end @@ -242,6 +248,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, grouped_clients_of_firm1.size end + def test_find_scoped_grouped + assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size + assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length + assert_equal 2, companies(:first_firm).clients_grouped_by_name.size + assert_equal 2, companies(:first_firm).clients_grouped_by_name.length + end + def test_adding force_signal37_to_load_all_clients_of_firm natural = Client.new("name" => "Natural Company") @@ -378,7 +391,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase company = companies(:first_firm) new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } assert !company.clients_of_firm.loaded? - + assert_equal "Another Client", new_client.name assert new_client.new_record? assert_equal new_client, company.clients_of_firm.last @@ -410,7 +423,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many company = companies(:first_firm) new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } - + assert_equal 2, new_clients.size company.name += '-changed' assert_queries(3) { assert company.save } @@ -649,10 +662,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_creation_respects_hash_condition ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build - + assert ms_client.save assert_equal 'Microsoft', ms_client.name - + another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create assert !another_ms_client.new_record? @@ -824,6 +837,22 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids end + def test_get_ids_for_loaded_associations + company = companies(:first_firm) + company.clients(true) + assert_queries(0) do + company.client_ids + company.client_ids + end + end + + def test_get_ids_for_unloaded_associations_does_not_load_them + company = companies(:first_firm) + assert !company.clients.loaded? + assert_equal [companies(:first_client).id, companies(:second_client).id], company.client_ids + assert !company.clients.loaded? + end + def test_assign_ids firm = Firm.new("name" => "Apple") firm.client_ids = [companies(:first_client).id, companies(:second_client).id] @@ -894,7 +923,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 4, authors(:david).limited_comments.find(:all, :conditions => "comments.type = 'SpecialComment'", :limit => 9_000).length assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length end - + def test_find_all_include_over_the_same_table_for_through assert_equal 2, people(:michael).posts.find(:all, :include => :people).length end @@ -931,13 +960,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_include_loads_collection_if_target_uses_finder_sql firm = companies(:first_firm) client = firm.clients_using_sql.first - + firm.reload assert ! firm.clients_using_sql.loaded? assert firm.clients_using_sql.include?(client) assert firm.clients_using_sql.loaded? end - + def test_include_returns_false_for_non_matching_record_to_verify_scoping firm = companies(:first_firm) diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index d51a3c7e1c..0be050ec81 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -196,4 +196,28 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # due to Unknown column 'comments.id' assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog') end + + def test_count_with_include_should_alias_join_table + assert_equal 2, people(:michael).posts.count(:include => :readers) + end + + def test_get_ids + assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort + end + + def test_get_ids_for_loaded_associations + person = people(:michael) + person.posts(true) + assert_queries(0) do + person.post_ids + person.post_ids + end + end + + def test_get_ids_for_unloaded_associations_does_not_load_them + person = people(:michael) + assert !person.posts.loaded? + assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort + assert !person.posts.loaded? + end 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 b61a3711e3..77e3cb1776 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -101,4 +101,13 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase assert_equal clubs(:crazy_club), members[0].sponsor_club end + def test_uninitialized_has_one_through_should_return_nil_for_unsaved_record + assert_nil Member.new.club + end + + def test_assigning_association_correctly_assigns_target + new_member = Member.create(:name => "Chris") + new_member.club = new_club = Club.create(:name => "LRUG") + assert_equal new_club, new_member.club.target + end end diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 0b2731ecd7..cde451de0e 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -182,119 +182,31 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_nil p.author.reset end - def test_reload_returns_assocition - david = developers(:david) - assert_nothing_raised do - assert_equal david.projects, david.projects.reload.reload - end - end - - def test_belongs_to_mass_assignment - post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } - author_attributes = { :name => 'David Dollar' } - - assert_no_difference 'Author.count' do - assert_raise(ActiveRecord::AssociationTypeMismatch) do - Post.create(post_attributes.merge({:author => author_attributes})) - end - end - - assert_difference 'Author.count' do - post = Post.create(post_attributes.merge({:creatable_author => author_attributes})) - assert_equal post.creatable_author.name, author_attributes[:name] - end - end - - def test_has_one_mass_assignment - post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } - comment_attributes = { :body => 'Setter Takes Hash' } - - assert_no_difference 'Comment.count' do - assert_raise(ActiveRecord::AssociationTypeMismatch) do - Post.create(post_attributes.merge({:uncreatable_comment => comment_attributes})) - end - end + def test_reset_loads_association_next_time + welcome = posts(:welcome) + david = authors(:david) + author_assoc = welcome.author - assert_difference 'Comment.count' do - post = Post.create(post_attributes.merge({:creatable_comment => comment_attributes})) - assert_equal post.creatable_comment.body, comment_attributes[:body] - end + assert_equal david, welcome.author # So we can be sure the test works correctly + author_assoc.reset + assert !author_assoc.loaded? + assert_nil author_assoc.target + assert_equal david, welcome.author end - def test_has_many_mass_assignment - post = posts(:welcome) - post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } - comment_attributes = { :body => 'Setter Takes Hash' } - - assert_no_difference 'Comment.count' do - assert_raise(ActiveRecord::AssociationTypeMismatch) do - Post.create(post_attributes.merge({:comments => [comment_attributes]})) - end - assert_raise(ActiveRecord::AssociationTypeMismatch) do - post.comments << comment_attributes - end - end - - assert_difference 'Comment.count' do - post = Post.create(post_attributes.merge({:creatable_comments => [comment_attributes]})) - assert_equal post.creatable_comments.last.body, comment_attributes[:body] - end - - assert_difference 'Comment.count' do - post.creatable_comments << comment_attributes - assert_equal post.comments.last.body, comment_attributes[:body] + def test_assigning_association_id_after_reload + welcome = posts(:welcome) + welcome.reload + assert_nothing_raised do + welcome.author_id = authors(:david).id end - - post.creatable_comments = [comment_attributes, comment_attributes] - assert_equal post.creatable_comments.count, 2 end - def test_has_and_belongs_to_many_mass_assignment - post = posts(:welcome) - post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } - category_attributes = { :name => 'Accessible Association', :type => 'Category' } - - assert_no_difference 'Category.count' do - assert_raise(ActiveRecord::AssociationTypeMismatch) do - Post.create(post_attributes.merge({:categories => [category_attributes]})) - end - assert_raise(ActiveRecord::AssociationTypeMismatch) do - post.categories << category_attributes - end - end - - assert_difference 'Category.count' do - post = Post.create(post_attributes.merge({:creatable_categories => [category_attributes]})) - assert_equal post.creatable_categories.last.name, category_attributes[:name] - end - - assert_difference 'Category.count' do - post.creatable_categories << category_attributes - assert_equal post.creatable_categories.last.name, category_attributes[:name] + def test_reload_returns_assocition + david = developers(:david) + assert_nothing_raised do + assert_equal david.projects, david.projects.reload.reload end - - post.creatable_categories = [category_attributes, category_attributes] - assert_equal post.creatable_categories.count, 2 - end - - def test_association_proxy_setter_can_take_hash - special_comment_attributes = { :body => 'Setter Takes Hash' } - - post = posts(:welcome) - post.creatable_comment = { :body => 'Setter Takes Hash' } - - assert_equal post.creatable_comment.body, special_comment_attributes[:body] - end - - def test_association_collection_can_take_hash - post_attributes = { :title => 'Setter Takes', :body => 'Hash' } - david = authors(:david) - - post = (david.posts << post_attributes).last - assert_equal post.title, post_attributes[:title] - - david.posts = [post_attributes, post_attributes] - assert_equal david.posts.count, 2 end def setup_dangling_association diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 7999e29264..ce293a469e 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -1,5 +1,6 @@ require "cases/helper" require 'models/topic' +require 'models/minimalistic' class AttributeMethodsTest < ActiveRecord::TestCase fixtures :topics @@ -219,6 +220,14 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end + def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable + Topic.skip_time_zone_conversion_for_attributes = [:field_a] + Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b] + + assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes + assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes + end + private def time_related_columns_on_topic Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index c8111358e3..aebcca634c 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -76,7 +76,7 @@ class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base end class BasicsTest < ActiveRecord::TestCase - fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories + fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts def test_table_exists assert !NonExistentTable.table_exists? @@ -664,10 +664,21 @@ class BasicsTest < ActiveRecord::TestCase end end - def test_update_all_ignores_order_limit_from_association - author = Author.find(1) + def test_update_all_ignores_order_without_limit_from_association + author = authors(:david) assert_nothing_raised do - assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all("body = 'bulk update!'") + assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ]) + end + end + + def test_update_all_with_order_and_limit_updates_subset_only + author = authors(:david) + assert_nothing_raised do + assert_equal 1, author.posts_sorted_by_id_limited.size + assert_equal 2, author.posts_sorted_by_id_limited.find(:all, :limit => 2).size + assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ]) + assert_equal "bulk update!", posts(:welcome).body + assert_not_equal "bulk update!", posts(:thinking).body end end @@ -880,7 +891,7 @@ class BasicsTest < ActiveRecord::TestCase def test_mass_assignment_protection_against_class_attribute_writers [:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :colorize_logging, - :default_timezone, :allow_concurrency, :schema_format, :verification_timeout, :lock_optimistically, :record_timestamps].each do |method| + :default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method| assert Task.respond_to?(method) assert Task.respond_to?("#{method}=") assert Task.new.respond_to?(method) @@ -1073,6 +1084,24 @@ class BasicsTest < ActiveRecord::TestCase Time.zone = nil Topic.skip_time_zone_conversion_for_attributes = [] end + + def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion + ActiveRecord::Base.time_zone_aware_attributes = true + ActiveRecord::Base.default_timezone = :utc + Time.zone = ActiveSupport::TimeZone[-28800] + attributes = { + "bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1", + "bonus_time(4i)" => "16", "bonus_time(5i)" => "24" + } + topic = Topic.find(1) + topic.attributes = attributes + assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time + assert topic.bonus_time.utc? + ensure + ActiveRecord::Base.time_zone_aware_attributes = false + ActiveRecord::Base.default_timezone = :local + Time.zone = nil + end def test_multiparameter_attributes_on_time_with_empty_seconds attributes = { diff --git a/activerecord/test/cases/connection_test_mysql.rb b/activerecord/test/cases/connection_test_mysql.rb index 1adbf18e73..40ddcf5420 100644 --- a/activerecord/test/cases/connection_test_mysql.rb +++ b/activerecord/test/cases/connection_test_mysql.rb @@ -24,7 +24,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase assert @connection.active? @connection.update('set @@wait_timeout=1') sleep 2 - @connection.verify!(0) + @connection.verify! assert @connection.active? end end diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index 3473b846a0..ee84cb8af8 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -19,6 +19,37 @@ class DefaultTest < ActiveRecord::TestCase end if current_adapter?(:MysqlAdapter) + + #MySQL 5 and higher is quirky with not null text/blob columns. + #With MySQL Text/blob columns cannot have defaults. If the column is not null MySQL will report that the column has a null default + #but it behaves as though the column had a default of '' + def test_mysql_text_not_null_defaults + klass = Class.new(ActiveRecord::Base) + klass.table_name = 'test_mysql_text_not_null_defaults' + klass.connection.create_table klass.table_name do |t| + t.column :non_null_text, :text, :null => false + t.column :non_null_blob, :blob, :null => false + t.column :null_text, :text, :null => true + t.column :null_blob, :blob, :null => true + end + assert_equal '', klass.columns_hash['non_null_blob'].default + assert_equal '', klass.columns_hash['non_null_text'].default + + assert_equal nil, klass.columns_hash['null_blob'].default + assert_equal nil, klass.columns_hash['null_text'].default + + assert_nothing_raised do + instance = klass.create! + assert_equal '', instance.non_null_text + assert_equal '', instance.non_null_blob + assert_nil instance.null_text + assert_nil instance.null_blob + end + ensure + klass.connection.drop_table(klass.table_name) rescue nil + end + + # MySQL uses an implicit default 0 rather than NULL unless in strict mode. # We use an implicit NULL so schema.rb is compatible with other databases. def test_mysql_integer_not_null_defaults diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index feb47a15a8..39d38c4e1e 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -45,6 +45,19 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.catchphrase_change end + def test_aliased_attribute_changes + # the actual attribute here is name, title is an + # alias setup via alias_attribute + parrot = Parrot.new + assert !parrot.title_changed? + assert_nil parrot.title_change + + parrot.name = 'Sam' + assert parrot.title_changed? + assert_nil parrot.title_was + assert_equal parrot.name_change, parrot.title_change + end + def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank pirate = Pirate.new @@ -191,6 +204,42 @@ class DirtyTest < ActiveRecord::TestCase assert !pirate.changed? end + def test_reverted_changes_are_not_dirty + phrase = "shiver me timbers" + pirate = Pirate.create!(:catchphrase => phrase) + pirate.catchphrase = "*hic*" + assert pirate.changed? + pirate.catchphrase = phrase + assert !pirate.changed? + end + + def test_reverted_changes_are_not_dirty_after_multiple_changes + phrase = "shiver me timbers" + pirate = Pirate.create!(:catchphrase => phrase) + 10.times do |i| + pirate.catchphrase = "*hic*" * i + assert pirate.changed? + end + assert pirate.changed? + pirate.catchphrase = phrase + assert !pirate.changed? + end + + + def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back + pirate = Pirate.create!(:catchphrase => "Yar!") + + pirate.parrot_id = 1 + assert pirate.changed? + assert pirate.parrot_id_changed? + assert !pirate.catchphrase_changed? + + pirate.parrot_id = nil + assert !pirate.changed? + assert !pirate.parrot_id_changed? + assert !pirate.catchphrase_changed? + end + def test_save_should_store_serialized_attributes_even_with_partial_updates with_partial_updates(Topic) do topic = Topic.create!(:content => {:a => "a"}) diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 2ce49ed76f..cbdff382fe 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -169,6 +169,12 @@ class FinderTest < ActiveRecord::TestCase assert_equal("fixture_3", developers.first.name) end + def test_find_with_group + developers = Developer.find(:all, :group => "salary", :select => "salary") + assert_equal 4, developers.size + assert_equal 4, developers.map(&:salary).uniq.size + end + def test_find_with_entire_select_statement topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'" @@ -197,11 +203,11 @@ class FinderTest < ActiveRecord::TestCase first = Topic.find(:first, :conditions => "title = 'The First Topic!'") assert_nil(first) end - + def test_first assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title end - + def test_first_failing assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'") end @@ -297,7 +303,6 @@ class FinderTest < ActiveRecord::TestCase assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) } end - def test_condition_interpolation assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"]) assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"]) @@ -392,7 +397,7 @@ class FinderTest < ActiveRecord::TestCase Company.find(:first, :conditions => ["id=? AND name = ?", 2]) } assert_raises(ActiveRecord::PreparedStatementInvalid) { - Company.find(:first, :conditions => ["id=?", 2, 3, 4]) + Company.find(:first, :conditions => ["id=?", 2, 3, 4]) } end @@ -418,7 +423,7 @@ class FinderTest < ActiveRecord::TestCase def test_named_bind_variables assert_equal '1', bind(':a', :a => 1) # ' ruby-mode assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode - + assert_nothing_raised { bind("'+00:00'", :foo => "bar") } assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }]) @@ -455,6 +460,15 @@ class FinderTest < ActiveRecord::TestCase assert_equal ActiveRecord::Base.connection.quote(''), bind('?', '') end + def test_bind_chars + quoted_bambi = ActiveRecord::Base.connection.quote("Bambi") + quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi") + assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".chars) + assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".chars) + end + def test_bind_record o = Struct.new(:quoted_id).new(1) assert_equal '1', bind('?', o) @@ -589,6 +603,38 @@ class FinderTest < ActiveRecord::TestCase assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary") end + def test_find_last_by_one_attribute + assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title) + assert_nil Topic.find_last_by_title("A title with no matches") + end + + def test_find_last_by_one_attribute_caches_dynamic_finder + # ensure this test can run independently of order + class << Topic; self; end.send(:remove_method, :find_last_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } + assert !Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } + t = Topic.find_last_by_title(Topic.last.title) + assert Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } + end + + def test_find_last_by_invalid_method_syntax + assert_raises(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") } + assert_raises(NoMethodError) { Topic.find_last_by_title?("The First Topic") } + end + + def test_find_last_by_one_attribute_with_several_options + assert_equal accounts(:signals37), Account.find_last_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3]) + end + + def test_find_last_by_one_missing_attribute + assert_raises(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") } + end + + def test_find_last_by_two_attributes + topic = Topic.last + assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name) + assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous") + end + def test_find_all_by_one_attribute topics = Topic.find_all_by_content("Have a nice day") assert_equal 2, topics.size @@ -782,7 +828,7 @@ class FinderTest < ActiveRecord::TestCase assert c.valid? assert !c.new_record? end - + def test_dynamic_find_or_initialize_from_one_attribute_caches_method class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index f30d58546e..f7bdac8013 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -46,3 +46,17 @@ end class << ActiveRecord::Base public :with_scope, :with_exclusive_scope end + +unless ENV['FIXTURE_DEBUG'] + module Test #:nodoc: + module Unit #:nodoc: + class << TestCase #:nodoc: + def try_to_load_dependency_with_silence(*args) + ActiveRecord::Base.logger.silence { try_to_load_dependency_without_silence(*args)} + end + + alias_method_chain :try_to_load_dependency, :silence + end + end + end +end
\ No newline at end of file diff --git a/activerecord/test/cases/i18n_test.rb b/activerecord/test/cases/i18n_test.rb index 06036733f5..ea06e377e3 100644 --- a/activerecord/test/cases/i18n_test.rb +++ b/activerecord/test/cases/i18n_test.rb @@ -5,42 +5,37 @@ require 'models/reply' class ActiveRecordI18nTests < Test::Unit::TestCase def setup - reset_translations + I18n.backend = I18n::Backend::Simple.new end def test_translated_model_attributes - I18n.store_translations 'en-US', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } + I18n.backend.store_translations 'en-US', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } assert_equal 'topic title attribute', Topic.human_attribute_name('title') end def test_translated_model_attributes_with_sti - I18n.store_translations 'en-US', :activerecord => {:attributes => {:reply => {:title => 'reply title attribute'} } } + I18n.backend.store_translations 'en-US', :activerecord => {:attributes => {:reply => {:title => 'reply title attribute'} } } assert_equal 'reply title attribute', Reply.human_attribute_name('title') end def test_translated_model_attributes_with_sti_fallback - I18n.store_translations 'en-US', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } + I18n.backend.store_translations 'en-US', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } assert_equal 'topic title attribute', Reply.human_attribute_name('title') end def test_translated_model_names - I18n.store_translations 'en-US', :activerecord => {:models => {:topic => 'topic model'} } + I18n.backend.store_translations 'en-US', :activerecord => {:models => {:topic => 'topic model'} } assert_equal 'topic model', Topic.human_name end def test_translated_model_names_with_sti - I18n.store_translations 'en-US', :activerecord => {:models => {:reply => 'reply model'} } + I18n.backend.store_translations 'en-US', :activerecord => {:models => {:reply => 'reply model'} } assert_equal 'reply model', Reply.human_name end def test_translated_model_names_with_sti_fallback - I18n.store_translations 'en-US', :activerecord => {:models => {:topic => 'topic model'} } + I18n.backend.store_translations 'en-US', :activerecord => {:models => {:topic => 'topic model'} } assert_equal 'topic model', Reply.human_name end - - private - def reset_translations - I18n.backend = I18n::Backend::Simple.new - end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 4fd38bfbc9..a39415618d 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -193,7 +193,7 @@ class InheritanceTest < ActiveRecord::TestCase def test_eager_load_belongs_to_primary_key_quoting con = Account.connection - assert_sql(/\(#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} IN \(1\)\)/) do + assert_sql(/\(#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} = 1\)/) do Account.find(1, :include => :firm) end end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 701187223f..0a14b1d906 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -210,13 +210,6 @@ unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :OpenBaseAdapter) def setup # Avoid introspection queries during tests. Person.columns; Reader.columns - - @allow_concurrency = ActiveRecord::Base.allow_concurrency - ActiveRecord::Base.allow_concurrency = true - end - - def teardown - ActiveRecord::Base.allow_concurrency = @allow_concurrency end # Test typical find. @@ -264,6 +257,8 @@ unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :OpenBaseAdapter) end if current_adapter?(:PostgreSQLAdapter, :OracleAdapter) + use_concurrent_connections + def test_no_locks_no_wait first, second = duel { Person.find 1 } assert first.end > second.end diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index ee66ac948d..af6fcd32ad 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'models/author' require 'models/developer' require 'models/project' require 'models/comment' @@ -6,7 +7,7 @@ require 'models/post' require 'models/category' class MethodScopingTest < ActiveRecord::TestCase - fixtures :developers, :projects, :comments, :posts, :developers_projects + fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects def test_set_conditions Developer.with_scope(:find => { :conditions => 'just a test...' }) do @@ -97,6 +98,46 @@ class MethodScopingTest < ActiveRecord::TestCase assert_equal developers(:david).attributes, scoped_developers.first.attributes end + def test_scoped_find_using_new_style_joins + scoped_developers = Developer.with_scope(:find => { :joins => :projects }) do + Developer.find(:all, :conditions => 'projects.id = 2') + end + assert scoped_developers.include?(developers(:david)) + assert !scoped_developers.include?(developers(:jamis)) + assert_equal 1, scoped_developers.size + assert_equal developers(:david).attributes, scoped_developers.first.attributes + end + + def test_scoped_find_merges_old_style_joins + scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id ' }) do + Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1') + end + assert scoped_authors.include?(authors(:david)) + assert !scoped_authors.include?(authors(:mary)) + assert_equal 1, scoped_authors.size + assert_equal authors(:david).attributes, scoped_authors.first.attributes + end + + def test_scoped_find_merges_new_style_joins + scoped_authors = Author.with_scope(:find => { :joins => :posts }) do + Author.find(:all, :select => 'DISTINCT authors.*', :joins => :comments, :conditions => 'comments.id = 1') + end + assert scoped_authors.include?(authors(:david)) + assert !scoped_authors.include?(authors(:mary)) + assert_equal 1, scoped_authors.size + assert_equal authors(:david).attributes, scoped_authors.first.attributes + end + + def test_scoped_find_merges_new_and_old_style_joins + scoped_authors = Author.with_scope(:find => { :joins => :posts }) do + Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1') + end + assert scoped_authors.include?(authors(:david)) + assert !scoped_authors.include?(authors(:mary)) + assert_equal 1, scoped_authors.size + assert_equal authors(:david).attributes, scoped_authors.first.attributes + end + def test_scoped_count_include # with the include, will retrieve only developers for the given project Developer.with_scope(:find => { :include => :projects }) do @@ -152,7 +193,7 @@ class MethodScopingTest < ActiveRecord::TestCase end class NestedScopingTest < ActiveRecord::TestCase - fixtures :developers, :projects, :comments, :posts + fixtures :authors, :developers, :projects, :comments, :posts def test_merge_options Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do @@ -357,6 +398,42 @@ class NestedScopingTest < ActiveRecord::TestCase assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods') end end + + def test_nested_scoped_find_merges_old_style_joins + scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id' }) do + Author.with_scope(:find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do + Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1') + end + end + assert scoped_authors.include?(authors(:david)) + assert !scoped_authors.include?(authors(:mary)) + assert_equal 1, scoped_authors.size + assert_equal authors(:david).attributes, scoped_authors.first.attributes + end + + def test_nested_scoped_find_merges_new_style_joins + scoped_authors = Author.with_scope(:find => { :joins => :posts }) do + Author.with_scope(:find => { :joins => :comments }) do + Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1') + end + end + assert scoped_authors.include?(authors(:david)) + assert !scoped_authors.include?(authors(:mary)) + assert_equal 1, scoped_authors.size + assert_equal authors(:david).attributes, scoped_authors.first.attributes + end + + def test_nested_scoped_find_merges_new_and_old_style_joins + scoped_authors = Author.with_scope(:find => { :joins => :posts }) do + Author.with_scope(:find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do + Author.find(:all, :select => 'DISTINCT authors.*', :joins => '', :conditions => 'comments.id = 1') + end + end + assert scoped_authors.include?(authors(:david)) + assert !scoped_authors.include?(authors(:mary)) + assert_equal 1, scoped_authors.size + assert_equal authors(:david).attributes, scoped_authors.first.attributes + end end class HasManyScopingTest< ActiveRecord::TestCase diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index c1a8da2270..ac44dd7ffe 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -1133,7 +1133,11 @@ if ActiveRecord::Base.connection.supports_migrations? columns = Person.connection.columns(:binary_testings) data_column = columns.detect { |c| c.name == "data" } - assert_nil data_column.default + if current_adapter?(:MysqlAdapter) + assert_equal '', data_column.default + else + assert_nil data_column.default + end Person.connection.drop_table :binary_testings rescue nil end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 6f6ea1cbe9..444debd255 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -249,7 +249,26 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal Topic.base.select(&:approved), Topic.base.find_all(&:approved) end + def test_rand_should_select_a_random_object_from_proxy + assert Topic.approved.rand.is_a?(Topic) + end + def test_should_use_where_in_query_for_named_scope assert_equal Developer.find_all_by_name('Jamis'), Developer.find_all_by_id(Developer.jamises) end + + def test_size_should_use_count_when_results_are_not_loaded + topics = Topic.base + assert_queries(1) do + assert_sql(/COUNT/i) { topics.size } + end + end + + def test_size_should_use_length_when_results_are_loaded + topics = Topic.base + topics.reload # force load + assert_no_queries do + topics.size # use loaded (no query) + end + end end diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb new file mode 100644 index 0000000000..078ca1d679 --- /dev/null +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -0,0 +1,87 @@ +require "cases/helper" + +class PooledConnectionsTest < ActiveRecord::TestCase + def setup + super + @connection = ActiveRecord::Base.remove_connection + end + + def teardown + ActiveRecord::Base.clear_all_connections! + ActiveRecord::Base.establish_connection(@connection) + super + end + + def checkout_connections + ActiveRecord::Base.establish_connection(@connection.merge({:pool => 2, :wait_timeout => 0.3})) + @connections = [] + @timed_out = 0 + + 4.times do + Thread.new do + begin + @connections << ActiveRecord::Base.connection_pool.checkout + rescue ActiveRecord::ConnectionTimeoutError + @timed_out += 1 + end + end.join + end + end + + def test_pooled_connection_checkout + checkout_connections + assert_equal @connections.length, 2 + assert_equal @timed_out, 2 + end + + def checkout_checkin_connections(pool_size, threads) + ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :wait_timeout => 0.5})) + @connection_count = 0 + @timed_out = 0 + threads.times do + Thread.new do + begin + conn = ActiveRecord::Base.connection_pool.checkout + sleep 0.1 + ActiveRecord::Base.connection_pool.checkin conn + @connection_count += 1 + rescue ActiveRecord::ConnectionTimeoutError + @timed_out += 1 + end + end.join + end + end + + def test_pooled_connection_checkin_one + checkout_checkin_connections 1, 2 + assert_equal 2, @connection_count + assert_equal 0, @timed_out + end + + def test_pooled_connection_checkin_two + checkout_checkin_connections 2, 3 + assert_equal 3, @connection_count + assert_equal 0, @timed_out + end + + def test_pooled_connection_checkout_existing_first + ActiveRecord::Base.establish_connection(@connection.merge({:pool => 1})) + conn_pool = ActiveRecord::Base.connection_pool + conn = conn_pool.checkout + conn_pool.checkin(conn) + conn = conn_pool.checkout + assert ActiveRecord::ConnectionAdapters::AbstractAdapter === conn + conn_pool.checkin(conn) + end +end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name + +class AllowConcurrencyDeprecatedTest < ActiveRecord::TestCase + def test_allow_concurrency_is_deprecated + assert_deprecated('ActiveRecord::Base.allow_concurrency') do + ActiveRecord::Base.allow_concurrency + end + assert_deprecated('ActiveRecord::Base.allow_concurrency=') do + ActiveRecord::Base.allow_concurrency = true + end + end +end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 4b86e32dbf..e339ef41ab 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -160,8 +160,8 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 24, Firm.reflect_on_all_associations.size - assert_equal 18, Firm.reflect_on_all_associations(:has_many).size + assert_equal 26, Firm.reflect_on_all_associations.size + assert_equal 20, Firm.reflect_on_all_associations(:has_many).size assert_equal 6, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb new file mode 100644 index 0000000000..0106572ced --- /dev/null +++ b/activerecord/test/cases/sanitize_test.rb @@ -0,0 +1,25 @@ +require "cases/helper" +require 'models/binary' + +class SanitizeTest < ActiveRecord::TestCase + def setup + end + + def test_sanitize_sql_array_handles_string_interpolation + quoted_bambi = ActiveRecord::Base.connection.quote_string("Bambi") + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi"]) + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi".chars]) + quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote_string("Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper"]) + assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper".chars]) + end + + def test_sanitize_sql_array_handles_bind_variables + quoted_bambi = ActiveRecord::Base.connection.quote("Bambi") + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi"]) + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi".chars]) + quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper"]) + assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper".chars]) + end +end diff --git a/activerecord/test/cases/schema_authorization_test_postgresql.rb b/activerecord/test/cases/schema_authorization_test_postgresql.rb index 7a0796ef53..ba7754513d 100644 --- a/activerecord/test/cases/schema_authorization_test_postgresql.rb +++ b/activerecord/test/cases/schema_authorization_test_postgresql.rb @@ -18,8 +18,8 @@ class SchemaAuthorizationTest < ActiveRecord::TestCase @connection.execute "SET search_path TO '$user',public" set_session_auth USERS.each do |u| - @connection.execute "CREATE USER #{u}" - @connection.execute "CREATE SCHEMA AUTHORIZATION #{u}" + @connection.execute "CREATE USER #{u}" rescue nil + @connection.execute "CREATE SCHEMA AUTHORIZATION #{u}" rescue nil set_session_auth u @connection.execute "CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" @connection.execute "INSERT INTO #{TABLE_NAME} (name) VALUES ('#{u}')" diff --git a/activerecord/test/cases/threaded_connections_test.rb b/activerecord/test/cases/threaded_connections_test.rb deleted file mode 100644 index 28f8302367..0000000000 --- a/activerecord/test/cases/threaded_connections_test.rb +++ /dev/null @@ -1,48 +0,0 @@ -require "cases/helper" -require 'models/topic' -require 'models/reply' - -unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name - class ThreadedConnectionsTest < ActiveRecord::TestCase - self.use_transactional_fixtures = false - - fixtures :topics - - def setup - @connection = ActiveRecord::Base.remove_connection - @connections = [] - @allow_concurrency = ActiveRecord::Base.allow_concurrency - end - - def teardown - # clear the connection cache - ActiveRecord::Base.send(:clear_all_cached_connections!) - # set allow_concurrency to saved value - ActiveRecord::Base.allow_concurrency = @allow_concurrency - # reestablish old connection - ActiveRecord::Base.establish_connection(@connection) - end - - def gather_connections(use_threaded_connections) - ActiveRecord::Base.allow_concurrency = use_threaded_connections - ActiveRecord::Base.establish_connection(@connection) - - 5.times do - Thread.new do - Topic.find :first - @connections << ActiveRecord::Base.active_connections.values.first - end.join - end - end - - def test_threaded_connections - gather_connections(true) - assert_equal @connections.uniq.length, 5 - end - - def test_unthreaded_connections - gather_connections(false) - assert_equal @connections.uniq.length, 1 - end - end -end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index af3ee6ddba..b12ec36455 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -216,6 +216,7 @@ class TransactionTest < ActiveRecord::TestCase uses_mocha 'mocking connection.commit_db_transaction' do def test_rollback_when_commit_raises Topic.connection.expects(:begin_db_transaction) + Topic.connection.expects(:transaction_active?).returns(true) if current_adapter?(:PostgreSQLAdapter) Topic.connection.expects(:commit_db_transaction).raises('OH NOES') Topic.connection.expects(:rollback_db_transaction) @@ -283,16 +284,7 @@ end if current_adapter?(:PostgreSQLAdapter) class ConcurrentTransactionTest < TransactionTest - def setup - @allow_concurrency = ActiveRecord::Base.allow_concurrency - ActiveRecord::Base.allow_concurrency = true - super - end - - def teardown - super - ActiveRecord::Base.allow_concurrency = @allow_concurrency - end + use_concurrent_connections # This will cause transactions to overlap and fail unless they are performed on # separate database connections. diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 43592bcee3..42246f18b6 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -6,12 +6,16 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def setup reset_callbacks Topic @topic = Topic.new + @old_load_path, @old_backend = I18n.load_path, I18n.backend + I18n.load_path.clear + I18n.backend = I18n::Backend::Simple.new I18n.backend.store_translations('en-US', :activerecord => {:errors => {:messages => {:custom => nil}}}) end def teardown reset_callbacks Topic - I18n.load_translations File.dirname(__FILE__) + '/../../lib/active_record/locale/en-US.yml' + I18n.load_path.replace @old_load_path + I18n.backend = @old_backend end def unique_topic @@ -40,6 +44,32 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end end + def test_percent_s_interpolation_syntax_in_error_messages_still_works + ActiveSupport::Deprecation.silence do + result = I18n.t :does_not_exist, :default => "%s interpolation syntax is deprecated", :value => 'this' + assert_equal result, "this interpolation syntax is deprecated" + end + end + + def test_percent_s_interpolation_syntax_in_error_messages_is_deprecated + assert_deprecated('using %s in messages') do + I18n.t :does_not_exist, :default => "%s interpolation syntax is deprected", :value => 'this' + end + end + + def test_percent_d_interpolation_syntax_in_error_messages_still_works + ActiveSupport::Deprecation.silence do + result = I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprecated", :count => 2 + assert_equal result, "2 interpolation syntaxes are deprecated" + end + end + + def test_percent_d_interpolation_syntax_in_error_messages_is_deprecated + assert_deprecated('using %d in messages') do + I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprected", :count => 2 + end + end + # ActiveRecord::Errors uses_mocha 'ActiveRecord::Errors' do @@ -675,6 +705,38 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase replied_topic.valid? assert_equal 'global message', replied_topic.errors.on(:replies) end + + def test_validations_with_message_symbol_must_translate + I18n.backend.store_translations 'en-US', :activerecord => {:errors => {:messages => {:custom_error => "I am a custom error"}}} + Topic.validates_presence_of :title, :message => :custom_error + @topic.title = nil + @topic.valid? + assert_equal "I am a custom error", @topic.errors.on(:title) + end + + def test_validates_with_message_symbol_must_translate_per_attribute + I18n.backend.store_translations 'en-US', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:custom_error => "I am a custom error"}}}}}} + Topic.validates_presence_of :title, :message => :custom_error + @topic.title = nil + @topic.valid? + assert_equal "I am a custom error", @topic.errors.on(:title) + end + + def test_validates_with_message_symbol_must_translate_per_model + I18n.backend.store_translations 'en-US', :activerecord => {:errors => {:models => {:topic => {:custom_error => "I am a custom error"}}}} + Topic.validates_presence_of :title, :message => :custom_error + @topic.title = nil + @topic.valid? + assert_equal "I am a custom error", @topic.errors.on(:title) + end + + def test_validates_with_message_string + Topic.validates_presence_of :title, :message => "I am a custom error" + @topic.title = nil + @topic.valid? + assert_equal "I am a custom error", @topic.errors.on(:title) + end + end class ActiveRecordValidationsGenerateMessageI18nTests < Test::Unit::TestCase @@ -855,4 +917,5 @@ class ActiveRecordValidationsGenerateMessageI18nTests < Test::Unit::TestCase def test_generate_message_even_with_default_message assert_equal "must be even", @topic.errors.generate_message(:title, :even, :default => nil, :value => 'title', :count => 10) end + end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index a40bda2533..c049659327 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -364,6 +364,13 @@ class ValidationsTest < ActiveRecord::TestCase assert t2.save, "Should now save t2 as unique" end + def test_validates_uniquness_with_newline_chars + Topic.validates_uniqueness_of(:title, :case_sensitive => false) + + t = Topic.new("title" => "new\nline") + assert t.save, "Should save t as unique" + end + def test_validate_uniqueness_with_scope Reply.validates_uniqueness_of(:content, :scope => "parent_id") @@ -451,6 +458,18 @@ class ValidationsTest < ActiveRecord::TestCase t2.title = nil assert t2.valid?, "should validate with nil" assert t2.save, "should save with nil" + + with_kcode('UTF8') do + t_utf8 = Topic.new("title" => "Я тоже уникальный!") + assert t_utf8.save, "Should save t_utf8 as unique" + + # If database hasn't UTF-8 character set, this test fails + if Topic.find(t_utf8, :select => 'LOWER(title) AS title').title == "я тоже уникальный!" + t2_utf8 = Topic.new("title" => "я тоже УНИКАЛЬНЫЙ!") + assert !t2_utf8.valid?, "Shouldn't be valid" + assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique" + end + end end def test_validate_case_sensitive_uniqueness @@ -593,7 +612,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validate_format_with_formatted_message - Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %s") + Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}") t = Topic.create(:title => 'Invalid title') assert_equal "can't be Invalid title", t.errors.on(:title) end @@ -654,7 +673,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_inclusion_of_with_formatted_message - Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %s is not in the list" ) + Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {{value}} is not in the list" ) assert Topic.create("title" => "a", "content" => "abc").valid? @@ -679,7 +698,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_exclusion_of_with_formatted_message - Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %s is restricted" ) + Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" ) assert Topic.create("title" => "something", "content" => "abc") @@ -779,7 +798,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_optionally_validates_length_of_using_within_on_create - Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %d" + Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}" t = Topic.create("title" => "thisisnotvalid", "content" => "whatever") assert !t.save @@ -800,7 +819,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_optionally_validates_length_of_using_within_on_update - Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %d" + Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}" t = Topic.create("title" => "vali", "content" => "whatever") assert !t.save @@ -863,7 +882,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_validates_length_with_globally_modified_error_message ActiveSupport::Deprecation.silence do - ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre %d' + ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre {{count}}' end Topic.validates_length_of :title, :minimum => 10 t = Topic.create(:title => 'too short') @@ -907,7 +926,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_minimum_with_message - Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %d" ) + Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" ) t = Topic.create("title" => "uhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -915,7 +934,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_minimum_with_too_short - Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %d" ) + Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" ) t = Topic.create("title" => "uhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -923,7 +942,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_maximum_with_message - Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %d" ) + Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -931,7 +950,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_maximum_with_too_long - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d" ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -939,7 +958,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_is_with_message - Topic.validates_length_of( :title, :is=>5, :message=>"boo %d" ) + Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -947,7 +966,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_is_with_wrong_length - Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %d" ) + Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1013,7 +1032,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_optionally_validates_length_of_using_within_on_create_utf8 with_kcode('UTF8') do - Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %d" + Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}" t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever") assert !t.save @@ -1036,7 +1055,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_optionally_validates_length_of_using_within_on_update_utf8 with_kcode('UTF8') do - Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %d" + Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}" t = Topic.create("title" => "一二三4", "content" => "whatever") assert !t.save @@ -1071,7 +1090,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_with_block - Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %d words.", + Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.", :tokenizer => lambda {|str| str.scan(/\w+/) } t = Topic.create!(:content => "this content should be long enough") assert t.valid? @@ -1222,7 +1241,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_method_true # When the method returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1231,7 +1250,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_method_true # When the method returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => :condition_is_true ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1239,7 +1258,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_method_false # When the method returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true_but_its_not ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true_but_its_not ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1247,7 +1266,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_method_false # When the method returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => :condition_is_true_but_its_not ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1256,7 +1275,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_string_true # When the evaluated string returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "a = 1; a == 1" ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1265,7 +1284,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_string_true # When the evaluated string returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => "a = 1; a == 1" ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1273,7 +1292,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_string_false # When the evaluated string returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "false") + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "false") t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1281,7 +1300,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_string_false # When the evaluated string returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => "false") + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "false") t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1290,7 +1309,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_block_true # When the block returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => Proc.new { |r| r.content.size > 4 } ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? @@ -1300,7 +1319,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_block_true # When the block returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => Proc.new { |r| r.content.size > 4 } ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? @@ -1309,7 +1328,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_block_false # When the block returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => Proc.new { |r| r.title != "uhohuhoh"} ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? @@ -1318,7 +1337,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_block_false # When the block returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => Proc.new { |r| r.title != "uhohuhoh"} ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? @@ -1495,13 +1514,13 @@ class ValidatesNumericalityTest < ActiveRecord::TestCase end def test_validates_numericality_with_numeric_message - Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %d" + Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}" topic = Topic.new("title" => "numeric test", "approved" => 10) assert !topic.valid? assert_equal "smaller than 4", topic.errors.on(:approved) - Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %d" + Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {{count}}" topic = Topic.new("title" => "numeric test", "approved" => 1) assert !topic.valid? |