diff options
Diffstat (limited to 'activerecord/test/cases')
33 files changed, 492 insertions, 106 deletions
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 0de3786eb8..6c345cd8cc 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -188,6 +188,12 @@ module ActiveRecord assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"]) end + def test_raise_error_when_cannot_translate_exception + assert_raise TypeError do + @connection.send(:log, nil) { @connection.execute(nil) } + end + end + private def insert(ctx, data) binds = data.map { |name, value| diff --git a/activerecord/test/cases/adapters/postgresql/sql_types_test.rb b/activerecord/test/cases/adapters/postgresql/sql_types_test.rb new file mode 100644 index 0000000000..d7d40f6385 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/sql_types_test.rb @@ -0,0 +1,18 @@ +require "cases/helper" + +class SqlTypesTest < ActiveRecord::TestCase + def test_binary_types + assert_equal 'bytea', type_to_sql(:binary, 100_000) + assert_raise ActiveRecord::ActiveRecordError do + type_to_sql :binary, 4294967295 + end + assert_equal 'text', type_to_sql(:text, 100_000) + assert_raise ActiveRecord::ActiveRecordError do + type_to_sql :text, 4294967295 + end + end + + def type_to_sql(*args) + ActiveRecord::Base.connection.type_to_sql(*args) + end +end diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb index 575b4806c1..74288a98d1 100644 --- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb @@ -57,6 +57,14 @@ class CopyTableTest < ActiveRecord::TestCase end end + def test_copy_table_with_unconventional_primary_key + test_copy_table('owners', 'owners_unconventional') do |from, to, options| + original_pk = @connection.primary_key('owners') + copied_pk = @connection.primary_key('owners_unconventional') + assert_equal original_pk, copied_pk + end + end + protected def copy_table(from, to, options = {}) @connection.copy_table(from, to, {:temporary => true}.merge(options)) diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index ec69a36174..614be8760a 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -157,7 +157,6 @@ module ActiveRecord binary = DualEncoding.new :name => 'いただきます!', :data => str binary.save! assert_equal str, binary.data - ensure if "<3".respond_to?(:encode) DualEncoding.connection.drop_table('dual_encodings') @@ -167,8 +166,9 @@ module ActiveRecord def test_type_cast_should_not_mutate_encoding return skip('only test encoding on 1.9') unless "<3".encoding_aware? - name = 'hello'.force_encoding(Encoding::ASCII_8BIT) - owner = Owner.create(:name => name) + name = 'hello'.force_encoding(Encoding::ASCII_8BIT) + Owner.create(:name => name) + assert_equal Encoding::ASCII_8BIT, name.encoding end diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index 588adc38e3..6556219205 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -11,23 +11,31 @@ if ActiveRecord::Base.connection.supports_migrations? def teardown @connection.drop_table :fruits rescue nil + @connection.drop_table :"_p_fruits_s_" rescue nil + @connection.drop_table :"_p_schema_migrations_s_" rescue nil end def test_schema_define - ActiveRecord::Schema.define(:version => 7) do - create_table :fruits do |t| - t.column :color, :string - t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle - t.column :texture, :string - t.column :flavor, :string - end - end + perform_schema_define! assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" } assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" } assert_equal 7, ActiveRecord::Migrator::current_version end + def test_schema_define_with_table_prefix_and_suffix + # Use shorter prefix and suffix as in Oracle database identifier cannot be larger than 30 characters + ActiveRecord::Base.table_name_prefix = '_p_' + ActiveRecord::Base.table_name_suffix = '_s_' + + perform_schema_define! + + assert_equal 7, ActiveRecord::Migrator::current_version + ensure + ActiveRecord::Base.table_name_prefix = '' + ActiveRecord::Base.table_name_suffix = '' + end + def test_schema_raises_an_error_for_invalid_column_type assert_raise NoMethodError do ActiveRecord::Schema.define(:version => 8) do @@ -39,4 +47,17 @@ if ActiveRecord::Base.connection.supports_migrations? end end + private + + def perform_schema_define! + ActiveRecord::Schema.define(:version => 7) do + create_table :fruits do |t| + t.column :color, :string + t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle + t.column :texture, :string + t.column :flavor, :string + end + end + end + end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index e7d1893ff3..c9b26895ae 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -14,6 +14,8 @@ require 'models/sponsor' require 'models/member' require 'models/essay' require 'models/toy' +require 'models/person' +require 'models/reader' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -66,7 +68,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_id_assignment apple = Firm.create("name" => "Apple") citibank = Account.create("credit_limit" => 10) - assert_raise(NoMethodError) { citibank.firm_id = apple } + citibank.firm_id = apple + assert_nil citibank.firm_id end def test_natural_assignment_with_primary_key @@ -544,6 +547,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal new_firm.name, "Apple" end + def test_attributes_are_set_without_error_when_initialized_from_belongs_to_association_with_array_in_where_clause + new_account = Account.where(:credit_limit => [ 50, 60 ]).new + assert_nil new_account.credit_limit + end + def test_reassigning_the_parent_id_updates_the_object client = companies(:second_client) @@ -710,4 +718,16 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal toy, sponsor.reload.sponsorable end + + def test_saving_nested_association + post1, post2 = Post.limit(2) + person = Person.new(:first_name => 'foo') + reader = Reader.new(:post => post1) + + reader.post_id = post2.id + person.readers = [reader] + + assert person.save + assert_equal reader.post_id, post2.id + end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index bf01b46852..42061d3d73 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -592,7 +592,6 @@ class EagerAssociationTest < ActiveRecord::TestCase # gets raw row hashes from the database and then instantiates them, this test ensures that # it only instantiates one actual object per record from the database. def test_has_and_belongs_to_many_should_not_instantiate_same_records_multiple_times - welcome = posts(:welcome) categories = Category.includes(:posts) general = categories.find { |c| c == categories(:general) } @@ -916,6 +915,12 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal 3, Developer.find(:all, :include => 'projects', :conditions => 'developers_projects.access_level = 1', :limit => 5).size end + def test_dont_create_temporary_active_record_instances + Developer.instance_count = 0 + developers = Developer.find(:all, :include => 'projects', :conditions => 'developers_projects.access_level = 1', :limit => 5).to_a + assert_equal developers.count, Developer.instance_count + end + def test_order_on_join_table_with_include_and_limit assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size end @@ -1107,4 +1112,17 @@ class EagerAssociationTest < ActiveRecord::TestCase Post.includes(:comments).order(nil).where(:comments => {:body => "Thank you for the welcome"}).first end end + + test "preloading does not cache has many association subset when preloaded with a through association" do + author = Author.order(:id).includes(:comments_with_order_and_conditions, :posts).first + assert_no_queries { assert_equal 2, author.comments_with_order_and_conditions.size } + assert_no_queries { assert_equal 5, author.posts.size, "should not cache a subset of the association" } + end + + test "preloading a through association twice does not reset it" do + members = Member.includes(:current_membership => :club).includes(:club).to_a + assert_no_queries { + assert_equal 3, members.map(&:current_membership).map(&:club).size + } + 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 ed4475770b..869ec1e4b8 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1697,6 +1697,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [tagging], post.taggings end + def test_build_with_polymotphic_has_many_does_not_allow_to_override_type_and_id + welcome = posts(:welcome) + tagging = welcome.taggings.build(:taggable_id => 99, :taggable_type => 'ShouldNotChange') + + assert_equal welcome.id, tagging.taggable_id + assert_equal 'Post', tagging.taggable_type + end + def test_dont_call_save_callbacks_twice_on_has_many firm = companies(:first_firm) contract = firm.contracts.create! 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 ffd7f4efa2..277a3bddaa 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -346,6 +346,17 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end end + def test_update_counter_caches_on_replace_association + post = posts(:welcome) + tag = post.tags.create!(:name => 'doomed') + tag.tagged_posts << posts(:thinking) + + tag.tagged_posts = [] + post.reload + + assert_equal(post.taggings.count, post.taggings_count) + end + def test_replace_association assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)} @@ -851,11 +862,6 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end end - def test_assign_array_to_new_record_builds_join_records - c = Category.new(:name => 'Fishing', :authors => [Author.first]) - assert_equal 1, c.categorizations.size - end - def test_create_bang_should_raise_exception_when_join_record_has_errors repair_validations(Categorization) do Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 08831a42ba..31aa3788c7 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -173,6 +173,12 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal account, firm.account end + def test_build_association_dont_create_transaction + assert_no_queries { + Firm.new.build_account + } + end + def test_build_and_create_should_not_happen_within_scope pirate = pirates(:blackbeard) scoped_count = pirate.association(:foo_bulb).scoped.where_values.count diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 073e856e5e..67b5d174aa 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -23,6 +23,8 @@ require 'models/edge' require 'models/joke' require 'models/bulb' require 'models/bird' +require 'models/car' +require 'models/bulb' require 'rexml/document' require 'active_support/core_ext/exception' require 'bcrypt' @@ -323,6 +325,12 @@ class BasicsTest < ActiveRecord::TestCase assert parrot.valid? end + def test_default_values_are_deeply_dupped + company = Company.new + company.description << "foo" + assert_equal "", Company.new.description + end + def test_load topics = Topic.find(:all, :order => 'id') assert_equal(4, topics.size) @@ -1293,6 +1301,16 @@ class BasicsTest < ActiveRecord::TestCase assert_equal({ :foo => :bar }, t.content_before_type_cast) end + def test_serialized_attributes_before_type_cast_returns_unserialized_value + Topic.serialize :content, Hash + + t = Topic.new(:content => { :foo => :bar }) + assert_equal({ :foo => :bar }, t.attributes_before_type_cast["content"]) + t.save! + t.reload + assert_equal({ :foo => :bar }, t.attributes_before_type_cast["content"]) + end + def test_serialized_attribute_calling_dup_method klass = Class.new(ActiveRecord::Base) klass.table_name = "topics" @@ -1430,6 +1448,29 @@ class BasicsTest < ActiveRecord::TestCase Topic.serialize(:content) end + def test_serialize_attribute_via_select_method_when_time_zone_available + ActiveRecord::Base.time_zone_aware_attributes = true + Topic.serialize(:content, MyObject) + + myobj = MyObject.new('value1', 'value2') + topic = Topic.create(:content => myobj) + + ActiveRecord::IdentityMap.without do + assert_equal(myobj, Topic.select(:content).find(topic.id).content) + assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content } + end + ensure + ActiveRecord::Base.time_zone_aware_attributes = false + end + + def test_serialize_attribute_can_be_serialized_in_an_integer_column + insures = ['life'] + person = SerializedPerson.new(:first_name => 'David', :insures => insures) + assert person.save + person = person.reload + assert_equal(insures, person.insures) + end + def test_quote author_name = "\\ \001 ' \n \\n \"" topic = Topic.create('author_name' => author_name) @@ -1499,6 +1540,16 @@ class BasicsTest < ActiveRecord::TestCase end end + def test_dont_clear_inheritnce_column_when_setting_explicitly + Joke.inheritance_column = "my_type" + before_inherit = Joke.inheritance_column + + Joke.reset_column_information + after_inherit = Joke.inheritance_column + + assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank? + end + def test_set_table_name_symbol_converted_to_string Joke.table_name = :cold_jokes assert_equal 'cold_jokes', Joke.table_name @@ -2113,7 +2164,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_attribute_names - assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"], + assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id", "description"], Company.attribute_names end @@ -2144,6 +2195,29 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:number)}", dev.cache_key end + def test_cache_key_format_for_existing_record_with_updated_at_and_custom_cache_timestamp_format + return skip "Only in Ruby 1.9" if RUBY_VERSION < '1.9' + + dev = CachedDeveloper.first + assert_equal "cached_developers/#{dev.id}-#{dev.updated_at.utc.to_s(:nsec)}", dev.cache_key + end + + def test_cache_key_changes_when_child_touched + return skip "Only in Ruby 1.9" if RUBY_VERSION < '1.9' + + old_timestamp_format = Car.cache_timestamp_format + Car.cache_timestamp_format = :nsec + car = Car.create + Bulb.create(:car => car) + + key = car.cache_key + car.bulb.touch + car.reload + assert_not_equal key, car.cache_key + ensure + Car.cache_timestamp_format = old_timestamp_format + end + def test_cache_key_format_for_existing_record_with_nil_updated_at dev = Developer.first dev.update_attribute(:updated_at, nil) diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 660098b9ad..ad2a749ab4 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -1,8 +1,9 @@ require 'cases/helper' require 'models/post' +require 'models/subscriber' class EachTest < ActiveRecord::TestCase - fixtures :posts + fixtures :posts, :subscribers def setup @posts = Post.order("id asc") @@ -136,4 +137,24 @@ class EachTest < ActiveRecord::TestCase assert_equal special_posts_ids, posts.map(&:id) end + def test_find_in_batches_should_use_any_column_as_primary_key + nick_order_subscribers = Subscriber.order('nick asc') + start_nick = nick_order_subscribers.second.nick + + subscribers = [] + Subscriber.find_in_batches(:batch_size => 1, :start => start_nick) do |batch| + subscribers.concat(batch) + end + + assert_equal nick_order_subscribers[1..-1].map(&:id), subscribers.map(&:id) + end + + def test_find_in_batches_should_use_any_column_as_primary_key_when_start_is_not_specified + Subscriber.count('nick') # preheat arel's table cache + assert_queries(Subscriber.count + 1) do + Subscriber.find_each(:batch_size => 1) do |subscriber| + assert_kind_of Subscriber, subscriber + end + end + end end diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb index 3652255c38..32726e8d8b 100644 --- a/activerecord/test/cases/bind_parameter_test.rb +++ b/activerecord/test/cases/bind_parameter_test.rb @@ -30,8 +30,7 @@ module ActiveRecord end def test_binds_are_logged - # FIXME: use skip with minitest - return unless @connection.supports_statement_cache? + return skip_bind_parameter_test unless supports_statement_cache? sub = @connection.substitute_at(@pk, 0) binds = [[@pk, 1]] @@ -44,8 +43,7 @@ module ActiveRecord end def test_find_one_uses_binds - # FIXME: use skip with minitest - return unless @connection.supports_statement_cache? + return skip_bind_parameter_test unless supports_statement_cache? Topic.find(1) binds = [[@pk, 1]] @@ -54,8 +52,7 @@ module ActiveRecord end def test_logs_bind_vars - # FIXME: use skip with minitest - return unless @connection.supports_statement_cache? + return skip_bind_parameter_test unless supports_statement_cache? pk = Topic.columns.find { |x| x.primary } @@ -86,5 +83,15 @@ module ActiveRecord logger.sql event assert_match([[pk.name, 10]].inspect, logger.debugs.first) end + + private + + def skip_bind_parameter_test + skip('prepared statement caching is not supported') + end + + def supports_statement_cache? + @connection.supports_statement_cache? + end end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index cf1181e829..a1dc1de38d 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -1,10 +1,11 @@ require "cases/helper" +require 'models/club' require 'models/company' require "models/contract" -require 'models/topic' require 'models/edge' -require 'models/club' require 'models/organization' +require 'models/possession' +require 'models/topic' Company.has_many :accounts @@ -368,6 +369,10 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 5, Account.count(:firm_id) end + def test_count_with_uniq + assert_equal 4, Account.select(:credit_limit).uniq.count + end + def test_count_with_column_and_options_parameter assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50 AND firm_id IS NOT NULL") end @@ -487,4 +492,26 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_with_qualified_column_name assert_equal [1,2,3,4], Topic.order(:id).pluck("topics.id") end + + def test_pluck_replaces_select_clause + taks_relation = Topic.select([:approved, :id]).order(:id) + assert_equal [1,2,3,4], taks_relation.pluck(:id) + assert_equal [false, true, true, true], taks_relation.pluck(:approved) + end + + def test_pluck_auto_table_name_prefix + c = Company.create!(:name => "test", :contracts => [Contract.new]) + assert_equal [c.id], Company.joins(:contracts).pluck(:id) + end + + def test_pluck_not_auto_table_name_prefix_if_column_joined + Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + assert_equal [7], Company.joins(:contracts).pluck(:developer_id).map(&:to_i) + end + + def test_pluck_with_reserved_words + Possession.create!(:where => "Over There") + + assert_equal ["Over There"], Possession.pluck(:where) + end end diff --git a/activerecord/test/cases/column_test.rb b/activerecord/test/cases/column_test.rb index b1c1165bd9..800cfbdef9 100644 --- a/activerecord/test/cases/column_test.rb +++ b/activerecord/test/cases/column_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'models/company' module ActiveRecord module ConnectionAdapters @@ -40,12 +41,27 @@ module ActiveRecord def test_type_cast_non_integer_to_integer column = Column.new("field", nil, "integer") - assert_raises(NoMethodError) do - column.type_cast([]) - end + assert_nil column.type_cast([1,2]) + assert_nil column.type_cast({1 => 2}) + assert_nil column.type_cast((1..2)) + end + + def test_type_cast_activerecord_to_integer + column = Column.new("field", nil, "integer") + firm = Firm.create(:name => 'Apple') + assert_nil column.type_cast(firm) + end + + def test_type_cast_object_without_to_i_to_integer + column = Column.new("field", nil, "integer") + assert_nil column.type_cast(Object.new) + end - assert_raises(NoMethodError) do - column.type_cast(Object.new) + if RUBY_VERSION > '1.9' + def test_type_cast_nan_and_infinity_to_integer + column = Column.new("field", nil, "integer") + assert_nil column.type_cast(Float::NAN) + assert_nil column.type_cast(1.0/0.0) end end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 4fc7e77786..9756c182b9 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -76,6 +76,8 @@ class DirtyTest < ActiveRecord::TestCase assert pirate.created_on_changed? assert_kind_of ActiveSupport::TimeWithZone, pirate.created_on_was assert_equal old_created_on, pirate.created_on_was + pirate.created_on = old_created_on + assert !pirate.created_on_changed? end end @@ -201,6 +203,20 @@ class DirtyTest < ActiveRecord::TestCase end end + def test_nullable_datetime_not_marked_as_changed_if_new_value_is_blank + in_time_zone 'Edinburgh' do + target = Class.new(ActiveRecord::Base) + target.table_name = 'topics' + + topic = target.create + assert_equal nil, topic.written_on + + topic.written_on = "" + assert_equal nil, topic.written_on + assert !topic.written_on_changed? + end + end + def test_integer_zero_to_string_zero_not_marked_as_changed pirate = Pirate.new pirate.parrot_id = 0 @@ -535,18 +551,17 @@ class DirtyTest < ActiveRecord::TestCase end end - def test_setting_time_attributes_with_time_zone_field_to_same_time_should_not_be_marked_as_a_change + def test_datetime_attribute_can_be_updated_with_fractional_seconds in_time_zone 'Paris' do target = Class.new(ActiveRecord::Base) - target.table_name = 'pirates' + target.table_name = 'topics' - created_on = Time.now + written_on = Time.utc(2012, 12, 1, 12, 0, 0).in_time_zone('Paris') - pirate = target.create(:created_on => created_on) - pirate.reload # Here mysql truncate the usec value to 0 + topic = target.create(:written_on => written_on) + topic.written_on += 0.3 - pirate.created_on = created_on - assert !pirate.created_on_changed? + assert topic.written_on_changed?, 'Fractional second update not detected' end end diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb index b2a3cb5733..17a02f139a 100644 --- a/activerecord/test/cases/dup_test.rb +++ b/activerecord/test/cases/dup_test.rb @@ -113,5 +113,14 @@ module ActiveRecord assert topic.invalid? assert duped.valid? end + + def test_dup_with_default_scope + prev_default_scopes = Topic.default_scopes + Topic.default_scopes = [Topic.where(:approved => true)] + topic = Topic.new(:approved => false) + assert !topic.dup.approved?, "should not be overriden by default scopes" + ensure + Topic.default_scopes = prev_default_scopes + end end end diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb index cb7781f8e7..bdeb0a033c 100644 --- a/activerecord/test/cases/explain_test.rb +++ b/activerecord/test/cases/explain_test.rb @@ -98,6 +98,16 @@ if ActiveRecord::Base.connection.supports_explain? assert_equal expected, base.exec_explain(queries) end + def test_unsupported_connection_adapter + connection.stubs(:supports_explain?).returns(false) + + base.logger.expects(:warn).never + + with_threshold(0) do + Car.where(:name => 'honda').to_a + end + end + def test_silence_auto_explain base.expects(:collecting_sqls_for_explain).never base.logger.expects(:warn).never diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 77ca3b574d..7d63d76c34 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -664,6 +664,11 @@ class FinderTest < ActiveRecord::TestCase assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") } end + def test_find_by_one_attribute_bang_with_blank_defined + blank_topic = BlankTopic.create(:title => "The Blank One") + assert_equal blank_topic, BlankTopic.find_by_title!("The Blank One") + end + def test_find_by_one_attribute_with_order_option assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id') assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC') diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index e352a55104..cf49b125d7 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -4,7 +4,7 @@ require 'config' require 'test/unit' require 'stringio' -require 'mocha' +require 'mocha/setup' require 'active_record' require 'active_support/dependencies' diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 015a3ccefd..066a60f81a 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -7,6 +7,7 @@ require 'models/ship' require 'models/legacy_thing' require 'models/reference' require 'models/string_key_object' +require 'models/treasure' class LockWithoutDefault < ActiveRecord::Base; end @@ -20,7 +21,7 @@ class ReadonlyNameShip < Ship end class OptimisticLockingTest < ActiveRecord::TestCase - fixtures :people, :legacy_things, :references, :string_key_objects + fixtures :people, :legacy_things, :references, :string_key_objects, :peoples_treasures def test_non_integer_lock_existing s1 = StringKeyObject.find("record1") @@ -267,6 +268,15 @@ class SetLockingColumnTest < ActiveRecord::TestCase assert_equal "omg", k.original_locking_column end end + + def test_removing_has_and_belongs_to_many_associations_upon_destroy + p = RichPerson.create! :first_name => 'Jon' + p.treasures.create! + assert !p.treasures.empty? + p.destroy + assert p.treasures.empty? + assert RichPerson.connection.select_all("SELECT * FROM peoples_treasures WHERE rich_person_id = 1").empty? + end end class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index e24a5ca5aa..10ee86de4a 100644 --- a/activerecord/test/cases/log_subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -7,6 +7,19 @@ class LogSubscriberTest < ActiveRecord::TestCase include ActiveSupport::LogSubscriber::TestHelper include ActiveSupport::BufferedLogger::Severity + class TestDebugLogSubscriber < ActiveRecord::LogSubscriber + attr_reader :debugs + + def initialize + @debugs = [] + super + end + + def debug message + @debugs << message + end + end + fixtures :posts def setup @@ -32,18 +45,7 @@ class LogSubscriberTest < ActiveRecord::TestCase def test_schema_statements_are_ignored event = Struct.new(:duration, :payload) - logger = Class.new(ActiveRecord::LogSubscriber) { - attr_accessor :debugs - - def initialize - @debugs = [] - super - end - - def debug message - @debugs << message - end - }.new + logger = TestDebugLogSubscriber.new assert_equal 0, logger.debugs.length logger.sql(event.new(0, { :sql => 'hi mom!' })) @@ -56,6 +58,14 @@ class LogSubscriberTest < ActiveRecord::TestCase assert_equal 2, logger.debugs.length end + def test_ignore_binds_payload_with_nil_column + event = Struct.new(:duration, :payload) + + logger = TestDebugLogSubscriber.new + logger.sql(event.new(0, :sql => 'hi mom!', :binds => [[nil, 1]])) + assert_equal 1, logger.debugs.length + end + def test_basic_query_logging Developer.all wait diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 0ab4f30363..ac84306eae 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -212,14 +212,14 @@ class MethodScopingTest < ActiveRecord::TestCase table = VerySpecialComment.arel_table relation = VerySpecialComment.scoped relation.where_values << table[:id].not_eq(1) - assert_equal({:type => "VerySpecialComment"}, relation.send(:scope_for_create)) + assert_equal({'type' => "VerySpecialComment"}, relation.send(:scope_for_create)) end def test_scoped_create new_comment = nil VerySpecialComment.send(:with_scope, :create => { :post_id => 1 }) do - assert_equal({:post_id => 1, :type => 'VerySpecialComment' }, VerySpecialComment.scoped.send(:scope_for_create)) + assert_equal({'post_id' => 1, 'type' => 'VerySpecialComment' }, VerySpecialComment.scoped.send(:scope_for_create)) new_comment = VerySpecialComment.create :body => "Wonderful world" end @@ -228,7 +228,7 @@ class MethodScopingTest < ActiveRecord::TestCase def test_scoped_create_with_join_and_merge Comment.where(:body => "but Who's Buying?").joins(:post).merge(Post.where(:body => 'Peace Sells...')).with_scope do - assert_equal({:body => "but Who's Buying?"}, Comment.scoped.scope_for_create) + assert_equal({'body' => "but Who's Buying?"}, Comment.scoped.scope_for_create) end end @@ -441,7 +441,7 @@ class NestedScopingTest < ActiveRecord::TestCase comment = nil Comment.send(:with_scope, :create => { :post_id => 1}) do Comment.send(:with_scope, :create => { :post_id => 2}) do - assert_equal({:post_id => 2}, Comment.scoped.send(:scope_for_create)) + assert_equal({'post_id' => 2}, Comment.scoped.send(:scope_for_create)) comment = Comment.create :body => "Hey guys, nested scopes are broken. Please fix!" end end @@ -453,7 +453,7 @@ class NestedScopingTest < ActiveRecord::TestCase Comment.send(:with_scope, :create => { :body => "Hey guys, nested scopes are broken. Please fix!" }) do Comment.send(:with_exclusive_scope, :create => { :post_id => 1 }) do - assert_equal({:post_id => 1}, Comment.scoped.send(:scope_for_create)) + assert_equal({'post_id' => 1}, Comment.scoped.send(:scope_for_create)) assert_blank Comment.new.body comment = Comment.create :body => "Hey guys" end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index f0c55b1535..7f0d921545 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -61,7 +61,7 @@ if ActiveRecord::Base.connection.supports_migrations? ActiveRecord::Base.connection.initialize_schema_migrations_table ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}" - %w(things awesome_things prefix_things_suffix prefix_awesome_things_suffix).each do |table| + %w(things awesome_things prefix_things_suffix p_awesome_things_s).each do |table| Thing.connection.drop_table(table) rescue nil end Thing.reset_column_information @@ -874,8 +874,6 @@ if ActiveRecord::Base.connection.supports_migrations? end def test_remove_column_with_array_as_an_argument_is_deprecated - return skip "remove_column with array as argument is not supported with OracleAdapter" if current_adapter? :OracleAdapter - ActiveRecord::Base.connection.create_table(:hats) do |table| table.column :hat_name, :string, :limit => 100 table.column :hat_size, :integer @@ -886,7 +884,21 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.remove_column("hats", ["hat_name", "hat_size"]) end ensure - ActiveRecord::Base.connection.drop_table(:hats) rescue nil + ActiveRecord::Base.connection.drop_table(:hats) + end + + def test_removing_and_renaming_column_preserves_custom_primary_key + ActiveRecord::Base.connection.create_table "my_table", :primary_key => "my_table_id", :force => true do |t| + t.integer "col_one" + t.string "col_two", :limit => 128, :null => false + end + + ActiveRecord::Base.connection.remove_column("my_table", "col_two") + ActiveRecord::Base.connection.rename_column("my_table", "col_one", "col_three") + + assert_equal 'my_table_id', ActiveRecord::Base.connection.primary_key('my_table') + ensure + ActiveRecord::Base.connection.drop_table(:my_table) rescue nil end def test_change_type_of_not_null_column @@ -1051,6 +1063,18 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.remove_column("people", "administrator") rescue nil end + def test_change_column_with_custom_index_name + Person.connection.add_column "people", "category", :string, :default => 'human' + Person.connection.add_index :people, :category, :name => 'people_categories_idx' + + assert_equal ['people_categories_idx'], Person.connection.indexes('people').map(&:name) + Person.connection.change_column "people", "category", :string, :null => false, :default => 'article' + + assert_equal ['people_categories_idx'], Person.connection.indexes('people').map(&:name) + ensure + Person.connection.remove_column("people", "category") rescue nil + end + def test_change_column_default Person.connection.change_column_default "people", "first_name", "Tester" Person.reset_column_information @@ -1430,6 +1454,12 @@ if ActiveRecord::Base.connection.supports_migrations? end end + def test_finds_migrations_in_numbered_directory + migrations = ActiveRecord::Migrator.migrations [MIGRATIONS_ROOT + '/10_urban'] + assert_equal 9, migrations[0].version + assert_equal 'AddExpressions', migrations[0].name + end + def test_dump_schema_information_outputs_lexically_ordered_versions migration_path = MIGRATIONS_ROOT + '/valid_with_timestamps' ActiveRecord::Migrator.run(:up, migration_path, 20100301010101) @@ -1615,8 +1645,8 @@ if ActiveRecord::Base.connection.supports_migrations? def test_rename_table_with_prefix_and_suffix assert !Thing.table_exists? - ActiveRecord::Base.table_name_prefix = 'prefix_' - ActiveRecord::Base.table_name_suffix = '_suffix' + ActiveRecord::Base.table_name_prefix = 'p_' + ActiveRecord::Base.table_name_suffix = '_s' Thing.reset_table_name Thing.reset_sequence_name WeNeedThings.up @@ -1625,7 +1655,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "hello world", Thing.find(:first).content RenameThings.up - Thing.table_name = "prefix_awesome_things_suffix" + Thing.table_name = "p_awesome_things_s" assert_equal "hello world", Thing.find(:first).content ensure diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 16b1eb040e..85b9d3c1a1 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -172,6 +172,17 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase man.interests_attributes = [{:id => interest.id, :topic => 'gardening'}] assert_equal man.interests.first.topic, man.interests[0].topic end + + def test_accepts_nested_attributes_for_can_be_overridden_in_subclasses + Pirate.accepts_nested_attributes_for(:parrot) + + mean_pirate_class = Class.new(Pirate) do + accepts_nested_attributes_for :parrot + end + mean_pirate = mean_pirate_class.new + mean_pirate.parrot_attributes = { :name => "James" } + assert_equal "James", mean_pirate.parrot.name + end end class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index a35cb3c4a5..db1ba3549f 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -394,7 +394,6 @@ class PersistencesTest < ActiveRecord::TestCase def test_update_attribute_with_one_updated t = Topic.first - title = t.title t.update_attribute(:title, 'super_title') assert_equal 'super_title', t.title assert !t.changed?, "topic should not have changed" @@ -492,7 +491,7 @@ class PersistencesTest < ActiveRecord::TestCase def test_update_column_with_one_changed_and_one_updated t = Topic.order('id').limit(1).first - title, author_name = t.title, t.author_name + author_name = t.author_name t.author_name = 'John' t.update_column(:title, 'super_title') assert_equal 'John', t.author_name @@ -519,6 +518,14 @@ class PersistencesTest < ActiveRecord::TestCase assert return_value end + def test_update_column_with_default_scope + developer = DeveloperCalledDavid.first + developer.name = 'John' + developer.save! + + assert developer.update_column(:name, 'Will'), 'did not update record due to default scope' + end + def test_update_attributes topic = Topic.find(1) assert !topic.approved? diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index dd881f8230..dfc6ea2457 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -173,6 +173,17 @@ class QueryCacheTest < ActiveRecord::TestCase assert_queries(2) { task.lock!; task.lock! } end end + + def test_cache_is_available_when_connection_is_connected + conf = ActiveRecord::Base.configurations + + ActiveRecord::Base.configurations = {} + Task.cache do + assert_queries(1) { Task.find(1); Task.find(1) } + end + ensure + ActiveRecord::Base.configurations = conf + end end class QueryCacheExpiryTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index babeaec5f6..80ee74e41e 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -122,35 +122,35 @@ module ActiveRecord def test_quote_float float = 1.2 assert_equal float.to_s, @quoter.quote(float, nil) - assert_equal float.to_s, @quoter.quote(float, FakeColumn.new(:float)) + assert_equal float.to_s, @quoter.quote(float, Object.new) end def test_quote_fixnum fixnum = 1 assert_equal fixnum.to_s, @quoter.quote(fixnum, nil) - assert_equal fixnum.to_s, @quoter.quote(fixnum, FakeColumn.new(:integer)) + assert_equal fixnum.to_s, @quoter.quote(fixnum, Object.new) end def test_quote_bignum bignum = 1 << 100 assert_equal bignum.to_s, @quoter.quote(bignum, nil) - assert_equal bignum.to_s, @quoter.quote(bignum, FakeColumn.new(:integer)) + assert_equal bignum.to_s, @quoter.quote(bignum, Object.new) end def test_quote_bigdecimal bigdec = BigDecimal.new((1 << 100).to_s) assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, nil) - assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, FakeColumn.new(:decimal)) + assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, Object.new) end def test_dates_and_times @quoter.extend(Module.new { def quoted_date(value) 'lol' end }) assert_equal "'lol'", @quoter.quote(Date.today, nil) - assert_equal "'lol'", @quoter.quote(Date.today, FakeColumn.new(:date)) + assert_equal "'lol'", @quoter.quote(Date.today, Object.new) assert_equal "'lol'", @quoter.quote(Time.now, nil) - assert_equal "'lol'", @quoter.quote(Time.now, FakeColumn.new(:time)) + assert_equal "'lol'", @quoter.quote(Time.now, Object.new) assert_equal "'lol'", @quoter.quote(DateTime.now, nil) - assert_equal "'lol'", @quoter.quote(DateTime.now, FakeColumn.new(:datetime)) + assert_equal "'lol'", @quoter.quote(DateTime.now, Object.new) end def test_crazy_object diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index ba9df1651b..80158332f9 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -35,30 +35,5 @@ module ActiveRecord def test_where_with_empty_hash_and_no_foreign_key assert_equal 0, Edge.where(:sink => {}).count end - - def test_where_with_integer_for_string_column - count = Post.where(:title => 0).count - assert_equal 0, count - end - - def test_where_with_float_for_string_column - count = Post.where(:title => 0.0).count - assert_equal 0, count - end - - def test_where_with_boolean_for_string_column - count = Post.where(:title => false).count - assert_equal 0, count - end - - def test_where_with_decimal_for_string_column - count = Post.where(:title => BigDecimal.new('0')).count - assert_equal 0, count - end - - def test_where_with_duration_for_string_column - count = Post.where(:title => 0.seconds).count - assert_equal 0, count - end end end diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index aec2487aee..f33e765c59 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -380,19 +380,19 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scope_with_inheritance wheres = InheritedPoorDeveloperCalledJamis.scoped.where_values_hash assert_equal "Jamis", wheres[:name] - assert_equal Arel.sql("50000"), wheres[:salary] + assert_equal 50000, wheres[:salary] end def test_default_scope_with_module_includes wheres = ModuleIncludedPoorDeveloperCalledJamis.scoped.where_values_hash assert_equal "Jamis", wheres[:name] - assert_equal Arel.sql("50000"), wheres[:salary] + assert_equal 50000, wheres[:salary] end def test_default_scope_with_multiple_calls wheres = MultiplePoorDeveloperCalledJamis.scoped.where_values_hash assert_equal "Jamis", wheres[:name] - assert_equal Arel.sql("50000"), wheres[:salary] + assert_equal 50000, wheres[:salary] end def test_method_scope diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 7a75a8436b..6efdeac3d9 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -71,7 +71,7 @@ module ActiveRecord def test_has_values relation = Relation.new Post, Post.arel_table relation.where_values << relation.table[:id].eq(10) - assert_equal({:id => 10}, relation.where_values_hash) + assert_equal({'id' => 10}, relation.where_values_hash) end def test_values_wrong_table @@ -101,7 +101,7 @@ module ActiveRecord def test_create_with_value relation = Relation.new Post, Post.arel_table - hash = { :hello => 'world' } + hash = { 'hello' => 'world' } relation.create_with_value = hash assert_equal hash, relation.scope_for_create end @@ -110,7 +110,7 @@ module ActiveRecord relation = Relation.new Post, Post.arel_table relation.where_values << relation.table[:id].eq(10) relation.create_with_value = {:hello => 'world'} - assert_equal({:hello => 'world', :id => 10}, relation.scope_for_create) + assert_equal({'hello' => 'world', 'id' => 10}, relation.scope_for_create) end # FIXME: is this really wanted or expected behavior? diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index b24df47efd..98fe6b7611 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -332,6 +332,13 @@ class RelationTest < ActiveRecord::TestCase end end + def test_preload_applies_to_all_chained_preloaded_scopes + assert_queries(3) do + post = Post.with_tags.with_comments.first + assert post + end + end + def test_find_with_included_associations assert_queries(2) do posts = Post.includes(:comments).order('posts.id') @@ -1185,4 +1192,18 @@ class RelationTest < ActiveRecord::TestCase end assert_equal ['Foo', 'Foo'], query.uniq(true).uniq(false).map(&:name) end + + test 'group with select and includes' do + authors_count = Post.select('author_id, COUNT(author_id) AS num_posts'). + group('author_id').order('author_id').includes(:author).to_a + + assert_no_queries do + result = authors_count.map do |post| + [post.num_posts.to_i, post.author.try(:name)] + end + + expected = [[1, nil], [5, "David"], [3, "Mary"], [2, "Bob"]] + assert_equal expected, result + end + end end diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 8708117129..0f9cb10f0f 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -22,6 +22,14 @@ end class Thaumaturgist < IneptWizard end +class ReplyTitle; end + +class ReplyWithTitleObject < Reply + validates_uniqueness_of :content, :scope => :title + + def title; ReplyTitle.new; end +end + class UniquenessValidationTest < ActiveRecord::TestCase fixtures :topics, 'warehouse-things', :developers @@ -80,6 +88,14 @@ class UniquenessValidationTest < ActiveRecord::TestCase assert r3.valid?, "Saving r3" end + def test_validate_uniqueness_with_composed_attribute_scope + r1 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world" + assert r1.valid?, "Saving r1" + + r2 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world" + assert !r2.valid?, "Saving r2 first time" + end + def test_validate_uniqueness_scoped_to_defining_class t = Topic.create("title" => "What, me worry?") |