diff options
Diffstat (limited to 'activerecord/test/cases')
157 files changed, 3177 insertions, 1804 deletions
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index b164c12c89..9828e682ef 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -32,57 +32,49 @@ module ActiveRecord def test_tables tables = nil - ActiveSupport::Deprecation.silence { tables = @connection.tables } - assert tables.include?("accounts") - assert tables.include?("authors") - assert tables.include?("tasks") - assert tables.include?("topics") + tables = @connection.tables + assert_includes tables, "accounts" + assert_includes tables, "authors" + assert_includes tables, "tasks" + assert_includes tables, "topics" end def test_table_exists? - ActiveSupport::Deprecation.silence do - assert @connection.table_exists?("accounts") - assert !@connection.table_exists?("nonexistingtable") - assert !@connection.table_exists?(nil) - end - end - - def test_table_exists_checking_both_tables_and_views_is_deprecated - assert_deprecated { @connection.table_exists?("accounts") } + assert @connection.table_exists?("accounts") + assert @connection.table_exists?(:accounts) + assert_not @connection.table_exists?("nonexistingtable") + assert_not @connection.table_exists?("'") + assert_not @connection.table_exists?(nil) end def test_data_sources data_sources = @connection.data_sources - assert data_sources.include?("accounts") - assert data_sources.include?("authors") - assert data_sources.include?("tasks") - assert data_sources.include?("topics") + assert_includes data_sources, "accounts" + assert_includes data_sources, "authors" + assert_includes data_sources, "tasks" + assert_includes data_sources, "topics" end def test_data_source_exists? assert @connection.data_source_exists?("accounts") assert @connection.data_source_exists?(:accounts) assert_not @connection.data_source_exists?("nonexistingtable") + assert_not @connection.data_source_exists?("'") assert_not @connection.data_source_exists?(nil) end def test_indexes idx_name = "accounts_idx" - if @connection.respond_to?(:indexes) - indexes = @connection.indexes("accounts") - assert indexes.empty? - - @connection.add_index :accounts, :firm_id, name: idx_name - indexes = @connection.indexes("accounts") - assert_equal "accounts", indexes.first.table - assert_equal idx_name, indexes.first.name - assert !indexes.first.unique - assert_equal ["firm_id"], indexes.first.columns - else - warn "#{@connection.class} does not respond to #indexes" - end + indexes = @connection.indexes("accounts") + assert indexes.empty? + @connection.add_index :accounts, :firm_id, name: idx_name + indexes = @connection.indexes("accounts") + assert_equal "accounts", indexes.first.table + assert_equal idx_name, indexes.first.name + assert !indexes.first.unique + assert_equal ["firm_id"], indexes.first.columns ensure @connection.remove_index(:accounts, name: idx_name) rescue nil end @@ -184,6 +176,14 @@ module ActiveRecord assert_not_nil error.cause end + def test_not_null_violations_are_translated_to_specific_exception + error = assert_raises(ActiveRecord::NotNullViolation) do + Post.create + end + + assert_not_nil error.cause + end + unless current_adapter?(:SQLite3Adapter) def test_foreign_key_violations_are_translated_to_specific_exception error = assert_raises(ActiveRecord::InvalidForeignKey) do @@ -220,6 +220,14 @@ module ActiveRecord assert_not_nil error.cause end + + def test_numeric_value_out_of_ranges_are_translated_to_specific_exception + error = assert_raises(ActiveRecord::RangeError) do + Book.connection.create("INSERT INTO books(author_id) VALUES (2147483648)") + end + + assert_not_nil error.cause + end end def test_disable_referential_integrity @@ -248,8 +256,8 @@ module ActiveRecord author = Author.create!(name: "john") Post.create!(author: author, title: "foo", body: "bar") query = author.posts.where(title: "foo").select(:title) - assert_equal({"title" => "foo"}, @connection.select_one(query.arel, nil, query.bound_attributes)) - assert_equal({"title" => "foo"}, @connection.select_one(query)) + assert_equal({ "title" => "foo" }, @connection.select_one(query.arel, nil, query.bound_attributes)) + assert_equal({ "title" => "foo" }, @connection.select_one(query)) assert @connection.select_all(query).is_a?(ActiveRecord::Result) assert_equal "foo", @connection.select_value(query) assert_equal ["foo"], @connection.select_values(query) @@ -258,8 +266,8 @@ module ActiveRecord def test_select_methods_passing_a_relation Post.create!(title: "foo", body: "bar") query = Post.where(title: "foo").select(:title) - assert_equal({"title" => "foo"}, @connection.select_one(query.arel, nil, query.bound_attributes)) - assert_equal({"title" => "foo"}, @connection.select_one(query)) + assert_equal({ "title" => "foo" }, @connection.select_one(query.arel, nil, query.bound_attributes)) + assert_equal({ "title" => "foo" }, @connection.select_one(query)) assert @connection.select_all(query).is_a?(ActiveRecord::Result) assert_equal "foo", @connection.select_value(query) assert_equal ["foo"], @connection.select_values(query) @@ -271,25 +279,15 @@ module ActiveRecord unless current_adapter?(:PostgreSQLAdapter) def test_log_invalid_encoding - error = assert_raise ActiveRecord::StatementInvalid do + error = assert_raises RuntimeError do @connection.send :log, "SELECT 'ы' FROM DUAL" do raise "ы".force_encoding(Encoding::ASCII_8BIT) end end - assert_not_nil error.cause - end - end - - if current_adapter?(:Mysql2Adapter, :SQLite3Adapter) - def test_tables_returning_both_tables_and_views_is_deprecated - assert_deprecated { @connection.tables } + assert_not_nil error.message end end - - def test_passing_arguments_to_tables_is_deprecated - assert_deprecated { @connection.tables(:books) } - end end class AdapterTestWithoutTransaction < ActiveRecord::TestCase diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index e7e37cac36..2a528b2cb1 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -28,12 +28,15 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15)) " assert_equal expected, add_index(:people, [:last_name, :first_name], length: 15) + assert_equal expected, add_index(:people, ["last_name", "first_name"], length: 15) expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`) " - assert_equal expected, add_index(:people, [:last_name, :first_name], length: {last_name: 15}) + assert_equal expected, add_index(:people, [:last_name, :first_name], length: { last_name: 15 }) + assert_equal expected, add_index(:people, ["last_name", "first_name"], length: { last_name: 15 }) expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10)) " - assert_equal expected, add_index(:people, [:last_name, :first_name], length: {last_name: 15, first_name: 10}) + assert_equal expected, add_index(:people, [:last_name, :first_name], length: { last_name: 15, first_name: 10 }) + assert_equal expected, add_index(:people, ["last_name", :first_name], length: { last_name: 15, "first_name" => 10 }) %w(SPATIAL FULLTEXT UNIQUE).each do |type| expected = "CREATE #{type} INDEX `index_people_on_last_name` ON `people` (`last_name`) " diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb index 4d81877a9a..50ba9ab831 100644 --- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb +++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb @@ -30,7 +30,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase CollationTest.create!(string_cs_column: "A") invalid = CollationTest.new(string_cs_column: "a") queries = assert_sql { invalid.save } - cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/)} + cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } assert_match(/lower/i, cs_uniqueness_query) end diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index a3f83e73a6..c1de2218e2 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -63,6 +63,27 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase assert @connection.active? end + def test_execute_after_disconnect + @connection.disconnect! + + assert_raise(ActiveRecord::StatementInvalid) do + @connection.execute("SELECT 1") + end + end + + def test_quote_after_disconnect + @connection.disconnect! + + assert_raise(Mysql2::Error) do + @connection.quote("string") + end + end + + def test_active_after_disconnect + @connection.disconnect! + assert_equal false, @connection.active? + end + def test_mysql_connection_collation_is_configured assert_equal "utf8_unicode_ci", @connection.show_variable("collation_connection") assert_equal "utf8_general_ci", ARUnit2Model.connection.show_variable("collation_connection") @@ -101,7 +122,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_passing_arbitary_flags_to_adapter run_without_connection do |orig_connection| ActiveRecord::Base.establish_connection(orig_connection.merge(flags: Mysql2::Client::COMPRESS)) - assert_equal (Mysql2::Client::COMPRESS | Mysql2::Client::FOUND_ROWS), ActiveRecord::Base.connection.raw_connection.query_options[:flags] + assert_equal (Mysql2::Client::COMPRESS | Mysql2::Client::FOUND_ROWS), ActiveRecord::Base.connection.raw_connection.query_options[:flags] end end @@ -114,7 +135,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_mysql_set_session_variable run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: {default_week_format: 3})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { default_week_format: 3 })) session_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.DEFAULT_WEEK_FORMAT" assert_equal 3, session_mode.rows.first.first.to_i end @@ -122,7 +143,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_mysql_set_session_variable_to_default run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: {default_week_format: :default})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { default_week_format: :default })) global_mode = ActiveRecord::Base.connection.exec_query "SELECT @@GLOBAL.DEFAULT_WEEK_FORMAT" session_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.DEFAULT_WEEK_FORMAT" assert_equal global_mode.rows, session_mode.rows @@ -165,7 +186,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase "expected release_advisory_lock to return false when there was no lock to release" end - protected + private def test_lock_free(lock_name) @connection.select_value("SELECT IS_FREE_LOCK(#{@connection.quote(lock_name)})") == 1 diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb index 9f51223d58..7ad3e3ca2d 100644 --- a/activerecord/test/cases/adapters/mysql2/enum_test.rb +++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb @@ -9,11 +9,6 @@ class Mysql2EnumTest < ActiveRecord::Mysql2TestCase assert_equal 8, column.limit end - def test_should_not_be_blob_or_text_column - column = EnumTest.columns_hash["enum_column"] - assert_not column.blob_or_text_column? - end - def test_should_not_be_unsigned column = EnumTest.columns_hash["enum_column"] assert_not column.unsigned? diff --git a/activerecord/test/cases/adapters/mysql2/json_test.rb b/activerecord/test/cases/adapters/mysql2/json_test.rb index 2f7dc3f7ef..6954006003 100644 --- a/activerecord/test/cases/adapters/mysql2/json_test.rb +++ b/activerecord/test/cases/adapters/mysql2/json_test.rb @@ -51,11 +51,11 @@ if ActiveRecord::Base.connection.supports_json? end def test_cast_value_on_write - x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar} - assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast) - assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload) + x = JsonDataType.new payload: { "string" => "foo", :symbol => :bar } + assert_equal({ "string" => "foo", :symbol => :bar }, x.payload_before_type_cast) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.payload) x.save - assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.reload.payload) end def test_type_cast_json @@ -63,12 +63,12 @@ if ActiveRecord::Base.connection.supports_json? data = "{\"a_key\":\"a_value\"}" hash = type.deserialize(data) - assert_equal({"a_key" => "a_value"}, hash) - assert_equal({"a_key" => "a_value"}, type.deserialize(data)) + assert_equal({ "a_key" => "a_value" }, hash) + assert_equal({ "a_key" => "a_value" }, type.deserialize(data)) assert_equal({}, type.deserialize("{}")) - assert_equal({"key"=>nil}, type.deserialize('{"key": null}')) - assert_equal({"c"=>"}",'"a"'=>'b "a b'}, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) + assert_equal({ "key" => nil }, type.deserialize('{"key": null}')) + assert_equal({ "c" => "}", '"a"' => 'b "a b' }, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) end def test_rewrite @@ -81,31 +81,47 @@ if ActiveRecord::Base.connection.supports_json? def test_select @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" x = JsonDataType.first - assert_equal({"k" => "v"}, x.payload) + assert_equal({ "k" => "v" }, x.payload) end def test_select_multikey @connection.execute %q|insert into json_data_type (payload) VALUES ('{"k1":"v1", "k2":"v2", "k3":[1,2,3]}')| x = JsonDataType.first - assert_equal({"k1" => "v1", "k2" => "v2", "k3" => [1,2,3]}, x.payload) + assert_equal({ "k1" => "v1", "k2" => "v2", "k3" => [1, 2, 3] }, x.payload) end def test_null_json @connection.execute "insert into json_data_type (payload) VALUES(null)" x = JsonDataType.first - assert_equal(nil, x.payload) + assert_nil(x.payload) end def test_select_array_json_value @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| x = JsonDataType.first - assert_equal(["v0", {"k1" => "v1"}], x.payload) + assert_equal(["v0", { "k1" => "v1" }], x.payload) + end + + def test_select_nil_json_after_create + json = JsonDataType.create(payload: nil) + x = JsonDataType.where(payload: nil).first + assert_equal(json, x) + end + + def test_select_nil_json_after_update + json = JsonDataType.create(payload: "foo") + x = JsonDataType.where(payload: nil).first + assert_nil(x) + + json.update_attributes payload: nil + x = JsonDataType.where(payload: nil).first + assert_equal(json.reload, x) end def test_rewrite_array_json_value @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| x = JsonDataType.first - x.payload = ["v1", {"k2" => "v2"}, "v3"] + x.payload = ["v1", { "k2" => "v2" }, "v3"] assert x.save! end diff --git a/activerecord/test/cases/adapters/mysql2/legacy_migration_test.rb b/activerecord/test/cases/adapters/mysql2/legacy_migration_test.rb new file mode 100644 index 0000000000..5d3125c2be --- /dev/null +++ b/activerecord/test/cases/adapters/mysql2/legacy_migration_test.rb @@ -0,0 +1,60 @@ +require "cases/helper" + +class MysqlLegacyMigrationTest < ActiveRecord::Mysql2TestCase + self.use_transactional_tests = false + + class GenerateTableWithoutBigint < ActiveRecord::Migration[5.0] + def change + create_table :legacy_integer_pk do |table| + table.string :foo + end + + create_table :override_pk, id: :bigint do |table| + table.string :bar + end + end + end + + def setup + super + @connection = ActiveRecord::Base.connection + + @migration_verbose_old = ActiveRecord::Migration.verbose + ActiveRecord::Migration.verbose = false + + migrations = [GenerateTableWithoutBigint.new(nil, 1)] + + ActiveRecord::Migrator.new(:up, migrations).migrate + end + + def teardown + ActiveRecord::Migration.verbose = @migration_verbose_old + @connection.drop_table("legacy_integer_pk") + @connection.drop_table("override_pk") + ActiveRecord::SchemaMigration.delete_all rescue nil + super + end + + def test_create_table_uses_integer_as_pkey_by_default + col = column(:legacy_integer_pk, :id) + assert_equal "int(11)", sql_type_for(col) + assert col.auto_increment? + end + + def test_create_tables_respects_pk_column_type_override + col = column(:override_pk, :id) + assert_equal "bigint(20)", sql_type_for(col) + end + + private + + def column(table_name, column_name) + ActiveRecord::Base.connection + .columns(table_name.to_s) + .detect { |c| c.name == column_name.to_s } + end + + def sql_type_for(col) + col && col.sql_type + end +end diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index 69336eb906..aab3dcb724 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -65,6 +65,19 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase @conn.columns_for_distinct("posts.id", [order]) end + def test_errors_for_bigint_fks_on_integer_pk_table + # table old_cars has primary key of integer + + error = assert_raises(ActiveRecord::MismatchedForeignKey) do + @conn.add_reference :engines, :old_car + @conn.add_foreign_key :engines, :old_cars + end + + assert_match "Column `old_car_id` on table `engines` has a type of `bigint(20)`", error.message + assert_not_nil error.cause + @conn.exec_query("ALTER TABLE engines DROP COLUMN old_car_id") + end + private def with_example_table(definition = "id int auto_increment primary key, number int, data varchar(255)", &block) diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb index 7736113a19..2c778b1150 100644 --- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb @@ -30,11 +30,11 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase # we call execute directly here (and do similar below) because ActiveRecord::Base#create_table() # will fail with these table names if these test cases fail - create_tables_directly "group"=>"id int auto_increment primary key, `order` varchar(255), select_id int", - "select"=>"id int auto_increment primary key", - "values"=>"id int auto_increment primary key, group_id int", - "distinct"=>"id int auto_increment primary key", - "distinct_select"=>"distinct_id int, select_id int" + create_tables_directly "group" => "id int auto_increment primary key, `order` varchar(255), select_id int", + "select" => "id int auto_increment primary key", + "values" => "id int auto_increment primary key, group_id int", + "distinct" => "id int auto_increment primary key", + "distinct_select" => "distinct_id int, select_id int" end teardown do @@ -130,20 +130,20 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase #the following functions were added to DRY test cases private - # custom fixture loader, uses FixtureSet#create_fixtures and appends base_path to the current file's path + # custom fixture loader, uses FixtureSet#create_fixtures and appends base_path to the current file's path def create_test_fixtures(*fixture_names) ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT + "/reserved_words", fixture_names) end - # custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name + # custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name def drop_tables_directly(table_names, connection = @connection) table_names.each do |name| connection.drop_table name, if_exists: true end end - # custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns - def create_tables_directly (tables, connection = @connection) + # custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns + def create_tables_directly(tables, connection = @connection) tables.each do |table_name, column_properties| connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )") end diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb index 3c08a4ed1f..1fad5585de 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb @@ -76,11 +76,11 @@ module ActiveRecord table = "key_tests" indexes = @connection.indexes(table).sort_by(&:name) - assert_equal 3,indexes.size + assert_equal 3, indexes.size - index_a = indexes.select{|i| i.name == index_a_name}[0] - index_b = indexes.select{|i| i.name == index_b_name}[0] - index_c = indexes.select{|i| i.name == index_c_name}[0] + index_a = indexes.select { |i| i.name == index_a_name }[0] + index_b = indexes.select { |i| i.name == index_b_name }[0] + index_c = indexes.select { |i| i.name == index_c_name }[0] assert_equal :btree, index_a.using assert_nil index_a.type assert_equal :btree, index_b.using @@ -121,6 +121,6 @@ class Mysql2AnsiQuotesTest < ActiveRecord::Mysql2TestCase def test_foreign_keys_method_with_ansi_quotes fks = @connection.foreign_keys("lessons_students") assert_equal([["lessons_students", "students", :cascade]], - fks.map {|fk| [fk.from_table, fk.to_table, fk.on_delete] }) + fks.map { |fk| [fk.from_table, fk.to_table, fk.on_delete] }) end end diff --git a/activerecord/test/cases/adapters/mysql2/transaction_test.rb b/activerecord/test/cases/adapters/mysql2/transaction_test.rb index edd5353ee3..16101e38cb 100644 --- a/activerecord/test/cases/adapters/mysql2/transaction_test.rb +++ b/activerecord/test/cases/adapters/mysql2/transaction_test.rb @@ -10,6 +10,8 @@ module ActiveRecord end setup do + @abort, Thread.abort_on_exception = Thread.abort_on_exception, false + @connection = ActiveRecord::Base.connection @connection.clear_cache! @@ -25,30 +27,34 @@ module ActiveRecord teardown do @connection.drop_table "samples", if_exists: true + + Thread.abort_on_exception = @abort end test "raises Deadlocked when a deadlock is encountered" do assert_raises(ActiveRecord::Deadlocked) do + barrier = Concurrent::CyclicBarrier.new(2) + s1 = Sample.create value: 1 s2 = Sample.create value: 2 thread = Thread.new do Sample.transaction do s1.lock! - sleep 1 + barrier.wait s2.update_attributes value: 1 end end - sleep 0.5 - - Sample.transaction do - s2.lock! - sleep 1 - s1.update_attributes value: 2 + begin + Sample.transaction do + s2.lock! + barrier.wait + s1.update_attributes value: 2 + end + ensure + thread.join end - - thread.join end end end diff --git a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb index 3df11ce11b..a0823be143 100644 --- a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb +++ b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb @@ -15,6 +15,7 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase t.bigint :unsigned_bigint, unsigned: true t.float :unsigned_float, unsigned: true t.decimal :unsigned_decimal, unsigned: true, precision: 10, scale: 2 + t.column :unsigned_zerofill, "int unsigned zerofill" end end @@ -34,10 +35,10 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase assert_raise(ActiveModel::RangeError) do UnsignedType.create(unsigned_bigint: -10) end - assert_raise(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::RangeError) do UnsignedType.create(unsigned_float: -10.0) end - assert_raise(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::RangeError) do UnsignedType.create(unsigned_decimal: -10.0) end end @@ -50,7 +51,7 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase t.unsigned_decimal :unsigned_decimal_t, precision: 10, scale: 2 end - @connection.columns("unsigned_types").select { |c| /^unsigned_/ === c.name }.each do |column| + @connection.columns("unsigned_types").select { |c| /^unsigned_/.match?(c.name) }.each do |column| assert column.unsigned? end end diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb index d3c65f3d94..b787de8453 100644 --- a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb @@ -39,6 +39,10 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase expected = %(CREATE INDEX CONCURRENTLY "index_people_on_last_name" ON "people" ("last_name")) assert_equal expected, add_index(:people, :last_name, algorithm: :concurrently) + expected = %(CREATE INDEX "index_people_on_last_name_and_first_name" ON "people" ("last_name" DESC, "first_name" ASC)) + assert_equal expected, add_index(:people, [:last_name, :first_name], order: { last_name: :desc, first_name: :asc }) + assert_equal expected, add_index(:people, ["last_name", :first_name], order: { last_name: :desc, "first_name" => :asc }) + %w(gin gist hash btree).each do |type| expected = %(CREATE INDEX "index_people_on_last_name" ON "people" USING #{type} ("last_name")) assert_equal expected, add_index(:people, :last_name, using: type) diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index e496960f21..c78c6178ff 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -16,10 +16,12 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase @connection.transaction do @connection.create_table("pg_arrays") do |t| - t.string "tags", array: true + t.string "tags", array: true, limit: 255 t.integer "ratings", array: true t.datetime :datetimes, array: true t.hstore :hstores, array: true + t.decimal :decimals, array: true, default: [], precision: 10, scale: 2 + t.timestamp :timestamps, array: true, default: [], precision: 6 end end PgArray.reset_column_information @@ -34,7 +36,7 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase def test_column assert_equal :string, @column.type - assert_equal "character varying", @column.sql_type + assert_equal "character varying(255)", @column.sql_type assert @column.array? assert_not @type.binary? @@ -110,22 +112,23 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase def test_schema_dump_with_shorthand output = dump_table_schema "pg_arrays" - assert_match %r[t\.string\s+"tags",\s+array: true], output + assert_match %r[t\.string\s+"tags",\s+limit: 255,\s+array: true], output assert_match %r[t\.integer\s+"ratings",\s+array: true], output + assert_match %r[t\.decimal\s+"decimals",\s+precision: 10,\s+scale: 2,\s+default: \[\],\s+array: true], output end def test_select_with_strings @connection.execute "insert into pg_arrays (tags) VALUES ('{1,2,3}')" x = PgArray.first - assert_equal(["1","2","3"], x.tags) + assert_equal(["1", "2", "3"], x.tags) end def test_rewrite_with_strings @connection.execute "insert into pg_arrays (tags) VALUES ('{1,2,3}')" x = PgArray.first - x.tags = ["1","2","3","4"] + x.tags = ["1", "2", "3", "4"] x.save! - assert_equal ["1","2","3","4"], x.reload.tags + assert_equal ["1", "2", "3", "4"], x.reload.tags end def test_select_with_integers @@ -163,28 +166,28 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase end def test_strings_with_quotes - assert_cycle(:tags, ["this has",'some "s that need to be escaped"']) + assert_cycle(:tags, ["this has", 'some "s that need to be escaped"']) end def test_strings_with_commas - assert_cycle(:tags, ["this,has","many,values"]) + assert_cycle(:tags, ["this,has", "many,values"]) end def test_strings_with_array_delimiters - assert_cycle(:tags, ["{","}"]) + assert_cycle(:tags, ["{", "}"]) end def test_strings_with_null_strings - assert_cycle(:tags, ["NULL","NULL"]) + assert_cycle(:tags, ["NULL", "NULL"]) end def test_contains_nils - assert_cycle(:tags, ["1",nil,nil]) + assert_cycle(:tags, ["1", nil, nil]) end def test_insert_fixture tag_values = ["val1", "val2", "val3_with_'_multiple_quote_'_chars"] - @connection.insert_fixture({"tags" => tag_values}, "pg_arrays" ) + @connection.insert_fixture({ "tags" => tag_values }, "pg_arrays") assert_equal(PgArray.last.tags, tag_values) end @@ -211,7 +214,7 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase x = PgArray.create!(tags: tags) x.reload - assert_equal x.tags_before_type_cast, PgArray.type_for_attribute("tags").serialize(tags) + refute x.changed? end def test_quoting_non_standard_delimiters @@ -219,9 +222,10 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase oid = ActiveRecord::ConnectionAdapters::PostgreSQL::OID comma_delim = oid::Array.new(ActiveRecord::Type::String.new, ",") semicolon_delim = oid::Array.new(ActiveRecord::Type::String.new, ";") + conn = PgArray.connection - assert_equal %({"hello,",world;}), comma_delim.serialize(strings) - assert_equal %({hello,;"world;"}), semicolon_delim.serialize(strings) + assert_equal %({"hello,",world;}), conn.type_cast(comma_delim.serialize(strings)) + assert_equal %({hello,;"world;"}), conn.type_cast(semicolon_delim.serialize(strings)) end def test_mutate_array @@ -290,6 +294,12 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase assert_equal record.tags, record.reload.tags end + def test_where_by_attribute_with_array + tags = ["black", "blue"] + record = PgArray.create!(tags: tags) + assert_equal record, PgArray.where(tags: tags).take + end + def test_uniqueness_validation klass = Class.new(PgArray) do validates_uniqueness_of :tags @@ -305,6 +315,21 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase assert_equal ["has already been taken"], e2.errors[:tags], "Should have uniqueness message for tags" end + def test_encoding_arrays_of_utf8_strings + arrays_of_utf8_strings = %w(nový ファイル) + assert_equal arrays_of_utf8_strings, @type.deserialize(@type.serialize(arrays_of_utf8_strings)) + assert_equal [arrays_of_utf8_strings], @type.deserialize(@type.serialize([arrays_of_utf8_strings])) + end + + def test_precision_is_respected_on_timestamp_columns + time = Time.now.change(usec: 123) + record = PgArray.create!(timestamps: [time]) + + assert_equal 123, record.timestamps.first.usec + record.reload + assert_equal 123, record.timestamps.first.usec + end + private def assert_cycle(field, array) # test creation diff --git a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb index f646e59848..7712e809a2 100644 --- a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb @@ -65,10 +65,11 @@ class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase end def test_roundtrip - PostgresqlBitString.create! a_bit: "00001010", a_bit_varying: "0101" - record = PostgresqlBitString.first + record = PostgresqlBitString.create!(a_bit: "00001010", a_bit_varying: "0101") assert_equal "00001010", record.a_bit assert_equal "0101", record.a_bit_varying + assert_nil record.another_bit + assert_nil record.another_bit_varying record.a_bit = "11111111" record.a_bit_varying = "0xF" diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb index dc0df8715a..5c207116c4 100644 --- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -52,7 +52,7 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase end def test_type_case_nil - assert_equal(nil, @type.deserialize(nil)) + assert_nil(@type.deserialize(nil)) end def test_read_value @@ -66,7 +66,7 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase def test_read_nil_value @connection.execute "insert into bytea_data_type (payload) VALUES (null)" record = ByteaDataType.first - assert_equal(nil, record.payload) + assert_nil(record.payload) record.delete end @@ -106,8 +106,8 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase def test_write_nil record = ByteaDataType.create(payload: nil) assert_not record.new_record? - assert_equal(nil, record.payload) - assert_equal(nil, ByteaDataType.where(id: record.id).first.payload) + assert_nil(record.payload) + assert_nil(ByteaDataType.where(id: record.id).first.payload) end class Serializer diff --git a/activerecord/test/cases/adapters/postgresql/case_insensitive_test.rb b/activerecord/test/cases/adapters/postgresql/case_insensitive_test.rb new file mode 100644 index 0000000000..03b44feab6 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/case_insensitive_test.rb @@ -0,0 +1,26 @@ +require "cases/helper" + +class PostgresqlCaseInsensitiveTest < ActiveRecord::PostgreSQLTestCase + class Default < ActiveRecord::Base; end + + def test_case_insensitiveness + connection = ActiveRecord::Base.connection + table = Default.arel_table + + column = Default.columns_hash["char1"] + comparison = connection.case_insensitive_comparison table, :char1, column, nil + assert_match(/lower/i, comparison.to_sql) + + column = Default.columns_hash["char2"] + comparison = connection.case_insensitive_comparison table, :char2, column, nil + assert_match(/lower/i, comparison.to_sql) + + column = Default.columns_hash["char3"] + comparison = connection.case_insensitive_comparison table, :char3, column, nil + assert_match(/lower/i, comparison.to_sql) + + column = Default.columns_hash["multiline_default"] + comparison = connection.case_insensitive_comparison table, :multiline_default, column, nil + assert_match(/lower/i, comparison.to_sql) + end +end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index d01f601031..e916d15f7f 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -90,7 +90,7 @@ module ActiveRecord end def test_tables_logs_name - ActiveSupport::Deprecation.silence { @connection.tables("hello") } + @connection.tables assert_equal "SCHEMA", @subscriber.logged[0][1] end @@ -100,7 +100,7 @@ module ActiveRecord end def test_table_exists_logs_name - ActiveSupport::Deprecation.silence { @connection.table_exists?("items") } + @connection.table_exists?("items") assert_equal "SCHEMA", @subscriber.logged[0][1] end @@ -184,7 +184,7 @@ module ActiveRecord def test_set_session_variable_true run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: {debug_print_plan: true})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: true })) set_true = ActiveRecord::Base.connection.exec_query "SHOW DEBUG_PRINT_PLAN" assert_equal set_true.rows, [["on"]] end @@ -192,7 +192,7 @@ module ActiveRecord def test_set_session_variable_false run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: {debug_print_plan: false})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: false })) set_false = ActiveRecord::Base.connection.exec_query "SHOW DEBUG_PRINT_PLAN" assert_equal set_false.rows, [["off"]] end @@ -201,14 +201,14 @@ module ActiveRecord def test_set_session_variable_nil run_without_connection do |orig_connection| # This should be a no-op that does not raise an error - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: {debug_print_plan: nil})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: nil })) end end def test_set_session_variable_default run_without_connection do |orig_connection| # This should execute a query that does not raise an error - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: {debug_print_plan: :default})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: :default })) end end @@ -224,14 +224,14 @@ module ActiveRecord got_lock = @connection.get_advisory_lock(lock_id) assert got_lock, "get_advisory_lock should have returned true but it didn't" - advisory_lock = @connection.query(list_advisory_locks).find {|l| l[1] == lock_id} + advisory_lock = @connection.query(list_advisory_locks).find { |l| l[1] == lock_id } assert advisory_lock, "expected to find an advisory lock with lock_id #{lock_id} but there wasn't one" released_lock = @connection.release_advisory_lock(lock_id) assert released_lock, "expected release_advisory_lock to return true but it didn't" - advisory_locks = @connection.query(list_advisory_locks).select {|l| l[1] == lock_id} + advisory_locks = @connection.query(list_advisory_locks).select { |l| l[1] == lock_id } assert_empty advisory_locks, "expected to have released advisory lock with lock_id #{lock_id} but it was still held" end @@ -245,7 +245,7 @@ module ActiveRecord end end - protected + private def with_warning_suppression log_level = @connection.client_min_messages diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb index 27a7467326..c1f3a4ae2c 100644 --- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb +++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb @@ -27,22 +27,10 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase t.point :legacy_y, default: [12.2, 13.3] t.point :legacy_z, default: "(14.4,15.5)" end - @connection.create_table("deprecated_points") do |t| - t.point :x - end end teardown do @connection.drop_table "postgresql_points", if_exists: true - @connection.drop_table "deprecated_points", if_exists: true - end - - class DeprecatedPoint < ActiveRecord::Base; end - - def test_deprecated_legacy_type - assert_deprecated do - DeprecatedPoint.new - end end def test_column @@ -108,7 +96,7 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase assert_nothing_raised { PostgresqlPoint.new(x: "") } p = PostgresqlPoint.new(x: "") - assert_equal nil, p.x + assert_nil p.x end def test_array_of_points_round_trip diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 817dfbf705..f9cce10fb8 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -10,6 +10,12 @@ if ActiveRecord::Base.connection.supports_extensions? store_accessor :settings, :language, :timezone end + class FakeParameters + def to_unsafe_h + { "hi" => "hi" } + end + end + def setup @connection = ActiveRecord::Base.connection @@ -38,7 +44,7 @@ if ActiveRecord::Base.connection.supports_extensions? def test_hstore_included_in_extensions assert @connection.respond_to?(:extensions), "connection should have a list of extensions" - assert @connection.extensions.include?("hstore"), "extension list should include hstore" + assert_includes @connection.extensions, "hstore", "extension list should include hstore" end def test_disable_enable_hstore @@ -64,8 +70,8 @@ if ActiveRecord::Base.connection.supports_extensions? @connection.add_column "hstores", "permissions", :hstore, default: '"users"=>"read", "articles"=>"write"' Hstore.reset_column_information - assert_equal({"users"=>"read", "articles"=>"write"}, Hstore.column_defaults["permissions"]) - assert_equal({"users"=>"read", "articles"=>"write"}, Hstore.new.permissions) + assert_equal({ "users" => "read", "articles" => "write" }, Hstore.column_defaults["permissions"]) + assert_equal({ "users" => "read", "articles" => "write" }, Hstore.new.permissions) ensure Hstore.reset_column_information end @@ -103,18 +109,18 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_cast_value_on_write - x = Hstore.new tags: {"bool" => true, "number" => 5} - assert_equal({"bool" => true, "number" => 5}, x.tags_before_type_cast) - assert_equal({"bool" => "true", "number" => "5"}, x.tags) + x = Hstore.new tags: { "bool" => true, "number" => 5 } + assert_equal({ "bool" => true, "number" => 5 }, x.tags_before_type_cast) + assert_equal({ "bool" => "true", "number" => "5" }, x.tags) x.save - assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags) + assert_equal({ "bool" => "true", "number" => "5" }, x.reload.tags) end def test_type_cast_hstore - assert_equal({"1" => "2"}, @type.deserialize("\"1\"=>\"2\"")) + assert_equal({ "1" => "2" }, @type.deserialize("\"1\"=>\"2\"")) assert_equal({}, @type.deserialize("")) - assert_equal({"key"=>nil}, @type.deserialize("key => NULL")) - assert_equal({"c"=>"}",'"a"'=>'b "a b'}, @type.deserialize(%q(c=>"}", "\"a\""=>"b \"a b"))) + assert_equal({ "key" => nil }, @type.deserialize("key => NULL")) + assert_equal({ "c" => "}", '"a"' => 'b "a b' }, @type.deserialize(%q(c=>"}", "\"a\""=>"b \"a b"))) end def test_with_store_accessors @@ -165,48 +171,67 @@ if ActiveRecord::Base.connection.supports_extensions? assert_not hstore.changed? end + def test_dirty_from_user_equal + settings = { "alongkey" => "anything", "key" => "value" } + hstore = Hstore.create!(settings: settings) + + hstore.settings = { "key" => "value", "alongkey" => "anything" } + assert_equal settings, hstore.settings + refute hstore.changed? + end + + def test_hstore_dirty_from_database_equal + settings = { "alongkey" => "anything", "key" => "value" } + hstore = Hstore.create!(settings: settings) + hstore.reload + + assert_equal settings, hstore.settings + hstore.settings = settings + refute hstore.changed? + end + def test_gen1 - assert_equal('" "=>""', @type.serialize(" "=>"")) + assert_equal('" "=>""', @type.serialize(" " => "")) end def test_gen2 - assert_equal('","=>""', @type.serialize(","=>"")) + assert_equal('","=>""', @type.serialize("," => "")) end def test_gen3 - assert_equal('"="=>""', @type.serialize("="=>"")) + assert_equal('"="=>""', @type.serialize("=" => "")) end def test_gen4 - assert_equal('">"=>""', @type.serialize(">"=>"")) + assert_equal('">"=>""', @type.serialize(">" => "")) end def test_parse1 - assert_equal({"a"=>nil,"b"=>nil,"c"=>"NuLl","null"=>"c"}, @type.deserialize('a=>null,b=>NuLl,c=>"NuLl",null=>c')) + assert_equal({ "a" => nil, "b" => nil, "c" => "NuLl", "null" => "c" }, @type.deserialize('a=>null,b=>NuLl,c=>"NuLl",null=>c')) end def test_parse2 - assert_equal({" " => " "}, @type.deserialize("\\ =>\\ ")) + assert_equal({ " " => " " }, @type.deserialize("\\ =>\\ ")) end def test_parse3 - assert_equal({"=" => ">"}, @type.deserialize("==>>")) + assert_equal({ "=" => ">" }, @type.deserialize("==>>")) end def test_parse4 - assert_equal({"=a"=>"q=w"}, @type.deserialize('\=a=>q=w')) + assert_equal({ "=a" => "q=w" }, @type.deserialize('\=a=>q=w')) end def test_parse5 - assert_equal({"=a"=>"q=w"}, @type.deserialize('"=a"=>q\=w')) + assert_equal({ "=a" => "q=w" }, @type.deserialize('"=a"=>q\=w')) end def test_parse6 - assert_equal({"\"a"=>"q>w"}, @type.deserialize('"\"a"=>q>w')) + assert_equal({ "\"a" => "q>w" }, @type.deserialize('"\"a"=>q>w')) end def test_parse7 - assert_equal({"\"a"=>"q\"w"}, @type.deserialize('\"a=>q"w')) + assert_equal({ "\"a" => "q\"w" }, @type.deserialize('\"a=>q"w')) end def test_rewrite @@ -219,19 +244,19 @@ if ActiveRecord::Base.connection.supports_extensions? def test_select @connection.execute "insert into hstores (tags) VALUES ('1=>2')" x = Hstore.first - assert_equal({"1" => "2"}, x.tags) + assert_equal({ "1" => "2" }, x.tags) end def test_array_cycle - assert_array_cycle([{"AA" => "BB", "CC" => "DD"}, {"AA" => nil}]) + assert_array_cycle([{ "AA" => "BB", "CC" => "DD" }, { "AA" => nil }]) end def test_array_strings_with_quotes - assert_array_cycle([{"this has" => 'some "s that need to be escaped"'}]) + assert_array_cycle([{ "this has" => 'some "s that need to be escaped"' }]) end def test_array_strings_with_commas - assert_array_cycle([{"this,has" => "many,values"}]) + assert_array_cycle([{ "this,has" => "many,values" }]) end def test_array_strings_with_array_delimiters @@ -239,17 +264,17 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_array_strings_with_null_strings - assert_array_cycle([{"NULL" => "NULL"}]) + assert_array_cycle([{ "NULL" => "NULL" }]) end def test_contains_nils - assert_array_cycle([{"NULL" => nil}]) + assert_array_cycle([{ "NULL" => nil }]) end def test_select_multikey @connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')" x = Hstore.first - assert_equal({"1" => "2", "2" => "3"}, x.tags) + assert_equal({ "1" => "2", "2" => "3" }, x.tags) end def test_create @@ -303,17 +328,17 @@ if ActiveRecord::Base.connection.supports_extensions? HstoreWithSerialize.create! tags: TagCollection.new("one" => "two") record = HstoreWithSerialize.first assert_instance_of TagCollection, record.tags - assert_equal({"one" => "two"}, record.tags.to_hash) + assert_equal({ "one" => "two" }, record.tags.to_hash) record.tags = TagCollection.new("three" => "four") record.save! - assert_equal({"three" => "four"}, HstoreWithSerialize.first.tags.to_hash) + assert_equal({ "three" => "four" }, HstoreWithSerialize.first.tags.to_hash) end def test_clone_hstore_with_serialized_attributes HstoreWithSerialize.create! tags: TagCollection.new("one" => "two") record = HstoreWithSerialize.first dupe = record.dup - assert_equal({"one" => "two"}, dupe.tags.to_hash) + assert_equal({ "one" => "two" }, dupe.tags.to_hash) end def test_schema_dump_with_shorthand @@ -321,6 +346,10 @@ if ActiveRecord::Base.connection.supports_extensions? assert_match %r[t\.hstore "tags",\s+default: {}], output end + def test_supports_to_unsafe_h_values + assert_equal("\"hi\"=>\"hi\"", @type.serialize(FakeParameters.new)) + end + private def assert_array_cycle(array) # test creation diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index d0e206ae80..93558ac4d2 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -38,11 +38,11 @@ module PostgresqlJSONSharedTestCases end def test_default - @connection.add_column "json_data_type", "permissions", column_type, default: {"users": "read", "posts": ["read", "write"]} + @connection.add_column "json_data_type", "permissions", column_type, default: { "users": "read", "posts": ["read", "write"] } JsonDataType.reset_column_information - assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.column_defaults["permissions"]) - assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.new.permissions) + assert_equal({ "users" => "read", "posts" => ["read", "write"] }, JsonDataType.column_defaults["permissions"]) + assert_equal({ "users" => "read", "posts" => ["read", "write"] }, JsonDataType.new.permissions) ensure JsonDataType.reset_column_information end @@ -68,11 +68,11 @@ module PostgresqlJSONSharedTestCases end def test_cast_value_on_write - x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar} - assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast) - assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload) + x = JsonDataType.new payload: { "string" => "foo", :symbol => :bar } + assert_equal({ "string" => "foo", :symbol => :bar }, x.payload_before_type_cast) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.payload) x.save - assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.reload.payload) end def test_type_cast_json @@ -80,12 +80,12 @@ module PostgresqlJSONSharedTestCases data = "{\"a_key\":\"a_value\"}" hash = type.deserialize(data) - assert_equal({"a_key" => "a_value"}, hash) - assert_equal({"a_key" => "a_value"}, type.deserialize(data)) + assert_equal({ "a_key" => "a_value" }, hash) + assert_equal({ "a_key" => "a_value" }, type.deserialize(data)) assert_equal({}, type.deserialize("{}")) - assert_equal({"key"=>nil}, type.deserialize('{"key": null}')) - assert_equal({"c"=>"}",'"a"'=>'b "a b'}, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) + assert_equal({ "key" => nil }, type.deserialize('{"key": null}')) + assert_equal({ "c" => "}", '"a"' => 'b "a b' }, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) end def test_rewrite @@ -98,31 +98,47 @@ module PostgresqlJSONSharedTestCases def test_select @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" x = JsonDataType.first - assert_equal({"k" => "v"}, x.payload) + assert_equal({ "k" => "v" }, x.payload) end def test_select_multikey @connection.execute %q|insert into json_data_type (payload) VALUES ('{"k1":"v1", "k2":"v2", "k3":[1,2,3]}')| x = JsonDataType.first - assert_equal({"k1" => "v1", "k2" => "v2", "k3" => [1,2,3]}, x.payload) + assert_equal({ "k1" => "v1", "k2" => "v2", "k3" => [1, 2, 3] }, x.payload) end def test_null_json @connection.execute "insert into json_data_type (payload) VALUES(null)" x = JsonDataType.first - assert_equal(nil, x.payload) + assert_nil(x.payload) + end + + def test_select_nil_json_after_create + json = JsonDataType.create(payload: nil) + x = JsonDataType.where(payload: nil).first + assert_equal(json, x) + end + + def test_select_nil_json_after_update + json = JsonDataType.create(payload: "foo") + x = JsonDataType.where(payload: nil).first + assert_nil(x) + + json.update_attributes payload: nil + x = JsonDataType.where(payload: nil).first + assert_equal(json.reload, x) end def test_select_array_json_value @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| x = JsonDataType.first - assert_equal(["v0", {"k1" => "v1"}], x.payload) + assert_equal(["v0", { "k1" => "v1" }], x.payload) end def test_rewrite_array_json_value @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| x = JsonDataType.first - x.payload = ["v1", {"k2" => "v2"}, "v3"] + x.payload = ["v1", { "k2" => "v2" }, "v3"] assert x.save! end diff --git a/activerecord/test/cases/adapters/postgresql/legacy_migration_test.rb b/activerecord/test/cases/adapters/postgresql/legacy_migration_test.rb new file mode 100644 index 0000000000..082fe95053 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/legacy_migration_test.rb @@ -0,0 +1,54 @@ +require "cases/helper" + +class PostgresqlLegacyMigrationTest < ActiveRecord::PostgreSQLTestCase + class GenerateTableWithoutBigserial < ActiveRecord::Migration[5.0] + def change + create_table :legacy_integer_pk do |table| + table.string :foo + end + + create_table :override_pk, id: :bigint do |table| + table.string :bar + end + end + end + + def setup + super + + @migration_verbose_old = ActiveRecord::Migration.verbose + ActiveRecord::Migration.verbose = false + + migrations = [GenerateTableWithoutBigserial.new(nil, 1)] + ActiveRecord::Migrator.new(:up, migrations).migrate + end + + def teardown + ActiveRecord::Migration.verbose = @migration_verbose_old + + super + end + + def test_create_table_uses_serial_as_pkey_by_default + col = column(:legacy_integer_pk, :id) + assert_equal "integer", sql_type_for(col) + assert col.serial? + end + + def test_create_tables_respects_pk_column_type_override + col = column(:override_pk, :id) + assert_equal "bigint", sql_type_for(col) + end + + private + + def column(table_name, column_name) + ActiveRecord::Base.connection. + columns(table_name.to_s). + detect { |c| c.name == column_name.to_s } + end + + def sql_type_for(col) + col && col.sql_type + end +end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 4b8d06be4b..e6af93a53e 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -88,12 +88,6 @@ module ActiveRecord assert_equal expect.to_i, result.rows.first.first end - def test_sql_for_insert_with_returning_disabled - connection = connection_without_insert_returning - sql, binds = connection.sql_for_insert("sql", nil, nil, nil, "binds") - assert_equal ["sql", "binds"], [sql, binds] - end - def test_serial_sequence assert_equal "public.accounts_id_seq", @connection.serial_sequence("accounts", "id") diff --git a/activerecord/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb b/activerecord/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb new file mode 100644 index 0000000000..8c62690866 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb @@ -0,0 +1,25 @@ +require "cases/helper" +require "models/computer" +require "models/developer" + +class PreparedStatementsDisabledTest < ActiveRecord::PostgreSQLTestCase + fixtures :developers + + def setup + @conn = ActiveRecord::Base.establish_connection :arunit_without_prepared_statements + end + + def teardown + @conn.release_connection + ActiveRecord::Base.establish_connection :arunit + end + + def test_select_query_works_even_when_prepared_statements_are_disabled + assert_not Developer.connection.prepared_statements + + david = developers(:david) + + assert_equal david, Developer.where(name: "David").last # With Binds + assert_operator Developer.count, :>, 0 # Without Binds + end +end diff --git a/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb b/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb deleted file mode 100644 index b898929f8a..0000000000 --- a/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require "cases/helper" -require "models/developer" - -class PreparedStatementsTest < ActiveRecord::PostgreSQLTestCase - fixtures :developers - - def setup - @default_prepared_statements = Developer.connection_config[:prepared_statements] - Developer.connection_config[:prepared_statements] = false - end - - def teardown - Developer.connection_config[:prepared_statements] = @default_prepared_statements - end - - def nothing_raised_with_falsy_prepared_statements - assert_nothing_raised do - Developer.where(id: 1) - end - end -end diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index 865a3a5098..141baffa5b 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -18,12 +18,12 @@ module ActiveRecord end def test_quote_float_nan - nan = 0.0/0 + nan = 0.0 / 0 assert_equal "'NaN'", @conn.quote(nan) end def test_quote_float_infinity - infinity = 1.0/0 + infinity = 1.0 / 0 assert_equal "'Infinity'", @conn.quote(infinity) end @@ -36,7 +36,7 @@ module ActiveRecord def test_quote_bit_string value = "'); SELECT * FROM users; /*\n01\n*/--" type = OID::Bit.new - assert_equal nil, @conn.quote(type.serialize(value)) + assert_nil @conn.quote(type.serialize(value)) end end end diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index 3f819f7bd5..f411884dfd 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -282,6 +282,12 @@ _SQL assert_raises(ArgumentError) { PostgresqlRange.create!(tstz_range: "(''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']") } end + def test_where_by_attribute_with_range + range = 1..100 + record = PostgresqlRange.create!(int4_range: range) + assert_equal record, PostgresqlRange.where(int4_range: range).take + end + def test_update_all_with_ranges PostgresqlRange.create! diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb index 461353d239..e9e7f717ac 100644 --- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb +++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb @@ -26,9 +26,9 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase def num_indices_named(name) @connection.execute(<<-SQL).values.length - SELECT 1 FROM "pg_index" - JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid" - WHERE "pg_class"."relname" = '#{name}' - SQL + SELECT 1 FROM "pg_index" + JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid" + WHERE "pg_class"."relname" = '#{name}' + SQL end end diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb index 22f935f24e..f6a07da85f 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb @@ -100,17 +100,17 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase end def test_tables_in_current_schemas - assert !@connection.tables.include?(TABLE_NAME) + assert_not_includes @connection.tables, TABLE_NAME USERS.each do |u| set_session_auth u - assert @connection.tables.include?(TABLE_NAME) + assert_includes @connection.tables, TABLE_NAME set_session_auth end end private def set_session_auth(auth = nil) - @connection.session_auth = auth || "default" + @connection.session_auth = auth || "default" end def bind_param(value) diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index d821cbafdf..237e9ff6a5 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -130,7 +130,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase ensure @connection.drop_schema "test_schema3" end - assert !@connection.schema_names.include?("test_schema3") + assert_not_includes @connection.schema_names, "test_schema3" end def test_drop_schema_if_exists @@ -332,7 +332,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase @connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" with_schema_search_path SCHEMA_NAME do - assert_nothing_raised { @connection.remove_index "things", name: "things_Index"} + assert_nothing_raised { @connection.remove_index "things", name: "things_Index" } end end @@ -383,7 +383,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase pk, seq = @connection.pk_and_sequence_for(given) assert_equal "id", pk, "primary key should be found when table referenced as #{given}" assert_equal pg_name.new(SCHEMA_NAME, "#{PK_TABLE_NAME}_id_seq"), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}") - assert_equal pg_name.new(SCHEMA_NAME, UNMATCHED_SEQUENCE_NAME), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}") + assert_equal pg_name.new(SCHEMA_NAME, UNMATCHED_SEQUENCE_NAME), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}") end end @@ -393,7 +393,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase SCHEMA_NAME => SCHEMA_NAME, %(#{SCHEMA2_NAME},#{SCHEMA_NAME},public) => SCHEMA2_NAME, %(public,#{SCHEMA2_NAME},#{SCHEMA_NAME}) => "public" - }.each do |given,expect| + }.each do |given, expect| with_schema_search_path(given) { assert_equal expect, @connection.current_schema } end end @@ -418,7 +418,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase SCHEMA_NAME => true, SCHEMA2_NAME => true, "darkside" => false - }.each do |given,expect| + }.each do |given, expect| assert_equal expect, @connection.schema_exists?(given) end end diff --git a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb index e7c1d97d16..962450aada 100644 --- a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb +++ b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb @@ -21,7 +21,7 @@ class PostgresqlTimestampTest < ActiveRecord::PostgreSQLTestCase @connection.reconnect! timestamp = PostgresqlTimestampWithZone.find(1) - assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time + assert_equal Time.utc(2010, 1, 1, 11, 0, 0), timestamp.time assert_instance_of Time, timestamp.time end ensure @@ -35,7 +35,7 @@ class PostgresqlTimestampTest < ActiveRecord::PostgreSQLTestCase @connection.execute("SET time zone 'America/Jamaica'", "SCHEMA") timestamp = PostgresqlTimestampWithZone.find(1) - assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time + assert_equal Time.utc(2010, 1, 1, 11, 0, 0), timestamp.time assert_instance_of Time, timestamp.time end ensure diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb index d992e22305..9b42d0383d 100644 --- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb +++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb @@ -1,5 +1,6 @@ require "cases/helper" require "support/connection_helper" +require "concurrent/atomic/cyclic_barrier" module ActiveRecord class PostgresqlTransactionTest < ActiveRecord::PostgreSQLTestCase @@ -10,6 +11,8 @@ module ActiveRecord end setup do + @abort, Thread.abort_on_exception = Thread.abort_on_exception, false + @connection = ActiveRecord::Base.connection @connection.transaction do @@ -24,35 +27,34 @@ module ActiveRecord teardown do @connection.drop_table "samples", if_exists: true + + Thread.abort_on_exception = @abort end test "raises SerializationFailure when a serialization failure occurs" do - with_warning_suppression do - assert_raises(ActiveRecord::SerializationFailure) do - thread = Thread.new do - Sample.transaction isolation: :serializable do - Sample.delete_all + assert_raises(ActiveRecord::SerializationFailure) do + before = Concurrent::CyclicBarrier.new(2) + after = Concurrent::CyclicBarrier.new(2) - 10.times do |i| - sleep 0.1 - - Sample.create value: i - end + thread = Thread.new do + with_warning_suppression do + Sample.transaction isolation: :serializable do + before.wait + Sample.create value: Sample.sum(:value) + after.wait end end + end - sleep 0.1 - - Sample.transaction isolation: :serializable do - Sample.delete_all - - 10.times do |i| - sleep 0.1 - - Sample.create value: i + begin + with_warning_suppression do + Sample.transaction isolation: :serializable do + before.wait + Sample.create value: Sample.sum(:value) + after.wait end end - + ensure thread.join end end @@ -61,37 +63,40 @@ module ActiveRecord test "raises Deadlocked when a deadlock is encountered" do with_warning_suppression do assert_raises(ActiveRecord::Deadlocked) do + barrier = Concurrent::CyclicBarrier.new(2) + s1 = Sample.create value: 1 s2 = Sample.create value: 2 thread = Thread.new do Sample.transaction do s1.lock! - sleep 1 + barrier.wait s2.update_attributes value: 1 end end - sleep 0.5 - - Sample.transaction do - s2.lock! - sleep 1 - s1.update_attributes value: 2 + begin + Sample.transaction do + s2.lock! + barrier.wait + s1.update_attributes value: 2 + end + ensure + thread.join end - - thread.join end end end - protected + private def with_warning_suppression - log_level = @connection.client_min_messages - @connection.client_min_messages = "error" + log_level = ActiveRecord::Base.connection.client_min_messages + ActiveRecord::Base.connection.client_min_messages = "error" yield - @connection.client_min_messages = log_level + ensure + ActiveRecord::Base.connection.client_min_messages = log_level end end end diff --git a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb index bd45a9daa0..784d77a8d1 100644 --- a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb +++ b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb @@ -19,7 +19,7 @@ class PostgresqlTypeLookupTest < ActiveRecord::PostgreSQLTestCase big_array = [123456789123456789] assert_raises(ActiveModel::RangeError) { int_array.serialize(big_array) } - assert_equal "{123456789123456789}", bigint_array.serialize(big_array) + assert_equal "{123456789123456789}", @connection.type_cast(bigint_array.serialize(big_array)) end test "range types correctly respect registration of subtypes" do diff --git a/activerecord/test/cases/adapters/postgresql/utils_test.rb b/activerecord/test/cases/adapters/postgresql/utils_test.rb index 70f72dd929..9f9e3bda2f 100644 --- a/activerecord/test/cases/adapters/postgresql/utils_test.rb +++ b/activerecord/test/cases/adapters/postgresql/utils_test.rb @@ -7,13 +7,13 @@ class PostgreSQLUtilsTest < ActiveRecord::PostgreSQLTestCase def test_extract_schema_qualified_name { - %(table_name) => [nil,"table_name"], - %("table.name") => [nil,"table.name"], + %(table_name) => [nil, "table_name"], + %("table.name") => [nil, "table.name"], %(schema.table_name) => %w{schema table_name}, %("schema".table_name) => %w{schema table_name}, %(schema."table_name") => %w{schema table_name}, %("schema"."table_name") => %w{schema table_name}, - %("even spaces".table) => ["even spaces","table"], + %("even spaces".table) => ["even spaces", "table"], %(schema."table.name") => ["schema", "table.name"] }.each do |given, expect| assert_equal Name.new(*expect), extract_schema_qualified_name(given) @@ -54,9 +54,9 @@ class PostgreSQLNameTest < ActiveRecord::PostgreSQLTestCase end test "can be used as hash key" do - hash = {Name.new("schema", "article_seq") => "success"} + hash = { Name.new("schema", "article_seq") => "success" } assert_equal "success", hash[Name.new("schema", "article_seq")] - assert_equal nil, hash[Name.new("schema", "articles")] - assert_equal nil, hash[Name.new("public", "article_seq")] + assert_nil hash[Name.new("schema", "articles")] + assert_nil hash[Name.new("public", "article_seq")] end end diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index 321b74c1f5..f34d50e25c 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -9,6 +9,10 @@ module PostgresqlUUIDHelper def drop_table(name) connection.drop_table name, if_exists: true end + + def uuid_function + connection.supports_pgcrypto_uuid? ? "gen_random_uuid()" : "uuid_generate_v4()" + end end class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase @@ -21,6 +25,7 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase setup do enable_extension!("uuid-ossp", connection) + enable_extension!("pgcrypto", connection) if connection.supports_pgcrypto_uuid? connection.create_table "uuid_data_type" do |t| t.uuid "guid" @@ -31,14 +36,22 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase drop_table "uuid_data_type" end + if ActiveRecord::Base.connection.supports_pgcrypto_uuid? + def test_uuid_column_default + connection.add_column :uuid_data_type, :thingy, :uuid, null: false, default: "gen_random_uuid()" + UUIDType.reset_column_information + column = UUIDType.columns_hash["thingy"] + assert_equal "gen_random_uuid()", column.default_function + end + end + def test_change_column_default - @connection.add_column :uuid_data_type, :thingy, :uuid, null: false, default: "uuid_generate_v1()" + connection.add_column :uuid_data_type, :thingy, :uuid, null: false, default: "uuid_generate_v1()" UUIDType.reset_column_information column = UUIDType.columns_hash["thingy"] assert_equal "uuid_generate_v1()", column.default_function - @connection.change_column :uuid_data_type, :thingy, :uuid, null: false, default: "uuid_generate_v4()" - + connection.change_column :uuid_data_type, :thingy, :uuid, null: false, default: "uuid_generate_v4()" UUIDType.reset_column_information column = UUIDType.columns_hash["thingy"] assert_equal "uuid_generate_v4()", column.default_function @@ -58,12 +71,12 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase def test_treat_blank_uuid_as_nil UUIDType.create! guid: "" - assert_equal(nil, UUIDType.last.guid) + assert_nil(UUIDType.last.guid) end def test_treat_invalid_uuid_as_nil uuid = UUIDType.create! guid: "foobar" - assert_equal(nil, uuid.guid) + assert_nil(uuid.guid) end def test_invalid_uuid_dont_modify_before_type_cast @@ -155,7 +168,7 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase # to test dumping tables which columns have defaults with custom functions connection.execute <<-SQL CREATE OR REPLACE FUNCTION my_uuid_generator() RETURNS uuid - AS $$ SELECT * FROM uuid_generate_v4() $$ + AS $$ SELECT * FROM #{uuid_function} $$ LANGUAGE SQL VOLATILE; SQL @@ -164,11 +177,16 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase t.string "name" t.uuid "other_uuid_2", default: "my_uuid_generator()" end + + connection.create_table("pg_uuids_3", id: :uuid) do |t| + t.string "name" + end end teardown do drop_table "pg_uuids" drop_table "pg_uuids_2" + drop_table "pg_uuids_3" connection.execute "DROP FUNCTION IF EXISTS my_uuid_generator();" end @@ -192,19 +210,49 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase def test_pk_and_sequence_for_uuid_primary_key pk, seq = connection.pk_and_sequence_for("pg_uuids") assert_equal "id", pk - assert_equal nil, seq + assert_nil seq end def test_schema_dumper_for_uuid_primary_key schema = dump_table_schema "pg_uuids" assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: -> { "uuid_generate_v1\(\)" }/, schema) - assert_match(/t\.uuid "other_uuid", default: -> { "uuid_generate_v4\(\)" }/, schema) + assert_match(/t\.uuid "other_uuid", default: -> { "uuid_generate_v4\(\)" }/, schema) end def test_schema_dumper_for_uuid_primary_key_with_custom_default schema = dump_table_schema "pg_uuids_2" assert_match(/\bcreate_table "pg_uuids_2", id: :uuid, default: -> { "my_uuid_generator\(\)" }/, schema) - assert_match(/t\.uuid "other_uuid_2", default: -> { "my_uuid_generator\(\)" }/, schema) + assert_match(/t\.uuid "other_uuid_2", default: -> { "my_uuid_generator\(\)" }/, schema) + end + + def test_schema_dumper_for_uuid_primary_key_default + schema = dump_table_schema "pg_uuids_3" + if connection.supports_pgcrypto_uuid? + assert_match(/\bcreate_table "pg_uuids_3", id: :uuid, default: -> { "gen_random_uuid\(\)" }/, schema) + else + assert_match(/\bcreate_table "pg_uuids_3", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema) + end + end + + if ActiveRecord::Base.connection.supports_pgcrypto_uuid? + def test_schema_dumper_for_uuid_primary_key_default_in_legacy_migration + @verbose_was = ActiveRecord::Migration.verbose + ActiveRecord::Migration.verbose = false + + migration = Class.new(ActiveRecord::Migration[4.2]) do + def version; 101 end + def migrate(x) + create_table("pg_uuids_4", id: :uuid) + end + end.new + ActiveRecord::Migrator.new(:up, [migration]).migrate + + schema = dump_table_schema "pg_uuids_4" + assert_match(/\bcreate_table "pg_uuids_4", id: :uuid, default: -> { "uuid_generate_v4\(\)" }/, schema) + ensure + drop_table "pg_uuids_4" + ActiveRecord::Migration.verbose = @verbose_was + end end 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 70e2f0fec1..91967c1e33 100644 --- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb @@ -11,7 +11,7 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase end def test_copy_table(from = "customers", to = "customers2", options = {}) - assert_nothing_raised {copy_table(from, to, options)} + assert_nothing_raised { copy_table(from, to, options) } assert_equal row_count(from), row_count(to) if block_given? @@ -25,7 +25,7 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase def test_copy_table_renaming_column test_copy_table("customers", "customers2", - rename: {"name" => "person_name"}) do |from, to, options| + rename: { "name" => "person_name" }) do |from, to, options| expected = column_values(from, "name") assert_equal expected, column_values(to, "person_name") assert expected.any?, "No values in table: #{expected.inspect}" @@ -55,8 +55,8 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase def test_copy_table_with_id_col_that_is_not_primary_key test_copy_table("goofy_string_id", "goofy_string_id2") do - original_id = @connection.columns("goofy_string_id").detect{|col| col.name == "id" } - copied_id = @connection.columns("goofy_string_id2").detect{|col| col.name == "id" } + original_id = @connection.columns("goofy_string_id").detect { |col| col.name == "id" } + copied_id = @connection.columns("goofy_string_id2").detect { |col| col.name == "id" } assert_equal original_id.type, copied_id.type assert_equal original_id.sql_type, copied_id.sql_type assert_equal original_id.limit, copied_id.limit @@ -75,17 +75,17 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase test_copy_table "binaries", "binaries2" end -protected +private def copy_table(from, to, options = {}) - @connection.copy_table(from, to, {temporary: true}.merge(options)) + @connection.copy_table(from, to, { temporary: true }.merge(options)) end def column_names(table) - @connection.table_structure(table).map {|column| column["name"]} + @connection.table_structure(table).map { |column| column["name"] } end def column_values(table, column) - @connection.select_all("SELECT #{column} FROM #{table} ORDER BY id").map {|row| row[column]} + @connection.select_all("SELECT #{column} FROM #{table} ORDER BY id").map { |row| row[column] } end def table_indexes_without_name(table) diff --git a/activerecord/test/cases/adapters/sqlite3/legacy_migration_test.rb b/activerecord/test/cases/adapters/sqlite3/legacy_migration_test.rb new file mode 100644 index 0000000000..fcca8d66b5 --- /dev/null +++ b/activerecord/test/cases/adapters/sqlite3/legacy_migration_test.rb @@ -0,0 +1,59 @@ +require "cases/helper" + +class SqliteLegacyMigrationTest < ActiveRecord::SQLite3TestCase + self.use_transactional_tests = false + + class GenerateTableWithoutBigint < ActiveRecord::Migration[5.0] + def change + create_table :legacy_integer_pk do |table| + table.string :foo + end + + create_table :override_pk, id: :bigint do |table| + table.string :bar + end + end + end + + def setup + super + @connection = ActiveRecord::Base.connection + + @migration_verbose_old = ActiveRecord::Migration.verbose + ActiveRecord::Migration.verbose = false + + migrations = [GenerateTableWithoutBigint.new(nil, 1)] + + ActiveRecord::Migrator.new(:up, migrations).migrate + end + + def teardown + ActiveRecord::Migration.verbose = @migration_verbose_old + @connection.drop_table("legacy_integer_pk") + @connection.drop_table("override_pk") + ActiveRecord::SchemaMigration.delete_all rescue nil + super + end + + def test_create_table_uses_integer_as_pkey_by_default + col = column(:legacy_integer_pk, :id) + assert_equal "INTEGER", sql_type_for(col) + assert primary_key?(:legacy_integer_pk, "id"), "id is not primary key" + end + + private + + def column(table_name, column_name) + ActiveRecord::Base.connection + .columns(table_name.to_s) + .detect { |c| c.name == column_name.to_s } + end + + def sql_type_for(col) + col && col.sql_type + end + + def primary_key?(table_name, column) + ActiveRecord::Base.connection.execute("PRAGMA table_info(#{table_name})").find { |col| col["name"] == column }["pk"] == 1 + end +end diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb index 80a37e83ff..9750840051 100644 --- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb @@ -37,7 +37,7 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase end def test_type_cast_nil - assert_equal nil, @conn.type_cast(nil) + assert_nil @conn.type_cast(nil) end def test_type_cast_true diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 4800d3d7d5..a6109348cc 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -190,7 +190,7 @@ module ActiveRecord end def test_type_cast_should_not_mutate_encoding - name = "hello".force_encoding(Encoding::ASCII_8BIT) + name = "hello".force_encoding(Encoding::ASCII_8BIT) Owner.create(name: name) assert_equal Encoding::ASCII_8BIT, name.encoding ensure @@ -267,9 +267,9 @@ module ActiveRecord def test_tables with_example_table do - ActiveSupport::Deprecation.silence { assert_equal %w{ ex }, @conn.tables } + assert_equal %w{ ex }, @conn.tables with_example_table "id integer PRIMARY KEY AUTOINCREMENT, number integer", "people" do - ActiveSupport::Deprecation.silence { assert_equal %w{ ex people }.sort, @conn.tables.sort } + assert_equal %w{ ex people }.sort, @conn.tables.sort end end end @@ -277,12 +277,10 @@ module ActiveRecord def test_tables_logs_name sql = <<-SQL SELECT name FROM sqlite_master - WHERE type IN ('table','view') AND name <> 'sqlite_sequence' + WHERE type = 'table' AND name <> 'sqlite_sequence' SQL assert_logged [[sql.squish, "SCHEMA", []]] do - ActiveSupport::Deprecation.silence do - @conn.tables("hello") - end + @conn.tables end end @@ -298,12 +296,10 @@ module ActiveRecord with_example_table do sql = <<-SQL SELECT name FROM sqlite_master - WHERE type IN ('table','view') AND name <> 'sqlite_sequence' AND name = 'ex' + WHERE type = 'table' AND name <> 'sqlite_sequence' AND name = 'ex' SQL assert_logged [[sql.squish, "SCHEMA", []]] do - ActiveSupport::Deprecation.silence do - assert @conn.table_exists?("ex") - end + assert @conn.table_exists?("ex") end end end @@ -405,7 +401,7 @@ module ActiveRecord configurations["arunit"]["database"]) statement = ::SQLite3::Statement.new(db, "CREATE TABLE statement_test (number integer not null)") - statement.stub(:step, ->{ raise ::SQLite3::BusyException.new("busy") }) do + statement.stub(:step, -> { raise ::SQLite3::BusyException.new("busy") }) do assert_called(statement, :columns, returns: []) do assert_called(statement, :close) do ::SQLite3::Statement.stub(:new, statement) do @@ -431,9 +427,9 @@ module ActiveRecord def with_example_table(definition = nil, table_name = "ex", &block) definition ||= <<-SQL - id integer PRIMARY KEY AUTOINCREMENT, - number integer - SQL + id integer PRIMARY KEY AUTOINCREMENT, + number integer + SQL super(@conn, table_name, definition, &block) end end diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index a4919c913d..397ac599b9 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -17,6 +17,7 @@ if ActiveRecord::Base.connection.supports_migrations? @connection.drop_table :nep_fruits rescue nil @connection.drop_table :nep_schema_migrations rescue nil @connection.drop_table :has_timestamps rescue nil + @connection.drop_table :multiple_indexes rescue nil ActiveRecord::SchemaMigration.delete_all rescue nil ActiveRecord::Migration.verbose = @original_verbose end @@ -53,7 +54,7 @@ if ActiveRecord::Base.connection.supports_migrations? def test_schema_define_w_table_name_prefix table_name = ActiveRecord::SchemaMigration.table_name old_table_name_prefix = ActiveRecord::Base.table_name_prefix - ActiveRecord::Base.table_name_prefix = "nep_" + ActiveRecord::Base.table_name_prefix = "nep_" ActiveRecord::SchemaMigration.table_name = "nep_#{table_name}" ActiveRecord::Schema.define(version: 7) do create_table :fruits do |t| @@ -65,7 +66,7 @@ if ActiveRecord::Base.connection.supports_migrations? end assert_equal 7, ActiveRecord::Migrator::current_version ensure - ActiveRecord::Base.table_name_prefix = old_table_name_prefix + ActiveRecord::Base.table_name_prefix = old_table_name_prefix ActiveRecord::SchemaMigration.table_name = table_name end @@ -93,6 +94,21 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "20131219224947", ActiveRecord::SchemaMigration.normalize_migration_number("20131219224947") end + def test_schema_load_with_multiple_indexes_for_column_of_different_names + ActiveRecord::Schema.define do + create_table :multiple_indexes do |t| + t.string "foo" + t.index ["foo"], name: "multiple_indexes_foo_1" + t.index ["foo"], name: "multiple_indexes_foo_2" + end + end + + indexes = @connection.indexes("multiple_indexes") + + assert_equal 2, indexes.length + assert_equal ["multiple_indexes_foo_1", "multiple_indexes_foo_2"], indexes.collect(&:name).sort + end + def test_timestamps_without_null_set_null_to_false_on_create_table ActiveRecord::Schema.define do create_table :has_timestamps do |t| diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 2413bf0c3a..5875a1871f 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -94,7 +94,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase account = model.new assert_not account.valid? - assert_equal [{error: :blank}], account.errors.details[:company] + assert_equal [{ error: :blank }], account.errors.details[:company] ensure ActiveRecord::Base.belongs_to_required_by_default = original_value end @@ -111,7 +111,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase account = model.new assert_not account.valid? - assert_equal [{error: :blank}], account.errors.details[:company] + assert_equal [{ error: :blank }], account.errors.details[:company] ensure ActiveRecord::Base.belongs_to_required_by_default = original_value end @@ -203,14 +203,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_eager_loading_with_primary_key Firm.create("name" => "Apple") Client.create("name" => "Citibank", :firm_name => "Apple") - citibank_result = Client.all.merge!(where: {name: "Citibank"}, includes: :firm_with_primary_key).first + citibank_result = Client.all.merge!(where: { name: "Citibank" }, includes: :firm_with_primary_key).first assert citibank_result.association(:firm_with_primary_key).loaded? end def test_eager_loading_with_primary_key_as_symbol Firm.create("name" => "Apple") Client.create("name" => "Citibank", :firm_name => "Apple") - citibank_result = Client.all.merge!(where: {name: "Citibank"}, includes: :firm_with_primary_key_symbols).first + citibank_result = Client.all.merge!(where: { name: "Citibank" }, includes: :firm_with_primary_key_symbols).first assert citibank_result.association(:firm_with_primary_key_symbols).loaded? end @@ -285,12 +285,22 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_failing_create! - client = Client.create!(name: "Jimmy") + client = Client.create!(name: "Jimmy") assert_raise(ActiveRecord::RecordInvalid) { client.create_account! } assert_not_nil client.account assert client.account.new_record? end + def test_reloading_the_belonging_object + odegy_account = accounts(:odegy_account) + + assert_equal "Odegy", odegy_account.firm.name + Company.where(id: odegy_account.firm_id).update_all(name: "ODEGY") + assert_equal "Odegy", odegy_account.firm.name + + assert_equal "ODEGY", odegy_account.reload_firm.name + end + def test_natural_assignment_to_nil client = Client.find(3) client.firm = nil @@ -346,7 +356,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_with_select assert_equal 1, Company.find(2).firm_with_select.attributes.size - assert_equal 1, Company.all.merge!(includes: :firm_with_select ).find(2).firm_with_select.attributes.size + assert_equal 1, Company.all.merge!(includes: :firm_with_select).find(2).firm_with_select.attributes.size end def test_belongs_to_without_counter_cache_option @@ -626,6 +636,12 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_queries(0) { tagging.super_tag } end + def test_dont_find_target_when_saving_foreign_key_after_stale_association_loaded + client = Client.create!(name: "Test client", firm_with_basic_id: Firm.find(1)) + client.firm_id = Firm.create!(name: "Test firm").id + assert_queries(1) { client.save! } + end + def test_field_name_same_as_foreign_key computer = Computer.find(1) assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # ' @@ -1004,21 +1020,21 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_build_with_block client = Client.create(name: "Client Company") - firm = client.build_firm{ |f| f.name = "Agency Company" } + firm = client.build_firm { |f| f.name = "Agency Company" } assert_equal "Agency Company", firm.name end def test_create_with_block client = Client.create(name: "Client Company") - firm = client.create_firm{ |f| f.name = "Agency Company" } + firm = client.create_firm { |f| f.name = "Agency Company" } assert_equal "Agency Company", firm.name end def test_create_bang_with_block client = Client.create(name: "Client Company") - firm = client.create_firm!{ |f| f.name = "Agency Company" } + firm = client.create_firm! { |f| f.name = "Agency Company" } assert_equal "Agency Company", firm.name end @@ -1041,7 +1057,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase comment.parent = nil comment.save! - assert_equal nil, comment.reload.parent + assert_nil comment.reload.parent assert_equal 0, comments(:greetings).reload.children_count end @@ -1056,6 +1072,20 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 1, parent.reload.children_count end + def test_belongs_to_with_out_of_range_value_assigning + model = Class.new(Comment) do + def self.name; "Temp"; end + validates :post, presence: true + end + + comment = model.new + comment.post_id = 9223372036854775808 # out of range in the bigint + + assert_nil comment.post + assert_not comment.valid? + assert_equal [{ error: :blank }], comment.errors.details[:post] + end + def test_polymorphic_with_custom_primary_key toy = Toy.create! sponsor = Sponsor.create!(sponsorable: toy) @@ -1101,12 +1131,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase Column.create! record: record assert_equal 1, Column.count end - - def test_association_force_reload_with_only_true_is_deprecated - client = Client.find(3) - - assert_deprecated { client.firm(true) } - end end class BelongsToWithForeignKeyTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/associations/callbacks_test.rb b/activerecord/test/cases/associations/callbacks_test.rb index 74876c8cf0..5fd2411f6f 100644 --- a/activerecord/test/cases/associations/callbacks_test.rb +++ b/activerecord/test/cases/associations/callbacks_test.rb @@ -109,7 +109,7 @@ class AssociationCallbacksTest < ActiveRecord::TestCase def self.name; Project.name; end has_and_belongs_to_many :developers_with_callbacks, class_name: "Developer", - before_add: lambda { |o,r| + before_add: lambda { |o, r| dev = r new_dev = r.new_record? } @@ -159,7 +159,7 @@ class AssociationCallbacksTest < ActiveRecord::TestCase activerecord.reload assert activerecord.developers_with_callbacks.size == 2 end - activerecord.developers_with_callbacks.flat_map {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.sort + activerecord.developers_with_callbacks.flat_map { |d| ["before_removing#{d.id}", "after_removing#{d.id}"] }.sort assert activerecord.developers_with_callbacks.clear assert_predicate activerecord.developers_log, :empty? end @@ -176,14 +176,14 @@ class AssociationCallbacksTest < ActiveRecord::TestCase end def test_dont_add_if_before_callback_raises_exception - assert !@david.unchangeable_posts.include?(@authorless) + assert_not_includes @david.unchangeable_posts, @authorless begin @david.unchangeable_posts << @authorless rescue Exception end assert @david.post_log.empty? - assert !@david.unchangeable_posts.include?(@authorless) + assert_not_includes @david.unchangeable_posts, @authorless @david.reload - assert !@david.unchangeable_posts.include?(@authorless) + assert_not_includes @david.unchangeable_posts, @authorless end end diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index d79246a6c7..ddb5c7a4aa 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -16,28 +16,28 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase :categorizations, :people, :categories, :edges, :vertices def test_eager_association_loading_with_cascaded_two_levels - authors = Author.all.merge!(includes: {posts: :comments}, order: "authors.id").to_a + authors = Author.all.merge!(includes: { posts: :comments }, order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + assert_equal 10, authors[0].posts.collect { |post| post.comments.size }.inject(0) { |sum, i| sum + i } end def test_eager_association_loading_with_cascaded_two_levels_and_one_level - authors = Author.all.merge!(includes: [{posts: :comments}, :categorizations], order: "authors.id").to_a + authors = Author.all.merge!(includes: [{ posts: :comments }, :categorizations], order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + assert_equal 10, authors[0].posts.collect { |post| post.comments.size }.inject(0) { |sum, i| sum + i } assert_equal 1, authors[0].categorizations.size assert_equal 2, authors[1].categorizations.size end def test_eager_association_loading_with_hmt_does_not_table_name_collide_when_joining_associations assert_nothing_raised do - Author.joins(:posts).eager_load(:comments).where(posts: {tags_count: 1}).to_a + Author.joins(:posts).eager_load(:comments).where(posts: { tags_count: 1 }).to_a end - authors = Author.joins(:posts).eager_load(:comments).where(posts: {tags_count: 1}).to_a + authors = Author.joins(:posts).eager_load(:comments).where(posts: { tags_count: 1 }).to_a assert_equal 1, assert_no_queries { authors.size } assert_equal 10, assert_no_queries { authors[0].comments.size } end @@ -50,7 +50,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_cascaded_eager_association_loading_with_join_for_count - categories = Category.joins(:categorizations).includes([{posts: :comments}, :authors]) + categories = Category.joins(:categorizations).includes([{ posts: :comments }, :authors]) assert_equal 4, categories.count assert_equal 4, categories.to_a.count @@ -82,29 +82,29 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations - authors = Author.all.merge!(includes: {posts: [:comments, :categorizations]}, order: "authors.id").to_a + authors = Author.all.merge!(includes: { posts: [:comments, :categorizations] }, order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + assert_equal 10, authors[0].posts.collect { |post| post.comments.size }.inject(0) { |sum, i| sum + i } end def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference - authors = Author.all.merge!(includes: {posts: [:comments, :author]}, order: "authors.id").to_a + authors = Author.all.merge!(includes: { posts: [:comments, :author] }, order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal authors(:david).name, authors[0].name - assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq + assert_equal [authors(:david).name], authors[0].posts.collect { |post| post.author.name }.uniq end def test_eager_association_loading_with_cascaded_two_levels_with_condition - authors = Author.all.merge!(includes: {posts: :comments}, where: "authors.id=1", order: "authors.id").to_a + authors = Author.all.merge!(includes: { posts: :comments }, where: "authors.id=1", order: "authors.id").to_a assert_equal 1, authors.size assert_equal 5, authors[0].posts.size end def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong - firms = Firm.all.merge!(includes: {account: {firm: :account}}, order: "companies.id").to_a + firms = Firm.all.merge!(includes: { account: { firm: :account } }, order: "companies.id").to_a assert_equal 2, firms.size assert_equal firms.first.account, firms.first.account.firm.account assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account } @@ -134,8 +134,8 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase def test_eager_association_loading_with_belongs_to_sti replies = Reply.all.merge!(includes: :topic, order: "topics.id").to_a - assert replies.include?(topics(:second)) - assert !replies.include?(topics(:first)) + assert_includes replies, topics(:second) + assert_not_includes replies, topics(:first) assert_equal topics(:first), assert_no_queries { replies.first.topic } end @@ -158,7 +158,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_where_first_level_returns_nil - authors = Author.all.merge!(includes: {post_about_thinking: :comments}, order: "authors.id DESC").to_a + authors = Author.all.merge!(includes: { post_about_thinking: :comments }, order: "authors.id DESC").to_a assert_equal [authors(:bob), authors(:mary), authors(:david)], authors assert_no_queries do authors[2].post_about_thinking.comments.first @@ -166,12 +166,12 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through - source = Vertex.all.merge!(includes: {sinks: {sinks: {sinks: :sinks}}}, order: "vertices.id").first + source = Vertex.all.merge!(includes: { sinks: { sinks: { sinks: :sinks } } }, order: "vertices.id").first assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first } end def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many - sink = Vertex.all.merge!(includes: {sources: {sources: {sources: :sources}}}, order: "vertices.id DESC").first + sink = Vertex.all.merge!(includes: { sources: { sources: { sources: :sources } } }, order: "vertices.id DESC").first assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first } end @@ -183,6 +183,6 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase assert_equal 1, authors[1].comments.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 3, authors[0].posts.collect { |post| post.categorizations.size }.inject(0) { |sum, i| sum+i } + assert_equal 3, authors[0].posts.collect { |post| post.categorizations.size }.inject(0) { |sum, i| sum + i } end end diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb index aa82b9dd2a..4f0fe3236e 100644 --- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -15,8 +15,8 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase end def generate_test_objects - post = Namespaced::Post.create( title: "Great stuff", body: "This is not", author_id: 1 ) - Tagging.create( taggable: post ) + post = Namespaced::Post.create(title: "Great stuff", body: "This is not", author_id: 1) + Tagging.create(taggable: post) end def test_class_names diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb index aebece1b91..e9f551b6b2 100644 --- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb +++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb @@ -12,7 +12,7 @@ module Remembered included do after_create :remember - protected + private def remember; self.class.remembered << self; end end @@ -39,7 +39,7 @@ class Triangle < ActiveRecord::Base has_many :shape_expressions, as: :shape include Remembered end -class PaintColor < ActiveRecord::Base +class PaintColor < ActiveRecord::Base has_many :shape_expressions, as: :paint belongs_to :non_poly, foreign_key: "non_poly_one_id", class_name: "NonPolyOne" include Remembered @@ -117,8 +117,8 @@ class EagerLoadNestedIncludeWithMissingDataTest < ActiveRecord::TestCase def test_missing_data_in_a_nested_include_should_not_cause_errors_when_constructing_objects assert_nothing_raised do # @davey_mcdave doesn't have any author_favorites - includes = {posts: :comments, categorizations: :category, author_favorites: :favorite_author } - Author.all.merge!(includes: includes, where: {authors: {name: @davey_mcdave.name}}, order: "categories.name").to_a + includes = { posts: :comments, categorizations: :category, author_favorites: :favorite_author } + Author.all.merge!(includes: includes, where: { authors: { name: @davey_mcdave.name } }, order: "categories.name").to_a end end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index c7c945e33f..ff1bf8acd4 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -42,11 +42,11 @@ class EagerAssociationTest < ActiveRecord::TestCase posts = Post.all.merge!(includes: :comments).to_a post = posts.find { |p| p.id == 1 } assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) post = Post.all.merge!(includes: :comments, where: "posts.title = 'Welcome to the weblog'").first assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) posts = Post.all.merge!(includes: :last_comment).to_a post = posts.find { |p| p.id == 1 } @@ -103,13 +103,13 @@ class EagerAssociationTest < ActiveRecord::TestCase posts = Post.all.merge!(includes: [ :comments, :author, :categories ], order: "posts.id").to_a assert_equal 2, posts.first.comments.size assert_equal 2, posts.first.categories.size - assert posts.first.comments.include?(comments(:greetings)) + assert_includes posts.first.comments, comments(:greetings) end def test_duplicate_middle_objects comments = Comment.all.merge!(where: "post_id = 1", includes: [post: :author]).to_a assert_no_queries do - comments.each {|comment| comment.post.author.name} + comments.each { |comment| comment.post.author.name } end end @@ -175,7 +175,7 @@ class EagerAssociationTest < ActiveRecord::TestCase popular_post.readers.create!(person: people(:david)) readers = Reader.all.merge!(where: ["post_id = ?", popular_post.id], - includes: {post: :comments}).to_a + includes: { post: :comments }).to_a readers.each do |reader| assert_equal [comment], reader.post.comments end @@ -188,7 +188,7 @@ class EagerAssociationTest < ActiveRecord::TestCase comment = car_post.comments.create!(body: "hmm") categories = Category.all.merge!(where: { "posts.id" => car_post.id }, - includes: {posts: :comments}).to_a + includes: { posts: :comments }).to_a categories.each do |category| assert_equal [comment], category.posts[0].comments end @@ -206,7 +206,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_finding_with_includes_on_has_many_association_with_same_include_includes_only_once author_id = authors(:david).id - author = assert_queries(3) { Author.all.merge!(includes: {posts_with_comments: :comments}).find(author_id) } # find the author, then find the posts, then find the comments + author = assert_queries(3) { Author.all.merge!(includes: { posts_with_comments: :comments }).find(author_id) } # find the author, then find the posts, then find the comments author.posts_with_comments.each do |post_with_comments| assert_equal post_with_comments.comments.length, post_with_comments.comments.count assert_nil post_with_comments.comments.to_a.uniq! @@ -217,7 +217,7 @@ class EagerAssociationTest < ActiveRecord::TestCase author = authors(:david) post = author.post_about_thinking_with_last_comment last_comment = post.last_comment - author = assert_queries(3) { Author.all.merge!(includes: {post_about_thinking_with_last_comment: :last_comment}).find(author.id)} # find the author, then find the posts, then find the comments + author = assert_queries(3) { Author.all.merge!(includes: { post_about_thinking_with_last_comment: :last_comment }).find(author.id) } # find the author, then find the posts, then find the comments assert_no_queries do assert_equal post, author.post_about_thinking_with_last_comment assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment @@ -228,7 +228,7 @@ class EagerAssociationTest < ActiveRecord::TestCase post = posts(:welcome) author = post.author author_address = author.author_address - post = assert_queries(3) { Post.all.merge!(includes: {author_with_address: :author_address}).find(post.id) } # find the post, then find the author, then find the address + post = assert_queries(3) { Post.all.merge!(includes: { author_with_address: :author_address }).find(post.id) } # find the post, then find the author, then find the address assert_no_queries do assert_equal author, post.author_with_address assert_equal author_address, post.author_with_address.author_address @@ -238,10 +238,10 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once post = posts(:welcome) post.update!(author: nil) - post = assert_queries(1) { Post.all.merge!(includes: {author_with_address: :author_address}).find(post.id) } + post = assert_queries(1) { Post.all.merge!(includes: { author_with_address: :author_address }).find(post.id) } # find the post, then find the author which is null so no query for the author or address assert_no_queries do - assert_equal nil, post.author_with_address + assert_nil post.author_with_address end end @@ -250,7 +250,7 @@ class EagerAssociationTest < ActiveRecord::TestCase sponsor.update!(sponsorable: nil) sponsor = assert_queries(1) { Sponsor.all.merge!(includes: :sponsorable).find(sponsor.id) } assert_no_queries do - assert_equal nil, sponsor.sponsorable + assert_nil sponsor.sponsorable end end @@ -261,7 +261,7 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_nothing_raised { Sponsor.all.merge!(includes: :sponsorable).find(sponsor.id) } end assert_no_queries do - assert_equal nil, sponsor.sponsorable + assert_nil sponsor.sponsorable end end @@ -284,7 +284,7 @@ class EagerAssociationTest < ActiveRecord::TestCase # Regression test for 21c75e5 def test_nested_loading_does_not_raise_exception_when_association_does_not_exist assert_nothing_raised do - Post.all.merge!(includes: {author: :author_addresss}).find(posts(:authorless).id) + Post.all.merge!(includes: { author: :author_addresss }).find(posts(:authorless).id) end end @@ -292,33 +292,33 @@ class EagerAssociationTest < ActiveRecord::TestCase post_id = Comment.where(author_id: nil).where.not(post_id: nil).first.post_id assert_nothing_raised do - Post.preload(comments: [{author: :essays}]).find(post_id) + Post.preload(comments: [{ author: :essays }]).find(post_id) end end def test_nested_loading_through_has_one_association - aa = AuthorAddress.all.merge!(includes: {author: :posts}).find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }).find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_order - aa = AuthorAddress.all.merge!(includes: {author: :posts}, order: "author_addresses.id").find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "author_addresses.id").find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_order_on_association - aa = AuthorAddress.all.merge!(includes: {author: :posts}, order: "authors.id").find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "authors.id").find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_order_on_nested_association - aa = AuthorAddress.all.merge!(includes: {author: :posts}, order: "posts.id").find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "posts.id").find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_conditions aa = AuthorAddress.references(:author_addresses).merge( - includes: {author: :posts}, + includes: { author: :posts }, where: "author_addresses.id > 0" ).find author_addresses(:david_address).id assert_equal aa.author.posts.count, aa.author.posts.length @@ -326,7 +326,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_nested_loading_through_has_one_association_with_conditions_on_association aa = AuthorAddress.references(:authors).merge( - includes: {author: :posts}, + includes: { author: :posts }, where: "authors.id > 0" ).find author_addresses(:david_address).id assert_equal aa.author.posts.count, aa.author.posts.length @@ -334,7 +334,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_nested_loading_through_has_one_association_with_conditions_on_nested_association aa = AuthorAddress.references(:posts).merge( - includes: {author: :posts}, + includes: { author: :posts }, where: "posts.id > 0" ).find author_addresses(:david_address).id assert_equal aa.author.posts.count, aa.author.posts.length @@ -349,38 +349,38 @@ class EagerAssociationTest < ActiveRecord::TestCase comments = Comment.all.merge!(includes: :post).to_a assert_equal 11, comments.length titles = comments.map { |c| c.post.title } - assert titles.include?(posts(:welcome).title) - assert titles.include?(posts(:sti_post_and_comments).title) + assert_includes titles, posts(:welcome).title + assert_includes titles, posts(:sti_post_and_comments).title end def test_eager_association_loading_with_belongs_to_and_limit comments = Comment.all.merge!(includes: :post, limit: 5, order: "comments.id").to_a assert_equal 5, comments.length - assert_equal [1,2,3,5,6], comments.collect(&:id) + assert_equal [1, 2, 3, 5, 6], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_conditions comments = Comment.all.merge!(includes: :post, where: "post_id = 4", limit: 3, order: "comments.id").to_a assert_equal 3, comments.length - assert_equal [5,6,7], comments.collect(&:id) + assert_equal [5, 6, 7], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset comments = Comment.all.merge!(includes: :post, limit: 3, offset: 2, order: "comments.id").to_a assert_equal 3, comments.length - assert_equal [3,5,6], comments.collect(&:id) + assert_equal [3, 5, 6], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions comments = Comment.all.merge!(includes: :post, where: "post_id = 4", limit: 3, offset: 1, order: "comments.id").to_a assert_equal 3, comments.length - assert_equal [6,7,8], comments.collect(&:id) + assert_equal [6, 7, 8], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array - comments = Comment.all.merge!(includes: :post, where: ["post_id = ?",4], limit: 3, offset: 1, order: "comments.id").to_a + comments = Comment.all.merge!(includes: :post, where: ["post_id = ?", 4], limit: 3, offset: 1, order: "comments.id").to_a assert_equal 3, comments.length - assert_equal [6,7,8], comments.collect(&:id) + assert_equal [6, 7, 8], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_conditions_string_with_unquoted_table_name @@ -392,17 +392,17 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_association_loading_with_belongs_to_and_conditions_hash comments = [] assert_nothing_raised do - comments = Comment.all.merge!(includes: :post, where: {posts: {id: 4}}, limit: 3, order: "comments.id").to_a + comments = Comment.all.merge!(includes: :post, where: { posts: { id: 4 } }, limit: 3, order: "comments.id").to_a end assert_equal 3, comments.length - assert_equal [5,6,7], comments.collect(&:id) + assert_equal [5, 6, 7], comments.collect(&:id) assert_no_queries do comments.first.post end end def test_eager_association_loading_with_belongs_to_and_conditions_string_with_quoted_table_name - quoted_posts_id= Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") + quoted_posts_id = Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") assert_nothing_raised do Comment.includes(:post).references(:posts).where("#{quoted_posts_id} = ?", 4) end @@ -415,7 +415,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name - quoted_posts_id= Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") + quoted_posts_id = Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") assert_nothing_raised do Comment.includes(:post).references(:posts).order(quoted_posts_id) end @@ -441,30 +441,30 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_load_belongs_to_quotes_table_and_column_names job = Job.includes(:ideal_reference).find jobs(:unicyclist).id references(:michael_unicyclist) - assert_no_queries{ assert_equal references(:michael_unicyclist), job.ideal_reference} + assert_no_queries { assert_equal references(:michael_unicyclist), job.ideal_reference } end def test_eager_load_has_one_quotes_table_and_column_names michael = Person.all.merge!(includes: :favourite_reference).find(people(:michael).id) references(:michael_unicyclist) - assert_no_queries{ assert_equal references(:michael_unicyclist), michael.favourite_reference} + assert_no_queries { assert_equal references(:michael_unicyclist), michael.favourite_reference } end def test_eager_load_has_many_quotes_table_and_column_names michael = Person.all.merge!(includes: :references).find(people(:michael).id) - references(:michael_magician,:michael_unicyclist) - assert_no_queries{ assert_equal references(:michael_magician,:michael_unicyclist), michael.references.sort_by(&:id) } + references(:michael_magician, :michael_unicyclist) + assert_no_queries { assert_equal references(:michael_magician, :michael_unicyclist), michael.references.sort_by(&:id) } end def test_eager_load_has_many_through_quotes_table_and_column_names michael = Person.all.merge!(includes: :jobs).find(people(:michael).id) jobs(:magician, :unicyclist) - assert_no_queries{ assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) } + assert_no_queries { assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) } end def test_eager_load_has_many_with_string_keys subscriptions = subscriptions(:webster_awdr, :webster_rfr) - subscriber =Subscriber.all.merge!(includes: :subscriptions).find(subscribers(:second).id) + subscriber = Subscriber.all.merge!(includes: :subscriptions).find(subscribers(:second).id) assert_equal subscriptions, subscriber.subscriptions.sort_by(&:id) end @@ -563,13 +563,13 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_has_many_and_limit_and_conditions posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: "posts.body = 'hello'", order: "posts.id").to_a assert_equal 2, posts.size - assert_equal [4,5], posts.collect(&:id) + assert_equal [4, 5], posts.collect(&:id) end def test_eager_with_has_many_and_limit_and_conditions_array posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: [ "posts.body = ?", "hello" ], order: "posts.id").to_a assert_equal 2, posts.size - assert_equal [4,5], posts.collect(&:id) + assert_equal [4, 5], posts.collect(&:id) end def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers @@ -630,8 +630,8 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal 2, posts[0].categories.size assert_equal 1, posts[1].categories.size assert_equal 0, posts[2].categories.size - assert posts[0].categories.include?(categories(:technology)) - assert posts[1].categories.include?(categories(:general)) + assert_includes posts[0].categories, categories(:technology) + assert_includes posts[1].categories, categories(:general) end # Since the preloader for habtm gets raw row hashes from the database and then @@ -695,8 +695,8 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal 2, posts[0].categories.size assert_equal 1, posts[1].categories.size assert_equal 0, posts[2].categories.size - assert posts[0].categories.include?(categories(:technology)) - assert posts[1].categories.include?(categories(:general)) + assert_includes posts[0].categories, categories(:technology) + assert_includes posts[1].categories, categories(:general) end def test_eager_with_inheritance @@ -740,7 +740,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_invalid_association_reference assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - Post.all.merge!(includes: :monkeys ).find(6) + Post.all.merge!(includes: :monkeys).find(6) } assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { Post.all.merge!(includes: [ :monkeys ]).find(6) @@ -844,7 +844,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end end - def find_all_ordered(className, include=nil) + def find_all_ordered(className, include = nil) className.all.merge!(order: "#{className.table_name}.#{className.primary_key}", includes: include).to_a end @@ -895,16 +895,16 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_polymorphic_type_condition post = Post.all.merge!(includes: :taggings).find(posts(:thinking).id) - assert post.taggings.include?(taggings(:thinking_general)) + assert_includes post.taggings, taggings(:thinking_general) post = SpecialPost.all.merge!(includes: :taggings).find(posts(:thinking).id) - assert post.taggings.include?(taggings(:thinking_general)) + assert_includes post.taggings, taggings(:thinking_general) end def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm # Eager includes of has many and habtm associations aren't necessarily sorted in the same way def assert_equal_after_sort(item1, item2, item3 = nil) - assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) - assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3 + assert_equal(item1.sort { |a, b| a.id <=> b.id }, item2.sort { |a, b| a.id <=> b.id }) + assert_equal(item3.sort { |a, b| a.id <=> b.id }, item2.sort { |a, b| a.id <=> b.id }) if item3 end # Test regular association, association with conditions, association with # STI, and association with conditions assured not to be true @@ -959,12 +959,12 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_preconfigured_includes_with_belongs_to author = posts(:welcome).author_with_posts - assert_no_queries {assert_equal 5, author.posts.size} + assert_no_queries { assert_equal 5, author.posts.size } end def test_preconfigured_includes_with_has_one comment = posts(:sti_comments).very_special_comment_with_post - assert_no_queries {assert_equal posts(:sti_comments), comment.post} + assert_no_queries { assert_equal posts(:sti_comments), comment.post } end def test_eager_association_with_scope_with_joins @@ -1066,7 +1066,7 @@ class EagerAssociationTest < ActiveRecord::TestCase Post.all.merge!(joins: :comments, includes: :author, order: "comments.id DESC").to_a end assert_equal posts(:eager_other), posts[1] - assert_equal authors(:mary), assert_no_queries { posts[1].author} + assert_equal authors(:mary), assert_no_queries { posts[1].author } end def test_eager_loading_with_conditions_on_joined_table_preloads @@ -1074,21 +1074,21 @@ class EagerAssociationTest < ActiveRecord::TestCase Post.all.merge!(select: "distinct posts.*", includes: :author, joins: [:comments], where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } posts = assert_queries(2) do Post.all.merge!(select: "distinct posts.*", includes: :author, joins: [:comments], where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } posts = assert_queries(2) do - Post.all.merge!(includes: :author, joins: {taggings: :tag}, where: "tags.name = 'General'", order: "posts.id").to_a + Post.all.merge!(includes: :author, joins: { taggings: :tag }, where: "tags.name = 'General'", order: "posts.id").to_a end assert_equal posts(:welcome, :thinking), posts posts = assert_queries(2) do - Post.all.merge!(includes: :author, joins: {taggings: {tag: :taggings}}, where: "taggings_tags.super_tag_id=2", order: "posts.id").to_a + Post.all.merge!(includes: :author, joins: { taggings: { tag: :taggings } }, where: "taggings_tags.super_tag_id=2", order: "posts.id").to_a end assert_equal posts(:welcome, :thinking), posts end @@ -1110,13 +1110,13 @@ class EagerAssociationTest < ActiveRecord::TestCase Post.all.merge!(select: "distinct posts.*", includes: :author, joins: "INNER JOIN comments on comments.post_id = posts.id", where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } posts = assert_queries(2) do Post.all.merge!(select: "distinct posts.*", includes: :author, joins: ["INNER JOIN comments on comments.post_id = posts.id"], where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } end def test_eager_loading_with_select_on_joined_table_preloads @@ -1124,7 +1124,7 @@ class EagerAssociationTest < ActiveRecord::TestCase Post.all.merge!(select: "posts.*, authors.name as author_name", includes: :comments, joins: :author, order: "posts.id").to_a end assert_equal "David", posts[0].author_name - assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments} + assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments } end def test_eager_loading_with_conditions_on_join_model_preloads @@ -1139,7 +1139,7 @@ class EagerAssociationTest < ActiveRecord::TestCase people = Person.males.merge(includes: :primary_contact).to_a assert_not_equal people.length, 0 people.each do |person| - assert_no_queries {assert_not_nil person.primary_contact} + assert_no_queries { assert_not_nil person.primary_contact } assert_equal Person.find(person.id).primary_contact, person.primary_contact end end @@ -1163,7 +1163,7 @@ class EagerAssociationTest < ActiveRecord::TestCase expected = Firm.find(1).clients_using_primary_key.sort_by(&:name) # Oracle adapter truncates alias to 30 characters if current_adapter?(:OracleAdapter) - firm = Firm.all.merge!(includes: :clients_using_primary_key, order: "clients_using_primary_keys_companies"[0,30]+".name").find(1) + firm = Firm.all.merge!(includes: :clients_using_primary_key, order: "clients_using_primary_keys_companies"[0, 30] + ".name").find(1) else firm = Firm.all.merge!(includes: :clients_using_primary_key, order: "clients_using_primary_keys_companies.name").find(1) end @@ -1182,7 +1182,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_include_has_one_using_primary_key expected = accounts(:signals37) - firm = Firm.all.merge!(includes: :account_using_primary_key, order: "accounts.id").to_a.detect {|f| f.id == 1} + firm = Firm.all.merge!(includes: :account_using_primary_key, order: "accounts.id").to_a.detect { |f| f.id == 1 } assert_no_queries do assert_equal expected, firm.account_using_primary_key end @@ -1253,16 +1253,16 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_join_eager_with_empty_order_should_generate_valid_sql assert_nothing_raised do - Post.includes(:comments).order("").where(comments: {body: "Thank you for the welcome"}).first + Post.includes(:comments).order("").where(comments: { body: "Thank you for the welcome" }).first end end def test_deep_including_through_habtm # warm up habtm cache - posts = Post.all.merge!(includes: {categories: :categorizations}, order: "posts.id").to_a + posts = Post.all.merge!(includes: { categories: :categorizations }, order: "posts.id").to_a posts[0].categories[0].categorizations.length - posts = Post.all.merge!(includes: {categories: :categorizations}, order: "posts.id").to_a + posts = Post.all.merge!(includes: { categories: :categorizations }, order: "posts.id").to_a assert_no_queries { assert_equal 2, posts[0].categories[0].categorizations.length } assert_no_queries { assert_equal 1, posts[0].categories[1].categorizations.length } assert_no_queries { assert_equal 2, posts[1].categories[0].categorizations.length } @@ -1360,7 +1360,7 @@ class EagerAssociationTest < ActiveRecord::TestCase test "including associations with where.not adds implicit references" do author = assert_queries(2) { - Author.includes(:posts).where.not(posts: { title: "Welcome to the weblog"} ).last + Author.includes(:posts).where.not(posts: { title: "Welcome to the weblog" }).last } assert_no_queries { @@ -1424,6 +1424,24 @@ class EagerAssociationTest < ActiveRecord::TestCase assert david.readonly_comments.first.readonly? end + test "eager-loading non-readonly association" do + # has_one + firm = Firm.where(id: "1").eager_load(:account).first! + assert_not firm.account.readonly? + + # has_and_belongs_to_many + project = Project.where(id: "2").eager_load(:developers).first! + assert_not project.developers.first.readonly? + + # has_many :through + david = Author.where(id: "1").eager_load(:comments).first! + assert_not david.comments.first.readonly? + + # belongs_to + post = Post.where(id: "1").eager_load(:author).first! + assert_not post.author.readonly? + end + test "eager-loading readonly association" do # has-one firm = Firm.where(id: "1").eager_load(:readonly_account).first! @@ -1438,8 +1456,8 @@ class EagerAssociationTest < ActiveRecord::TestCase assert david.readonly_comments.first.readonly? # belongs_to - post = Post.where(id: "1").eager_load(:author).first! - assert post.author.readonly? + post = Post.where(id: "1").eager_load(:readonly_author).first! + assert post.readonly_author.readonly? end test "preloading a polymorphic association with references to the associated table" do diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index 8f9fc10ba5..974a3080d4 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -45,7 +45,7 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase # Marshaling an association shouldn't make it unusable by wiping its reflection. assert_not_nil david.association(:projects).reflection - david_too = Marshal.load(marshalled) + david_too = Marshal.load(marshalled) assert_equal projects(:action_controller), david_too.projects.find_most_recent end @@ -76,6 +76,6 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase private def extend!(model) - ActiveRecord::Associations::Builder::HasMany.define_extensions(model, :association_name) { } + ActiveRecord::Associations::Builder::HasMany.define_extensions(model, :association_name) {} end end 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 ec6ae39835..54fb61d6a5 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 @@ -86,6 +86,10 @@ class DeveloperWithSymbolClassName < Developer has_and_belongs_to_many :projects, class_name: :ProjectWithSymbolsForKeys end +class DeveloperWithConstantClassName < Developer + has_and_belongs_to_many :projects, class_name: ProjectWithSymbolsForKeys +end + class DeveloperWithExtendOption < Developer module NamedExtension def category @@ -169,7 +173,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase active_record = Project.find(1) assert !active_record.developers.empty? assert_equal 3, active_record.developers.size - assert active_record.developers.include?(david) + assert_includes active_record.developers, david end def test_adding_single @@ -249,8 +253,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert !p.persisted? assert aredridel.save assert aredridel.persisted? - assert_equal no_of_devels+1, Developer.count - assert_equal no_of_projects+1, Project.count + assert_equal no_of_devels + 1, Developer.count + assert_equal no_of_projects + 1, Project.count assert_equal 2, aredridel.projects.size assert_equal 2, aredridel.projects.reload.size end @@ -258,7 +262,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_habtm_saving_multiple_relationships new_project = Project.new("name" => "Grimetime") amount_of_developers = 4 - developers = (0...amount_of_developers).collect {|i| Developer.create(name: "JME #{i}") }.reverse + developers = (0...amount_of_developers).collect { |i| Developer.create(name: "JME #{i}") }.reverse new_project.developer_ids = [developers[0].id, developers[1].id] new_project.developers_with_callback_ids = [developers[2].id, developers[3].id] @@ -379,7 +383,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase dev.projects << projects(:active_record) assert_equal 3, dev.projects.size - assert_equal 1, dev.projects.distinct.size + assert_equal 1, dev.projects.uniq.size end def test_distinct_before_the_fact @@ -544,7 +548,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert project.developers.loaded? - assert project.developers.include?(developer) + assert_includes project.developers, developer end end @@ -555,7 +559,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase project.reload assert ! project.developers.loaded? assert_queries(1) do - assert project.developers.include?(developer) + assert_includes project.developers, developer end assert ! project.developers.loaded? end @@ -588,7 +592,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_dynamic_find_all_should_respect_readonly_access - projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?} + projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid? } projects(:active_record).readonly_developers.each(&:readonly?) end @@ -600,8 +604,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase project.save! project.reload - assert project.developers.include?(jamis) - assert project.developers.include?(david) + assert_includes project.developers, jamis + assert_includes project.developers, david end def test_find_in_association_with_options @@ -628,7 +632,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")] david.save assert_equal 2, david.projects.length - assert !david.projects.include?(projects(:active_record)) + assert_not_includes david.projects, projects(:active_record) end def test_replace_on_new_object @@ -646,9 +650,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase developer.special_projects << special_project developer.reload - assert developer.projects.include?(special_project) - assert developer.special_projects.include?(special_project) - assert !developer.special_projects.include?(other_project) + assert_includes developer.projects, special_project + assert_includes developer.special_projects, special_project + assert_not_includes developer.special_projects, other_project end def test_symbol_join_table @@ -700,7 +704,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal( 3, Developer.references(:developers_projects_join).merge( - includes: {projects: :developers}, + includes: { projects: :developers }, where: "projects_developers_projects_join.joined_on IS NOT NULL" ).to_a.size ) @@ -720,7 +724,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal( 3, Developer.references(:developers_projects_join).merge( - includes: {projects: :developers}, where: "projects_developers_projects_join.joined_on IS NOT NULL", + includes: { projects: :developers }, where: "projects_developers_projects_join.joined_on IS NOT NULL", group: group.join(",") ).to_a.size ) @@ -854,7 +858,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_include_method_in_has_and_belongs_to_many_association_should_return_true_for_instance_added_with_build project = Project.new developer = project.developers.build - assert project.developers.include?(developer) + assert_includes project.developers, developer end def test_destruction_does_not_error_without_primary_key @@ -939,14 +943,16 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_with_symbol_class_name assert_nothing_raised do - DeveloperWithSymbolClassName.new + developer = DeveloperWithSymbolClassName.new + developer.projects end end - def test_association_force_reload_with_only_true_is_deprecated - developer = Developer.find(1) - - assert_deprecated { developer.projects(true) } + def test_with_constant_class_name + assert_nothing_raised do + developer = DeveloperWithConstantClassName.new + developer.projects + end end def test_alternate_database @@ -1000,4 +1006,17 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase user = User.create! assert_nothing_raised { user.jobs_pool.clear } end + + def test_has_and_belongs_to_many_while_partial_writes_false + begin + original_partial_writes = ActiveRecord::Base.partial_writes + ActiveRecord::Base.partial_writes = false + developer = Developer.new(name: "Mehmet Emin İNAÇ") + developer.projects << Project.new(name: "Bounty") + + assert developer.save + ensure + ActiveRecord::Base.partial_writes = original_partial_writes + end + 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 09692fc3a0..cbecfa84ff 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -84,7 +84,7 @@ class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase david = people(:david) assert_equal ["A Modest Proposal"], david.essays.map(&:name) - david.essays = [Essay.create!(name: "Remote Work" )] + david.essays = [Essay.create!(name: "Remote Work")] assert_equal ["Remote Work"], david.essays.map(&:name) end @@ -187,7 +187,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase ship.parts.clear part.reload - assert_equal nil, part.ship + assert_nil part.ship assert !part.updated_at_changed? end @@ -305,7 +305,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase test "building the association with an array" do speedometer = Speedometer.new(speedometer_id: "a") - data = [{name: "first"}, {name: "second"}] + data = [{ name: "first" }, { name: "second" }] speedometer.minivans.build(data) assert_equal 2, speedometer.minivans.size @@ -380,47 +380,78 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_no_queries do bulbs.first() - bulbs.first({}) end assert_no_queries do bulbs.second() - bulbs.second({}) end assert_no_queries do bulbs.third() - bulbs.third({}) end assert_no_queries do bulbs.fourth() - bulbs.fourth({}) end assert_no_queries do bulbs.fifth() - bulbs.fifth({}) end assert_no_queries do bulbs.forty_two() - bulbs.forty_two({}) end assert_no_queries do bulbs.third_to_last() - bulbs.third_to_last({}) end assert_no_queries do bulbs.second_to_last() - bulbs.second_to_last({}) end assert_no_queries do bulbs.last() - bulbs.last({}) + end + end + + def test_finder_method_with_dirty_target + company = companies(:first_firm) + new_clients = [] + assert_no_queries(ignore_none: false) do + new_clients << company.clients_of_firm.build(name: "Another Client") + new_clients << company.clients_of_firm.build(name: "Another Client II") + new_clients << company.clients_of_firm.build(name: "Another Client III") + end + + assert_not company.clients_of_firm.loaded? + assert_queries(1) do + assert_same new_clients[0], company.clients_of_firm.third + assert_same new_clients[1], company.clients_of_firm.fourth + assert_same new_clients[2], company.clients_of_firm.fifth + assert_same new_clients[0], company.clients_of_firm.third_to_last + assert_same new_clients[1], company.clients_of_firm.second_to_last + assert_same new_clients[2], company.clients_of_firm.last + end + end + + def test_finder_bang_method_with_dirty_target + company = companies(:first_firm) + new_clients = [] + assert_no_queries(ignore_none: false) do + new_clients << company.clients_of_firm.build(name: "Another Client") + new_clients << company.clients_of_firm.build(name: "Another Client II") + new_clients << company.clients_of_firm.build(name: "Another Client III") + end + + assert_not company.clients_of_firm.loaded? + assert_queries(1) do + assert_same new_clients[0], company.clients_of_firm.third! + assert_same new_clients[1], company.clients_of_firm.fourth! + assert_same new_clients[2], company.clients_of_firm.fifth! + assert_same new_clients[0], company.clients_of_firm.third_to_last! + assert_same new_clients[1], company.clients_of_firm.second_to_last! + assert_same new_clients[2], company.clients_of_firm.last! end end @@ -487,7 +518,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_finding_array_compatibility - assert_equal 3, Firm.order(:id).find{|f| f.id > 0}.clients.length + assert_equal 3, Firm.order(:id).find { |f| f.id > 0 }.clients.length end def test_find_many_with_merged_options @@ -497,7 +528,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_find_should_append_to_association_order - ordered_clients = companies(:first_firm).clients_sorted_desc.order("companies.id") + ordered_clients = companies(:first_firm).clients_sorted_desc.order("companies.id") assert_equal ["id DESC", "companies.id"], ordered_clients.order_values end @@ -525,14 +556,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_taking_with_a_number # taking from unloaded Relation bob = Author.find(authors(:bob).id) + new_post = bob.posts.build + assert_not bob.posts.loaded? assert_equal [posts(:misc_by_bob)], bob.posts.take(1) - bob = Author.find(authors(:bob).id) assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], bob.posts.take(2) + assert_equal [posts(:misc_by_bob), posts(:other_by_bob), new_post], bob.posts.take(3) # taking from loaded Relation - bob.posts.to_a - assert_equal [posts(:misc_by_bob)], authors(:bob).posts.take(1) - assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], authors(:bob).posts.take(2) + bob.posts.load + assert bob.posts.loaded? + assert_equal [posts(:misc_by_bob)], bob.posts.take(1) + assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], bob.posts.take(2) + assert_equal [posts(:misc_by_bob), posts(:other_by_bob), new_post], bob.posts.take(3) end def test_taking_with_inverse_of @@ -618,6 +653,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) } end + def test_find_one_message_on_primary_key + firm = Firm.all.merge!(order: "id").first + + e = assert_raises(ActiveRecord::RecordNotFound) do + firm.clients.find(0) + end + assert_equal 0, e.id + assert_equal "id", e.primary_key + assert_equal "Client", e.model + assert_match (/\ACouldn't find Client with 'id'=0/), e.message + end + def test_find_ids_and_inverse_of force_signal37_to_load_all_clients_of_firm @@ -644,7 +691,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert ! firm.clients.loaded? assert_queries(4) do - firm.clients.find_each(batch_size: 1) {|c| assert_equal firm.id, c.firm_id } + firm.clients.find_each(batch_size: 1) { |c| assert_equal firm.id, c.firm_id } end assert ! firm.clients.loaded? @@ -670,7 +717,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_queries(2) do firm.clients.find_in_batches(batch_size: 2) do |clients| - clients.each {|c| assert_equal firm.id, c.firm_id } + clients.each { |c| assert_equal firm.id, c.firm_id } end end @@ -701,7 +748,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_find_all_with_include_and_conditions assert_nothing_raised do - Developer.all.merge!(joins: :audit_logs, where: {"audit_logs.message" => nil, :name => "Smith"}).to_a + Developer.all.merge!(joins: :audit_logs, where: { "audit_logs.message" => nil, :name => "Smith" }).to_a end end @@ -823,7 +870,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase rescue Client::RaisedOnSave end - assert !companies(:first_firm).clients_of_firm.reload.include?(good) + assert_not_includes companies(:first_firm).clients_of_firm.reload, good end def test_transactions_when_adding_to_new_record @@ -865,6 +912,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase company.clients_of_firm.build("name" => "Another Client") company.clients_of_firm.build("name" => "Yet Another Client") assert_equal 4, company.clients_of_firm.size + assert_equal 4, company.clients_of_firm.uniq.size end def test_collection_not_empty_after_building @@ -888,7 +936,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many company = companies(:first_firm) - new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) } assert_equal 2, new_clients.size end @@ -914,7 +962,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_via_block company = companies(:first_firm) - new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build { |client| client.name = "Another Client" } } assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name @@ -925,7 +973,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many_via_block company = companies(:first_firm) new_clients = assert_no_queries(ignore_none: false) do - company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| + company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) do |client| client.name = "changed" end end @@ -936,7 +984,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_create_without_loading_association - first_firm = companies(:first_firm) + first_firm = companies(:first_firm) Firm.column_names Client.column_names @@ -962,7 +1010,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_create_many - companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}]) + companies(:first_firm).clients_of_firm.create([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) assert_equal 4, companies(:first_firm).clients_of_firm.reload.size end @@ -1527,26 +1575,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert firm.companies.exists?(name: "child") end - def test_restrict_with_error_is_deprecated_using_key_many - I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { many: "message for deprecated key" } } } } - - firm = RestrictedWithErrorFirm.create!(name: "restrict") - firm.companies.create(name: "child") - - assert !firm.companies.empty? - - assert_deprecated { firm.destroy } - - assert !firm.errors.empty? - - assert_equal "message for deprecated key", firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(name: "restrict") - assert firm.companies.exists?(name: "child") - ensure - I18n.backend.reload! - end - def test_restrict_with_error firm = RestrictedWithErrorFirm.create!(name: "restrict") firm.companies.create(name: "child") @@ -1564,7 +1592,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_restrict_with_error_with_locale I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations "en", activerecord: {attributes: {restricted_with_error_firm: {companies: "client companies"}}} + I18n.backend.store_translations "en", activerecord: { attributes: { restricted_with_error_firm: { companies: "client companies" } } } firm = RestrictedWithErrorFirm.create!(name: "restrict") firm.companies.create(name: "child") @@ -1688,6 +1716,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !company.clients.loaded? end + def test_counter_cache_on_unloaded_association + car = Car.create(name: "My AppliCar") + assert_equal car.engines.size, 0 + end + def test_get_ids_ignores_include_option assert_equal [readers(:michael_welcome).id], posts(:welcome).readers_with_person_ids end @@ -1742,7 +1775,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase lambda { authors(:mary).comments = [comments(:greetings), comments(:more_greetings)] }, lambda { authors(:mary).comments << Comment.create!(body: "Yay", post_id: 424242) }, lambda { authors(:mary).comments.delete(authors(:mary).comments.first) }, - ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } + ].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } end def test_dynamic_find_should_respect_association_order_for_through @@ -2244,7 +2277,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase test "does not duplicate associations when used with natural primary keys" do speedometer = Speedometer.create!(id: "4") - speedometer.minivans.create!(minivan_id: "a-van-red" ,name: "a van", color: "red") + speedometer.minivans.create!(minivan_id: "a-van-red" , name: "a van", color: "red") assert_equal 1, speedometer.minivans.to_a.size, "Only one association should be present:\n#{speedometer.minivans.to_a}" assert_equal 1, speedometer.reload.minivans.to_a.size @@ -2414,15 +2447,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end test "double insertion of new object to association when same association used in the after create callback of a new object" do - car = Car.create! - car.bulbs << TrickyBulb.new - assert_equal 1, car.bulbs.size - end - - def test_association_force_reload_with_only_true_is_deprecated - company = Company.find(1) - - assert_deprecated { company.clients_of_firm(true) } + reset_callbacks(:save, Bulb) do + Bulb.after_save { |record| record.car.bulbs.load } + car = Car.create! + car.bulbs << Bulb.new + assert_equal 1, car.bulbs.size + end end class AuthorWithErrorDestroyingAssociation < ActiveRecord::Base @@ -2463,9 +2493,34 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_no_queries { car.bulb_ids } end + def test_loading_association_in_validate_callback_doesnt_affect_persistence + reset_callbacks(:validation, Bulb) do + Bulb.after_validation { |m| m.car.bulbs.load } + + car = Car.create!(name: "Car") + bulb = car.bulbs.create! + + assert_equal [bulb], car.bulbs + end + end + private def force_signal37_to_load_all_clients_of_firm companies(:first_firm).clients_of_firm.load_target end + + def reset_callbacks(kind, klass) + old_callbacks = {} + old_callbacks[klass] = klass.send("_#{kind}_callbacks").dup + klass.subclasses.each do |subclass| + old_callbacks[subclass] = subclass.send("_#{kind}_callbacks").dup + end + yield + ensure + klass.send("_#{kind}_callbacks=", old_callbacks[klass]) + klass.subclasses.each do |subclass| + subclass.send("_#{kind}_callbacks=", old_callbacks[subclass]) + end + end end 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 90004eb70f..47c6480a8e 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -75,7 +75,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase posts = person_prime.includes(:posts).first.posts assert_operator posts.length, :>, 1 - posts.each_cons(2) do |left,right| + posts.each_cons(2) do |left, right| assert_operator left.id, :>, right.id end end @@ -175,7 +175,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = Person.new post = Post.new person.posts << post - assert person.posts.include?(post) + assert_includes person.posts, post end def test_associate_existing @@ -187,10 +187,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end assert_queries(1) do - assert post.people.include?(person) + assert_includes post.people, person end - assert post.reload.people.reload.include?(person) + assert_includes post.reload.people.reload, person end def test_delete_all_for_with_dependent_option_destroy @@ -266,7 +266,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post.people.delete(person) end - assert !post.people.reload.include?(person) + assert_not_includes post.people.reload, person end def test_associating_new @@ -284,10 +284,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end assert_queries(1) do - assert posts(:thinking).people.include?(new_person) + assert_includes posts(:thinking).people, new_person end - assert posts(:thinking).reload.people.reload.include?(new_person) + assert_includes posts(:thinking).reload.people.reload, new_person end def test_associate_new_by_building @@ -300,8 +300,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # Should only need to load the association once assert_queries(1) do - assert posts(:thinking).people.collect(&:first_name).include?("Bob") - assert posts(:thinking).people.collect(&:first_name).include?("Ted") + assert_includes posts(:thinking).people.collect(&:first_name), "Bob" + assert_includes posts(:thinking).people.collect(&:first_name), "Ted" end # 2 queries for each new record (1 to save the record itself, 1 for the join model) @@ -312,8 +312,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase posts(:thinking).save end - assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Bob") - assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Ted") + assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Bob" + assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Ted" end def test_build_then_save_with_has_many_inverse @@ -322,7 +322,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person.save post.reload - assert post.people.include?(person) + assert_includes post.people, person end def test_build_then_save_with_has_one_inverse @@ -331,7 +331,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person.save post.reload - assert post.single_people.include?(person) + assert_includes post.single_people, person end def test_both_parent_ids_set_when_saving_new @@ -348,7 +348,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_delete_association - assert_queries(2){posts(:welcome);people(:michael); } + assert_queries(2) { posts(:welcome);people(:michael); } assert_queries(1) do posts(:welcome).people.delete(people(:michael)) @@ -402,7 +402,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end end - assert_equal nil, reference.reload.job_id + assert_nil reference.reload.job_id ensure Reference.make_comments = false end @@ -423,7 +423,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end # Check that the destroy callback on Reference did not run - assert_equal nil, person.reload.comments + assert_nil person.reload.comments ensure Reference.make_comments = false end @@ -485,7 +485,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end references.each do |reference| - assert_equal nil, reference.reload.job_id + assert_nil reference.reload.job_id end end @@ -541,7 +541,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_replace_association - assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people.reload} + assert_queries(4) { posts(:welcome);people(:david);people(:michael); posts(:welcome).people.reload } # 1 query to delete the existing reader (michael) # 1 query to associate the new reader (david) @@ -549,13 +549,13 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase posts(:welcome).people = [people(:david)] end - assert_queries(0){ - assert posts(:welcome).people.include?(people(:david)) - assert !posts(:welcome).people.include?(people(:michael)) + assert_queries(0) { + assert_includes posts(:welcome).people, people(:david) + assert_not_includes posts(:welcome).people, people(:michael) } - assert posts(:welcome).reload.people.reload.include?(people(:david)) - assert !posts(:welcome).reload.people.reload.include?(people(:michael)) + assert_includes posts(:welcome).reload.people.reload, people(:david) + assert_not_includes posts(:welcome).reload.people.reload, people(:michael) end def test_replace_order_is_preserved @@ -591,10 +591,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # *Now* we actually need the collection so it's loaded assert_queries(1) do - assert posts(:thinking).people.collect(&:first_name).include?("Jeb") + assert_includes posts(:thinking).people.collect(&:first_name), "Jeb" end - assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Jeb") + assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Jeb" end def test_through_record_is_built_when_created_with_where @@ -658,7 +658,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_push_with_invalid_join_record repair_validations(Contract) do - Contract.validate {|r| r.errors[:base] << "Invalid Contract" } + Contract.validate { |r| r.errors[:base] << "Invalid Contract" } firm = companies(:first_firm) lifo = Developer.new(name: "lifo") @@ -702,7 +702,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase [:added, :after, "Bob"], [:added, :before, "Lary"], [:added, :after, "Lary"] - ],log.last(6) + ], log.last(6) post.people_with_callbacks.build(first_name: "Ted") assert_equal [ @@ -716,7 +716,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase [:added, :after, "Sam"] ], log.last(2) - post.people_with_callbacks = [people(:michael),people(:david), Person.new(first_name: "Julian"), Person.create!(first_name: "Roger")] + post.people_with_callbacks = [people(:michael), people(:david), Person.new(first_name: "Julian"), Person.create!(first_name: "Roger")] assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort) assert_equal [ [:added, :before, "Julian"], @@ -812,7 +812,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(body: "Gorp!", post_id: 1011), VerySpecialComment.create!(body: "Eep!", post_id: 1012)] }, lambda { authors(:david).very_special_comments << VerySpecialComment.create!(body: "Hoohah!", post_id: 1013) }, lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) }, - ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } + ].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } end def test_has_many_association_through_a_has_many_association_to_self @@ -832,14 +832,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase category = author.named_categories.build(name: "Primary") author.save assert Categorization.exists?(author_id: author.id, named_category_name: category.name) - assert author.named_categories.reload.include?(category) + assert_includes author.named_categories.reload, category end def test_collection_create_with_nonstandard_primary_key_on_belongs_to author = authors(:mary) category = author.named_categories.create(name: "Primary") assert Categorization.exists?(author_id: author.id, named_category_name: category.name) - assert author.named_categories.reload.include?(category) + assert_includes author.named_categories.reload, category end def test_collection_exists @@ -883,10 +883,32 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end + def test_collection_singular_ids_setter_with_changed_primary_key + company = companies(:first_firm) + client = companies(:first_client) + company.clients_using_primary_key_ids = [client.name] + assert_equal [client], company.clients_using_primary_key + end + def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set company = companies(:rails_core) - ids = [Developer.first.id, -9999] - assert_raises(ActiveRecord::AssociationTypeMismatch) {company.developer_ids= ids} + ids = [Developer.first.id, -9999] + e = assert_raises(ActiveRecord::RecordNotFound) { company.developer_ids = ids } + assert_match(/Couldn't find all Developers with 'id'/, e.message) + end + + def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set_with_changed_primary_key + company = companies(:first_firm) + ids = [Client.first.name, "unknown client"] + e = assert_raises(ActiveRecord::RecordNotFound) { company.clients_using_primary_key_ids = ids } + assert_match(/Couldn't find all Clients with 'name'/, e.message) + end + + def test_collection_singular_ids_through_setter_raises_exception_when_invalid_ids_set + author = authors(:david) + ids = [categories(:general).name, "Unknown"] + e = assert_raises(ActiveRecord::RecordNotFound) { author.essay_category_ids = ids } + assert_equal "Couldn't find all Categories with 'name': (General, Unknown) (found 1 results, but was looking for 2)", e.message end def test_build_a_model_from_hm_through_association_with_where_clause @@ -908,14 +930,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = Person.new reference = person.references.build job = reference.build_job - assert person.jobs.include?(job) + assert_includes person.jobs, job end def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds author = Author.new post = author.posts.build comment = post.comments.build - assert author.comments.include?(comment) + assert_includes author.comments, comment end def test_through_association_readonly_should_be_false @@ -1022,7 +1044,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post = posts(:welcome) address = author_addresses(:david_address) - assert post.author_addresses.include?(address) + assert_includes post.author_addresses, address post.author_addresses.delete(address) assert post[:author_count].nil? end @@ -1107,7 +1129,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_obeys_order_on_through_association owner = owners(:blackbeard) - assert owner.toys.to_sql.include?("pets.name desc") + assert_includes owner.toys.to_sql, "pets.name desc" assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name } end @@ -1182,12 +1204,6 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_nil Club.new.special_favourites.distinct_value end - def test_association_force_reload_with_only_true_is_deprecated - post = Post.find(1) - - assert_deprecated { post.people(true) } - end - def test_has_many_through_do_not_cache_association_reader_if_the_though_method_has_default_scopes member = Member.create! club = Club.create! diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index ad0d47920d..ed22a9802f 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -186,25 +186,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert firm.account.present? end - def test_restrict_with_error_is_deprecated_using_key_one - I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { one: "message for deprecated key" } } } } - - firm = RestrictedWithErrorFirm.create!(name: "restrict") - firm.create_account(credit_limit: 10) - - assert_not_nil firm.account - - assert_deprecated { firm.destroy } - - assert !firm.errors.empty? - assert_equal "message for deprecated key", firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(name: "restrict") - assert firm.account.present? - ensure - I18n.backend.reload! - end - def test_restrict_with_error firm = RestrictedWithErrorFirm.create!(name: "restrict") firm.create_account(credit_limit: 10) @@ -221,7 +202,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_restrict_with_error_with_locale I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations "en", activerecord: {attributes: {restricted_with_error_firm: {account: "firm account"}}} + I18n.backend.store_translations "en", activerecord: { attributes: { restricted_with_error_firm: { account: "firm account" } } } firm = RestrictedWithErrorFirm.create!(name: "restrict") firm.create_account(credit_limit: 10) @@ -326,6 +307,16 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end end + def test_reload_association + odegy = companies(:odegy) + + assert_equal 53, odegy.account.credit_limit + Account.where(id: odegy.account.id).update_all(credit_limit: 80) + assert_equal 53, odegy.account.credit_limit + + assert_equal 80, odegy.reload_account.credit_limit + end + def test_build firm = Firm.new("name" => "GlobalMegaCorp") firm.save @@ -539,21 +530,21 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_build_with_block car = Car.create(name: "honda") - bulb = car.build_bulb{ |b| b.color = "Red" } + bulb = car.build_bulb { |b| b.color = "Red" } assert_equal "RED!", bulb.color end def test_create_with_block car = Car.create(name: "honda") - bulb = car.create_bulb{ |b| b.color = "Red" } + bulb = car.create_bulb { |b| b.color = "Red" } assert_equal "RED!", bulb.color end def test_create_bang_with_block car = Car.create(name: "honda") - bulb = car.create_bulb!{ |b| b.color = "Red" } + bulb = car.create_bulb! { |b| b.color = "Red" } assert_equal "RED!", bulb.color end @@ -601,7 +592,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase new_ship = Ship.create(name: "new name") assert_queries(2) do - # One query for updating name and second query for updating pirate_id + # One query to nullify the old ship, one query to update the new ship pirate.ship = new_ship end @@ -654,12 +645,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end end - def test_association_force_reload_with_only_true_is_deprecated - firm = Firm.find(1) - - assert_deprecated { firm.account(true) } - end - class SpecialBook < ActiveRecord::Base self.table_name = "books" belongs_to :author, class_name: "SpecialAuthor" @@ -675,6 +660,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase book = SpecialBook.create!(status: "published") author.book = book - refute_equal 0, SpecialAuthor.joins(:book).where(books: { status: "published" } ).count + refute_equal 0, SpecialAuthor.joins(:book).where(books: { status: "published" }).count 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 3a7f48fbb7..432c3526a5 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -82,7 +82,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase def test_set_record_to_nil_should_delete_association @member.club = nil @member.reload - assert_equal nil, @member.current_membership + assert_nil @member.current_membership assert_nil @member.club end @@ -95,7 +95,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase Member.all.merge!(includes: :club, where: ["name = ?", "Groucho Marx"]).to_a end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].club} + assert_not_nil assert_no_queries { members[0].club } end def test_has_one_through_eager_loading_through_polymorphic @@ -103,19 +103,19 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase Member.all.merge!(includes: :sponsor_club, where: ["name = ?", "Groucho Marx"]).to_a end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].sponsor_club} + assert_not_nil assert_no_queries { members[0].sponsor_club } end def test_has_one_through_with_conditions_eager_loading # conditions on the through table assert_equal clubs(:moustache_club), Member.all.merge!(includes: :favourite_club).find(@member.id).favourite_club memberships(:membership_of_favourite_club).update_columns(favourite: false) - assert_equal nil, Member.all.merge!(includes: :favourite_club).find(@member.id).reload.favourite_club + assert_nil Member.all.merge!(includes: :favourite_club).find(@member.id).reload.favourite_club # conditions on the source table assert_equal clubs(:moustache_club), Member.all.merge!(includes: :hairy_club).find(@member.id).hairy_club clubs(:moustache_club).update_columns(name: "Association of Clean-Shaven Persons") - assert_equal nil, Member.all.merge!(includes: :hairy_club).find(@member.id).reload.hairy_club + assert_nil Member.all.merge!(includes: :hairy_club).find(@member.id).reload.hairy_club end def test_has_one_through_polymorphic_with_source_type @@ -123,9 +123,9 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_eager_has_one_through_polymorphic_with_source_type - clubs = Club.all.merge!(includes: :sponsored_member, where: ["name = ?","Moustache and Eyebrow Fancier Club"]).to_a + clubs = Club.all.merge!(includes: :sponsored_member, where: ["name = ?", "Moustache and Eyebrow Fancier Club"]).to_a # Only the eyebrow fanciers club has a sponsored_member - assert_not_nil assert_no_queries {clubs[0].sponsored_member} + assert_not_nil assert_no_queries { clubs[0].sponsored_member } end def test_has_one_through_nonpreload_eagerloading @@ -133,7 +133,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase Member.all.merge!(includes: :club, where: ["members.name = ?", "Groucho Marx"], order: "clubs.name").to_a #force fallback end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].club} + assert_not_nil assert_no_queries { members[0].club } end def test_has_one_through_nonpreload_eager_loading_through_polymorphic @@ -141,7 +141,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase Member.all.merge!(includes: :sponsor_club, where: ["members.name = ?", "Groucho Marx"], order: "clubs.name").to_a #force fallback end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].sponsor_club} + assert_not_nil assert_no_queries { members[0].sponsor_club } end def test_has_one_through_nonpreload_eager_loading_through_polymorphic_with_more_than_one_through_record @@ -182,7 +182,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase @member.organization = @organization end assert_equal @organization, @member.organization - assert @organization.members.include?(@member) + assert_includes @organization.members, @member assert_equal "Extra", @member.member_detail.extra_data end @@ -197,16 +197,16 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end assert_equal @organization, @member.organization assert_equal "Extra", @member.member_detail.extra_data - assert @organization.members.include?(@member) - assert !@new_organization.members.include?(@member) + assert_includes @organization.members, @member + assert_not_includes @new_organization.members, @member assert_no_difference "MemberDetail.count" do @member.organization = @new_organization end assert_equal @new_organization, @member.organization assert_equal "Extra", @member.member_detail.extra_data - assert !@organization.members.include?(@member) - assert @new_organization.members.include?(@member) + assert_not_includes @organization.members, @member + assert_includes @new_organization.members, @member end def test_preloading_has_one_through_on_belongs_to diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index be5c8854be..7414869c8f 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -20,7 +20,7 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations assert_nothing_raised do - sql = Person.joins(agents: {agents: :agents}).joins(agents: {agents: {primary_contact: :agents}}).to_sql + sql = Person.joins(agents: { agents: :agents }).joins(agents: { agents: { primary_contact: :agents } }).to_sql assert_match(/agents_people_4/i, sql) end end @@ -47,7 +47,7 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase end def test_join_conditions_allow_nil_associations - authors = Author.includes(:essays).where(essays: {id: nil}) + authors = Author.includes(:essays).where(essays: { id: nil }) assert_equal 2, authors.count end @@ -60,13 +60,13 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase def test_find_with_implicit_inner_joins_honors_readonly_with_select authors = Author.joins(:posts).select("authors.*").to_a assert !authors.empty?, "expected authors to be non-empty" - assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly" + assert authors.all? { |a| !a.readonly? }, "expected no authors to be readonly" end def test_find_with_implicit_inner_joins_honors_readonly_false authors = Author.joins(:posts).readonly(false).to_a assert !authors.empty?, "expected authors to be non-empty" - assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly" + assert authors.all? { |a| !a.readonly? }, "expected no authors to be readonly" end def test_find_with_implicit_inner_joins_does_not_set_associations @@ -76,17 +76,17 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase end def test_count_honors_implicit_inner_joins - real_count = Author.all.to_a.sum{|a| a.posts.count } + real_count = Author.all.to_a.sum { |a| a.posts.count } assert_equal real_count, Author.joins(:posts).count, "plain inner join count should match the number of referenced posts records" end def test_calculate_honors_implicit_inner_joins - real_count = Author.all.to_a.sum{|a| a.posts.count } + real_count = Author.all.to_a.sum { |a| a.posts.count } assert_equal real_count, Author.joins(:posts).calculate(:count, "authors.id"), "plain inner join count should match the number of referenced posts records" end def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions - real_count = Author.all.to_a.select {|a| a.posts.any? {|p| p.title.start_with?("Welcome")} }.length + real_count = Author.all.to_a.select { |a| a.posts.any? { |p| p.title.start_with?("Welcome") } }.length authors_with_welcoming_post_titles = Author.all.merge!(joins: :posts, where: "posts.title like 'Welcome%'").distinct.calculate(:count, "authors.id") assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'" end diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 4534cbe664..6fe6ee6783 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -227,7 +227,7 @@ class InverseHasOneTests < ActiveRecord::TestCase end def test_parent_instance_should_be_shared_with_eager_loaded_child_on_find - m = Man.all.merge!(where: {name: "Gordon"}, includes: :face).first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :face).first f = m.face assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" m.name = "Bongo" @@ -235,7 +235,7 @@ class InverseHasOneTests < ActiveRecord::TestCase f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to child-owned instance" - m = Man.all.merge!(where: {name: "Gordon"}, includes: :face, order: "faces.id").first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :face, order: "faces.id").first f = m.face assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" m.name = "Bongo" @@ -310,7 +310,7 @@ class InverseHasManyTests < ActiveRecord::TestCase end def test_parent_instance_should_be_shared_with_eager_loaded_children - m = Man.all.merge!(where: {name: "Gordon"}, includes: :interests).first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :interests).first is = m.interests is.each do |i| assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" @@ -320,7 +320,7 @@ class InverseHasManyTests < ActiveRecord::TestCase assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance" end - m = Man.all.merge!(where: {name: "Gordon"}, includes: :interests, order: "interests.id").first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :interests, order: "interests.id").first is = m.interests is.each do |i| assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" @@ -333,7 +333,7 @@ class InverseHasManyTests < ActiveRecord::TestCase def test_parent_instance_should_be_shared_with_newly_block_style_built_child m = Man.first - i = m.interests.build {|ii| ii.topic = "Industrial Revolution Re-enactment"} + i = m.interests.build { |ii| ii.topic = "Industrial Revolution Re-enactment" } assert_not_nil i.topic, "Child attributes supplied to build via blocks should be populated" assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" @@ -356,7 +356,7 @@ class InverseHasManyTests < ActiveRecord::TestCase def test_parent_instance_should_be_shared_with_newly_block_style_created_child m = Man.first - i = m.interests.create {|ii| ii.topic = "Industrial Revolution Re-enactment"} + i = m.interests.create { |ii| ii.topic = "Industrial Revolution Re-enactment" } assert_not_nil i.topic, "Child attributes supplied to create via blocks should be populated" assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" @@ -494,6 +494,33 @@ class InverseHasManyTests < ActiveRecord::TestCase assert !man.persisted? end + + def test_inverse_instance_should_be_set_before_find_callbacks_are_run + reset_callbacks(Interest, :find) do + Interest.after_find { raise unless association(:man).loaded? && man.present? } + + assert Man.first.interests.reload.any? + assert Man.includes(:interests).first.interests.any? + assert Man.joins(:interests).includes(:interests).first.interests.any? + end + end + + def test_inverse_instance_should_be_set_before_initialize_callbacks_are_run + reset_callbacks(Interest, :initialize) do + Interest.after_initialize { raise unless association(:man).loaded? && man.present? } + + assert Man.first.interests.reload.any? + assert Man.includes(:interests).first.interests.any? + assert Man.joins(:interests).includes(:interests).first.interests.any? + end + end + + def reset_callbacks(target, type) + old_callbacks = target.send(:get_callbacks, type).deep_dup + yield + ensure + target.send(:set_callbacks, type, old_callbacks) if old_callbacks + end end class InverseBelongsToTests < ActiveRecord::TestCase @@ -510,7 +537,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase end def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find - f = Face.all.merge!(includes: :man, where: {description: "trusting"}).first + f = Face.all.merge!(includes: :man, where: { description: "trusting" }).first m = f.man assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" f.description = "gormless" @@ -518,7 +545,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to parent-owned instance" - f = Face.all.merge!(includes: :man, order: "men.id", where: {description: "trusting"}).first + f = Face.all.merge!(includes: :man, order: "men.id", where: { description: "trusting" }).first m = f.man assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" f.description = "gormless" @@ -553,7 +580,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase i = interests(:trainspotting) m = i.man assert_not_nil m.interests - iz = m.interests.detect { |_iz| _iz.id == i.id} + iz = m.interests.detect { |_iz| _iz.id == i.id } assert_not_nil iz assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child" i.topic = "Eating cheese with a spoon" @@ -583,7 +610,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase fixtures :men, :faces, :interests def test_child_instance_should_be_shared_with_parent_on_find - f = Face.all.merge!(where: {description: "confused"}).first + f = Face.all.merge!(where: { description: "confused" }).first m = f.polymorphic_man assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance" f.description = "gormless" @@ -593,7 +620,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase end def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find - f = Face.all.merge!(where: {description: "confused"}, includes: :man).first + f = Face.all.merge!(where: { description: "confused" }, includes: :man).first m = f.polymorphic_man assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance" f.description = "gormless" @@ -601,7 +628,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase m.polymorphic_face.description = "pleasing" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance" - f = Face.all.merge!(where: {description: "confused"}, includes: :man, order: "men.id").first + f = Face.all.merge!(where: { description: "confused" }, includes: :man, order: "men.id").first m = f.polymorphic_man assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance" f.description = "gormless" @@ -654,7 +681,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase i = interests(:llama_wrangling) m = i.polymorphic_man assert_not_nil m.polymorphic_interests - iz = m.polymorphic_interests.detect { |_iz| _iz.id == i.id} + iz = m.polymorphic_interests.detect { |_iz| _iz.id == i.id } assert_not_nil iz assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child" i.topic = "Eating cheese with a spoon" diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index cf08cc9537..a4345f3857 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -24,15 +24,15 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase :edges def test_has_many - assert authors(:david).categories.include?(categories(:general)) + assert_includes authors(:david).categories, categories(:general) end def test_has_many_inherited - assert authors(:mary).categories.include?(categories(:sti_test)) + assert_includes authors(:mary).categories, categories(:sti_test) end def test_inherited_has_many - assert categories(:sti_test).authors.include?(authors(:mary)) + assert_includes categories(:sti_test).authors, authors(:mary) end def test_has_many_distinct_through_join_model @@ -155,21 +155,21 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase old_count = posts(:welcome).taggings.count tagging = posts(:welcome).taggings.create(tag: tags(:misc)) assert_equal "Post", tagging.taggable_type - assert_equal old_count+1, posts(:welcome).taggings.count + assert_equal old_count + 1, posts(:welcome).taggings.count end def test_create_bang_polymorphic_with_has_many_scope old_count = posts(:welcome).taggings.count tagging = posts(:welcome).taggings.create!(tag: tags(:misc)) assert_equal "Post", tagging.taggable_type - assert_equal old_count+1, posts(:welcome).taggings.count + assert_equal old_count + 1, posts(:welcome).taggings.count end def test_create_polymorphic_has_one_with_scope old_count = Tagging.count tagging = posts(:welcome).create_tagging(tag: tags(:misc)) assert_equal "Post", tagging.taggable_type - assert_equal old_count+1, Tagging.count + assert_equal old_count + 1, Tagging.count end def test_delete_polymorphic_has_many_with_delete_all @@ -179,7 +179,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase old_count = Tagging.count post.destroy - assert_equal old_count-1, Tagging.count + assert_equal old_count - 1, Tagging.count assert_equal 0, posts(:welcome).taggings.count end @@ -190,7 +190,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase old_count = Tagging.count post.destroy - assert_equal old_count-1, Tagging.count + assert_equal old_count - 1, Tagging.count assert_equal 0, posts(:welcome).taggings.count end @@ -212,7 +212,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase old_count = Tagging.count post.destroy - assert_equal old_count-1, Tagging.count + assert_equal old_count - 1, Tagging.count posts(:welcome).association(:tagging).reload assert_nil posts(:welcome).tagging end @@ -237,7 +237,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase category = categories(:sti_test) ernie = category.authors_with_select.create(name: "Ernie") assert_nothing_raised do - assert_equal ernie, category.authors_with_select.detect {|a| a.name == "Ernie"} + assert_equal ernie, category.authors_with_select.detect { |a| a.name == "Ernie" } end end @@ -402,7 +402,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_has_many_through_polymorphic_has_one - assert_equal Tagging.find(1,2).sort_by(&:id), authors(:david).taggings_2 + assert_equal Tagging.find(1, 2).sort_by(&:id), authors(:david).taggings_2 end def test_has_many_through_polymorphic_has_many @@ -413,7 +413,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase author = Author.includes(:taggings).find authors(:david).id expected_taggings = taggings(:welcome_general, :thinking_general) assert_no_queries do - assert_equal expected_taggings, author.taggings.distinct.sort_by(&:id) + assert_equal expected_taggings, author.taggings.uniq.sort_by(&:id) end end @@ -421,7 +421,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase author = Author.all.merge!(where: ["name = ?", "David"], includes: :comments, order: "comments.id").first SpecialComment.new; VerySpecialComment.new assert_no_queries do - assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id) + assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], author.comments.collect(&:id) end end @@ -467,10 +467,10 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase saved_post.tags << new_tag assert new_tag.persisted? #consistent with habtm! assert saved_post.persisted? - assert saved_post.tags.include?(new_tag) + assert_includes saved_post.tags, new_tag assert new_tag.persisted? - assert saved_post.reload.tags.reload.include?(new_tag) + assert_includes saved_post.reload.tags.reload, new_tag new_post = Post.new(title: "Association replacement works!", body: "You best believe it.") saved_tag = tags(:general) @@ -478,11 +478,11 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase new_post.tags << saved_tag assert !new_post.persisted? assert saved_tag.persisted? - assert new_post.tags.include?(saved_tag) + assert_includes new_post.tags, saved_tag new_post.save! assert new_post.persisted? - assert new_post.reload.tags.reload.include?(saved_tag) + assert_includes new_post.reload.tags.reload, saved_tag assert !posts(:thinking).tags.build.persisted? assert !posts(:thinking).tags.new.persisted? @@ -493,25 +493,25 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase push = Tag.create!(name: "pushme") post_thinking = posts(:thinking) assert_nothing_raised { post_thinking.tags << push } - assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag }, + assert_nil(wrong = post_thinking.tags.detect { |t| t.class != Tag }, message = "Expected a Tag in tags collection, got #{wrong.class}.") - assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, + assert_nil(wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, message = "Expected a Tagging in taggings collection, got #{wrong.class}.") assert_equal(count + 1, post_thinking.reload.tags.size) assert_equal(count + 1, post_thinking.tags.reload.size) assert_kind_of Tag, post_thinking.tags.create!(name: "foo") - assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag }, + assert_nil(wrong = post_thinking.tags.detect { |t| t.class != Tag }, message = "Expected a Tag in tags collection, got #{wrong.class}.") - assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, + assert_nil(wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, message = "Expected a Tagging in taggings collection, got #{wrong.class}.") assert_equal(count + 2, post_thinking.reload.tags.size) assert_equal(count + 2, post_thinking.tags.reload.size) assert_nothing_raised { post_thinking.tags.concat(Tag.create!(name: "abc"), Tag.create!(name: "def")) } - assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag }, + assert_nil(wrong = post_thinking.tags.detect { |t| t.class != Tag }, message = "Expected a Tag in tags collection, got #{wrong.class}.") - assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, + assert_nil(wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, message = "Expected a Tagging in taggings collection, got #{wrong.class}.") assert_equal(count + 4, post_thinking.reload.tags.size) assert_equal(count + 4, post_thinking.tags.reload.size) @@ -642,20 +642,20 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_polymorphic_has_many expected = taggings(:welcome_general) p = Post.all.merge!(includes: :taggings).find(posts(:welcome).id) - assert_no_queries {assert p.taggings.include?(expected)} - assert posts(:welcome).taggings.include?(taggings(:welcome_general)) + assert_no_queries { assert_includes p.taggings, expected } + assert_includes posts(:welcome).taggings, taggings(:welcome_general) end def test_polymorphic_has_one expected = posts(:welcome) tagging = Tagging.all.merge!(includes: :taggable).find(taggings(:welcome_general).id) - assert_no_queries { assert_equal expected, tagging.taggable} + assert_no_queries { assert_equal expected, tagging.taggable } end def test_polymorphic_belongs_to - p = Post.all.merge!(includes: {taggings: :taggable}).find(posts(:welcome).id) - assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable} + p = Post.all.merge!(includes: { taggings: :taggable }).find(posts(:welcome).id) + assert_no_queries { assert_equal posts(:welcome), p.taggings.first.taggable } end def test_preload_polymorphic_has_many_through @@ -675,8 +675,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end taggables = taggings.map(&:taggable) - assert taggables.include?(items(:dvd)) - assert taggables.include?(posts(:welcome)) + assert_includes taggables, items(:dvd) + assert_includes taggables, posts(:welcome) end def test_preload_nil_polymorphic_belongs_to @@ -709,7 +709,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase assert_no_queries do assert david.categories.loaded? - assert david.categories.include?(category) + assert_includes david.categories, category end end @@ -720,7 +720,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase david.reload assert ! david.categories.loaded? assert_queries(1) do - assert david.categories.include?(category) + assert_includes david.categories, category end assert ! david.categories.loaded? end @@ -748,17 +748,17 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_proper_error_message_for_eager_load_and_includes_association_errors includes_error = assert_raises(ActiveRecord::ConfigurationError) { - Post.includes(:nonexistent_relation).where(nonexistent_relation: {name: "Rochester"}).find(1) + Post.includes(:nonexistent_relation).where(nonexistent_relation: { name: "Rochester" }).find(1) } assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", includes_error.message) eager_load_error = assert_raises(ActiveRecord::ConfigurationError) { - Post.eager_load(:nonexistent_relation).where(nonexistent_relation: {name: "Rochester"}).find(1) + Post.eager_load(:nonexistent_relation).where(nonexistent_relation: { name: "Rochester" }).find(1) } assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", eager_load_error.message) includes_and_eager_load_error = assert_raises(ActiveRecord::ConfigurationError) { - Post.eager_load(:nonexistent_relation).includes(:nonexistent_relation).where(nonexistent_relation: {name: "Rochester"}).find(1) + Post.eager_load(:nonexistent_relation).includes(:nonexistent_relation).where(nonexistent_relation: { name: "Rochester" }).find(1) } assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", includes_and_eager_load_error.message) end diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb index 003240bb26..42dbbad1c8 100644 --- a/activerecord/test/cases/associations/left_outer_join_association_test.rb +++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb @@ -5,7 +5,6 @@ require "models/author" require "models/essay" require "models/categorization" require "models/person" -require "active_support/core_ext/regexp" class LeftOuterJoinAssociationTest < ActiveRecord::TestCase fixtures :authors, :essays, :posts, :comments, :categorizations, :people @@ -18,35 +17,44 @@ class LeftOuterJoinAssociationTest < ActiveRecord::TestCase def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations assert_nothing_raised do queries = capture_sql do - Person.left_outer_joins(agents: {agents: :agents}) - .left_outer_joins(agents: {agents: {primary_contact: :agents}}).to_a + Person.left_outer_joins(agents: { agents: :agents }) + .left_outer_joins(agents: { agents: { primary_contact: :agents } }).to_a end assert queries.any? { |sql| /agents_people_4/i.match?(sql) } end end - def test_construct_finder_sql_executes_a_left_outer_join - assert_not_equal Author.count, Author.joins(:posts).count - assert_equal Author.count, Author.left_outer_joins(:posts).count + def test_left_outer_joins_count_is_same_as_size_of_loaded_results + assert_equal 17, Post.left_outer_joins(:comments).to_a.size + assert_equal 17, Post.left_outer_joins(:comments).count end - def test_left_outer_join_by_left_joins - assert_not_equal Author.count, Author.joins(:posts).count - assert_equal Author.count, Author.left_joins(:posts).count + def test_left_joins_aliases_left_outer_joins + assert_equal Post.left_outer_joins(:comments).to_sql, Post.left_joins(:comments).to_sql + end + + def test_left_outer_joins_return_has_value_for_every_comment + all_post_ids = Post.pluck(:id) + assert_equal all_post_ids, all_post_ids & Post.left_outer_joins(:comments).pluck(:id) + end + + def test_left_outer_joins_actually_does_a_left_outer_join + queries = capture_sql { Author.left_outer_joins(:posts).to_a } + assert queries.any? { |sql| /LEFT OUTER JOIN/i.match?(sql) } end def test_construct_finder_sql_ignores_empty_left_outer_joins_hash - queries = capture_sql { Author.left_outer_joins({}) } + queries = capture_sql { Author.left_outer_joins({}).to_a } assert queries.none? { |sql| /LEFT OUTER JOIN/i.match?(sql) } end def test_construct_finder_sql_ignores_empty_left_outer_joins_array - queries = capture_sql { Author.left_outer_joins([]) } + queries = capture_sql { Author.left_outer_joins([]).to_a } assert queries.none? { |sql| /LEFT OUTER JOIN/i.match?(sql) } end def test_left_outer_joins_forbids_to_use_string_as_argument - assert_raise(ArgumentError){ Author.left_outer_joins('LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"').to_a } + assert_raise(ArgumentError) { Author.left_outer_joins('LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"').to_a } end def test_join_conditions_added_to_join_clause diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 45aefde3e1..a223b4338f 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -57,8 +57,8 @@ class AssociationsTest < ActiveRecord::TestCase end def test_include_with_order_works - assert_nothing_raised {Account.all.merge!(order: "id", includes: :firm).first} - assert_nothing_raised {Account.all.merge!(order: :id, includes: :firm).first} + assert_nothing_raised { Account.all.merge!(order: "id", includes: :firm).first } + assert_nothing_raised { Account.all.merge!(order: :id, includes: :firm).first } end def test_bad_collection_keys @@ -88,10 +88,10 @@ class AssociationsTest < ActiveRecord::TestCase assert firm.clients.empty?, "New firm should have cached no client objects" assert_equal 0, firm.clients.size, "New firm should have cached 0 clients count" - ActiveSupport::Deprecation.silence do - assert !firm.clients(true).empty?, "New firm should have reloaded client objects" - assert_equal 1, firm.clients(true).size, "New firm should have reloaded clients count" - end + firm.clients.reload + + assert !firm.clients.empty?, "New firm should have reloaded client objects" + assert_equal 1, firm.clients.size, "New firm should have reloaded clients count" end def test_using_limitable_reflections_helper @@ -104,19 +104,6 @@ class AssociationsTest < ActiveRecord::TestCase assert !using_limitable_reflections.call(mixed_reflections), "No collection associations (has many style) should pass" end - def test_force_reload_is_uncached - firm = Firm.create!("name" => "A New Firm, Inc") - Client.create!("name" => "TheClient.com", :firm => firm) - - ActiveSupport::Deprecation.silence do - ActiveRecord::Base.cache do - firm.clients.each {} - assert_queries(0) { assert_not_nil firm.clients.each {} } - assert_queries(1) { assert_not_nil firm.clients(true).each {} } - end - end - end - def test_association_with_references firm = companies(:first_firm) assert_includes firm.association_with_references.references_values, "foo" @@ -131,7 +118,7 @@ class AssociationProxyTest < ActiveRecord::TestCase david.posts << (post = Post.new(title: "New on Edge", body: "More cool stuff!")) assert !david.posts.loaded? - assert david.posts.include?(post) + assert_includes david.posts, post end def test_push_has_many_through_does_not_load_target @@ -139,7 +126,7 @@ class AssociationProxyTest < ActiveRecord::TestCase david.categories << categories(:technology) assert !david.categories.loaded? - assert david.categories.include?(categories(:technology)) + assert_includes david.categories, categories(:technology) end def test_push_followed_by_save_does_not_load_target @@ -149,7 +136,7 @@ class AssociationProxyTest < ActiveRecord::TestCase assert !david.posts.loaded? david.save assert !david.posts.loaded? - assert david.posts.include?(post) + assert_includes david.posts, post end def test_push_does_not_lose_additions_to_new_record @@ -199,13 +186,13 @@ class AssociationProxyTest < ActiveRecord::TestCase end def test_create_via_association_with_block - post = authors(:david).posts.create(title: "New on Edge") {|p| p.body = "More cool stuff!"} + post = authors(:david).posts.create(title: "New on Edge") { |p| p.body = "More cool stuff!" } assert_equal post.title, "New on Edge" assert_equal post.body, "More cool stuff!" end def test_create_with_bang_via_association_with_block - post = authors(:david).posts.create!(title: "New on Edge") {|p| p.body = "More cool stuff!"} + post = authors(:david).posts.create!(title: "New on Edge") { |p| p.body = "More cool stuff!" } assert_equal post.title, "New on Edge" assert_equal post.body, "More cool stuff!" end @@ -256,6 +243,13 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_no_queries { david.posts.first! } end + def test_pluck_uses_loaded_target + david = authors(:david) + assert_equal david.posts.pluck(:title), david.posts.load.pluck(:title) + assert david.posts.loaded? + assert_no_queries { david.posts.pluck(:title) } + end + def test_reset_unloads_target david = authors(:david) david.posts.reload diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb index 2d2ecb4079..978dd93fa4 100644 --- a/activerecord/test/cases/attribute_methods/read_test.rb +++ b/activerecord/test/cases/attribute_methods/read_test.rb @@ -1,5 +1,4 @@ require "cases/helper" -require "thread" module ActiveRecord module AttributeMethods @@ -15,6 +14,7 @@ module ActiveRecord def self.decorate_matching_attribute_types(*); end def self.initialize_generated_modules; end + include ActiveRecord::DefineCallbacks include ActiveRecord::AttributeMethods def self.attribute_names @@ -40,13 +40,13 @@ module ActiveRecord instance = @klass.new @klass.attribute_names.each do |name| - assert !instance.methods.map(&:to_s).include?(name) + assert_not_includes instance.methods.map(&:to_s), name end @klass.define_attribute_methods @klass.attribute_names.each do |name| - assert instance.methods.map(&:to_s).include?(name), "#{name} is not defined" + assert_includes instance.methods.map(&:to_s), name, "#{name} is not defined" end end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 7a2041937d..3dc0c0ce53 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -92,7 +92,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase test "attribute keys on a new instance" do t = Topic.new - assert_equal nil, t.title, "The topics table has a title column, so it should be nil" + assert_nil t.title, "The topics table has a title column, so it should be nil" assert_raise(NoMethodError) { t.title2 } end @@ -156,7 +156,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase keyboard = Keyboard.create keyboard.key_number = "10" assert_equal "10", keyboard.id_before_type_cast - assert_equal nil, keyboard.read_attribute_before_type_cast("id") + assert_nil keyboard.read_attribute_before_type_cast("id") assert_equal "10", keyboard.read_attribute_before_type_cast("key_number") assert_equal "10", keyboard.read_attribute_before_type_cast(:key_number) end @@ -213,7 +213,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase record.written_on = "345643456" assert_equal "345643456", record.written_on_before_type_cast - assert_equal nil, record.written_on + assert_nil record.written_on record.written_on = "2009-10-11 12:13:14" assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast @@ -294,7 +294,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = Topic.new(new_topic) assert_equal new_topic[:title], topic.title - topic.attributes= new_topic_values + topic.attributes = new_topic_values assert_equal new_topic_values[:title], topic.title end @@ -319,6 +319,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "Still another topic: part 4", topic.title end + test "write_attribute can write aliased attributes as well" do + topic = Topic.new(title: "Don't change the topic") + topic.write_attribute :heading, "New topic" + + assert_equal "New topic", topic.title + end + test "read_attribute" do topic = Topic.new topic.title = "Don't change the topic" @@ -329,6 +336,16 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "Don't change the topic", topic[:title] end + test "read_attribute can read aliased attributes as well" do + topic = Topic.new(title: "Don't change the topic") + + assert_equal "Don't change the topic", topic.read_attribute("heading") + assert_equal "Don't change the topic", topic["heading"] + + assert_equal "Don't change the topic", topic.read_attribute(:heading) + assert_equal "Don't change the topic", topic[:heading] + end + test "read_attribute raises ActiveModel::MissingAttributeError when the attribute does not exist" do computer = Computer.select("id").first assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] } @@ -609,7 +626,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase utc_time = Time.utc(2008, 1, 1) cst_time = utc_time.in_time_zone("Central Time (US & Canada)") in_time_zone "Pacific Time (US & Canada)" do - record = @target.new + record = @target.new record.written_on = cst_time assert_equal utc_time, record.written_on assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone @@ -633,7 +650,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase (-11..13).each do |timezone_offset| time_string = utc_time.in_time_zone(timezone_offset).to_s in_time_zone "Pacific Time (US & Canada)" do - record = @target.new + record = @target.new record.written_on = time_string assert_equal Time.zone.parse(time_string), record.written_on assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone @@ -654,7 +671,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase test "setting a time zone-aware attribute to a blank string returns nil" do in_time_zone "Pacific Time (US & Canada)" do - record = @target.new + record = @target.new record.written_on = " " assert_nil record.written_on assert_nil record[:written_on] @@ -665,7 +682,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase time_string = "Tue Jan 01 00:00:00 2008" (-11..13).each do |timezone_offset| in_time_zone timezone_offset do - record = @target.new + record = @target.new record.written_on = time_string assert_equal Time.zone.parse(time_string), record.written_on assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone @@ -677,7 +694,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase test "setting a time zone-aware datetime in the current time zone" do utc_time = Time.utc(2008, 1, 1) in_time_zone "Pacific Time (US & Canada)" do - record = @target.new + record = @target.new record.written_on = utc_time.in_time_zone assert_equal utc_time, record.written_on assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone @@ -737,7 +754,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase test "time zone-aware attributes do not recurse infinitely on invalid values" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new(bonus_time: []) - assert_equal nil, record.bonus_time + assert_nil record.bonus_time end end @@ -755,7 +772,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = @target.new(title: "The pros and cons of programming naked.") assert !topic.respond_to?(:title) exception = assert_raise(NoMethodError) { topic.title } - assert exception.message.include?("private method") + assert_includes exception.message, "private method" assert_equal "I'm private", topic.send(:title) end @@ -765,7 +782,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = @target.new assert !topic.respond_to?(:title=) exception = assert_raise(NoMethodError) { topic.title = "Pants" } - assert exception.message.include?("private method") + assert_includes exception.message, "private method" topic.send(:title=, "Very large pants") end @@ -775,7 +792,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = @target.new(title: "Isaac Newton's pants") assert !topic.respond_to?(:title?) exception = assert_raise(NoMethodError) { topic.title? } - assert exception.message.include?("private method") + assert_includes exception.message, "private method" assert topic.send(:title?) end @@ -1003,10 +1020,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase def privatize(method_signature) @target.class_eval(<<-private_method, __FILE__, __LINE__ + 1) - private - def #{method_signature} - "I'm private" - end - private_method + private + def #{method_signature} + "I'm private" + end + private_method end end diff --git a/activerecord/test/cases/attribute_set_test.rb b/activerecord/test/cases/attribute_set_test.rb index 059b5b2401..bd4b200735 100644 --- a/activerecord/test/cases/attribute_set_test.rb +++ b/activerecord/test/cases/attribute_set_test.rb @@ -25,7 +25,7 @@ module ActiveRecord attributes = builder.build_from_database(foo: "3.3") assert_equal "3.3", attributes[:foo].value_before_type_cast - assert_equal nil, attributes[:bar].value_before_type_cast + assert_nil attributes[:bar].value_before_type_cast assert_equal :bar, attributes[:bar].name end diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb index 7ec1f6f18c..3705a6be89 100644 --- a/activerecord/test/cases/attributes_test.rb +++ b/activerecord/test/cases/attributes_test.rb @@ -112,7 +112,7 @@ module ActiveRecord assert_equal 7, klass.attribute_types.length assert_equal 7, klass.column_defaults.length - assert klass.attribute_types.include?("wibble") + assert_includes klass.attribute_types, "wibble" end test "the given default value is cast from user" do @@ -249,5 +249,19 @@ module ActiveRecord model.foo = "lol" refute model.changed? end + + test "attributes not backed by database columns appear in inspect" do + inspection = OverloadedType.new.inspect + + assert_includes inspection, "non_existent_decimal" + end + + test "attributes do not require a type" do + klass = Class.new(OverloadedType) do + attribute :no_type + end + assert_equal 1, klass.new(no_type: 1).no_type + assert_equal "foo", klass.new(no_type: "foo").no_type + end end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index ae5127cc56..6d31b7a091 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -1,5 +1,6 @@ require "cases/helper" require "models/bird" +require "models/post" require "models/comment" require "models/company" require "models/customer" @@ -11,7 +12,6 @@ require "models/order" require "models/parrot" require "models/person" require "models/pirate" -require "models/post" require "models/reader" require "models/ship" require "models/ship_part" @@ -36,11 +36,11 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase private - def should_be_cool - unless self.first_name == "cool" - errors.add :first_name, "not cool" + def should_be_cool + unless self.first_name == "cool" + errors.add :first_name, "not cool" + end end - end } reference = Class.new(ActiveRecord::Base) { self.table_name = "references" @@ -196,21 +196,21 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas end def test_callbacks_firing_order_on_create - eye = Eye.create(iris_attributes: {color: "honey"}) + eye = Eye.create(iris_attributes: { color: "honey" }) assert_equal [true, false], eye.after_create_callbacks_stack end def test_callbacks_firing_order_on_update - eye = Eye.create(iris_attributes: {color: "honey"}) - eye.update(iris_attributes: {color: "green"}) + eye = Eye.create(iris_attributes: { color: "honey" }) + eye.update(iris_attributes: { color: "green" }) assert_equal [true, false], eye.after_update_callbacks_stack end def test_callbacks_firing_order_on_save - eye = Eye.create(iris_attributes: {color: "honey"}) + eye = Eye.create(iris_attributes: { color: "honey" }) assert_equal [false, false], eye.after_save_callbacks_stack - eye.update(iris_attributes: {color: "blue"}) + eye.update(iris_attributes: { color: "blue" }) assert_equal [false, false, false, false], eye.after_save_callbacks_stack end end @@ -443,7 +443,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not invalid_electron.valid? assert valid_electron.valid? assert_not molecule.valid? - assert_equal [{error: :blank}], molecule.errors.details["electrons.name"] + assert_equal [{ error: :blank }], molecule.errors.details[:"electrons.name"] end def test_errors_details_should_be_indexed_when_passed_as_array @@ -457,8 +457,8 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not tuning_peg_invalid.valid? assert tuning_peg_valid.valid? assert_not guitar.valid? - assert_equal [{error: :not_a_number, value: nil}] , guitar.errors.details["tuning_pegs[1].pitch"] - assert_equal [], guitar.errors.details["tuning_pegs.pitch"] + assert_equal [{ error: :not_a_number, value: nil }], guitar.errors.details[:"tuning_pegs[1].pitch"] + assert_equal [], guitar.errors.details[:"tuning_pegs.pitch"] end def test_errors_details_should_be_indexed_when_global_flag_is_set @@ -474,8 +474,8 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not invalid_electron.valid? assert valid_electron.valid? assert_not molecule.valid? - assert_equal [{error: :blank}], molecule.errors.details["electrons[1].name"] - assert_equal [], molecule.errors.details["electrons.name"] + assert_equal [{ error: :blank }], molecule.errors.details[:"electrons[1].name"] + assert_equal [], molecule.errors.details[:"electrons.name"] ensure ActiveRecord::Base.index_nested_attribute_errors = old_attribute_config end @@ -585,7 +585,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa firm.save firm.reload assert_equal 2, firm.clients.length - assert firm.clients.include?(companies(:second_client)) + assert_includes firm.clients, companies(:second_client) end def test_assign_ids_for_through_a_belongs_to @@ -594,7 +594,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa post.save post.reload assert_equal 2, post.people.length - assert post.people.include?(people(:david)) + assert_includes post.people, people(:david) end def test_build_before_save @@ -610,7 +610,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_many_before_save company = companies(:first_firm) - assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) } company.name += "-changed" assert_queries(3) { assert company.save } @@ -619,7 +619,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_via_block_before_save company = companies(:first_firm) - new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build { |client| client.name = "Another Client" } } assert !company.clients_of_firm.loaded? company.name += "-changed" @@ -631,7 +631,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_many_via_block_before_save company = companies(:first_firm) assert_no_queries(ignore_none: false) do - company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| + company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) do |client| client.name = "changed" end end @@ -647,7 +647,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.save firm.reload assert_equal 2, firm.clients.length - assert firm.clients.include?(Client.find_by_name("New Client")) + assert_includes firm.clients, Client.find_by_name("New Client") end end @@ -792,6 +792,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end @ship.pirate.catchphrase = "Changed Catchphrase" + @ship.name_will_change! assert_raise(RuntimeError) { assert !@pirate.save } assert_not_nil @pirate.reload.ship @@ -1130,7 +1131,7 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase assert_queries(0) { @ship.save! } @parrot = @pirate.parrots.create(name: "some_name") - @parrot.name="changed_name" + @parrot.name = "changed_name" assert_queries(1) { @ship.save! } assert_queries(0) { @ship.save! } end @@ -1390,6 +1391,14 @@ module AutosaveAssociationOnACollectionAssociationTests assert_equal "Squawky", parrot.reload.name end + def test_should_not_update_children_when_parent_creation_with_no_reason + parrot = Parrot.create!(name: "Polly") + assert_equal 0, parrot.updated_count + + Pirate.create!(parrot_ids: [parrot.id], catchphrase: "Arrrr") + assert_equal 0, parrot.reload.updated_count + end + def test_should_automatically_validate_the_associated_models @pirate.send(@association_name).each { |child| child.name = "" } @@ -1407,9 +1416,9 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_default_invalid_error_from_i18n - I18n.backend.store_translations(:en, activerecord: {errors: { models: + I18n.backend.store_translations(:en, activerecord: { errors: { models: { @associated_model_name.to_s.to_sym => { blank: "cannot be blank" } } - }}) + } }) @pirate.send(@association_name).build(name: "") @@ -1698,3 +1707,27 @@ class TestAutosaveAssociationWithTouch < ActiveRecord::TestCase assert_nothing_raised { invoice.line_items.create(amount: 10) } end end + +class TestAutosaveAssociationOnAHasManyAssociationWithInverse < ActiveRecord::TestCase + class Post < ActiveRecord::Base + has_many :comments, inverse_of: :post + end + + class Comment < ActiveRecord::Base + belongs_to :post, inverse_of: :comments + + attr_accessor :post_comments_count + after_save do + self.post_comments_count = post.comments.count + end + end + + def test_after_save_callback_with_autosave + post = Post.new(title: "Test", body: "...") + comment = post.comments.build(body: "...") + post.save! + + assert_equal 1, post.comments.count + assert_equal 1, comment.post_comments_count + end +end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index cd896e5948..a611cc208c 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -4,6 +4,7 @@ require "models/author" require "models/topic" require "models/reply" require "models/category" +require "models/categorization" require "models/company" require "models/customer" require "models/developer" @@ -33,8 +34,6 @@ class SecondAbstractClass < FirstAbstractClass self.abstract_class = true end class Photo < SecondAbstractClass; end -class Category < ActiveRecord::Base; end -class Categorization < ActiveRecord::Base; end class Smarts < ActiveRecord::Base; end class CreditCard < ActiveRecord::Base class PinNumber < ActiveRecord::Base @@ -45,8 +44,6 @@ class CreditCard < ActiveRecord::Base class Brand < Category; end end class MasterCreditCard < ActiveRecord::Base; end -class Post < ActiveRecord::Base; end -class Computer < ActiveRecord::Base; end class NonExistentTable < ActiveRecord::Base; end class TestOracleDefault < ActiveRecord::Base; end @@ -56,12 +53,6 @@ end class Weird < ActiveRecord::Base; end -class Boolean < ActiveRecord::Base - def has_fun - super - end -end - class LintTest < ActiveRecord::TestCase include ActiveModel::Lint::Tests @@ -107,12 +98,11 @@ class BasicsTest < ActiveRecord::TestCase assert_nil Edge.primary_key end - unless current_adapter?(:PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter, :FbAdapter) - def test_limit_with_comma - assert_deprecated do - assert Topic.limit("1,2").to_a - end - end + def test_many_mutations + car = Car.new name: "<3<3<3" + car.engines_count = 0 + 20_000.times { car.engines_count += 1 } + assert car.save end def test_limit_without_comma @@ -137,10 +127,8 @@ class BasicsTest < ActiveRecord::TestCase end def test_limit_should_sanitize_sql_injection_for_limit_with_commas - assert_deprecated do - assert_raises(ArgumentError) do - Topic.limit("1, 7 procedure help()").to_a - end + assert_raises(ArgumentError) do + Topic.limit("1, 7 procedure help()").to_a end end @@ -300,7 +288,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_create_after_initialize_with_block - cb = CustomBulb.create {|c| c.name = "Dude" } + cb = CustomBulb.create { |c| c.name = "Dude" } assert_equal("Dude", cb.name) assert_equal(true, cb.frickinawesome) end @@ -487,12 +475,12 @@ class BasicsTest < ActiveRecord::TestCase def test_utc_as_time_zone_and_new with_timezone_config default: :utc do - attributes = { "bonus_time(1i)"=>"2000", - "bonus_time(2i)"=>"1", - "bonus_time(3i)"=>"1", - "bonus_time(4i)"=>"10", - "bonus_time(5i)"=>"35", - "bonus_time(6i)"=>"50" } + attributes = { "bonus_time(1i)" => "2000", + "bonus_time(2i)" => "1", + "bonus_time(3i)" => "1", + "bonus_time(4i)" => "10", + "bonus_time(5i)" => "35", + "bonus_time(6i)" => "50" } topic = Topic.new(attributes) assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time end @@ -615,7 +603,7 @@ class BasicsTest < ActiveRecord::TestCase Topic.find(topic.id).destroy end - assert_equal nil, Topic.find_by_id(topic.id) + assert_nil Topic.find_by_id(topic.id) end def test_comparison_with_different_objects @@ -657,7 +645,7 @@ class BasicsTest < ActiveRecord::TestCase Weird.reset_column_information - assert_equal ["EUC-JP"], Weird.columns.map {|c| c.name.encoding.name }.uniq + assert_equal ["EUC-JP"], Weird.columns.map { |c| c.name.encoding.name }.uniq ensure silence_warnings { Encoding.default_internal = old_default_internal } Weird.reset_column_information @@ -891,7 +879,7 @@ class BasicsTest < ActiveRecord::TestCase # fixed dates / times assert_equal Date.new(2004, 1, 1), default.fixed_date - assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time + assert_equal Time.local(2004, 1, 1, 0, 0, 0, 0), default.fixed_time # char types assert_equal "Y", default.char1 @@ -1102,7 +1090,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_set_table_name_with_inheritance - k = Class.new( ActiveRecord::Base ) + k = Class.new(ActiveRecord::Base) def k.name; "Foo"; end def k.table_name; super + "ks"; end assert_equal "foosks", k.table_name @@ -1153,7 +1141,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_find_last - last = Developer.last + last = Developer.last assert_equal last, Developer.all.merge!(order: "id desc").first end @@ -1172,17 +1160,17 @@ class BasicsTest < ActiveRecord::TestCase end def test_find_ordered_last - last = Developer.all.merge!(order: "developers.salary ASC").last + last = Developer.all.merge!(order: "developers.salary ASC").last assert_equal last, Developer.all.merge!(order: "developers.salary ASC").to_a.last end def test_find_reverse_ordered_last - last = Developer.all.merge!(order: "developers.salary DESC").last + last = Developer.all.merge!(order: "developers.salary DESC").last assert_equal last, Developer.all.merge!(order: "developers.salary DESC").to_a.last end def test_find_multiple_ordered_last - last = Developer.all.merge!(order: "developers.name, developers.salary DESC").last + last = Developer.all.merge!(order: "developers.name, developers.salary DESC").last assert_equal last, Developer.all.merge!(order: "developers.name, developers.salary DESC").to_a.last end @@ -1197,7 +1185,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_find_symbol_ordered_last - last = Developer.all.merge!(order: :salary).last + last = Developer.all.merge!(order: :salary).last assert_equal last, Developer.all.merge!(order: :salary).to_a.last end @@ -1271,13 +1259,13 @@ class BasicsTest < ActiveRecord::TestCase ActiveSupport::Dependencies.remove_unloadable_constants! assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, klass) ensure - Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost) + Object.class_eval { remove_const :UnloadablePost } if defined?(UnloadablePost) end def test_marshal_round_trip expected = posts(:welcome) marshalled = Marshal.dump(expected) - actual = Marshal.load(marshalled) + actual = Marshal.load(marshalled) assert_equal expected.attributes, actual.attributes end @@ -1372,12 +1360,6 @@ class BasicsTest < ActiveRecord::TestCase end end - def test_uniq_delegates_to_scoped - assert_deprecated do - assert_equal Bird.all.distinct, Bird.uniq - end - end - def test_distinct_delegates_to_scoped assert_equal Bird.all.distinct, Bird.distinct end @@ -1421,6 +1403,16 @@ class BasicsTest < ActiveRecord::TestCase assert_nil hash["firm_name"] end + def test_slice_accepts_array_argument + attrs = { + title: "slice", + author_name: "@Cohen-Carlisle", + content: "accept arrays so I don't have to splat" + }.with_indifferent_access + topic = Topic.new(attrs) + assert_equal attrs, topic.slice(attrs.keys) + end + def test_default_values_are_deeply_dupped company = Company.new company.description << "foo" @@ -1512,7 +1504,7 @@ class BasicsTest < ActiveRecord::TestCase test "ignored columns are not present in columns_hash" do cache_columns = Developer.connection.schema_cache.columns_hash(Developer.table_name) assert_includes cache_columns.keys, "first_name" - refute_includes Developer.columns_hash.keys, "first_name" + assert_not_includes Developer.columns_hash.keys, "first_name" end test "ignored columns have no attribute methods" do diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 077e6d0bc0..f7e21faf0f 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -21,7 +21,7 @@ class EachTest < ActiveRecord::TestCase def test_each_should_not_return_query_chain_and_execute_only_one_query assert_queries(1) do - result = Post.find_each(batch_size: 100000){ } + result = Post.find_each(batch_size: 100000) {} assert_nil result end end @@ -135,11 +135,11 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_shouldnt_execute_query_unless_needed assert_queries(2) do - Post.find_in_batches(batch_size: @total) {|batch| assert_kind_of Array, batch } + Post.find_in_batches(batch_size: @total) { |batch| assert_kind_of Array, batch } end assert_queries(1) do - Post.find_in_batches(batch_size: @total + 1) {|batch| assert_kind_of Array, batch } + Post.find_in_batches(batch_size: @total + 1) { |batch| assert_kind_of Array, batch } end end @@ -156,7 +156,7 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_not_use_records_after_yielding_them_in_case_original_array_is_modified not_a_post = "not a post" def not_a_post.id; end - not_a_post.stub(:id, ->{ raise StandardError.new("not_a_post had #id called on it") }) do + not_a_post.stub(:id, -> { raise StandardError.new("not_a_post had #id called on it") }) do assert_nothing_raised do Post.find_in_batches(batch_size: 1) do |batch| assert_kind_of Array, batch @@ -182,7 +182,7 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_error_on_ignore_the_order assert_raise(ArgumentError) do - PostWithDefaultScope.find_in_batches(error_on_ignore: true){} + PostWithDefaultScope.find_in_batches(error_on_ignore: true) {} end end @@ -191,7 +191,7 @@ class EachTest < ActiveRecord::TestCase prev = ActiveRecord::Base.error_on_ignored_order ActiveRecord::Base.error_on_ignored_order = true assert_nothing_raised do - PostWithDefaultScope.find_in_batches(error_on_ignore: false){} + PostWithDefaultScope.find_in_batches(error_on_ignore: false) {} end ensure # Set back to default @@ -203,7 +203,7 @@ class EachTest < ActiveRecord::TestCase prev = ActiveRecord::Base.error_on_ignored_order ActiveRecord::Base.error_on_ignored_order = true assert_raise(ArgumentError) do - PostWithDefaultScope.find_in_batches(){} + PostWithDefaultScope.find_in_batches() {} end ensure # Set back to default @@ -212,7 +212,7 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_not_error_by_default assert_nothing_raised do - PostWithDefaultScope.find_in_batches(){} + PostWithDefaultScope.find_in_batches() {} end end @@ -227,7 +227,7 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_not_modify_passed_options assert_nothing_raised do - Post.find_in_batches({ batch_size: 42, start: 1 }.freeze){} + Post.find_in_batches({ batch_size: 42, start: 1 }.freeze) {} end end @@ -445,7 +445,7 @@ class EachTest < ActiveRecord::TestCase def test_in_batches_should_not_modify_passed_options assert_nothing_raised do - Post.in_batches({ of: 42, start: 1 }.freeze){} + Post.in_batches({ of: 42, start: 1 }.freeze) {} end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 13f9a47980..ffd5c1395d 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -92,21 +92,21 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_group_by_field c = Account.group(:firm_id).sum(:credit_limit) - [1,6,2].each do |firm_id| - assert c.keys.include?(firm_id), "Group #{c.inspect} does not contain firm_id #{firm_id}" + [1, 6, 2].each do |firm_id| + assert_includes c.keys, firm_id, "Group #{c.inspect} does not contain firm_id #{firm_id}" end end def test_should_group_by_arel_attribute c = Account.group(Account.arel_table[:firm_id]).sum(:credit_limit) - [1,6,2].each do |firm_id| - assert c.keys.include?(firm_id), "Group #{c.inspect} does not contain firm_id #{firm_id}" + [1, 6, 2].each do |firm_id| + assert_includes c.keys, firm_id, "Group #{c.inspect} does not contain firm_id #{firm_id}" end end def test_should_group_by_multiple_fields c = Account.group("firm_id", :credit_limit).count(:all) - [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) } + [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert_includes c.keys, firm_and_limit } end def test_should_group_by_multiple_fields_having_functions @@ -381,7 +381,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_perform_joined_include_when_referencing_included_tables - joined_count = Account.includes(:firm).where(companies: {name: "37signals"}).count + joined_count = Account.includes(:firm).where(companies: { name: "37signals" }).count assert_equal 1, joined_count end @@ -421,10 +421,6 @@ class CalculationsTest < ActiveRecord::TestCase def test_count_with_distinct assert_equal 4, Account.select(:credit_limit).distinct.count - - assert_deprecated do - assert_equal 4, Account.select(:credit_limit).uniq.count - end end def test_count_with_aliased_attribute @@ -453,7 +449,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_count_field_in_joined_table_with_group_by c = Account.group("accounts.firm_id").joins(:firm).count("companies.id") - [1,6,2,9].each { |firm_id| assert c.keys.include?(firm_id) } + [1, 6, 2, 9].each { |firm_id| assert_includes c.keys, firm_id } end def test_should_count_field_of_root_table_with_conflicting_group_by_column @@ -572,7 +568,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_pluck - assert_equal [1,2,3,4,5], Topic.order(:id).pluck(:id) + assert_equal [1, 2, 3, 4, 5], Topic.order(:id).pluck(:id) end def test_pluck_without_column_names @@ -604,11 +600,11 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_with_serialization t = Topic.create!(content: { foo: :bar }) - assert_equal [{foo: :bar}], Topic.where(id: t.id).pluck(:content) + assert_equal [{ foo: :bar }], Topic.where(id: t.id).pluck(:content) end def test_pluck_with_qualified_column_name - assert_equal [1,2,3,4,5], Topic.order(:id).pluck("topics.id") + assert_equal [1, 2, 3, 4, 5], Topic.order(:id).pluck("topics.id") end def test_pluck_auto_table_name_prefix @@ -688,7 +684,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_replaces_select_clause taks_relation = Topic.select(:approved, :id).order(:id) - assert_equal [1,2,3,4,5], taks_relation.pluck(:id) + assert_equal [1, 2, 3, 4, 5], taks_relation.pluck(:id) assert_equal [false, true, true, true, true], taks_relation.pluck(:approved) end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index e2352bd9f9..11ec6fb2c5 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -57,7 +57,7 @@ end class ParentDeveloper < ActiveRecord::Base self.table_name = "developers" attr_accessor :after_save_called - before_validation {|record| record.after_save_called = true} + before_validation { |record| record.after_save_called = true } end class ChildDeveloper < ParentDeveloper @@ -95,16 +95,16 @@ class OnCallbacksDeveloper < ActiveRecord::Base self.table_name = "developers" before_validation { history << :before_validation } - before_validation(on: :create){ history << :before_validation_on_create } - before_validation(on: :update){ history << :before_validation_on_update } + before_validation(on: :create) { history << :before_validation_on_create } + before_validation(on: :update) { history << :before_validation_on_update } validate do history << :validate end after_validation { history << :after_validation } - after_validation(on: :create){ history << :after_validation_on_create } - after_validation(on: :update){ history << :after_validation_on_update } + after_validation(on: :create) { history << :after_validation_on_create } + after_validation(on: :update) { history << :after_validation_on_update } def history @history ||= [] @@ -143,7 +143,7 @@ class CallbackCancellationDeveloper < ActiveRecord::Base attr_reader :after_save_called, :after_create_called, :after_update_called, :after_destroy_called attr_accessor :cancel_before_save, :cancel_before_create, :cancel_before_update, :cancel_before_destroy - before_save {defined?(@cancel_before_save) ? !@cancel_before_save : false} + before_save { defined?(@cancel_before_save) ? !@cancel_before_save : false } before_create { !@cancel_before_create } before_update { !@cancel_before_update } before_destroy { !@cancel_before_destroy } @@ -449,7 +449,7 @@ class CallbacksTest < ActiveRecord::TestCase assert david.valid? assert !david.save exc = assert_raise(ActiveRecord::RecordNotSaved) { david.save! } - assert_equal exc.record, david + assert_equal david, exc.record assert_equal "Failed to save the record", exc.message end @@ -493,7 +493,7 @@ class CallbacksTest < ActiveRecord::TestCase assert_deprecated do assert !david.destroy exc = assert_raise(ActiveRecord::RecordNotDestroyed) { david.destroy! } - assert_equal exc.record, david + assert_equal david, exc.record assert_equal "Failed to destroy the record", exc.message end assert_not_nil ImmutableDeveloper.find_by_id(1) @@ -527,7 +527,7 @@ class CallbacksTest < ActiveRecord::TestCase assert david.valid? assert !david.save exc = assert_raise(ActiveRecord::RecordNotSaved) { david.save! } - assert_equal exc.record, david + assert_equal david, exc.record david = DeveloperWithCanceledCallbacks.find(1) david.salary = 10_000_000 @@ -554,7 +554,7 @@ class CallbacksTest < ActiveRecord::TestCase david = DeveloperWithCanceledCallbacks.find(1) assert !david.destroy exc = assert_raise(ActiveRecord::RecordNotDestroyed) { david.destroy! } - assert_equal exc.record, david + assert_equal david, exc.record assert_not_nil ImmutableDeveloper.find_by_id(1) someone = CallbackHaltedDeveloper.find(1) diff --git a/activerecord/test/cases/collection_cache_key_test.rb b/activerecord/test/cases/collection_cache_key_test.rb index a2874438c1..381a78a8e2 100644 --- a/activerecord/test/cases/collection_cache_key_test.rb +++ b/activerecord/test/cases/collection_cache_key_test.rb @@ -28,20 +28,20 @@ module ActiveRecord end test "it triggers at most one query" do - developers = Developer.where(name: "David") + developers = Developer.where(name: "David") assert_queries(1) { developers.cache_key } assert_queries(0) { developers.cache_key } end test "it doesn't trigger any query if the relation is already loaded" do - developers = Developer.where(name: "David").load + developers = Developer.where(name: "David").load assert_queries(0) { developers.cache_key } end test "relation cache_key changes when the sql query changes" do developers = Developer.where(name: "David") - other_relation = Developer.where(name: "David").where("1 = 1") + other_relation = Developer.where(name: "David").where("1 = 1") assert_not_equal developers.cache_key, other_relation.cache_key end diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index 31e618664f..a65bb89052 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -6,7 +6,7 @@ module ActiveRecord def setup @adapter = AbstractAdapter.new(nil) def @adapter.native_database_types - {string: "varchar"} + { string: "varchar" } end @viz = @adapter.schema_creation end @@ -60,14 +60,13 @@ module ActiveRecord end def test_should_not_set_default_for_blob_and_text_data_types - text_type = MySQL::TypeMetadata.new( - SqlTypeMetadata.new(type: :text)) + text_type = MySQL::TypeMetadata.new(SqlTypeMetadata.new(type: :text)) text_column = MySQL::Column.new("title", nil, text_type) - assert_equal nil, text_column.default + assert_nil text_column.default not_null_text_column = MySQL::Column.new("title", nil, text_type, false) - assert_equal "", not_null_text_column.default + assert_nil not_null_text_column.default end def test_has_default_should_return_false_for_blob_and_text_data_types diff --git a/activerecord/test/cases/comment_test.rb b/activerecord/test/cases/comment_test.rb index 262ad319be..a625299e8d 100644 --- a/activerecord/test/cases/comment_test.rb +++ b/activerecord/test/cases/comment_test.rb @@ -2,7 +2,6 @@ require "cases/helper" require "support/schema_dumping_helper" if ActiveRecord::Base.connection.supports_comments? - class CommentTest < ActiveRecord::TestCase include SchemaDumpingHelper @@ -102,6 +101,7 @@ if ActiveRecord::Base.connection.supports_comments? # Do all the stuff from other tests @connection.add_column :commenteds, :rating, :integer, comment: "I am running out of imagination" @connection.change_column :commenteds, :content, :string, comment: "Whoa, content describes itself!" + @connection.change_column :commenteds, :content, :string @connection.change_column :commenteds, :obvious, :string, comment: nil @connection.add_index :commenteds, :obvious, name: "idx_obvious", comment: "We need to see obvious comments" @@ -135,5 +135,4 @@ if ActiveRecord::Base.connection.supports_comments? assert_no_match %r[t\.string\s+"absent_comment", comment:\n], output end end - end diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb index d9bcc0c130..2c33bf22ab 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -6,11 +6,11 @@ module ActiveRecord def setup @handler = ConnectionHandler.new @spec_name = "primary" - @pool = @handler.establish_connection(ActiveRecord::Base.configurations["arunit"]) + @pool = @handler.establish_connection(ActiveRecord::Base.configurations["arunit"]) end def test_establish_connection_uses_spec_name - config = {"readonly" => {"adapter" => "sqlite3"}} + config = { "readonly" => { "adapter" => "sqlite3" } } resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(config) spec = resolver.spec(:readonly) @handler.establish_connection(spec.to_hash) diff --git a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb index b1ba6f11f2..8faa67255d 100644 --- a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +++ b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb @@ -27,7 +27,7 @@ module ActiveRecord ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:default_env, config) - expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost", "name"=>"default_env" } + expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost", "name" => "default_env" } assert_equal expected, actual end @@ -37,7 +37,7 @@ module ActiveRecord config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:foo, config) - expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost","name"=>"foo" } + expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost", "name" => "foo" } assert_equal expected, actual end @@ -47,7 +47,7 @@ module ActiveRecord config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:foo, config) - expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost","name"=>"foo" } + expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost", "name" => "foo" } assert_equal expected, actual end @@ -55,13 +55,13 @@ module ActiveRecord ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } } actual = resolve_spec(:production, config) - expected = { "adapter"=>"not_postgres", "database"=>"not_foo", "host"=>"localhost", "name"=>"production" } + expected = { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost", "name" => "production" } assert_equal expected, actual end def test_resolver_with_database_uri_and_unknown_symbol_key ENV["DATABASE_URL"] = "postgres://localhost/foo" - config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } + config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } assert_raises AdapterNotSpecified do resolve_spec(:production, config) end @@ -71,7 +71,7 @@ module ActiveRecord ENV["DATABASE_URL"] = "not-postgres://not-localhost/not_foo" config = { "production" => { "adapter" => "also_not_postgres", "database" => "also_not_foo" } } actual = resolve_spec("postgres://localhost/foo", config) - expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" } assert_equal expected, actual end @@ -85,7 +85,7 @@ module ActiveRecord ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "not_default_env" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_config(config) - expect_prod = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + expect_prod = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" } assert_equal expect_prod, actual["default_env"] end @@ -93,7 +93,7 @@ module ActiveRecord ENV["DATABASE_URL"] = "ibm-db://localhost/foo" config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } } actual = resolve_spec(:default_env, config) - expected = { "adapter"=>"ibm_db", "database"=>"foo", "host"=>"localhost", "name"=>"default_env" } + expected = { "adapter" => "ibm_db", "database" => "foo", "host" => "localhost", "name" => "default_env" } assert_equal expected, actual end @@ -142,13 +142,13 @@ module ActiveRecord "database" => "foo", "host" => "localhost" } assert_equal expected, actual["default_env"] - assert_equal nil, actual["production"] - assert_equal nil, actual["development"] - assert_equal nil, actual["test"] - assert_equal nil, actual[:default_env] - assert_equal nil, actual[:production] - assert_equal nil, actual[:development] - assert_equal nil, actual[:test] + assert_nil actual["production"] + assert_nil actual["development"] + assert_nil actual["test"] + assert_nil actual[:default_env] + assert_nil actual[:production] + assert_nil actual[:development] + assert_nil actual[:test] end def test_blank_with_database_url_with_rails_env @@ -162,15 +162,15 @@ module ActiveRecord "host" => "localhost" } assert_equal expected, actual["not_production"] - assert_equal nil, actual["production"] - assert_equal nil, actual["default_env"] - assert_equal nil, actual["development"] - assert_equal nil, actual["test"] - assert_equal nil, actual[:default_env] - assert_equal nil, actual[:not_production] - assert_equal nil, actual[:production] - assert_equal nil, actual[:development] - assert_equal nil, actual[:test] + assert_nil actual["production"] + assert_nil actual["default_env"] + assert_nil actual["development"] + assert_nil actual["test"] + assert_nil actual[:default_env] + assert_nil actual[:not_production] + assert_nil actual[:production] + assert_nil actual[:development] + assert_nil actual[:test] end def test_blank_with_database_url_with_rack_env @@ -184,15 +184,15 @@ module ActiveRecord "host" => "localhost" } assert_equal expected, actual["not_production"] - assert_equal nil, actual["production"] - assert_equal nil, actual["default_env"] - assert_equal nil, actual["development"] - assert_equal nil, actual["test"] - assert_equal nil, actual[:default_env] - assert_equal nil, actual[:not_production] - assert_equal nil, actual[:production] - assert_equal nil, actual[:development] - assert_equal nil, actual[:test] + assert_nil actual["production"] + assert_nil actual["default_env"] + assert_nil actual["development"] + assert_nil actual["test"] + assert_nil actual[:default_env] + assert_nil actual[:not_production] + assert_nil actual[:production] + assert_nil actual[:development] + assert_nil actual[:test] end def test_database_url_with_ipv6_host_and_port @@ -213,7 +213,7 @@ module ActiveRecord config = { "default_env" => { "url" => "postgres://localhost/foo" } } actual = resolve_config(config) expected = { "default_env" => - { "adapter" => "postgresql", + { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" } @@ -224,7 +224,7 @@ module ActiveRecord def test_merge_no_conflicts_with_database_url ENV["DATABASE_URL"] = "postgres://localhost/foo" - config = {"default_env" => { "pool" => "5" } } + config = { "default_env" => { "pool" => "5" } } actual = resolve_config(config) expected = { "default_env" => { "adapter" => "postgresql", @@ -239,7 +239,7 @@ module ActiveRecord def test_merge_conflicts_with_database_url ENV["DATABASE_URL"] = "postgres://localhost/foo" - config = {"default_env" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } } + config = { "default_env" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } } actual = resolve_config(config) expected = { "default_env" => { "adapter" => "postgresql", diff --git a/activerecord/test/cases/connection_adapters/quoting_test.rb b/activerecord/test/cases/connection_adapters/quoting_test.rb deleted file mode 100644 index 59dcb96ebc..0000000000 --- a/activerecord/test/cases/connection_adapters/quoting_test.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "cases/helper" - -module ActiveRecord - module ConnectionAdapters - module Quoting - class QuotingTest < ActiveRecord::TestCase - def test_quoting_classes - assert_equal "'Object'", AbstractAdapter.new(nil).quote(Object) - end - end - end - end -end diff --git a/activerecord/test/cases/connection_adapters/schema_cache_test.rb b/activerecord/test/cases/connection_adapters/schema_cache_test.rb index d4459603af..106323ccc9 100644 --- a/activerecord/test/cases/connection_adapters/schema_cache_test.rb +++ b/activerecord/test/cases/connection_adapters/schema_cache_test.rb @@ -12,6 +12,33 @@ module ActiveRecord assert_equal "id", @cache.primary_keys("posts") end + def test_yaml_dump_and_load + @cache.columns("posts") + @cache.columns_hash("posts") + @cache.data_sources("posts") + @cache.primary_keys("posts") + + new_cache = YAML.load(YAML.dump(@cache)) + assert_no_queries do + assert_equal 11, new_cache.columns("posts").size + assert_equal 11, new_cache.columns_hash("posts").size + assert new_cache.data_sources("posts") + assert_equal "id", new_cache.primary_keys("posts") + end + end + + def test_yaml_loads_5_1_dump + body = File.open(schema_dump_path).read + cache = YAML.load(body) + + assert_no_queries do + assert_equal 11, cache.columns("posts").size + assert_equal 11, cache.columns_hash("posts").size + assert cache.data_sources("posts") + assert_equal "id", cache.primary_keys("posts") + end + end + def test_primary_key_for_non_existent_table assert_nil @cache.primary_keys("omgponies") end @@ -45,17 +72,28 @@ module ActiveRecord @cache = Marshal.load(Marshal.dump(@cache)) - assert_equal 11, @cache.columns("posts").size - assert_equal 11, @cache.columns_hash("posts").size - assert @cache.data_sources("posts") - assert_equal "id", @cache.primary_keys("posts") + assert_no_queries do + assert_equal 11, @cache.columns("posts").size + assert_equal 11, @cache.columns_hash("posts").size + assert @cache.data_sources("posts") + assert_equal "id", @cache.primary_keys("posts") + end end - def test_table_methods_deprecation - assert_deprecated { assert @cache.table_exists?("posts") } - assert_deprecated { assert @cache.tables("posts") } - assert_deprecated { @cache.clear_table_cache!("posts") } + def test_data_source_exist + assert @cache.data_source_exists?("posts") + assert_not @cache.data_source_exists?("foo") end + + def test_clear_data_source_cache + @cache.clear_data_source_cache!("posts") + end + + private + + def schema_dump_path + "test/assets/schema_dump_5_1.yml" + end end end end diff --git a/activerecord/test/cases/connection_management_test.rb b/activerecord/test/cases/connection_management_test.rb index 88620f9f09..d1e946d401 100644 --- a/activerecord/test/cases/connection_management_test.rb +++ b/activerecord/test/cases/connection_management_test.rb @@ -104,7 +104,7 @@ module ActiveRecord def middleware(app) lambda do |env| a, b, c = executor.wrap { app.call(env) } - [a, b, Rack::BodyProxy.new(c) { }] + [a, b, Rack::BodyProxy.new(c) {}] end end end diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index d7ff9d6880..42600e53fd 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -184,14 +184,14 @@ module ActiveRecord def test_checkout_behaviour pool = ConnectionPool.new ActiveRecord::Base.connection_pool.spec - connection = pool.connection - assert_not_nil connection + main_connection = pool.connection + assert_not_nil main_connection threads = [] 4.times do |i| threads << Thread.new(i) do - connection = pool.connection - assert_not_nil connection - connection.close + thread_connection = pool.connection + assert_not_nil thread_connection + thread_connection.close end end @@ -455,49 +455,63 @@ module ActiveRecord with_single_connection_pool do |pool| [:disconnect, :disconnect!, :clear_reloadable_connections, :clear_reloadable_connections!].each do |group_action_method| conn = pool.connection # drain the only available connection - second_thread_done = Concurrent::CountDownLatch.new - - # create a first_thread and let it get into the FIFO queue first - first_thread = Thread.new do - pool.with_connection { second_thread_done.wait } - end - - # wait for first_thread to get in queue - Thread.pass until pool.num_waiting_in_queue == 1 - - # create a different, later thread, that will attempt to do a "group action", - # but because of the group action semantics it should be able to preempt the - # first_thread when a connection is made available - second_thread = Thread.new do - pool.send(group_action_method) - second_thread_done.count_down - end + second_thread_done = Concurrent::Event.new - # wait for second_thread to get in queue - Thread.pass until pool.num_waiting_in_queue == 2 - - # return the only available connection - pool.checkin(conn) - - # if the second_thread is not able to preempt the first_thread, - # they will temporarily (until either of them timeouts with ConnectionTimeoutError) - # deadlock and a join(2) timeout will be reached - failed = true unless second_thread.join(2) - - #--- post test clean up start - second_thread_done.count_down if failed - - # after `pool.disconnect()` the first thread will be left stuck in queue, no need to wait for - # it to timeout with ConnectionTimeoutError - if (group_action_method == :disconnect || group_action_method == :disconnect!) && pool.num_waiting_in_queue > 0 - pool.with_connection {} # create a new connection in case there are threads still stuck in a queue + begin + # create a first_thread and let it get into the FIFO queue first + first_thread = Thread.new do + pool.with_connection { second_thread_done.wait } + end + + # wait for first_thread to get in queue + Thread.pass until pool.num_waiting_in_queue == 1 + + # create a different, later thread, that will attempt to do a "group action", + # but because of the group action semantics it should be able to preempt the + # first_thread when a connection is made available + second_thread = Thread.new do + pool.send(group_action_method) + second_thread_done.set + end + + # wait for second_thread to get in queue + Thread.pass until pool.num_waiting_in_queue == 2 + + # return the only available connection + pool.checkin(conn) + + # if the second_thread is not able to preempt the first_thread, + # they will temporarily (until either of them timeouts with ConnectionTimeoutError) + # deadlock and a join(2) timeout will be reached + assert second_thread.join(2), "#{group_action_method} is not able to preempt other waiting threads" + + ensure + # post test clean up + failed = !second_thread_done.set? + + if failed + second_thread_done.set + + puts + puts ">>> test_disconnect_and_clear_reloadable_connections_are_able_to_preempt_other_waiting_threads / #{group_action_method}" + p [first_thread, second_thread] + p pool.stat + p pool.connections.map(&:owner) + + first_thread.join(2) + second_thread.join(2) + + puts "---" + p [first_thread, second_thread] + p pool.stat + p pool.connections.map(&:owner) + puts "<<<" + puts + end + + first_thread.join(10) || raise("first_thread got stuck") + second_thread.join(10) || raise("second_thread got stuck") end - - first_thread.join - second_thread.join - #--- post test clean up end - - flunk "#{group_action_method} is not able to preempt other waiting threads" if failed end end end @@ -526,6 +540,26 @@ module ActiveRecord end end + def test_connection_pool_stat + with_single_connection_pool do |pool| + pool.with_connection do |connection| + stats = pool.stat + assert_equal({ size: 1, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }, stats) + end + + stats = pool.stat + assert_equal({ size: 1, connections: 1, busy: 0, dead: 0, idle: 1, waiting: 0, checkout_timeout: 5 }, stats) + + Thread.new do + pool.checkout + Thread.current.kill + end.join + + stats = pool.stat + assert_equal({ size: 1, connections: 1, busy: 0, dead: 1, idle: 0, waiting: 0, checkout_timeout: 5 }, stats) + end + end + private def with_single_connection_pool one_conn_spec = ActiveRecord::Base.connection_pool.spec.dup diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb index 4bfec47124..13b5bae13c 100644 --- a/activerecord/test/cases/connection_specification/resolver_test.rb +++ b/activerecord/test/cases/connection_specification/resolver_test.rb @@ -4,11 +4,11 @@ module ActiveRecord module ConnectionAdapters class ConnectionSpecification class ResolverTest < ActiveRecord::TestCase - def resolve(spec, config={}) + def resolve(spec, config = {}) Resolver.new(config).resolve(spec) end - def spec(spec, config={}) + def spec(spec, config = {}) Resolver.new(config).spec(spec) end @@ -29,27 +29,27 @@ module ActiveRecord "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_url_sub_key - spec = resolve :production, "production" => {"url" => "abstract://foo?encoding=utf8"} + spec = resolve :production, "production" => { "url" => "abstract://foo?encoding=utf8" } assert_equal({ "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_url_sub_key_merges_correctly - hash = {"url" => "abstract://foo?encoding=utf8&", "adapter" => "sqlite3", "host" => "bar", "pool" => "3"} + hash = { "url" => "abstract://foo?encoding=utf8&", "adapter" => "sqlite3", "host" => "bar", "pool" => "3" } spec = resolve :production, "production" => hash assert_equal({ "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", "pool" => "3", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_url_host_no_db @@ -112,16 +112,16 @@ module ActiveRecord end def test_url_sub_key_for_sqlite3 - spec = resolve :production, "production" => {"url" => "sqlite3:foo?encoding=utf8"} + spec = resolve :production, "production" => { "url" => "sqlite3:foo?encoding=utf8" } assert_equal({ "adapter" => "sqlite3", "database" => "foo", "encoding" => "utf8", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_spec_name_on_key_lookup - spec = spec(:readonly, "readonly" => {"adapter" => "sqlite3"}) + spec = spec(:readonly, "readonly" => { "adapter" => "sqlite3" }) assert_equal "readonly", spec.name end diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb index 84f2c3a465..c7d0ba32b4 100644 --- a/activerecord/test/cases/counter_cache_test.rb +++ b/activerecord/test/cases/counter_cache_test.rb @@ -211,4 +211,146 @@ class CounterCacheTest < ActiveRecord::TestCase aircraft.wheels.first.destroy end end + + test "update counters doesn't touch timestamps by default" do + @topic.update_column :updated_at, 5.minutes.ago + previously_updated_at = @topic.updated_at + + Topic.update_counters(@topic.id, replies_count: -1) + + assert_equal previously_updated_at, @topic.updated_at + end + + test "update counters with touch: true" do + assert_touching @topic, :updated_at do + Topic.update_counters(@topic.id, replies_count: -1, touch: true) + end + end + + test "update counters of multiple records with touch: true" do + t1, t2 = topics(:first, :second) + + assert_touching t1, :updated_at do + assert_difference ["t1.reload.replies_count", "t2.reload.replies_count"], 2 do + Topic.update_counters([t1.id, t2.id], replies_count: 2, touch: true) + end + end + end + + test "update multiple counters with touch: true" do + assert_touching @topic, :updated_at do + Topic.update_counters(@topic.id, replies_count: 2, unique_replies_count: 2, touch: true) + end + end + + test "reset counters with touch: true" do + assert_touching @topic, :updated_at do + Topic.reset_counters(@topic.id, :replies, touch: true) + end + end + + test "reset multiple counters with touch: true" do + assert_touching @topic, :updated_at do + Topic.update_counters(@topic.id, replies_count: 1, unique_replies_count: 1) + Topic.reset_counters(@topic.id, :replies, :unique_replies, touch: true) + end + end + + test "increment counters with touch: true" do + assert_touching @topic, :updated_at do + Topic.increment_counter(:replies_count, @topic.id, touch: true) + end + end + + test "decrement counters with touch: true" do + assert_touching @topic, :updated_at do + Topic.decrement_counter(:replies_count, @topic.id, touch: true) + end + end + + test "update counters with touch: :written_on" do + assert_touching @topic, :written_on do + Topic.update_counters(@topic.id, replies_count: -1, touch: :written_on) + end + end + + test "update multiple counters with touch: :written_on" do + assert_touching @topic, :written_on do + Topic.update_counters(@topic.id, replies_count: 2, unique_replies_count: 2, touch: :written_on) + end + end + + test "reset counters with touch: :written_on" do + assert_touching @topic, :written_on do + Topic.reset_counters(@topic.id, :replies, touch: :written_on) + end + end + + test "reset multiple counters with touch: :written_on" do + assert_touching @topic, :written_on do + Topic.update_counters(@topic.id, replies_count: 1, unique_replies_count: 1) + Topic.reset_counters(@topic.id, :replies, :unique_replies, touch: :written_on) + end + end + + test "increment counters with touch: :written_on" do + assert_touching @topic, :written_on do + Topic.increment_counter(:replies_count, @topic.id, touch: :written_on) + end + end + + test "decrement counters with touch: :written_on" do + assert_touching @topic, :written_on do + Topic.decrement_counter(:replies_count, @topic.id, touch: :written_on) + end + end + + test "update counters with touch: %i( updated_at written_on )" do + assert_touching @topic, :updated_at, :written_on do + Topic.update_counters(@topic.id, replies_count: -1, touch: %i( updated_at written_on )) + end + end + + test "update multiple counters with touch: %i( updated_at written_on )" do + assert_touching @topic, :updated_at, :written_on do + Topic.update_counters(@topic.id, replies_count: 2, unique_replies_count: 2, touch: %i( updated_at written_on )) + end + end + + test "reset counters with touch: %i( updated_at written_on )" do + assert_touching @topic, :updated_at, :written_on do + Topic.reset_counters(@topic.id, :replies, touch: %i( updated_at written_on )) + end + end + + test "reset multiple counters with touch: %i( updated_at written_on )" do + assert_touching @topic, :updated_at, :written_on do + Topic.update_counters(@topic.id, replies_count: 1, unique_replies_count: 1) + Topic.reset_counters(@topic.id, :replies, :unique_replies, touch: %i( updated_at written_on )) + end + end + + test "increment counters with touch: %i( updated_at written_on )" do + assert_touching @topic, :updated_at, :written_on do + Topic.increment_counter(:replies_count, @topic.id, touch: %i( updated_at written_on )) + end + end + + test "decrement counters with touch: %i( updated_at written_on )" do + assert_touching @topic, :updated_at, :written_on do + Topic.decrement_counter(:replies_count, @topic.id, touch: %i( updated_at written_on )) + end + end + + private + def assert_touching(record, *attributes) + record.update_columns attributes.map { |attr| [ attr, 5.minutes.ago ] }.to_h + touch_times = attributes.map { |attr| [ attr, record.public_send(attr) ] }.to_h + + yield + + touch_times.each do |attr, previous_touch_time| + assert_operator previous_touch_time, :<, record.reload.public_send(attr) + end + end end diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb index ac9912d4d1..66035865be 100644 --- a/activerecord/test/cases/database_statements_test.rb +++ b/activerecord/test/cases/database_statements_test.rb @@ -5,6 +5,13 @@ class DatabaseStatementsTest < ActiveRecord::TestCase @connection = ActiveRecord::Base.connection end + unless current_adapter?(:OracleAdapter) + def test_exec_insert + result = @connection.exec_insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)", nil, []) + assert_not_nil @connection.send(:last_inserted_id, result) + end + end + def test_insert_should_return_the_inserted_id assert_not_nil return_the_inserted_id(method: :insert) end @@ -13,12 +20,6 @@ class DatabaseStatementsTest < ActiveRecord::TestCase assert_not_nil return_the_inserted_id(method: :create) end - def test_insert_update_delete_sql_is_deprecated - assert_deprecated { @connection.insert_sql("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") } - assert_deprecated { @connection.update_sql("UPDATE accounts SET credit_limit = 6000 WHERE firm_id = 42") } - assert_deprecated { @connection.delete_sql("DELETE FROM accounts WHERE firm_id = 42") } - end - private def return_the_inserted_id(method:) diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index f94815d34c..6532efcf22 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -127,92 +127,66 @@ if current_adapter?(:Mysql2Adapter) ActiveRecord::Base.establish_connection connection end - # MySQL cannot have defaults on text/blob columns. It reports the - # default value as null. + # Strict mode controls how MySQL handles invalid or missing values + # in data-change statements such as INSERT or UPDATE. A value can be + # invalid for several reasons. For example, it might have the wrong + # data type for the column, or it might be out of range. A value is + # missing when a new row to be inserted does not contain a value for + # a non-NULL column that has no explicit DEFAULT clause in its definition. + # (For a NULL column, NULL is inserted if the value is missing.) # - # Despite this, in non-strict mode, MySQL will use an empty string - # as the default value of the field, if no other value is - # specified. + # If strict mode is not in effect, MySQL inserts adjusted values for + # invalid or missing values and produces warnings. In strict mode, + # you can produce this behavior by using INSERT IGNORE or UPDATE IGNORE. # - # Therefore, in non-strict mode, we want column.default to report - # an empty string as its default, to be consistent with that. - # - # In strict mode, column.default should be nil. - def test_mysql_text_not_null_defaults_non_strict + # https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict + def test_mysql_not_null_defaults_non_strict using_strict(false) do - with_text_blob_not_null_table do |klass| + with_mysql_not_null_table do |klass| record = klass.new - assert_equal "", record.non_null_blob - assert_equal "", record.non_null_text - - assert_nil record.null_blob - assert_nil record.null_text + assert_nil record.non_null_integer + assert_nil record.non_null_string + assert_nil record.non_null_text + assert_nil record.non_null_blob record.save! record.reload + assert_equal 0, record.non_null_integer + assert_equal "", record.non_null_string assert_equal "", record.non_null_text assert_equal "", record.non_null_blob - - assert_nil record.null_text - assert_nil record.null_blob end end end - def test_mysql_text_not_null_defaults_strict + def test_mysql_not_null_defaults_strict using_strict(true) do - with_text_blob_not_null_table do |klass| + with_mysql_not_null_table do |klass| record = klass.new - assert_nil record.non_null_blob + assert_nil record.non_null_integer + assert_nil record.non_null_string assert_nil record.non_null_text - assert_nil record.null_blob - assert_nil record.null_text + assert_nil record.non_null_blob - assert_raises(ActiveRecord::StatementInvalid) { klass.create } + assert_raises(ActiveRecord::NotNullViolation) { klass.create } end end end - def with_text_blob_not_null_table + def with_mysql_not_null_table klass = Class.new(ActiveRecord::Base) - klass.table_name = "test_mysql_text_not_null_defaults" + klass.table_name = "test_mysql_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 + t.integer :non_null_integer, null: false + t.string :non_null_string, null: false + t.text :non_null_text, null: false + t.blob :non_null_blob, null: false end yield klass 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 - klass = Class.new(ActiveRecord::Base) - klass.table_name = "test_integer_not_null_default_zero" - klass.connection.create_table klass.table_name do |t| - t.column :zero, :integer, null: false, default: 0 - t.column :omit, :integer, null: false - end - - assert_equal "0", klass.columns_hash["zero"].default - assert !klass.columns_hash["zero"].null - assert_equal nil, klass.columns_hash["omit"].default - assert !klass.columns_hash["omit"].null - - assert_raise(ActiveRecord::StatementInvalid) { klass.create! } - - assert_nothing_raised do - instance = klass.create!(omit: 1) - assert_equal 0, instance.zero - assert_equal 1, instance.omit - end - ensure - klass.connection.drop_table(klass.table_name) rescue nil - end end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 32df15eef3..0e58e65a07 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -280,7 +280,7 @@ class DirtyTest < ActiveRecord::TestCase assert pirate.changed? assert_nil pirate.catchphrase_was assert_equal %w(catchphrase), pirate.changed - assert_equal({"catchphrase" => [nil, "arrr"]}, pirate.changes) + assert_equal({ "catchphrase" => [nil, "arrr"] }, pirate.changes) pirate.save assert !pirate.changed? @@ -314,7 +314,7 @@ class DirtyTest < ActiveRecord::TestCase assert !topic.approved_changed? # Coming from web form. - params = {topic: {approved: 1}} + params = { topic: { approved: 1 } } # In the controller. topic.attributes = params[:topic] assert topic.approved? @@ -341,7 +341,7 @@ class DirtyTest < ActiveRecord::TestCase def test_partial_update_with_optimistic_locking person = Person.new(first_name: "foo") - old_lock_version = 1 + old_lock_version = person.lock_version with_partial_writes Person, false do assert_queries(2) { 2.times { person.save! } } @@ -423,7 +423,7 @@ class DirtyTest < ActiveRecord::TestCase def test_save_should_store_serialized_attributes_even_with_partial_writes with_partial_writes(Topic) do - topic = Topic.create!(content: {a: "a"}) + topic = Topic.create!(content: { a: "a" }) assert_not topic.changed? @@ -444,7 +444,7 @@ class DirtyTest < ActiveRecord::TestCase def test_save_always_should_update_timestamps_when_serialized_attributes_are_present with_partial_writes(Topic) do - topic = Topic.create!(content: {a: "a"}) + topic = Topic.create!(content: { a: "a" }) topic.save! updated_at = topic.updated_at @@ -460,7 +460,7 @@ class DirtyTest < ActiveRecord::TestCase def test_save_should_not_save_serialized_attribute_with_partial_writes_if_not_present with_partial_writes(Topic) do - Topic.create!(author_name: "Bill", content: {a: "a"}) + Topic.create!(author_name: "Bill", content: { a: "a" }) topic = Topic.select("id, author_name").first topic.update_columns author_name: "John" topic = Topic.first @@ -495,8 +495,8 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 4, pirate.previous_changes.size assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"] assert_equal [nil, pirate.id], pirate.previous_changes["id"] - assert pirate.previous_changes.include?("updated_on") - assert pirate.previous_changes.include?("created_on") + assert_includes pirate.previous_changes, "updated_on" + assert_includes pirate.previous_changes, "created_on" assert !pirate.previous_changes.key?("parrot_id") pirate.catchphrase = "Yar!!" @@ -631,7 +631,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal("arrrr", pirate.catchphrase_was) assert pirate.catchphrase_changed?(from: "arrrr") assert_not pirate.catchphrase_changed?(from: "anything else") - assert pirate.changed_attributes.include?(:catchphrase) + assert_includes pirate.changed_attributes, :catchphrase pirate.save! pirate.reload @@ -726,6 +726,89 @@ class DirtyTest < ActiveRecord::TestCase assert person.changed? end + test "saved_change_to_attribute? returns whether a change occurred in the last save" do + person = Person.create!(first_name: "Sean") + + assert person.saved_change_to_first_name? + refute person.saved_change_to_gender? + assert person.saved_change_to_first_name?(from: nil, to: "Sean") + assert person.saved_change_to_first_name?(from: nil) + assert person.saved_change_to_first_name?(to: "Sean") + refute person.saved_change_to_first_name?(from: "Jim", to: "Sean") + refute person.saved_change_to_first_name?(from: "Jim") + refute person.saved_change_to_first_name?(to: "Jim") + end + + test "saved_change_to_attribute returns the change that occurred in the last save" do + person = Person.create!(first_name: "Sean", gender: "M") + + assert_equal [nil, "Sean"], person.saved_change_to_first_name + assert_equal [nil, "M"], person.saved_change_to_gender + + person.update(first_name: "Jim") + + assert_equal ["Sean", "Jim"], person.saved_change_to_first_name + assert_nil person.saved_change_to_gender + end + + test "attribute_before_last_save returns the original value before saving" do + person = Person.create!(first_name: "Sean", gender: "M") + + assert_nil person.first_name_before_last_save + assert_nil person.gender_before_last_save + + person.first_name = "Jim" + + assert_nil person.first_name_before_last_save + assert_nil person.gender_before_last_save + + person.save + + assert_equal "Sean", person.first_name_before_last_save + assert_equal "M", person.gender_before_last_save + end + + test "saved_changes? returns whether the last call to save changed anything" do + person = Person.create!(first_name: "Sean") + + assert person.saved_changes? + + person.save + + refute person.saved_changes? + end + + test "saved_changes returns a hash of all the changes that occurred" do + person = Person.create!(first_name: "Sean", gender: "M") + + assert_equal [nil, "Sean"], person.saved_changes[:first_name] + assert_equal [nil, "M"], person.saved_changes[:gender] + assert_equal %w(id first_name gender created_at updated_at).sort, person.saved_changes.keys.sort + + travel(1.second) do + person.update(first_name: "Jim") + end + + assert_equal ["Sean", "Jim"], person.saved_changes[:first_name] + assert_equal %w(first_name lock_version updated_at).sort, person.saved_changes.keys.sort + end + + test "changed? in after callbacks returns true but is deprecated" do + klass = Class.new(ActiveRecord::Base) do + self.table_name = "people" + + after_save do + ActiveSupport::Deprecation.silence do + raise "changed? should be true" unless changed? + end + raise "has_changes_to_save? should be false" if has_changes_to_save? + end + end + + person = klass.create!(first_name: "Sean") + refute person.changed? + end + private def with_partial_writes(klass, on = true) old = klass.partial_writes? diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb index c2009843f0..b7641fcf32 100644 --- a/activerecord/test/cases/enum_test.rb +++ b/activerecord/test/cases/enum_test.rb @@ -18,6 +18,7 @@ class EnumTest < ActiveRecord::TestCase assert @book.author_visibility_visible? assert @book.illustrator_visibility_visible? assert @book.with_medium_font_size? + assert @book.medium_to_read? end test "query state with strings" do @@ -26,6 +27,7 @@ class EnumTest < ActiveRecord::TestCase assert_equal "english", @book.language assert_equal "visible", @book.author_visibility assert_equal "visible", @book.illustrator_visibility + assert_equal "medium", @book.difficulty end test "find via scope" do @@ -34,6 +36,7 @@ class EnumTest < ActiveRecord::TestCase assert_equal @book, Book.in_english.first assert_equal @book, Book.author_visibility_visible.first assert_equal @book, Book.illustrator_visibility_visible.first + assert_equal @book, Book.medium_to_read.first end test "find via where with values" do @@ -422,6 +425,43 @@ class EnumTest < ActiveRecord::TestCase assert_not @book.in_french? end + test "query state by predicate with custom suffix" do + assert @book.medium_to_read? + assert_not @book.easy_to_read? + assert_not @book.hard_to_read? + end + + test "enum methods with custom suffix defined" do + assert @book.class.respond_to?(:easy_to_read) + assert @book.class.respond_to?(:medium_to_read) + assert @book.class.respond_to?(:hard_to_read) + + assert @book.respond_to?(:easy_to_read?) + assert @book.respond_to?(:medium_to_read?) + assert @book.respond_to?(:hard_to_read?) + + assert @book.respond_to?(:easy_to_read!) + assert @book.respond_to?(:medium_to_read!) + assert @book.respond_to?(:hard_to_read!) + end + + test "update enum attributes with custom suffix" do + @book.medium_to_read! + assert_not @book.easy_to_read? + assert @book.medium_to_read? + assert_not @book.hard_to_read? + + @book.easy_to_read! + assert @book.easy_to_read? + assert_not @book.medium_to_read? + assert_not @book.hard_to_read? + + @book.hard_to_read! + assert_not @book.easy_to_read? + assert_not @book.medium_to_read? + assert @book.hard_to_read? + end + test "uses default status when no status is provided in fixtures" do book = books(:tlg) assert book.proposed?, "expected fixture to default to proposed status" diff --git a/activerecord/test/cases/errors_test.rb b/activerecord/test/cases/errors_test.rb index 0711a372f2..73feb831d0 100644 --- a/activerecord/test/cases/errors_test.rb +++ b/activerecord/test/cases/errors_test.rb @@ -5,7 +5,7 @@ class ErrorsTest < ActiveRecord::TestCase base = ActiveRecord::ActiveRecordError error_klasses = ObjectSpace.each_object(Class).select { |klass| klass < base } - error_klasses.each do |error_klass| + (error_klasses - [ActiveRecord::AmbiguousSourceReflectionForThroughAssociation]).each do |error_klass| begin error_klass.new.inspect rescue ArgumentError diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb index 43f1d401dd..86fe90ae51 100644 --- a/activerecord/test/cases/explain_test.rb +++ b/activerecord/test/cases/explain_test.rb @@ -40,7 +40,7 @@ if ActiveRecord::Base.connection.supports_explain? queries = sqls.zip(binds) stub_explain_for_query_plans do - expected = sqls.map {|sql| "EXPLAIN for: #{sql}\nquery plan #{sql}"}.join("\n") + expected = sqls.map { |sql| "EXPLAIN for: #{sql}\nquery plan #{sql}" }.join("\n") assert_equal expected, base.exec_explain(queries) end end @@ -75,7 +75,7 @@ if ActiveRecord::Base.connection.supports_explain? def stub_explain_for_query_plans(query_plans = ["query plan foo", "query plan bar"]) explain_called = 0 - connection.stub(:explain, proc{ explain_called += 1; query_plans[explain_called - 1] }) do + connection.stub(:explain, proc { explain_called += 1; query_plans[explain_called - 1] }) do yield end end diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb index a7af8ac0ea..3eaa993d45 100644 --- a/activerecord/test/cases/finder_respond_to_test.rb +++ b/activerecord/test/cases/finder_respond_to_test.rb @@ -10,7 +10,7 @@ class FinderRespondToTest < ActiveRecord::TestCase end def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method - class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { } + class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) {} assert_respond_to Topic, :method_added_for_finder_respond_to_test ensure class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test) diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index bf0ce18bb8..ca22fe969c 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -22,13 +22,13 @@ class FinderTest < ActiveRecord::TestCase fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars def test_find_by_id_with_hash - assert_raises(ActiveRecord::StatementInvalid) do + assert_nothing_raised do Post.find_by_id(limit: 1) end end def test_find_by_title_and_id_with_hash - assert_raises(ActiveRecord::StatementInvalid) do + assert_nothing_raised do Post.find_by_title_and_id("foo", limit: 1) end end @@ -49,22 +49,22 @@ class FinderTest < ActiveRecord::TestCase end def test_find_with_ids_returning_ordered - records = Topic.find([4,2,5]) + records = Topic.find([4, 2, 5]) assert_equal "The Fourth Topic of the day", records[0].title assert_equal "The Second Topic of the day", records[1].title assert_equal "The Fifth Topic of the day", records[2].title - records = Topic.find(4,2,5) + records = Topic.find(4, 2, 5) assert_equal "The Fourth Topic of the day", records[0].title assert_equal "The Second Topic of the day", records[1].title assert_equal "The Fifth Topic of the day", records[2].title - records = Topic.find(["4","2","5"]) + records = Topic.find(["4", "2", "5"]) assert_equal "The Fourth Topic of the day", records[0].title assert_equal "The Second Topic of the day", records[1].title assert_equal "The Fifth Topic of the day", records[2].title - records = Topic.find("4","2","5") + records = Topic.find("4", "2", "5") assert_equal "The Fourth Topic of the day", records[0].title assert_equal "The Second Topic of the day", records[1].title assert_equal "The Fifth Topic of the day", records[2].title @@ -72,12 +72,12 @@ class FinderTest < ActiveRecord::TestCase def test_find_with_ids_and_order_clause # The order clause takes precedence over the informed ids - records = Topic.order(:author_name).find([5,3,1]) + records = Topic.order(:author_name).find([5, 3, 1]) assert_equal "The Third Topic of the day", records[0].title assert_equal "The First Topic", records[1].title assert_equal "The Fifth Topic of the day", records[2].title - records = Topic.order(:id).find([5,3,1]) + records = Topic.order(:id).find([5, 3, 1]) assert_equal "The First Topic", records[0].title assert_equal "The Third Topic of the day", records[1].title assert_equal "The Fifth Topic of the day", records[2].title @@ -85,14 +85,14 @@ class FinderTest < ActiveRecord::TestCase def test_find_with_ids_with_limit_and_order_clause # The order clause takes precedence over the informed ids - records = Topic.limit(2).order(:id).find([5,3,1]) + records = Topic.limit(2).order(:id).find([5, 3, 1]) assert_equal 2, records.size assert_equal "The First Topic", records[0].title assert_equal "The Third Topic of the day", records[1].title end def test_find_with_ids_and_limit - records = Topic.limit(3).find([3,2,5,1,4]) + records = Topic.limit(3).find([3, 2, 5, 1, 4]) assert_equal 3, records.size assert_equal "The Third Topic of the day", records[0].title assert_equal "The Second Topic of the day", records[1].title @@ -102,7 +102,7 @@ class FinderTest < ActiveRecord::TestCase def test_find_with_ids_where_and_limit # Please note that Topic 1 is the only not approved so # if it were among the first 3 it would raise an ActiveRecord::RecordNotFound - records = Topic.where(approved: true).limit(3).find([3,2,5,1,4]) + records = Topic.where(approved: true).limit(3).find([3, 2, 5, 1, 4]) assert_equal 3, records.size assert_equal "The Third Topic of the day", records[0].title assert_equal "The Second Topic of the day", records[1].title @@ -110,7 +110,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_with_ids_and_offset - records = Topic.offset(2).find([3,2,5,1,4]) + records = Topic.offset(2).find([3, 2, 5, 1, 4]) assert_equal 3, records.size assert_equal "The Fifth Topic of the day", records[0].title assert_equal "The First Topic", records[1].title @@ -118,7 +118,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_passing_active_record_object_is_deprecated - assert_deprecated do + assert_raises(ArgumentError) do Topic.find(Topic.last) end end @@ -127,7 +127,7 @@ class FinderTest < ActiveRecord::TestCase gc_disabled = GC.disable Post.where("author_id" => nil) # warm up x = Symbol.all_symbols.count - Post.where("title" => {"xxxqqqq" => "bar"}) + Post.where("title" => { "xxxqqqq" => "bar" }) assert_equal x, Symbol.all_symbols.count ensure GC.enable if gc_disabled == false @@ -136,7 +136,7 @@ class FinderTest < ActiveRecord::TestCase # find should handle strings that come from URLs # (example: Category.find(params[:id])) def test_find_with_string - assert_equal(Topic.find(1).title,Topic.find("1").title) + assert_equal(Topic.find(1).title, Topic.find("1").title) end def test_exists @@ -151,7 +151,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal false, Topic.exists?(45) assert_equal false, Topic.exists?(Topic.new.id) - assert_raise(NoMethodError) { Topic.exists?([1,2]) } + assert_raise(NoMethodError) { Topic.exists?([1, 2]) } end def test_exists_with_polymorphic_relation @@ -167,15 +167,15 @@ class FinderTest < ActiveRecord::TestCase assert_equal false, relation.exists?(false) end - def test_exists_passing_active_record_object_is_deprecated - assert_deprecated do + def test_exists_passing_active_record_object_is_not_permited + assert_raises(ArgumentError) do Topic.exists?(Topic.new) end end def test_exists_returns_false_when_parameter_has_invalid_type assert_equal false, Topic.exists?("foo") - assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int + assert_equal false, Topic.exists?(("9" * 53).to_i) # number that's bigger than int end def test_exists_does_not_select_columns_without_alias @@ -258,8 +258,8 @@ class FinderTest < ActiveRecord::TestCase end def test_find_by_ids_with_limit_and_offset - assert_equal 2, Entrant.limit(2).find([1,3,2]).size - entrants = Entrant.limit(3).offset(2).find([1,3,2]) + assert_equal 2, Entrant.limit(2).find([1, 3, 2]).size + entrants = Entrant.limit(3).offset(2).find([1, 3, 2]) assert_equal 1, entrants.size assert_equal "Ruby Guru", entrants.first.name @@ -488,12 +488,12 @@ class FinderTest < ActiveRecord::TestCase assert_equal topics(:fourth), Topic.offset(1).second_to_last assert_equal topics(:fourth), Topic.offset(2).second_to_last assert_equal topics(:fourth), Topic.offset(3).second_to_last - assert_equal nil, Topic.offset(4).second_to_last - assert_equal nil, Topic.offset(5).second_to_last + assert_nil Topic.offset(4).second_to_last + assert_nil Topic.offset(5).second_to_last #test with limit - # assert_equal nil, Topic.limit(1).second # TODO: currently failing - assert_equal nil, Topic.limit(1).second_to_last + # assert_nil Topic.limit(1).second # TODO: currently failing + assert_nil Topic.limit(1).second_to_last end def test_second_to_last_have_primary_key_order_by_default @@ -516,15 +516,15 @@ class FinderTest < ActiveRecord::TestCase # test with offset assert_equal topics(:third), Topic.offset(1).third_to_last assert_equal topics(:third), Topic.offset(2).third_to_last - assert_equal nil, Topic.offset(3).third_to_last - assert_equal nil, Topic.offset(4).third_to_last - assert_equal nil, Topic.offset(5).third_to_last + assert_nil Topic.offset(3).third_to_last + assert_nil Topic.offset(4).third_to_last + assert_nil Topic.offset(5).third_to_last # test with limit - # assert_equal nil, Topic.limit(1).third # TODO: currently failing - assert_equal nil, Topic.limit(1).third_to_last - # assert_equal nil, Topic.limit(2).third # TODO: currently failing - assert_equal nil, Topic.limit(2).third_to_last + # assert_nil Topic.limit(1).third # TODO: currently failing + assert_nil Topic.limit(1).third_to_last + # assert_nil Topic.limit(2).third # TODO: currently failing + assert_nil Topic.limit(2).third_to_last end def test_third_to_last_have_primary_key_order_by_default @@ -584,7 +584,7 @@ class FinderTest < ActiveRecord::TestCase end def test_last_on_loaded_relation_should_not_use_sql - relation = Topic.limit(10).load + relation = Topic.limit(10).load assert_no_queries do relation.last relation.last(2) @@ -592,7 +592,7 @@ class FinderTest < ActiveRecord::TestCase end def test_last_with_irreversible_order - assert_deprecated do + assert_raises(ActiveRecord::IrreversibleOrderError) do Topic.order("coalesce(author_name, title)").last end end @@ -627,8 +627,8 @@ class FinderTest < ActiveRecord::TestCase def test_find_only_some_columns topic = Topic.select("author_name").find(1) - assert_raise(ActiveModel::MissingAttributeError) {topic.title} - assert_raise(ActiveModel::MissingAttributeError) {topic.title?} + assert_raise(ActiveModel::MissingAttributeError) { topic.title } + assert_raise(ActiveModel::MissingAttributeError) { topic.title? } assert_nil topic.read_attribute("title") assert_equal "David", topic.author_name assert !topic.attribute_present?("title") @@ -693,27 +693,27 @@ class FinderTest < ActiveRecord::TestCase end def test_find_on_hash_conditions_with_range - assert_equal [1,2], Topic.where(id: 1..2).to_a.map(&:id).sort + assert_equal [1, 2], Topic.where(id: 1..2).to_a.map(&:id).sort assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2..3).find(1) } end def test_find_on_hash_conditions_with_end_exclusive_range - assert_equal [1,2,3], Topic.where(id: 1..3).to_a.map(&:id).sort - assert_equal [1,2], Topic.where(id: 1...3).to_a.map(&:id).sort + assert_equal [1, 2, 3], Topic.where(id: 1..3).to_a.map(&:id).sort + assert_equal [1, 2], Topic.where(id: 1...3).to_a.map(&:id).sort assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2...3).find(3) } end def test_find_on_hash_conditions_with_multiple_ranges - assert_equal [1,2,3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort + assert_equal [1, 2, 3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort assert_equal [1], Comment.where(id: 1..1, post_id: 1..10).to_a.map(&:id).sort end def test_find_on_hash_conditions_with_array_of_integers_and_ranges - assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort + assert_equal [1, 2, 3, 5, 6, 7, 8, 9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort end def test_find_on_hash_conditions_with_array_of_ranges - assert_equal [1,2,6,7,8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort + assert_equal [1, 2, 6, 7, 8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort end def test_find_on_multiple_hash_conditions @@ -864,7 +864,7 @@ class FinderTest < ActiveRecord::TestCase def test_named_bind_variables_with_quotes Company.create("name" => "37signals' go'es agains") - assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first + assert Company.where(["name = :name", { name: "37signals' go'es agains" }]).first end def test_named_bind_variables @@ -874,11 +874,6 @@ class FinderTest < ActiveRecord::TestCase assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on end - def test_string_sanitation - assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1") - assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table") - end - def test_count_by_sql assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3")) assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2])) @@ -988,7 +983,6 @@ class FinderTest < ActiveRecord::TestCase assert_equal devs[2], Developer.offset(2).first assert_equal devs[-3], Developer.offset(2).last - assert_equal devs[-3], Developer.offset(2).last assert_equal devs[-3], Developer.offset(2).order("id DESC").first end @@ -1013,8 +1007,8 @@ class FinderTest < ActiveRecord::TestCase where("project_id=1").to_a assert_equal 3, developers_on_project_one.length developer_names = developers_on_project_one.map(&:name) - assert developer_names.include?("David") - assert developer_names.include?("Jamis") + assert_includes developer_names, "David" + assert_includes developer_names, "Jamis" end def test_joins_dont_clobber_id @@ -1034,7 +1028,7 @@ class FinderTest < ActiveRecord::TestCase def test_find_by_id_with_conditions_with_or assert_nothing_raised do - Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3]) + Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1, 2, 3]) end end @@ -1066,8 +1060,8 @@ class FinderTest < ActiveRecord::TestCase end def test_select_values - assert_equal ["1","2","3","4","5","6","7","8","9", "10", "11"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map!(&:to_s) - assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux", "Apex"], Company.connection.select_values("SELECT name FROM companies ORDER BY id") + assert_equal ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map!(&:to_s) + assert_equal ["37signals", "Summit", "Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux", "Apex"], Company.connection.select_values("SELECT name FROM companies ORDER BY id") end def test_select_rows @@ -1075,9 +1069,9 @@ class FinderTest < ActiveRecord::TestCase [["1", "1", nil, "37signals"], ["2", "1", "2", "Summit"], ["3", "1", "1", "Microsoft"]], - Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}}) + Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! { |i| i.map! { |j| j.to_s unless j.nil? } }) assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]], - Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}} + Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! { |i| i.map! { |j| j.to_s unless j.nil? } } end def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct @@ -1097,7 +1091,7 @@ class FinderTest < ActiveRecord::TestCase order("client_of DESC"). map(&:client_of) - assert client_of.include?(nil) + assert_includes client_of, nil assert_equal [2, 1].sort, client_of.compact.sort end @@ -1119,6 +1113,16 @@ class FinderTest < ActiveRecord::TestCase assert_equal [0, 1, 1], posts.map(&:author_id).sort end + def test_find_one_message_on_primary_key + e = assert_raises(ActiveRecord::RecordNotFound) do + Car.find(0) + end + assert_equal 0, e.id + assert_equal "id", e.primary_key + assert_equal "Car", e.model + assert_equal "Couldn't find Car with 'id'=0", e.message + end + def test_find_one_message_with_custom_primary_key table_with_custom_primary_key do |model| model.primary_key = :name @@ -1162,12 +1166,12 @@ class FinderTest < ActiveRecord::TestCase end test "find_by returns nil if the record is missing" do - assert_equal nil, Post.find_by("1 = 0") + assert_nil Post.find_by("1 = 0") end test "find_by with associations" do assert_equal authors(:david), Post.find_by(author: authors(:david)).author - assert_equal authors(:mary) , Post.find_by(author: authors(:mary) ).author + assert_equal authors(:mary) , Post.find_by(author: authors(:mary)).author end test "find_by doesn't have implicit ordering" do @@ -1216,7 +1220,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal tyre2, zyke.tyres.custom_find_by(id: tyre2.id) end - protected + private def table_with_custom_primary_key yield(Class.new(Toy) do def self.name diff --git a/activerecord/test/cases/fixture_set/file_test.rb b/activerecord/test/cases/fixture_set/file_test.rb index e69c9f303a..533edcc2e0 100644 --- a/activerecord/test/cases/fixture_set/file_test.rb +++ b/activerecord/test/cases/fixture_set/file_test.rb @@ -31,7 +31,7 @@ module ActiveRecord def test_values File.open(::File.join(FIXTURES_ROOT, "accounts.yml")) do |fh| - assert_equal [1,2,3,4,5,6].sort, fh.to_a.map(&:last).map { |x| + assert_equal [1, 2, 3, 4, 5, 6].sort, fh.to_a.map(&:last).map { |x| x["id"] }.sort end @@ -77,7 +77,7 @@ module ActiveRecord yaml = "one:\n name: <%= fixture_helper %>\n" tmp_yaml ["curious", "yml"], yaml do |t| golden = - [["one", {"name" => "Fixture helper"}]] + [["one", { "name" => "Fixture helper" }]] assert_equal golden, File.open(t.path) { |fh| fh.to_a } end ActiveRecord::FixtureSet.context_class.class_eval do diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 24a9894f19..dd48053823 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -12,9 +12,11 @@ require "models/company" require "models/computer" require "models/course" require "models/developer" +require "models/dog" require "models/doubloon" require "models/joke" require "models/matey" +require "models/other_dog" require "models/parrot" require "models/pirate" require "models/post" @@ -192,28 +194,38 @@ class FixturesTest < ActiveRecord::TestCase end def test_empty_yaml_fixture - assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts") + assert_not_nil ActiveRecord::FixtureSet.new(Account.connection, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts") end def test_empty_yaml_fixture_with_a_comment_in_it - assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies") + assert_not_nil ActiveRecord::FixtureSet.new(Account.connection, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies") end def test_nonexistent_fixture_file nonexistent_fixture_path = FIXTURES_ROOT + "/imnothere" #sanity check to make sure that this file never exists - assert Dir[nonexistent_fixture_path+"*"].empty? + assert Dir[nonexistent_fixture_path + "*"].empty? assert_raise(Errno::ENOENT) do - ActiveRecord::FixtureSet.new( Account.connection, "companies", Company, nonexistent_fixture_path) + ActiveRecord::FixtureSet.new(Account.connection, "companies", Company, nonexistent_fixture_path) end end def test_dirty_dirty_yaml_file - assert_raise(ActiveRecord::Fixture::FormatError) do - ActiveRecord::FixtureSet.new( Account.connection, "courses", Course, FIXTURES_ROOT + "/naked/yml/courses") + fixture_path = FIXTURES_ROOT + "/naked/yml/courses" + error = assert_raise(ActiveRecord::Fixture::FormatError) do + ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path) end + assert_equal "fixture is not a hash: #{fixture_path}.yml", error.to_s + end + + def test_yaml_file_with_one_invalid_fixture + fixture_path = FIXTURES_ROOT + "/naked/yml/courses_with_invalid_key" + error = assert_raise(ActiveRecord::Fixture::FormatError) do + ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path) + end + assert_equal "fixture key is not a hash: #{fixture_path}.yml, keys: [\"two\"]", error.to_s end def test_yaml_file_with_invalid_column @@ -728,7 +740,7 @@ class LoadAllFixturesTest < ActiveRecord::TestCase self.class.fixtures :all if File.symlink? FIXTURES_ROOT + "/all/admin" - assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort end ensure ActiveRecord::FixtureSet.reset_cache @@ -741,7 +753,7 @@ class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase self.class.fixtures :all if File.symlink? FIXTURES_ROOT + "/all/admin" - assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort end ensure ActiveRecord::FixtureSet.reset_cache @@ -923,7 +935,7 @@ class FoxyFixturesTest < ActiveRecord::TestCase end def test_namespaced_models - assert admin_accounts(:signals37).users.include?(admin_users(:david)) + assert_includes admin_accounts(:signals37).users, admin_users(:david) assert_equal 2, admin_accounts(:signals37).users.size end @@ -948,7 +960,7 @@ end class CustomNameForFixtureOrModelTest < ActiveRecord::TestCase ActiveRecord::FixtureSet.reset_cache - set_fixture_class :randomly_named_a9 => + set_fixture_class :randomly_named_a9 => ClassNameThatDoesNotFollowCONVENTIONS, :'admin/randomly_named_a9' => Admin::ClassNameThatDoesNotFollowCONVENTIONS1, @@ -1011,3 +1023,16 @@ class FixtureClassNamesTest < ActiveRecord::TestCase assert_nil fixture_class_names["unregistered_identifier"] end end + +class SameNameDifferentDatabaseFixturesTest < ActiveRecord::TestCase + fixtures :dogs, :other_dogs + + test "fixtures are properly loaded" do + # Force loading the fixtures again to reproduce issue + ActiveRecord::FixtureSet.reset_cache + create_fixtures("dogs", "other_dogs") + + assert_kind_of Dog, dogs(:sophie) + assert_kind_of OtherDog, other_dogs(:lassie) + end +end diff --git a/activerecord/test/cases/forbidden_attributes_protection_test.rb b/activerecord/test/cases/forbidden_attributes_protection_test.rb index b17daafe01..ffa3f63e0d 100644 --- a/activerecord/test/cases/forbidden_attributes_protection_test.rb +++ b/activerecord/test/cases/forbidden_attributes_protection_test.rb @@ -140,11 +140,11 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase def test_where_not_works_with_permitted_params params = ProtectedParams.new(first_name: "Guille").permit! Person.create!(params) - assert_empty Person.where.not(params).select {|p| p.first_name == "Guille" } + assert_empty Person.where.not(params).select { |p| p.first_name == "Guille" } end def test_strong_params_style_objects_work_with_singular_associations - params = ProtectedParams.new( name: "Stern", ship_attributes: ProtectedParams.new(name: "The Black Rock").permit!).permit! + params = ProtectedParams.new(name: "Stern", ship_attributes: ProtectedParams.new(name: "The Black Rock").permit!).permit! part = ShipPart.new(params) assert_equal "Stern", part.name @@ -155,7 +155,7 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase params = ProtectedParams.new( trinkets_attributes: ProtectedParams.new( "0" => ProtectedParams.new(name: "Necklace").permit!, - "1" => ProtectedParams.new(name: "Spoon").permit! ) ).permit! + "1" => ProtectedParams.new(name: "Spoon").permit!)).permit! part = ShipPart.new(params) assert_equal "Necklace", part.trinkets[0].name diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index ebd4437a87..1ddcbf0e4f 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -1,7 +1,5 @@ require "config" -require "active_support/testing/autorun" -require "active_support/testing/method_call_assertions" require "stringio" require "active_record" @@ -29,9 +27,6 @@ ARTest.connect # Quote "type" if it's a reserved word for the current connection. QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name("type") -# FIXME: Remove this when the deprecation cycle on TZ aware types by default ends. -ActiveRecord::Base.time_zone_aware_types << :time - def current_adapter?(*types) types.any? do |type| ActiveRecord::ConnectionAdapters.const_defined?(type) && @@ -134,21 +129,6 @@ def disable_extension!(extension, connection) connection.reconnect! end -require "cases/validations_repair_helper" -class ActiveSupport::TestCase - include ActiveRecord::TestFixtures - include ActiveRecord::ValidationsRepairHelper - include ActiveSupport::Testing::MethodCallAssertions - - self.fixture_path = FIXTURES_ROOT - self.use_instantiated_fixtures = false - self.use_transactional_tests = true - - def create_fixtures(*fixture_set_names, &block) - ActiveRecord::FixtureSet.create_fixtures(ActiveSupport::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block) - end -end - def load_schema # silence verbose schema loading original_stdout = $stdout diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb index e0946544ef..e107ff2362 100644 --- a/activerecord/test/cases/hot_compatibility_test.rb +++ b/activerecord/test/cases/hot_compatibility_test.rb @@ -119,11 +119,11 @@ class HotCompatibilityTest < ActiveRecord::TestCase .instance_variable_get(:@cache)[Process.pid] end - # Rails will automatically clear the prepared statements on the connection - # that runs the migration, so we use two connections to simulate what would - # actually happen on a production system; we'd have one connection running the - # migration from the rake task ("ddl_connection" here), and we'd have another - # connection in a web worker. + # Rails will automatically clear the prepared statements on the connection + # that runs the migration, so we use two connections to simulate what would + # actually happen on a production system; we'd have one connection running the + # migration from the rake task ("ddl_connection" here), and we'd have another + # connection in a web worker. def with_two_connections run_without_connection do |original_connection| ActiveRecord::Base.establish_connection(original_connection.merge(pool_size: 2)) diff --git a/activerecord/test/cases/i18n_test.rb b/activerecord/test/cases/i18n_test.rb index ab3a1132e8..7f03c5b23d 100644 --- a/activerecord/test/cases/i18n_test.rb +++ b/activerecord/test/cases/i18n_test.rb @@ -8,37 +8,37 @@ class ActiveRecordI18nTests < ActiveRecord::TestCase end def test_translated_model_attributes - I18n.backend.store_translations "en", activerecord: {attributes: {topic: {title: "topic title attribute"} } } + I18n.backend.store_translations "en", activerecord: { attributes: { topic: { title: "topic title attribute" } } } assert_equal "topic title attribute", Topic.human_attribute_name("title") end def test_translated_model_attributes_with_symbols - I18n.backend.store_translations "en", activerecord: {attributes: {topic: {title: "topic title attribute"} } } + I18n.backend.store_translations "en", 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.backend.store_translations "en", activerecord: {attributes: {reply: {title: "reply title attribute"} } } + I18n.backend.store_translations "en", 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.backend.store_translations "en", activerecord: {attributes: {topic: {title: "topic title attribute"} } } + I18n.backend.store_translations "en", activerecord: { attributes: { topic: { title: "topic title attribute" } } } assert_equal "topic title attribute", Reply.human_attribute_name("title") end def test_translated_model_names - I18n.backend.store_translations "en", activerecord: {models: {topic: "topic model"} } + I18n.backend.store_translations "en", activerecord: { models: { topic: "topic model" } } assert_equal "topic model", Topic.model_name.human end def test_translated_model_names_with_sti - I18n.backend.store_translations "en", activerecord: {models: {reply: "reply model"} } + I18n.backend.store_translations "en", activerecord: { models: { reply: "reply model" } } assert_equal "reply model", Reply.model_name.human end def test_translated_model_names_with_sti_fallback - I18n.backend.store_translations "en", activerecord: {models: {topic: "topic model"} } + I18n.backend.store_translations "en", activerecord: { models: { topic: "topic model" } } assert_equal "topic model", Reply.model_name.human end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 9090184622..e570e9ac1d 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -58,21 +58,21 @@ class InheritanceTest < ActiveRecord::TestCase end def test_compute_type_success - assert_equal Author, ActiveRecord::Base.send(:compute_type, "Author") + assert_equal Author, Company.send(:compute_type, "Author") end def test_compute_type_nonexistent_constant e = assert_raises NameError do - ActiveRecord::Base.send :compute_type, "NonexistentModel" + Company.send :compute_type, "NonexistentModel" end - assert_equal "uninitialized constant ActiveRecord::Base::NonexistentModel", e.message - assert_equal "ActiveRecord::Base::NonexistentModel", e.name + assert_equal "uninitialized constant Company::NonexistentModel", e.message + assert_equal "Company::NonexistentModel", e.name end def test_compute_type_no_method_error - ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise NoMethodError }) do + ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise NoMethodError }) do assert_raises NoMethodError do - ActiveRecord::Base.send :compute_type, "InvalidModel" + Company.send :compute_type, "InvalidModel" end end end @@ -87,19 +87,19 @@ class InheritanceTest < ActiveRecord::TestCase error = e end - ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise e }) do + ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise e }) do exception = assert_raises NameError do - ActiveRecord::Base.send :compute_type, "InvalidModel" + Company.send :compute_type, "InvalidModel" end assert_equal error.message, exception.message end end def test_compute_type_argument_error - ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise ArgumentError }) do + ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise ArgumentError }) do assert_raises ArgumentError do - ActiveRecord::Base.send :compute_type, "InvalidModel" + Company.send :compute_type, "InvalidModel" end end end diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb index 766917b196..d7aa091623 100644 --- a/activerecord/test/cases/integration_test.rb +++ b/activerecord/test/cases/integration_test.rb @@ -15,7 +15,7 @@ class IntegrationTest < ActiveRecord::TestCase def test_to_param_returns_nil_if_not_persisted client = Client.new - assert_equal nil, client.to_param + assert_nil client.to_param end def test_to_param_returns_id_if_not_persisted_but_id_is_set @@ -89,7 +89,7 @@ class IntegrationTest < ActiveRecord::TestCase def test_to_param_class_method_uses_default_if_not_persisted firm = Firm.new(name: "Fancy Shirts") - assert_equal nil, firm.to_param + assert_nil firm.to_param end def test_to_param_with_no_arguments @@ -172,4 +172,10 @@ class IntegrationTest < ActiveRecord::TestCase owner = owners(:blackbeard) assert_equal "owners/#{owner.id}-#{owner.happy_at.utc.to_s(:usec)}", owner.cache_key(:updated_at, :happy_at) end + + def test_cache_key_when_named_timestamp_is_nil + owner = owners(:blackbeard) + owner.happy_at = nil + assert_equal "owners/#{owner.id}", owner.cache_key(:happy_at) + end end diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index 81e8b0000a..cc3951e2ba 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -165,10 +165,8 @@ module ActiveRecord teardown do %w[horses new_horses].each do |table| - ActiveSupport::Deprecation.silence do - if ActiveRecord::Base.connection.table_exists?(table) - ActiveRecord::Base.connection.drop_table(table) - end + if ActiveRecord::Base.connection.table_exists?(table) + ActiveRecord::Base.connection.drop_table(table) end end ActiveRecord::Migration.verbose = @verbose_was @@ -199,14 +197,14 @@ module ActiveRecord def test_migrate_up migration = InvertibleMigration.new migration.migrate(:up) - ActiveSupport::Deprecation.silence { assert migration.connection.table_exists?("horses"), "horses should exist" } + assert migration.connection.table_exists?("horses"), "horses should exist" end def test_migrate_down migration = InvertibleMigration.new migration.migrate :up migration.migrate :down - ActiveSupport::Deprecation.silence { assert !migration.connection.table_exists?("horses") } + assert !migration.connection.table_exists?("horses") end def test_migrate_revert @@ -214,36 +212,30 @@ module ActiveRecord revert = InvertibleRevertMigration.new migration.migrate :up revert.migrate :up - ActiveSupport::Deprecation.silence { assert !migration.connection.table_exists?("horses") } + assert !migration.connection.table_exists?("horses") revert.migrate :down - ActiveSupport::Deprecation.silence { assert migration.connection.table_exists?("horses") } + assert migration.connection.table_exists?("horses") migration.migrate :down - ActiveSupport::Deprecation.silence { assert !migration.connection.table_exists?("horses") } + assert !migration.connection.table_exists?("horses") end def test_migrate_revert_by_part InvertibleMigration.new.migrate :up received = [] migration = InvertibleByPartsMigration.new - migration.test = ->(dir){ - ActiveSupport::Deprecation.silence do - assert migration.connection.table_exists?("horses") - assert migration.connection.table_exists?("new_horses") - end + migration.test = ->(dir) { + assert migration.connection.table_exists?("horses") + assert migration.connection.table_exists?("new_horses") received << dir } migration.migrate :up assert_equal [:both, :up], received - ActiveSupport::Deprecation.silence do - assert !migration.connection.table_exists?("horses") - assert migration.connection.table_exists?("new_horses") - end + assert !migration.connection.table_exists?("horses") + assert migration.connection.table_exists?("new_horses") migration.migrate :down assert_equal [:both, :up, :both, :down], received - ActiveSupport::Deprecation.silence do - assert migration.connection.table_exists?("horses") - assert !migration.connection.table_exists?("new_horses") - end + assert migration.connection.table_exists?("horses") + assert !migration.connection.table_exists?("new_horses") end def test_migrate_revert_whole_migration @@ -252,20 +244,20 @@ module ActiveRecord revert = RevertWholeMigration.new(klass) migration.migrate :up revert.migrate :up - ActiveSupport::Deprecation.silence { assert !migration.connection.table_exists?("horses") } + assert !migration.connection.table_exists?("horses") revert.migrate :down - ActiveSupport::Deprecation.silence { assert migration.connection.table_exists?("horses") } + assert migration.connection.table_exists?("horses") migration.migrate :down - ActiveSupport::Deprecation.silence { assert !migration.connection.table_exists?("horses") } + assert !migration.connection.table_exists?("horses") end end def test_migrate_nested_revert_whole_migration revert = NestedRevertWholeMigration.new(InvertibleRevertMigration) revert.migrate :down - ActiveSupport::Deprecation.silence { assert revert.connection.table_exists?("horses") } + assert revert.connection.table_exists?("horses") revert.migrate :up - ActiveSupport::Deprecation.silence { assert !revert.connection.table_exists?("horses") } + assert !revert.connection.table_exists?("horses") end def test_migrate_revert_change_column_default @@ -305,7 +297,7 @@ module ActiveRecord end def test_revert_order - block = Proc.new{|t| t.string :name } + block = Proc.new { |t| t.string :name } recorder = ActiveRecord::Migration::CommandRecorder.new(ActiveRecord::Base.connection) recorder.instance_eval do create_table("apples", &block) @@ -330,24 +322,24 @@ module ActiveRecord def test_legacy_up LegacyMigration.migrate :up - ActiveSupport::Deprecation.silence { assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" } + assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" end def test_legacy_down LegacyMigration.migrate :up LegacyMigration.migrate :down - ActiveSupport::Deprecation.silence { assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" } + assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" end def test_up LegacyMigration.up - ActiveSupport::Deprecation.silence { assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" } + assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" end def test_down LegacyMigration.up LegacyMigration.down - ActiveSupport::Deprecation.silence { assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" } + assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" end def test_migrate_down_with_table_name_prefix @@ -356,7 +348,7 @@ module ActiveRecord migration = InvertibleMigration.new migration.migrate(:up) assert_nothing_raised { migration.migrate(:down) } - ActiveSupport::Deprecation.silence { assert !ActiveRecord::Base.connection.table_exists?("p_horses_s"), "p_horses_s should not exist" } + assert !ActiveRecord::Base.connection.table_exists?("p_horses_s"), "p_horses_s should not exist" ensure ActiveRecord::Base.table_name_prefix = ActiveRecord::Base.table_name_suffix = "" end diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index 814d3b63b2..155e858822 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -51,7 +51,7 @@ class JsonSerializationTest < ActiveRecord::TestCase assert_match %r{^\{"contact":\{}, json assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -62,7 +62,7 @@ class JsonSerializationTest < ActiveRecord::TestCase assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -73,7 +73,7 @@ class JsonSerializationTest < ActiveRecord::TestCase assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json assert_no_match %r{"awesome":true}, json - assert !json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_not_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_no_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -83,7 +83,7 @@ class JsonSerializationTest < ActiveRecord::TestCase assert_no_match %r{"name":"Konata Izumi"}, json assert_no_match %r{"age":16}, json assert_match %r{"awesome":true}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -102,7 +102,7 @@ class JsonSerializationTest < ActiveRecord::TestCase end def test_uses_serializable_hash_with_only_option - def @contact.serializable_hash(options=nil) + def @contact.serializable_hash(options = nil) super(only: %w(name)) end @@ -113,7 +113,7 @@ class JsonSerializationTest < ActiveRecord::TestCase end def test_uses_serializable_hash_with_except_option - def @contact.serializable_hash(options=nil) + def @contact.serializable_hash(options = nil) super(except: %w(age)) end @@ -137,7 +137,7 @@ class JsonSerializationTest < ActiveRecord::TestCase @contact = ContactSti.new(@contact.attributes) assert_equal "ContactSti", @contact.type - def @contact.serializable_hash(options={}) + def @contact.serializable_hash(options = {}) super({ except: %w(age) }.merge!(options)) end @@ -243,7 +243,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase assert !@david.posts.first.respond_to?(:favorite_quote) assert_match %r{"favorite_quote":"Constraints are liberating"}, json - assert_equal %r{"favorite_quote":}.match(json).size, 1 + assert_equal 1, %r{"favorite_quote":}.match(json).size end def test_should_allow_only_option_for_list_of_authors @@ -275,7 +275,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase ['"name":"David"', '"posts":[', '{"id":1}', '{"id":2}', '{"id":4}', '{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[', '{"id":7}', '{"id":9}'].each do |fragment| - assert json.include?(fragment), json + assert_includes json, fragment, json end end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 5c55584ff7..95fb670dac 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -161,14 +161,6 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal(error.record.object_id, p2.object_id) end - def test_lock_new_with_nil - p1 = Person.new(first_name: "anika") - p1.save! - p1.lock_version = nil # simulate bad fixture or column with no default - p1.save! - assert_equal 1, p1.lock_version - end - def test_lock_new_when_explicitly_passing_nil p1 = Person.new(first_name: "anika", lock_version: nil) p1.save! @@ -181,6 +173,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase p1.touch assert_equal 1, p1.lock_version + assert_not p1.changed?, "Changes should have been cleared" end def test_touch_stale_object @@ -221,22 +214,149 @@ class OptimisticLockingTest < ActiveRecord::TestCase def test_lock_without_default_sets_version_to_zero t1 = LockWithoutDefault.new + + assert_equal 0, t1.lock_version + assert_nil t1.lock_version_before_type_cast + + t1.save! + t1.reload + assert_equal 0, t1.lock_version + assert_equal 0, t1.lock_version_before_type_cast + end + + def test_lock_without_default_should_work_with_null_in_the_database + ActiveRecord::Base.connection.execute("INSERT INTO lock_without_defaults(title) VALUES('title1')") + t1 = LockWithoutDefault.last + t2 = LockWithoutDefault.last + + assert_equal 0, t1.lock_version + assert_nil t1.lock_version_before_type_cast + assert_equal 0, t2.lock_version + assert_nil t2.lock_version_before_type_cast + + t1.title = "new title1" + t2.title = "new title2" + + assert_nothing_raised { t1.save! } + assert_equal 1, t1.lock_version + assert_equal "new title1", t1.title + + assert_raise(ActiveRecord::StaleObjectError) { t2.save! } + assert_equal 0, t2.lock_version + assert_equal "new title2", t2.title + end + + def test_lock_without_default_should_update_with_lock_col + t1 = LockWithoutDefault.create(title: "title1", lock_version: 6) + + assert_equal 6, t1.lock_version + + t1.update(lock_version: 0) + t1.reload - t1.save - t1 = LockWithoutDefault.find(t1.id) assert_equal 0, t1.lock_version end + def test_lock_without_default_queries_count + t1 = LockWithoutDefault.create(title: "title1") + + assert_equal "title1", t1.title + assert_equal 0, t1.lock_version + + assert_queries(1) { t1.update(title: "title2") } + + t1.reload + assert_equal "title2", t1.title + assert_equal 1, t1.lock_version + + assert_queries(1) { t1.update(title: "title3", lock_version: 6) } + + t1.reload + assert_equal "title3", t1.title + assert_equal 6, t1.lock_version + + t2 = LockWithoutDefault.new(title: "title1") + + assert_queries(1) { t2.save! } + + t2.reload + assert_equal "title1", t2.title + assert_equal 0, t2.lock_version + end + def test_lock_with_custom_column_without_default_sets_version_to_zero t1 = LockWithCustomColumnWithoutDefault.new + assert_equal 0, t1.custom_lock_version assert_nil t1.custom_lock_version_before_type_cast t1.save! t1.reload + + assert_equal 0, t1.custom_lock_version + assert_equal 0, t1.custom_lock_version_before_type_cast + end + + def test_lock_with_custom_column_without_default_should_work_with_null_in_the_database + ActiveRecord::Base.connection.execute("INSERT INTO lock_without_defaults_cust(title) VALUES('title1')") + + t1 = LockWithCustomColumnWithoutDefault.last + t2 = LockWithCustomColumnWithoutDefault.last + assert_equal 0, t1.custom_lock_version - assert [0, "0"].include?(t1.custom_lock_version_before_type_cast) + assert_nil t1.custom_lock_version_before_type_cast + assert_equal 0, t2.custom_lock_version + assert_nil t2.custom_lock_version_before_type_cast + + t1.title = "new title1" + t2.title = "new title2" + + assert_nothing_raised { t1.save! } + assert_equal 1, t1.custom_lock_version + assert_equal "new title1", t1.title + + assert_raise(ActiveRecord::StaleObjectError) { t2.save! } + assert_equal 0, t2.custom_lock_version + assert_equal "new title2", t2.title + end + + def test_lock_with_custom_column_without_default_should_update_with_lock_col + t1 = LockWithCustomColumnWithoutDefault.create(title: "title1", custom_lock_version: 6) + + assert_equal 6, t1.custom_lock_version + + t1.update(custom_lock_version: 0) + t1.reload + + assert_equal 0, t1.custom_lock_version + end + + def test_lock_with_custom_column_without_default_queries_count + t1 = LockWithCustomColumnWithoutDefault.create(title: "title1") + + assert_equal "title1", t1.title + assert_equal 0, t1.custom_lock_version + + assert_queries(1) { t1.update(title: "title2") } + + t1.reload + assert_equal "title2", t1.title + assert_equal 1, t1.custom_lock_version + + assert_queries(1) { t1.update(title: "title3", custom_lock_version: 6) } + + t1.reload + assert_equal "title3", t1.title + assert_equal 6, t1.custom_lock_version + + t2 = LockWithCustomColumnWithoutDefault.new(title: "title1") + + assert_queries(1) { t2.save! } + + t2.reload + assert_equal "title1", t2.title + assert_equal 0, t2.custom_lock_version end def test_readonly_attributes @@ -350,7 +470,7 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase private - def add_counter_column_to(model, col="test_count") + def add_counter_column_to(model, col = "test_count") model.connection.add_column model.table_name, col, :integer, null: false, default: 0 model.reset_column_information end @@ -459,7 +579,8 @@ unless in_memory_db? assert first.end > second.end end - protected + private + def duel(zzz = 5) t0, t1, t2, t3 = nil, nil, nil, nil diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index 0191c9d03b..48cfe89882 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -43,7 +43,7 @@ module ActiveRecord t.column :foo, :string, null: false end - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::NotNullViolation) do connection.execute "insert into testings (foo) values (NULL)" end end @@ -200,8 +200,8 @@ module ActiveRecord end created_columns = connection.columns(table_name) - created_at_column = created_columns.detect {|c| c.name == "created_at" } - updated_at_column = created_columns.detect {|c| c.name == "updated_at" } + created_at_column = created_columns.detect { |c| c.name == "created_at" } + updated_at_column = created_columns.detect { |c| c.name == "updated_at" } assert !created_at_column.null assert !updated_at_column.null @@ -213,8 +213,8 @@ module ActiveRecord end created_columns = connection.columns(table_name) - created_at_column = created_columns.detect {|c| c.name == "created_at" } - updated_at_column = created_columns.detect {|c| c.name == "updated_at" } + created_at_column = created_columns.detect { |c| c.name == "created_at" } + updated_at_column = created_columns.detect { |c| c.name == "updated_at" } assert created_at_column.null assert updated_at_column.null @@ -233,7 +233,7 @@ module ActiveRecord end connection.add_column :testings, :bar, :string, null: false - assert_raise(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::NotNullViolation) do connection.execute "insert into testings (foo, bar) values ('hello', NULL)" end end @@ -244,12 +244,16 @@ module ActiveRecord t.column :foo, :string end - con = connection - connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')" - assert_nothing_raised {connection.add_column :testings, :bar, :string, null: false, default: "default" } + quoted_id = connection.quote_column_name("id") + quoted_foo = connection.quote_column_name("foo") + quoted_bar = connection.quote_column_name("bar") + connection.execute("insert into testings (#{quoted_id}, #{quoted_foo}) values (1, 'hello')") + assert_nothing_raised do + connection.add_column :testings, :bar, :string, null: false, default: "default" + end - assert_raises(ActiveRecord::StatementInvalid) do - connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)" + assert_raises(ActiveRecord::NotNullViolation) do + connection.execute("insert into testings (#{quoted_id}, #{quoted_foo}, #{quoted_bar}) values (2, 'hello', NULL)") end end @@ -298,9 +302,9 @@ module ActiveRecord assert_equal false, person_klass.columns_hash["wealth"].null # Oracle needs primary key value from sequence if current_adapter?(:OracleAdapter) - assert_nothing_raised {person_klass.connection.execute("insert into testings (id, title) values (testings_seq.nextval, 'tester')")} + assert_nothing_raised { person_klass.connection.execute("insert into testings (id, title) values (testings_seq.nextval, 'tester')") } else - assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")} + assert_nothing_raised { person_klass.connection.execute("insert into testings (title) values ('tester')") } end # change column default to see that column doesn't lose its not null definition @@ -346,9 +350,9 @@ module ActiveRecord end notnull_migration.new.suppress_messages do notnull_migration.migrate(:up) - assert_equal false, connection.columns(:testings).find{ |c| c.name == "foo"}.null + assert_equal false, connection.columns(:testings).find { |c| c.name == "foo" }.null notnull_migration.migrate(:down) - assert connection.columns(:testings).find{ |c| c.name == "foo"}.null + assert connection.columns(:testings).find { |c| c.name == "foo" }.null end end end @@ -405,9 +409,9 @@ module ActiveRecord def test_drop_table_if_exists connection.create_table(:testings) - ActiveSupport::Deprecation.silence { assert connection.table_exists?(:testings) } + assert connection.table_exists?(:testings) connection.drop_table(:testings, if_exists: true) - ActiveSupport::Deprecation.silence { assert_not connection.table_exists?(:testings) } + assert_not connection.table_exists?(:testings) end def test_drop_table_if_exists_nothing_raised diff --git a/activerecord/test/cases/migration/change_table_test.rb b/activerecord/test/cases/migration/change_table_test.rb index 87da9c90fe..8a4242cf1d 100644 --- a/activerecord/test/cases/migration/change_table_test.rb +++ b/activerecord/test/cases/migration/change_table_test.rb @@ -101,7 +101,12 @@ module ActiveRecord def test_primary_key_creates_primary_key_column with_change_table do |t| - @connection.expect :add_column, nil, [:delete_me, :id, :primary_key, primary_key: true, first: true] + if current_adapter?(:Mysql2Adapter) + @connection.expect :add_column, nil, [:delete_me, :id, :primary_key, { first: true, auto_increment: true, limit: 8, primary_key: true }] + else + @connection.expect :add_column, nil, [:delete_me, :id, :primary_key, primary_key: true, first: true] + end + t.primary_key :id, first: true end end @@ -157,7 +162,7 @@ module ActiveRecord def test_column_creates_column_with_options with_change_table do |t| - @connection.expect :add_column, nil, [:delete_me, :bar, :integer, {null: false}] + @connection.expect :add_column, nil, [:delete_me, :bar, :integer, { null: false }] t.column :bar, :integer, null: false end end @@ -171,7 +176,7 @@ module ActiveRecord def test_index_creates_index_with_options with_change_table do |t| - @connection.expect :add_index, nil, [:delete_me, :bar, {unique: true}] + @connection.expect :add_index, nil, [:delete_me, :bar, { unique: true }] t.index :bar, unique: true end end @@ -185,7 +190,7 @@ module ActiveRecord def test_index_exists_with_options with_change_table do |t| - @connection.expect :index_exists?, nil, [:delete_me, :bar, {unique: true}] + @connection.expect :index_exists?, nil, [:delete_me, :bar, { unique: true }] t.index_exists?(:bar, unique: true) end end @@ -206,7 +211,7 @@ module ActiveRecord def test_change_changes_column_with_options with_change_table do |t| - @connection.expect :change_column, nil, [:delete_me, :bar, :string, {null: true}] + @connection.expect :change_column, nil, [:delete_me, :bar, :string, { null: true }] t.change :bar, :string, null: true end end @@ -234,7 +239,7 @@ module ActiveRecord def test_remove_index_removes_index_with_options with_change_table do |t| - @connection.expect :remove_index, nil, [:delete_me, {unique: true}] + @connection.expect :remove_index, nil, [:delete_me, { unique: true }] t.remove_index unique: true end end diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb index ab8229dbae..48df931543 100644 --- a/activerecord/test/cases/migration/column_attributes_test.rb +++ b/activerecord/test/cases/migration/column_attributes_test.rb @@ -63,8 +63,6 @@ module ActiveRecord # Do a manual insertion if current_adapter?(:OracleAdapter) connection.execute "insert into test_models (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)" - elsif current_adapter?(:PostgreSQLAdapter) - connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)" else connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)" end @@ -74,9 +72,7 @@ module ActiveRecord assert_kind_of BigDecimal, row.wealth # If this assert fails, that means the SELECT is broken! - unless current_adapter?(:SQLite3Adapter) - assert_equal correct_value, row.wealth - end + assert_equal correct_value, row.wealth # Reset to old state TestModel.delete_all @@ -167,7 +163,7 @@ module ActiveRecord assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, limit: 10 } unless current_adapter?(:PostgreSQLAdapter) - assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, limit: 0xfffffffff } + assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :text, limit: 0xfffffffff } end end end diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb index 70d40ed87a..55c06da411 100644 --- a/activerecord/test/cases/migration/columns_test.rb +++ b/activerecord/test/cases/migration/columns_test.rb @@ -32,7 +32,7 @@ module ActiveRecord rename_column :test_models, :first_name, :nick_name TestModel.reset_column_information - assert TestModel.column_names.include?("nick_name") + assert_includes TestModel.column_names, "nick_name" assert_equal ["foo"], TestModel.all.map(&:nick_name) end @@ -45,7 +45,7 @@ module ActiveRecord rename_column "test_models", "first_name", "nick_name" TestModel.reset_column_information - assert TestModel.column_names.include?("nick_name") + assert_includes TestModel.column_names, "nick_name" assert_equal ["foo"], TestModel.all.map(&:nick_name) end @@ -57,7 +57,7 @@ module ActiveRecord rename_column "test_models", "salary", "annual_salary" - assert TestModel.column_names.include?("annual_salary") + assert_includes TestModel.column_names, "annual_salary" default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default assert_equal "70000", default_after end @@ -88,7 +88,7 @@ module ActiveRecord add_column "test_models", "first_name", :string rename_column "test_models", "first_name", "group" - assert TestModel.column_names.include?("group") + assert_includes TestModel.column_names, "group" end def test_rename_column_with_an_index @@ -192,8 +192,8 @@ module ActiveRecord new_columns = connection.columns(TestModel.table_name) - assert_not new_columns.find { |c| c.name == "age" and c.type == :integer } - assert new_columns.find { |c| c.name == "age" and c.type == :string } + assert_not new_columns.find { |c| c.name == "age" && c.type == :integer } + assert new_columns.find { |c| c.name == "age" && c.type == :string } old_columns = connection.columns(TestModel.table_name) assert old_columns.find { |c| @@ -206,11 +206,11 @@ module ActiveRecord assert_not new_columns.find { |c| default = connection.lookup_cast_type_from_column(c).deserialize(c.default) - c.name == "approved" and c.type == :boolean and default == true + c.name == "approved" && c.type == :boolean && default == true } assert new_columns.find { |c| default = connection.lookup_cast_type_from_column(c).deserialize(c.default) - c.name == "approved" and c.type == :boolean and default == false + c.name == "approved" && c.type == :boolean && default == false } change_column :test_models, :approved, :boolean, default: true end diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 39f3fd99c7..802a969cb7 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -44,7 +44,7 @@ module ActiveRecord def test_irreversible_commands_raise_exception assert_raises(ActiveRecord::IrreversibleMigration) do - @recorder.revert{ @recorder.execute "some sql" } + @recorder.revert { @recorder.execute "some sql" } end end @@ -58,12 +58,12 @@ module ActiveRecord @recorder.record :create_table, [:hello] @recorder.record :create_table, [:world] end - tables = @recorder.commands.map{|_cmd, args, _block| args} + tables = @recorder.commands.map { |_cmd, args, _block| args } assert_equal [[:world], [:hello]], tables end def test_revert_order - block = Proc.new{|t| t.string :name } + block = Proc.new { |t| t.string :name } @recorder.instance_eval do create_table("apples", &block) revert do @@ -115,13 +115,13 @@ module ActiveRecord end def test_invert_create_table_with_options_and_block - block = Proc.new{} + block = Proc.new {} drop_table = @recorder.inverse_of :create_table, [:people_reminders, id: false], &block assert_equal [:drop_table, [:people_reminders, id: false], block], drop_table end def test_invert_drop_table - block = Proc.new{} + block = Proc.new {} create_table = @recorder.inverse_of :drop_table, [:people_reminders, id: false], &block assert_equal [:create_table, [:people_reminders, id: false], block], create_table end @@ -143,7 +143,7 @@ module ActiveRecord end def test_invert_drop_join_table - block = Proc.new{} + block = Proc.new {} create_join_table = @recorder.inverse_of :drop_join_table, [:musics, :artists, table_name: :catalog], &block assert_equal [:create_join_table, [:musics, :artists, table_name: :catalog], block], create_join_table end @@ -203,17 +203,17 @@ module ActiveRecord def test_invert_add_index remove = @recorder.inverse_of :add_index, [:table, [:one, :two]] - assert_equal [:remove_index, [:table, {column: [:one, :two]}]], remove + assert_equal [:remove_index, [:table, { column: [:one, :two] }]], remove end def test_invert_add_index_with_name remove = @recorder.inverse_of :add_index, [:table, [:one, :two], name: "new_index"] - assert_equal [:remove_index, [:table, {name: "new_index"}]], remove + assert_equal [:remove_index, [:table, { name: "new_index" }]], remove end def test_invert_add_index_with_no_options remove = @recorder.inverse_of :add_index, [:table, [:one, :two]] - assert_equal [:remove_index, [:table, {column: [:one, :two]}]], remove + assert_equal [:remove_index, [:table, { column: [:one, :two] }]], remove end def test_invert_remove_index @@ -222,17 +222,17 @@ module ActiveRecord end def test_invert_remove_index_with_column - add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two], options: true}] + add = @recorder.inverse_of :remove_index, [:table, { column: [:one, :two], options: true }] assert_equal [:add_index, [:table, [:one, :two], options: true]], add end def test_invert_remove_index_with_name - add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two], name: "new_index"}] + add = @recorder.inverse_of :remove_index, [:table, { column: [:one, :two], name: "new_index" }] assert_equal [:add_index, [:table, [:one, :two], name: "new_index"]], add end def test_invert_remove_index_with_no_special_options - add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two]}] + add = @recorder.inverse_of :remove_index, [:table, { column: [:one, :two] }] assert_equal [:add_index, [:table, [:one, :two], {}]], add end @@ -254,7 +254,7 @@ module ActiveRecord def test_invert_remove_timestamps add = @recorder.inverse_of :remove_timestamps, [:table, { null: true }] - assert_equal [:add_timestamps, [:table, {null: true }], nil], add + assert_equal [:add_timestamps, [:table, { null: true }], nil], add end def test_invert_add_reference diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb index 0a4b604601..e5a7412bc3 100644 --- a/activerecord/test/cases/migration/compatibility_test.rb +++ b/activerecord/test/cases/migration/compatibility_test.rb @@ -55,7 +55,7 @@ module ActiveRecord end def test_references_does_not_add_index_by_default - migration = Class.new(ActiveRecord::Migration) { + migration = Class.new(ActiveRecord::Migration[4.2]) { def migrate(x) create_table :more_testings do |t| t.references :foo @@ -73,7 +73,7 @@ module ActiveRecord end def test_timestamps_have_null_constraints_if_not_present_in_migration_of_create_table - migration = Class.new(ActiveRecord::Migration) { + migration = Class.new(ActiveRecord::Migration[4.2]) { def migrate(x) create_table :more_testings do |t| t.timestamps @@ -90,7 +90,7 @@ module ActiveRecord end def test_timestamps_have_null_constraints_if_not_present_in_migration_for_adding_timestamps_to_existing_table - migration = Class.new(ActiveRecord::Migration) { + migration = Class.new(ActiveRecord::Migration[4.2]) { def migrate(x) add_timestamps :testings end @@ -102,15 +102,9 @@ module ActiveRecord assert connection.columns(:testings).find { |c| c.name == "updated_at" }.null end - def test_legacy_migrations_get_deprecation_warning_when_run - migration = Class.new(ActiveRecord::Migration) { - def up - add_column :testings, :baz, :string - end - } - - assert_deprecated do - migration.migrate :up + def test_legacy_migrations_raises_exception_when_inherited + assert_raises(StandardError) do + Class.new(ActiveRecord::Migration) end end end diff --git a/activerecord/test/cases/migration/create_join_table_test.rb b/activerecord/test/cases/migration/create_join_table_test.rb index 372ec40a04..26b1bb4419 100644 --- a/activerecord/test/cases/migration/create_join_table_test.rb +++ b/activerecord/test/cases/migration/create_join_table_test.rb @@ -12,9 +12,7 @@ module ActiveRecord teardown do %w(artists_musics musics_videos catalog).each do |table_name| - ActiveSupport::Deprecation.silence do - connection.drop_table table_name if connection.table_exists?(table_name) - end + connection.drop_table table_name if connection.table_exists?(table_name) end end @@ -61,7 +59,7 @@ module ActiveRecord end def test_create_join_table_with_column_options - connection.create_join_table :artists, :musics, column_options: {null: true} + connection.create_join_table :artists, :musics, column_options: { null: true } assert_equal [true, true], connection.columns(:artists_musics).map(&:null) end @@ -84,51 +82,51 @@ module ActiveRecord connection.create_join_table :artists, :musics connection.drop_join_table :artists, :musics - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("artists_musics") } + assert !connection.table_exists?("artists_musics") end def test_drop_join_table_with_strings connection.create_join_table :artists, :musics connection.drop_join_table "artists", "musics" - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("artists_musics") } + assert !connection.table_exists?("artists_musics") end def test_drop_join_table_with_the_proper_order connection.create_join_table :videos, :musics connection.drop_join_table :videos, :musics - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("musics_videos") } + assert !connection.table_exists?("musics_videos") end def test_drop_join_table_with_the_table_name connection.create_join_table :artists, :musics, table_name: :catalog connection.drop_join_table :artists, :musics, table_name: :catalog - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("catalog") } + assert !connection.table_exists?("catalog") end def test_drop_join_table_with_the_table_name_as_string connection.create_join_table :artists, :musics, table_name: "catalog" connection.drop_join_table :artists, :musics, table_name: "catalog" - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("catalog") } + assert !connection.table_exists?("catalog") end def test_drop_join_table_with_column_options - connection.create_join_table :artists, :musics, column_options: {null: true} - connection.drop_join_table :artists, :musics, column_options: {null: true} + connection.create_join_table :artists, :musics, column_options: { null: true } + connection.drop_join_table :artists, :musics, column_options: { null: true } - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("artists_musics") } + assert !connection.table_exists?("artists_musics") end def test_create_and_drop_join_table_with_common_prefix with_table_cleanup do connection.create_join_table "audio_artists", "audio_musics" - ActiveSupport::Deprecation.silence { assert connection.table_exists?("audio_artists_musics") } + assert connection.table_exists?("audio_artists_musics") connection.drop_join_table "audio_artists", "audio_musics" - ActiveSupport::Deprecation.silence { assert !connection.table_exists?("audio_artists_musics"), "Should have dropped join table, but didn't" } + assert !connection.table_exists?("audio_artists_musics"), "Should have dropped join table, but didn't" end end diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb index cab2069754..9be6667aa1 100644 --- a/activerecord/test/cases/migration/foreign_key_test.rb +++ b/activerecord/test/cases/migration/foreign_key_test.rb @@ -76,7 +76,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? end def test_add_foreign_key_with_non_standard_primary_key - with_example_table @connection, "space_shuttles", "pk integer PRIMARY KEY" do + with_example_table @connection, "space_shuttles", "pk BIGINT PRIMARY KEY" do @connection.add_foreign_key(:astronauts, :space_shuttles, column: "rocket_id", primary_key: "pk", name: "custom_pk") @@ -101,7 +101,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? fk = foreign_keys.first if current_adapter?(:Mysql2Adapter) # ON DELETE RESTRICT is the default on MySQL - assert_equal nil, fk.on_delete + assert_nil fk.on_delete else assert_equal :restrict, fk.on_delete end @@ -229,7 +229,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? create_table("cities") { |t| } create_table("houses") do |t| - t.column :city_id, :integer + t.column :city_id, :bigint end add_foreign_key :houses, :cities, column: "city_id" @@ -261,7 +261,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? create_table(:schools) create_table(:classes) do |t| - t.column :school_id, :integer + t.column :school_id, :bigint end add_foreign_key :classes, :schools end diff --git a/activerecord/test/cases/migration/index_test.rb b/activerecord/test/cases/migration/index_test.rb index 85e09986ea..0f975026b8 100644 --- a/activerecord/test/cases/migration/index_test.rb +++ b/activerecord/test/cases/migration/index_test.rb @@ -143,7 +143,7 @@ module ActiveRecord end def test_add_index_attribute_length_limit - connection.add_index :testings, [:foo, :bar], length: {foo: 10, bar: nil} + connection.add_index :testings, [:foo, :bar], length: { foo: 10, bar: nil } assert connection.index_exists?(:testings, [:foo, :bar]) end @@ -169,13 +169,13 @@ module ActiveRecord connection.add_index("testings", ["last_name"], length: 10) connection.remove_index("testings", "last_name") - connection.add_index("testings", ["last_name"], length: {last_name: 10}) + connection.add_index("testings", ["last_name"], length: { last_name: 10 }) connection.remove_index("testings", ["last_name"]) connection.add_index("testings", ["last_name", "first_name"], length: 10) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["last_name", "first_name"], length: {last_name: 10, first_name: 20}) + connection.add_index("testings", ["last_name", "first_name"], length: { last_name: 10, first_name: 20 }) connection.remove_index("testings", ["last_name", "first_name"]) connection.add_index("testings", ["key"], name: "key_idx", unique: true) @@ -186,11 +186,11 @@ module ActiveRecord # Selected adapters support index sort order if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter) - connection.add_index("testings", ["last_name"], order: {last_name: :desc}) + connection.add_index("testings", ["last_name"], order: { last_name: :desc }) connection.remove_index("testings", ["last_name"]) - connection.add_index("testings", ["last_name", "first_name"], order: {last_name: :desc}) + connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc }) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["last_name", "first_name"], order: {last_name: :desc, first_name: :asc}) + connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc, first_name: :asc }) connection.remove_index("testings", ["last_name", "first_name"]) connection.add_index("testings", ["last_name", "first_name"], order: :desc) connection.remove_index("testings", ["last_name", "first_name"]) diff --git a/activerecord/test/cases/migration/references_foreign_key_test.rb b/activerecord/test/cases/migration/references_foreign_key_test.rb index 8436435170..4957ab8b3d 100644 --- a/activerecord/test/cases/migration/references_foreign_key_test.rb +++ b/activerecord/test/cases/migration/references_foreign_key_test.rb @@ -42,7 +42,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? test "options hash can be passed" do @connection.change_table :testing_parents do |t| - t.integer :other_id + t.bigint :other_id t.index :other_id, unique: true end @connection.create_table :testings do |t| @@ -59,7 +59,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? end fks = @connection.foreign_keys("testings") assert_equal([["testings", "testing_parents", "parent_id"]], - fks.map {|fk| [fk.from_table, fk.to_table, fk.column] }) + fks.map { |fk| [fk.from_table, fk.to_table, fk.column] }) end test "foreign keys cannot be added to polymorphic relations when creating the table" do @@ -92,7 +92,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? test "foreign keys accept options when changing the table" do @connection.change_table :testing_parents do |t| - t.integer :other_id + t.bigint :other_id t.index :other_id, unique: true end @connection.create_table :testings @@ -177,8 +177,8 @@ if ActiveRecord::Base.connection.supports_foreign_keys? test "multiple foreign keys can be added to the same table" do @connection.create_table :testings do |t| - t.integer :col_1 - t.integer :col_2 + t.bigint :col_1 + t.bigint :col_2 t.foreign_key :testing_parents, column: :col_1 t.foreign_key :testing_parents, column: :col_2 @@ -186,7 +186,7 @@ if ActiveRecord::Base.connection.supports_foreign_keys? fks = @connection.foreign_keys("testings") - fk_definitions = fks.map {|fk| [fk.from_table, fk.to_table, fk.column] } + fk_definitions = fks.map { |fk| [fk.from_table, fk.to_table, fk.column] } assert_equal([["testings", "testing_parents", "col_1"], ["testings", "testing_parents", "col_2"]], fk_definitions) end diff --git a/activerecord/test/cases/migration/references_index_test.rb b/activerecord/test/cases/migration/references_index_test.rb index 0d0b0a193b..2866cabab6 100644 --- a/activerecord/test/cases/migration/references_index_test.rb +++ b/activerecord/test/cases/migration/references_index_test.rb @@ -41,8 +41,8 @@ module ActiveRecord def test_creates_index_with_options connection.create_table table_name do |t| - t.references :foo, index: {name: :index_testings_on_yo_momma} - t.references :bar, index: {unique: true} + t.references :foo, index: { name: :index_testings_on_yo_momma } + t.references :bar, index: { unique: true } end assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_yo_momma) diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb index 8fbe60f24e..df15d7cb45 100644 --- a/activerecord/test/cases/migration/references_statements_test.rb +++ b/activerecord/test/cases/migration/references_statements_test.rb @@ -57,7 +57,7 @@ module ActiveRecord def test_creates_named_unique_index add_reference table_name, :tag, index: { name: "index_taggings_on_tag_id", unique: true } - assert index_exists?(table_name, :tag_id, name: "index_taggings_on_tag_id", unique: true ) + assert index_exists?(table_name, :tag_id, name: "index_taggings_on_tag_id", unique: true) end def test_creates_reference_id_with_specified_type diff --git a/activerecord/test/cases/migration/rename_table_test.rb b/activerecord/test/cases/migration/rename_table_test.rb index 5474c9ce71..19588d28a2 100644 --- a/activerecord/test/cases/migration/rename_table_test.rb +++ b/activerecord/test/cases/migration/rename_table_test.rb @@ -15,7 +15,7 @@ module ActiveRecord end def teardown - ActiveSupport::Deprecation.silence { rename_table :octopi, :test_models if connection.table_exists? :octopi } + rename_table :octopi, :test_models if connection.table_exists? :octopi super end @@ -57,7 +57,7 @@ module ActiveRecord assert_equal "http://www.foreverflying.com/octopus-black7.jpg", connection.select_value("SELECT url FROM octopi WHERE id=1") index = connection.indexes(:octopi).first - assert index.columns.include?("url") + assert_includes index.columns, "url" assert_equal "index_octopi_on_url", index.name end @@ -82,7 +82,7 @@ module ActiveRecord def test_renaming_table_doesnt_attempt_to_rename_non_existent_sequences connection.create_table :cats, id: :uuid assert_nothing_raised { rename_table :cats, :felines } - ActiveSupport::Deprecation.silence { assert connection.table_exists? :felines } + assert connection.table_exists? :felines ensure connection.drop_table :cats, if_exists: true connection.drop_table :felines, if_exists: true diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 5d96569d38..082cfd3242 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -388,7 +388,7 @@ class MigrationTest < ActiveRecord::TestCase original_rails_env = ENV["RAILS_ENV"] original_rack_env = ENV["RACK_ENV"] ENV["RAILS_ENV"] = ENV["RACK_ENV"] = "foofoo" - new_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call + new_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call refute_equal current_env, new_env @@ -413,7 +413,7 @@ class MigrationTest < ActiveRecord::TestCase original_rails_env = ENV["RAILS_ENV"] original_rack_env = ENV["RACK_ENV"] ENV["RAILS_ENV"] = ENV["RACK_ENV"] = "foofoo" - new_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call + new_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call refute_equal current_env, new_env @@ -429,14 +429,14 @@ class MigrationTest < ActiveRecord::TestCase def test_internal_metadata_stores_environment_when_other_data_exists ActiveRecord::InternalMetadata.delete_all - ActiveRecord::InternalMetadata[:foo] = "bar" + ActiveRecord::InternalMetadata[:foo] = "bar" current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" old_path = ActiveRecord::Migrator.migrations_paths ActiveRecord::Migrator.migrations_paths = migrations_path - current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call + current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call ActiveRecord::Migrator.up(migrations_path) assert_equal current_env, ActiveRecord::InternalMetadata[:environment] assert_equal "bar", ActiveRecord::InternalMetadata[:foo] @@ -551,6 +551,23 @@ class MigrationTest < ActiveRecord::TestCase end end + if current_adapter?(:SQLite3Adapter) + def test_allows_sqlite3_rollback_on_invalid_column_type + Person.connection.create_table :something, force: true do |t| + t.column :number, :integer + t.column :name, :string + t.column :foo, :bar + end + assert Person.connection.column_exists?(:something, :foo) + assert_nothing_raised { Person.connection.remove_column :something, :foo, :bar } + assert !Person.connection.column_exists?(:something, :foo) + assert Person.connection.column_exists?(:something, :name) + assert Person.connection.column_exists?(:something, :number) + ensure + Person.connection.drop_table :something, if_exists: true + end + end + if current_adapter? :OracleAdapter def test_create_table_with_custom_sequence_name # table name is 29 chars, the standard sequence name will @@ -688,7 +705,7 @@ class MigrationTest < ActiveRecord::TestCase end end - protected + private # This is needed to isolate class_attribute assignments like `table_name_prefix` # for each test case. def new_isolated_reminder_class @@ -759,7 +776,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? class BulkAlterTableMigrationsTest < ActiveRecord::TestCase def setup @connection = Person.connection - @connection.create_table(:delete_me, force: true) {|t| } + @connection.create_table(:delete_me, force: true) { |t| } Person.reset_column_information Person.reset_sequence_name end @@ -780,7 +797,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? end assert_equal 8, columns.size - [:name, :qualification, :experience].each {|s| assert_equal :string, column(s).type } + [:name, :qualification, :experience].each { |s| assert_equal :string, column(s).type } assert_equal "0", column(:age).default end @@ -789,7 +806,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? t.string :qualification, :experience end - [:qualification, :experience].each {|c| assert column(c) } + [:qualification, :experience].each { |c| assert column(c) } assert_queries(1) do with_bulk_change_table do |t| @@ -798,7 +815,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? end end - [:qualification, :experience].each {|c| assert ! column(c) } + [:qualification, :experience].each { |c| assert ! column(c) } assert column(:qualification_experience) end @@ -882,7 +899,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? end def column(name) - columns.detect {|c| c.name == name.to_s } + columns.detect { |c| c.name == name.to_s } end def columns @@ -890,7 +907,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? end def index(name) - indexes.detect {|i| i.name == name.to_s } + indexes.detect { |i| i.name == name.to_s } end def indexes diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb index 1ba18bc9c2..bb9835394b 100644 --- a/activerecord/test/cases/migrator_test.rb +++ b/activerecord/test/cases/migrator_test.rb @@ -11,7 +11,7 @@ class MigratorTest < ActiveRecord::TestCase def initialize(name = self.class.name, version = nil) super - @went_up = false + @went_up = false @went_down = false end @@ -313,9 +313,9 @@ class MigratorTest < ActiveRecord::TestCase _, migrator = migrator_class(3) ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true - ActiveSupport::Deprecation.silence { assert_not ActiveRecord::Base.connection.table_exists?("schema_migrations") } + assert_not ActiveRecord::Base.connection.table_exists?("schema_migrations") migrator.migrate("valid", 1) - ActiveSupport::Deprecation.silence { assert ActiveRecord::Base.connection.table_exists?("schema_migrations") } + assert ActiveRecord::Base.connection.table_exists?("schema_migrations") end def test_migrator_forward @@ -344,10 +344,10 @@ class MigratorTest < ActiveRecord::TestCase _, migrator = migrator_class(3) migrator.migrate("valid") - assert_equal([1,2,3], ActiveRecord::Migrator.get_all_versions) + assert_equal([1, 2, 3], ActiveRecord::Migrator.get_all_versions) migrator.rollback("valid") - assert_equal([1,2], ActiveRecord::Migrator.get_all_versions) + assert_equal([1, 2], ActiveRecord::Migrator.get_all_versions) migrator.rollback("valid") assert_equal([1], ActiveRecord::Migrator.get_all_versions) @@ -368,7 +368,7 @@ class MigratorTest < ActiveRecord::TestCase def sensors(count) calls = [] migrations = count.times.map { |i| - m(nil, i + 1) { |c,migration| + m(nil, i + 1) { |c, migration| calls << [c, migration.version] } } diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb index 1b7720e4f8..f8a7bab35f 100644 --- a/activerecord/test/cases/modules_test.rb +++ b/activerecord/test/cases/modules_test.rb @@ -73,7 +73,7 @@ class ModulesTest < ActiveRecord::TestCase clients = [] assert_nothing_raised do - clients << MyApplication::Business::Client.references(:accounts).merge!(includes: {firm: :account}, where: "accounts.id IS NOT NULL").find(3) + clients << MyApplication::Business::Client.references(:accounts).merge!(includes: { firm: :account }, where: "accounts.id IS NOT NULL").find(3) clients << MyApplication::Business::Client.includes(firm: :account).find(3) end diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb index b2f76398df..ceb5724377 100644 --- a/activerecord/test/cases/multiparameter_attributes_test.rb +++ b/activerecord/test/cases/multiparameter_attributes_test.rb @@ -260,6 +260,13 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase topic.attributes = attributes assert_equal Time.zone.local(2000, 1, 1, 16, 24, 0), topic.bonus_time assert_not topic.bonus_time.utc? + + attributes = { + "written_on(1i)" => "2000", "written_on(2i)" => "", "written_on(3i)" => "", + "written_on(4i)" => "", "written_on(5i)" => "" + } + topic.attributes = attributes + assert_nil topic.written_on end ensure Topic.reset_column_information @@ -280,14 +287,14 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase unless current_adapter? :OracleAdapter def test_multiparameter_attributes_setting_time_attribute - topic = Topic.new( "bonus_time(4i)"=> "01", "bonus_time(5i)" => "05" ) + topic = Topic.new("bonus_time(4i)" => "01", "bonus_time(5i)" => "05") assert_equal 1, topic.bonus_time.hour assert_equal 5, topic.bonus_time.min end end def test_multiparameter_attributes_setting_date_attribute - topic = Topic.new( "written_on(1i)" => "1952", "written_on(2i)" => "3", "written_on(3i)" => "11" ) + topic = Topic.new("written_on(1i)" => "1952", "written_on(2i)" => "3", "written_on(3i)" => "11") assert_equal 1952, topic.written_on.year assert_equal 3, topic.written_on.month assert_equal 11, topic.written_on.day @@ -308,8 +315,8 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase end def test_multiparameter_attributes_setting_time_but_not_date_on_date_field - assert_raise( ActiveRecord::MultiparameterAssignmentErrors ) do - Topic.new( "written_on(4i)" => "13", "written_on(5i)" => "55" ) + assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do + Topic.new("written_on(4i)" => "13", "written_on(5i)" => "55") end end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 788277faea..b87419d203 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -31,7 +31,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase def test_should_not_build_a_new_record_using_reject_all_even_if_destroy_is_given pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") - pirate.birds_with_reject_all_blank_attributes = [{name: "", color: "", _destroy: "0"}] + pirate.birds_with_reject_all_blank_attributes = [{ name: "", color: "", _destroy: "0" }] pirate.save! assert pirate.birds_with_reject_all_blank.empty? @@ -39,7 +39,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase def test_should_not_build_a_new_record_if_reject_all_blank_returns_false pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") - pirate.birds_with_reject_all_blank_attributes = [{name: "", color: ""}] + pirate.birds_with_reject_all_blank_attributes = [{ name: "", color: "" }] pirate.save! assert pirate.birds_with_reject_all_blank.empty? @@ -47,7 +47,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase def test_should_build_a_new_record_if_reject_all_blank_does_not_return_false pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") - pirate.birds_with_reject_all_blank_attributes = [{name: "Tweetie", color: ""}] + pirate.birds_with_reject_all_blank_attributes = [{ name: "Tweetie", color: "" }] pirate.save! assert_equal 1, pirate.birds_with_reject_all_blank.count @@ -108,7 +108,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase end def test_reject_if_with_indifferent_keys - Pirate.accepts_nested_attributes_for :ship, reject_if: proc {|attributes| attributes[:name].blank? } + Pirate.accepts_nested_attributes_for :ship, reject_if: proc { |attributes| attributes[:name].blank? } pirate = Pirate.new(catchphrase: "Stop wastin' me time") pirate.ship_attributes = { name: "Hello Pearl" } @@ -116,7 +116,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase end def test_reject_if_with_a_proc_which_returns_true_always_for_has_one - Pirate.accepts_nested_attributes_for :ship, reject_if: proc {|attributes| true } + Pirate.accepts_nested_attributes_for :ship, reject_if: proc { |attributes| true } pirate = Pirate.new(catchphrase: "Stop wastin' me time") ship = pirate.create_ship(name: "s1") pirate.update(ship_attributes: { name: "s2", id: ship.id }) @@ -138,7 +138,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase end def test_reject_if_with_a_proc_which_returns_true_always_for_has_many - Man.accepts_nested_attributes_for :interests, reject_if: proc {|attributes| true } + Man.accepts_nested_attributes_for :interests, reject_if: proc { |attributes| true } man = Man.create(name: "John") interest = man.interests.create(topic: "photography") man.update(interests_attributes: { topic: "gardening", id: interest.id }) @@ -146,7 +146,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase end def test_destroy_works_independent_of_reject_if - Man.accepts_nested_attributes_for :interests, reject_if: proc {|attributes| true }, allow_destroy: true + Man.accepts_nested_attributes_for :interests, reject_if: proc { |attributes| true }, allow_destroy: true man = Man.create(name: "Jon") interest = man.interests.create(topic: "the ladies") man.update(interests_attributes: { _destroy: "1", id: interest.id }) @@ -170,13 +170,13 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase Man.accepts_nested_attributes_for(:interests) man = Man.create(name: "John") interest = man.interests.create(topic: "photography") - man.update(interests_attributes: {topic: "gardening", id: interest.id}) + man.update(interests_attributes: { topic: "gardening", id: interest.id }) assert_equal "gardening", interest.reload.topic end def test_reject_if_with_blank_nested_attributes_id # When using a select list to choose an existing 'ship' id, with include_blank: true - Pirate.accepts_nested_attributes_for :ship, reject_if: proc {|attributes| attributes[:id].blank? } + Pirate.accepts_nested_attributes_for :ship, reject_if: proc { |attributes| attributes[:id].blank? } pirate = Pirate.new(catchphrase: "Stop wastin' me time") pirate.ship_attributes = { id: "" } @@ -188,7 +188,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase man = Man.create(name: "John") interest = man.interests.create topic: "gardening" man = Man.find man.id - man.interests_attributes = [{id: interest.id, topic: "gardening"}] + man.interests_attributes = [{ id: interest.id, topic: "gardening" }] assert_equal man.interests.first.topic, man.interests[0].topic end @@ -225,7 +225,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_raise_argument_error_if_trying_to_build_polymorphic_belongs_to exception = assert_raise ArgumentError do - Treasure.new(name: "pearl", looter_attributes: {catchphrase: "Arrr"}) + Treasure.new(name: "pearl", looter_attributes: { catchphrase: "Arrr" }) end assert_equal "Cannot build association `looter'. Are you trying to build a polymorphic one-to-one association?", exception.message end @@ -700,7 +700,7 @@ module NestedAttributesOnACollectionAssociationTests def test_should_automatically_build_new_associated_models_for_each_entry_in_a_hash_where_the_id_is_missing @pirate.send(@association_name).destroy_all @pirate.reload.attributes = { - association_getter => { "foo" => { name: "Grace OMalley" }, "bar" => { name: "Privateers Greed" }} + association_getter => { "foo" => { name: "Grace OMalley" }, "bar" => { name: "Privateers Greed" } } } assert !@pirate.send(@association_name).first.persisted? @@ -757,7 +757,7 @@ module NestedAttributesOnACollectionAssociationTests def test_should_work_with_update_as_well @pirate.update(catchphrase: "Arr", - association_getter => { "foo" => { id: @child_1.id, name: "Grace OMalley" }}) + association_getter => { "foo" => { id: @child_1.id, name: "Grace OMalley" } }) assert_equal "Grace OMalley", @child_1.reload.name end @@ -813,7 +813,7 @@ module NestedAttributesOnACollectionAssociationTests assert_difference "Man.count" do assert_difference "Interest.count", 2 do man = Man.create!(name: "John", - interests_attributes: [{topic: "Cars"}, {topic: "Sports"}]) + interests_attributes: [{ topic: "Cars" }, { topic: "Sports" }]) assert_equal 2, man.interests.count end end @@ -911,7 +911,7 @@ module NestedAttributesLimitTests assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do @pirate.attributes = { parrots_attributes: { "foo" => { name: "Lovely Day" }, "bar" => { name: "Blown Away" }, - "car" => { name: "The Happening" }} } + "car" => { name: "The Happening" } } } end end end @@ -971,10 +971,10 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase def test_attr_accessor_of_child_should_be_value_provided_during_update @owner = owners(:ashley) @pet1 = pets(:chew) - attributes = {pets_attributes: { "1"=> { id: @pet1.id, + attributes = { pets_attributes: { "1" => { id: @pet1.id, name: "Foo2", current_user: "John", - _destroy: true }}} + _destroy: true } } } @owner.update(attributes) assert_equal "John", Pet.after_destroy_output end @@ -997,18 +997,18 @@ class TestHasOneAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRe end test "when great-grandchild changed via attributes, saving parent should save great-grandchild" do - @pirate.attributes = {ship_attributes: {id: @ship.id, parts_attributes: [{id: @part.id, trinkets_attributes: [{id: @trinket.id, name: "changed"}]}]}} + @pirate.attributes = { ship_attributes: { id: @ship.id, parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, name: "changed" }] }] } } @pirate.save assert_equal "changed", @trinket.reload.name end test "when great-grandchild marked_for_destruction via attributes, saving parent should destroy great-grandchild" do - @pirate.attributes = {ship_attributes: {id: @ship.id, parts_attributes: [{id: @part.id, trinkets_attributes: [{id: @trinket.id, _destroy: true}]}]}} + @pirate.attributes = { ship_attributes: { id: @ship.id, parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, _destroy: true }] }] } } assert_difference("@part.trinkets.count", -1) { @pirate.save } end test "when great-grandchild added via attributes, saving parent should create great-grandchild" do - @pirate.attributes = {ship_attributes: {id: @ship.id, parts_attributes: [{id: @part.id, trinkets_attributes: [{name: "created"}]}]}} + @pirate.attributes = { ship_attributes: { id: @ship.id, parts_attributes: [{ id: @part.id, trinkets_attributes: [{ name: "created" }] }] } } assert_difference("@part.trinkets.count", 1) { @pirate.save } end @@ -1030,13 +1030,13 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR end test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do - @ship.parts_attributes=[{id: @part.id,name: "Deck"}] + @ship.parts_attributes = [{ id: @part.id, name: "Deck" }] assert_equal 1, @ship.association(:parts).target.size assert_equal "Deck", @ship.parts[0].name end test "if association is not loaded and child doesn't change and I am saving a grandchild then in memory record should be used" do - @ship.parts_attributes=[{id: @part.id,trinkets_attributes: [{id: @trinket.id, name: "Ruby"}]}] + @ship.parts_attributes = [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, name: "Ruby" }] }] assert_equal 1, @ship.association(:parts).target.size assert_equal "Mast", @ship.parts[0].name assert_no_difference("@ship.parts[0].association(:trinkets).target.size") do @@ -1054,18 +1054,18 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR end test "when grandchild changed via attributes, saving parent should save grandchild" do - @ship.attributes = {parts_attributes: [{id: @part.id, trinkets_attributes: [{id: @trinket.id, name: "changed"}]}]} + @ship.attributes = { parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, name: "changed" }] }] } @ship.save assert_equal "changed", @trinket.reload.name end test "when grandchild marked_for_destruction via attributes, saving parent should destroy grandchild" do - @ship.attributes = {parts_attributes: [{id: @part.id, trinkets_attributes: [{id: @trinket.id, _destroy: true}]}]} + @ship.attributes = { parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, _destroy: true }] }] } assert_difference("@part.trinkets.count", -1) { @ship.save } end test "when grandchild added via attributes, saving parent should create grandchild" do - @ship.attributes = {parts_attributes: [{id: @part.id, trinkets_attributes: [{name: "created"}]}]} + @ship.attributes = { parts_attributes: [{ id: @part.id, trinkets_attributes: [{ name: "created" }] }] } assert_difference("@part.trinkets.count", 1) { @ship.save } end diff --git a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb index d606a6c12d..350a966d40 100644 --- a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb +++ b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb @@ -5,13 +5,13 @@ require "models/bird" class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase Pirate.has_many(:birds_with_add_load, class_name: "Bird", - before_add: proc { |p,b| + before_add: proc { |p, b| @@add_callback_called << b p.birds_with_add_load.to_a }) Pirate.has_many(:birds_with_add, class_name: "Bird", - before_add: proc { |p,b| @@add_callback_called << b }) + before_add: proc { |p, b| @@add_callback_called << b }) Pirate.accepts_nested_attributes_for(:birds_with_add_load, :birds_with_add, @@ -21,7 +21,7 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase @@add_callback_called = [] @pirate = Pirate.new.tap do |pirate| pirate.catchphrase = "Don't call me!" - pirate.birds_attributes = [{name: "Bird1"},{name: "Bird2"}] + pirate.birds_attributes = [{ name: "Bird1" }, { name: "Bird2" }] pirate.save! end @birds = @pirate.birds.to_a @@ -37,7 +37,7 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase def existing_birds_attributes @birds.map do |bird| - bird.attributes.slice("id","name") + bird.attributes.slice("id", "name") end end @@ -46,17 +46,17 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase end def new_bird_attributes - [{"name" => "New Bird"}] + [{ "name" => "New Bird" }] end def destroy_bird_attributes - [{"id" => bird_to_destroy.id.to_s, "_destroy" => true}] + [{ "id" => bird_to_destroy.id.to_s, "_destroy" => true }] end def update_new_and_destroy_bird_attributes - [{"id" => @birds[0].id.to_s, "name" => "New Name"}, - {"name" => "New Bird"}, - {"id" => bird_to_destroy.id.to_s, "_destroy" => true}] + [{ "id" => @birds[0].id.to_s, "name" => "New Name" }, + { "name" => "New Bird" }, + { "id" => bird_to_destroy.id.to_s, "_destroy" => true }] end # Characterizing when :before_add callback is called @@ -136,9 +136,9 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase def assert_assignment_affects_records_in_target(association_name) association = @pirate.send(association_name) - assert association.detect {|b| b == bird_to_update }.name_changed?, + assert association.detect { |b| b == bird_to_update }.name_changed?, "Update record not updated" - assert association.detect {|b| b == bird_to_destroy }.marked_for_destruction?, + assert association.detect { |b| b == bird_to_destroy }.marked_for_destruction?, "Destroy record not marked for destruction" end end diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index e293770725..3f1da82cb4 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -83,13 +83,21 @@ class PersistenceTest < ActiveRecord::TestCase end def test_delete_all_with_joins_and_where_part_is_hash - where_args = {toys: {name: "Bone"}} + where_args = { toys: { name: "Bone" } } count = Pet.joins(:toys).where(where_args).count assert_equal count, 1 assert_equal count, Pet.joins(:toys).where(where_args).delete_all end + def test_delete_all_with_left_joins + where_args = { toys: { name: "Bone" } } + count = Pet.left_joins(:toys).where(where_args).count + + assert_equal count, 1 + assert_equal count, Pet.left_joins(:toys).where(where_args).delete_all + end + def test_delete_all_with_joins_and_where_part_is_not_hash where_args = ["toys.name = ?", "Bone"] count = Pet.joins(:toys).where(where_args).count @@ -391,14 +399,14 @@ class PersistenceTest < ActiveRecord::TestCase end topic = klass.create(title: "Another New Topic") assert_queries(0) do - topic.update_attribute(:title, "Another New Topic") + assert topic.update_attribute(:title, "Another New Topic") end end def test_update_does_not_run_sql_if_record_has_not_changed topic = Topic.create(title: "Another New Topic") - assert_queries(0) { topic.update(title: "Another New Topic") } - assert_queries(0) { topic.update_attributes(title: "Another New Topic") } + assert_queries(0) { assert topic.update(title: "Another New Topic") } + assert_queries(0) { assert topic.update_attributes(title: "Another New Topic") } end def test_delete @@ -453,6 +461,20 @@ class PersistenceTest < ActiveRecord::TestCase assert_nil Topic.find(2).last_read end + def test_update_all_with_joins + where_args = { toys: { name: "Bone" } } + count = Pet.left_joins(:toys).where(where_args).count + + assert_equal count, Pet.joins(:toys).where(where_args).update_all(name: "Bob") + end + + def test_update_all_with_left_joins + where_args = { toys: { name: "Bone" } } + count = Pet.left_joins(:toys).where(where_args).count + + assert_equal count, Pet.left_joins(:toys).where(where_args).update_all(name: "Bob") + end + def test_update_all_with_non_standard_table_name assert_equal 1, WarehouseThing.where(id: 1).update_all(["value = ?", 0]) assert_equal 0, WarehouseThing.find(1).value @@ -967,7 +989,7 @@ class PersistenceTest < ActiveRecord::TestCase self.table_name = :widgets end - instance = widget.create!( + instance = widget.create!( name: "Bob", created_at: 1.day.ago, updated_at: 1.day.ago) diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index 31d612abd1..1d72899102 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -120,7 +120,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase assert_nothing_raised { MixedCaseMonkey.find(1) } end def test_find_with_multiple_ids_should_quote_pkey - assert_nothing_raised { MixedCaseMonkey.find([1,2]) } + assert_nothing_raised { MixedCaseMonkey.find([1, 2]) } end def test_instance_update_should_quote_pkey assert_nothing_raised { MixedCaseMonkey.find(1).save } @@ -129,12 +129,6 @@ class PrimaryKeysTest < ActiveRecord::TestCase assert_nothing_raised { MixedCaseMonkey.find(1).destroy } end - def test_supports_primary_key - assert_nothing_raised do - ActiveRecord::Base.connection.supports_primary_key? - end - end - if ActiveRecord::Base.connection.supports_primary_key? def test_primary_key_returns_value_if_it_exists klass = Class.new(ActiveRecord::Base) do @@ -154,7 +148,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase end def test_quoted_primary_key_after_set_primary_key - k = Class.new( ActiveRecord::Base ) + k = Class.new(ActiveRecord::Base) assert_equal k.connection.quote_column_name("id"), k.quoted_primary_key k.primary_key = "foo" assert_equal k.connection.quote_column_name("foo"), k.quoted_primary_key @@ -216,6 +210,43 @@ class PrimaryKeyWithNoConnectionTest < ActiveRecord::TestCase end end +class PrimaryKeyWithAutoIncrementTest < ActiveRecord::TestCase + self.use_transactional_tests = false + + class AutoIncrement < ActiveRecord::Base + end + + def setup + @connection = ActiveRecord::Base.connection + end + + def teardown + @connection.drop_table(:auto_increments, if_exists: true) + end + + def test_primary_key_with_auto_increment + @connection.create_table(:auto_increments, id: :integer, auto_increment: true, force: true) + assert_auto_incremented + end + + def test_primary_key_with_auto_increment_and_bigint + @connection.create_table(:auto_increments, id: :bigint, auto_increment: true, force: true) + assert_auto_incremented + end + + private + def assert_auto_incremented + record1 = AutoIncrement.create! + assert_not_nil record1.id + + record1.destroy + + record2 = AutoIncrement.create! + assert_not_nil record2.id + assert_operator record2.id, :>, record1.id + end +end + class PrimaryKeyAnyTypeTest < ActiveRecord::TestCase include SchemaDumpingHelper @@ -289,85 +320,69 @@ class CompositePrimaryKeyTest < ActiveRecord::TestCase end if current_adapter?(:Mysql2Adapter) - class PrimaryKeyBigintNilDefaultTest < ActiveRecord::TestCase + class PrimaryKeyIntegerNilDefaultTest < ActiveRecord::TestCase include SchemaDumpingHelper self.use_transactional_tests = false def setup @connection = ActiveRecord::Base.connection - @connection.create_table(:bigint_defaults, id: :bigint, default: nil, force: true) + @connection.create_table(:int_defaults, id: :integer, default: nil, force: true) end def teardown - @connection.drop_table :bigint_defaults, if_exists: true + @connection.drop_table :int_defaults, if_exists: true end - test "primary key with bigint allows default override via nil" do - column = @connection.columns(:bigint_defaults).find { |c| c.name == "id" } - assert column.bigint? + test "primary key with integer allows default override via nil" do + column = @connection.columns(:int_defaults).find { |c| c.name == "id" } + assert_equal :integer, column.type assert_not column.auto_increment? end - test "schema dump primary key with bigint default nil" do - schema = dump_table_schema "bigint_defaults" - assert_match %r{create_table "bigint_defaults", id: :bigint, default: nil}, schema + test "schema dump primary key with int default nil" do + schema = dump_table_schema "int_defaults" + assert_match %r{create_table "int_defaults", id: :integer, default: nil}, schema end end end -if current_adapter?(:PostgreSQLAdapter, :Mysql2Adapter) - class PrimaryKeyBigSerialTest < ActiveRecord::TestCase - include SchemaDumpingHelper +class PrimaryKeyIntegerTest < ActiveRecord::TestCase + include SchemaDumpingHelper - self.use_transactional_tests = false + self.use_transactional_tests = false - class Widget < ActiveRecord::Base - end + class Widget < ActiveRecord::Base + end - setup do - @connection = ActiveRecord::Base.connection - if current_adapter?(:PostgreSQLAdapter) - @connection.create_table(:widgets, id: :bigserial, force: true) - else - @connection.create_table(:widgets, id: :bigint, force: true) - end - end + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table(:widgets, force: true) + end - teardown do - @connection.drop_table :widgets, if_exists: true - Widget.reset_column_information - end + teardown do + @connection.drop_table :widgets, if_exists: true + Widget.reset_column_information + end - test "primary key column type with bigserial" do - column_type = Widget.type_for_attribute(Widget.primary_key) - assert_equal :integer, column_type.type - assert_equal 8, column_type.limit + if current_adapter?(:PostgreSQLAdapter, :Mysql2Adapter) + test "schema dump primary key with bigserial" do + schema = dump_table_schema "widgets" + assert_match %r{create_table "widgets", force: :cascade}, schema end + end - test "primary key with bigserial are automatically numbered" do - widget = Widget.create! - assert_not_nil widget.id - end + test "primary key column type" do + column_type = Widget.type_for_attribute(Widget.primary_key) + assert_equal :integer, column_type.type - test "schema dump primary key with bigserial" do - schema = dump_table_schema "widgets" - if current_adapter?(:PostgreSQLAdapter) - assert_match %r{create_table "widgets", id: :bigserial, force: :cascade}, schema - else - assert_match %r{create_table "widgets", id: :bigint, force: :cascade}, schema - end + if current_adapter?(:PostgreSQLAdapter, :Mysql2Adapter) + assert_equal 8, column_type.limit end if current_adapter?(:Mysql2Adapter) - test "primary key column type with options" do - @connection.create_table(:widgets, id: :primary_key, limit: 8, unsigned: true, force: true) - column = @connection.columns(:widgets).find { |c| c.name == "id" } - assert column.auto_increment? - assert_equal :integer, column.type - assert_equal 8, column.limit - assert column.unsigned? - end + column = @connection.columns(:widgets).find { |c| c.name == "id" } + assert column.auto_increment? end end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index d99e8a1dc6..4a49bfe9b1 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -10,13 +10,34 @@ class QueryCacheTest < ActiveRecord::TestCase fixtures :tasks, :topics, :categories, :posts, :categories_posts - teardown do + class ShouldNotHaveExceptionsLogger < ActiveRecord::LogSubscriber + attr_reader :logger + + def initialize + super + @logger = ::Logger.new File::NULL + @exception = false + end + + def exception? + @exception + end + + def sql(event) + super + rescue + @exception = true + end + end + + def teardown Task.connection.clear_query_cache ActiveRecord::Base.connection.disable_query_cache! + super end def test_exceptional_middleware_clears_and_disables_cache_on_error - assert !ActiveRecord::Base.connection.query_cache_enabled, "cache off" + assert_cache :off mw = middleware { |env| Task.find 1 @@ -26,19 +47,66 @@ class QueryCacheTest < ActiveRecord::TestCase } assert_raises(RuntimeError) { mw.call({}) } - assert_equal 0, ActiveRecord::Base.connection.query_cache.length - assert !ActiveRecord::Base.connection.query_cache_enabled, "cache off" + assert_cache :off end - def test_exceptional_middleware_leaves_enabled_cache_alone - ActiveRecord::Base.connection.enable_query_cache! + def test_query_cache_across_threads + ActiveRecord::Base.connection_pool.connections.each do |conn| + assert_cache :off, conn + end - mw = middleware { |env| - raise "lol borked" - } - assert_raises(RuntimeError) { mw.call({}) } + assert !ActiveRecord::Base.connection.nil? + assert_cache :off + + middleware { + assert_cache :clean + + Task.find 1 + assert_cache :dirty + + thread_1_connection = ActiveRecord::Base.connection + ActiveRecord::Base.clear_active_connections! + assert_cache :off, thread_1_connection - assert ActiveRecord::Base.connection.query_cache_enabled, "cache on" + started = Concurrent::Event.new + checked = Concurrent::Event.new + + thread_2_connection = nil + thread = Thread.new { + thread_2_connection = ActiveRecord::Base.connection + + assert_equal thread_2_connection, thread_1_connection + assert_cache :off + + middleware { + assert_cache :clean + + Task.find 1 + assert_cache :dirty + + started.set + checked.wait + + ActiveRecord::Base.clear_active_connections! + }.call({}) + } + + started.wait + + thread_1_connection = ActiveRecord::Base.connection + assert_not_equal thread_1_connection, thread_2_connection + assert_cache :dirty, thread_2_connection + checked.set + thread.join + + assert_cache :off, thread_2_connection + }.call({}) + + ActiveRecord::Base.connection_pool.connections.each do |conn| + assert_cache :off, conn + end + ensure + ActiveRecord::Base.clear_all_connections! end def test_middleware_delegates @@ -62,10 +130,10 @@ class QueryCacheTest < ActiveRecord::TestCase end def test_cache_enabled_during_call - assert !ActiveRecord::Base.connection.query_cache_enabled, "cache off" + assert_cache :off mw = middleware { |env| - assert ActiveRecord::Base.connection.query_cache_enabled, "cache on" + assert_cache :clean [200, {}, nil] } mw.call({}) @@ -121,6 +189,33 @@ class QueryCacheTest < ActiveRecord::TestCase end end + def test_cache_does_not_raise_exceptions + logger = ShouldNotHaveExceptionsLogger.new + subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger + + ActiveRecord::Base.cache do + assert_queries(1) { Task.find(1); Task.find(1) } + end + + assert_not_predicate logger, :exception? + ensure + ActiveSupport::Notifications.unsubscribe subscriber + end + + def test_query_cache_does_not_allow_sql_key_mutation + subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |_, _, _, _, payload| + payload[:sql].downcase! + end + + assert_raises RuntimeError do + ActiveRecord::Base.cache do + assert_queries(1) { Task.find(1); Task.find(1) } + end + end + ensure + ActiveSupport::Notifications.unsubscribe subscriber + end + def test_cache_is_flat Task.cache do assert_queries(1) { Topic.find(1); Topic.find(1); } @@ -138,7 +233,7 @@ class QueryCacheTest < ActiveRecord::TestCase assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter) # Future versions of the sqlite3 adapter will return numeric - assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") + assert_instance_of 0.class, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") else assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") end @@ -212,12 +307,82 @@ class QueryCacheTest < ActiveRecord::TestCase end end + def test_query_cached_even_when_types_are_reset + Task.cache do + # Warm the cache + Task.find(1) + + Task.connection.type_map.clear + + # Preload the type cache again (so we don't have those queries issued during our assertions) + Task.connection.send(:initialize_type_map, Task.connection.type_map) + + # Clear places where type information is cached + Task.reset_column_information + Task.initialize_find_by_cache + + assert_queries(0) do + Task.find(1) + end + end + end + + def test_query_cache_does_not_establish_connection_if_unconnected + ActiveRecord::Base.clear_active_connections! + refute ActiveRecord::Base.connection_handler.active_connections? # sanity check + + middleware { + refute ActiveRecord::Base.connection_handler.active_connections?, "QueryCache forced ActiveRecord::Base to establish a connection in setup" + }.call({}) + + refute ActiveRecord::Base.connection_handler.active_connections?, "QueryCache forced ActiveRecord::Base to establish a connection in cleanup" + end + + def test_query_cache_is_enabled_on_connections_established_after_middleware_runs + ActiveRecord::Base.clear_active_connections! + refute ActiveRecord::Base.connection_handler.active_connections? # sanity check + + middleware { + assert ActiveRecord::Base.connection.query_cache_enabled, "QueryCache did not get lazily enabled" + }.call({}) + end + + def test_query_caching_is_local_to_the_current_thread + ActiveRecord::Base.clear_active_connections! + + middleware { + assert ActiveRecord::Base.connection_pool.query_cache_enabled + assert ActiveRecord::Base.connection.query_cache_enabled + + Thread.new { + refute ActiveRecord::Base.connection_pool.query_cache_enabled + refute ActiveRecord::Base.connection.query_cache_enabled + }.join + }.call({}) + end + private def middleware(&app) executor = Class.new(ActiveSupport::Executor) ActiveRecord::QueryCache.install_executor_hooks executor lambda { |env| executor.wrap { app.call(env) } } end + + def assert_cache(state, connection = ActiveRecord::Base.connection) + case state + when :off + assert !connection.query_cache_enabled, "cache should be off" + assert connection.query_cache.empty?, "cache should be empty" + when :clean + assert connection.query_cache_enabled, "cache should be on" + assert connection.query_cache.empty?, "cache should be empty" + when :dirty + assert connection.query_cache_enabled, "cache should be on" + assert !connection.query_cache.empty?, "cache should be dirty" + else + raise "unknown state" + end + end end class QueryCacheExpiryTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 1c276aa765..5ff5e3c735 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -82,67 +82,67 @@ module ActiveRecord end def test_quote_with_quoted_id - assert_equal 1, @quoter.quote(Struct.new(:quoted_id).new(1), nil) + assert_equal 1, @quoter.quote(Struct.new(:quoted_id).new(1)) end def test_quote_nil - assert_equal "NULL", @quoter.quote(nil, nil) + assert_equal "NULL", @quoter.quote(nil) end def test_quote_true - assert_equal @quoter.quoted_true, @quoter.quote(true, nil) + assert_equal @quoter.quoted_true, @quoter.quote(true) end def test_quote_false - assert_equal @quoter.quoted_false, @quoter.quote(false, nil) + assert_equal @quoter.quoted_false, @quoter.quote(false) end def test_quote_float float = 1.2 - assert_equal float.to_s, @quoter.quote(float, nil) + assert_equal float.to_s, @quoter.quote(float) end def test_quote_integer integer = 1 - assert_equal integer.to_s, @quoter.quote(integer, nil) + assert_equal integer.to_s, @quoter.quote(integer) 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) 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) 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(Time.now, nil) - assert_equal "'lol'", @quoter.quote(DateTime.now, nil) + assert_equal "'lol'", @quoter.quote(Date.today) + assert_equal "'lol'", @quoter.quote(Time.now) + assert_equal "'lol'", @quoter.quote(DateTime.now) + end + + def test_quoting_classes + assert_equal "'Object'", @quoter.quote(Object) end def test_crazy_object crazy = Object.new e = assert_raises(TypeError) do - @quoter.quote(crazy, nil) + @quoter.quote(crazy) end assert_equal "can't quote Object", e.message end def test_quote_string_no_column - assert_equal "'lo\\\\l'", @quoter.quote('lo\l', nil) + assert_equal "'lo\\\\l'", @quoter.quote('lo\l') end def test_quote_as_mb_chars_no_column string = ActiveSupport::Multibyte::Chars.new('lo\l') - assert_equal "'lo\\\\l'", @quoter.quote(string, nil) - end - - def test_string_with_crazy_column - assert_equal "'lo\\\\l'", @quoter.quote('lo\l') + assert_equal "'lo\\\\l'", @quoter.quote(string) end def test_quote_duration diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index d71b30af69..0ef51272b9 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -86,8 +86,8 @@ class ReflectionTest < ActiveRecord::TestCase column = @first.column_for_attribute("attribute_that_doesnt_exist") assert_instance_of ActiveRecord::ConnectionAdapters::NullColumn, column assert_equal "attribute_that_doesnt_exist", column.name - assert_equal nil, column.sql_type - assert_equal nil, column.type + assert_nil column.sql_type + assert_nil column.type end def test_non_existent_types_are_identity_types @@ -100,7 +100,13 @@ class ReflectionTest < ActiveRecord::TestCase end def test_reflection_klass_for_nested_class_name - reflection = ActiveRecord::Reflection.create(:has_many, nil, nil, { class_name: "MyApplication::Business::Company" }, ActiveRecord::Base) + reflection = ActiveRecord::Reflection.create( + :has_many, + nil, + nil, + { class_name: "MyApplication::Business::Company" }, + Customer + ) assert_nothing_raised do assert_equal MyApplication::Business::Company, reflection.klass end @@ -124,12 +130,12 @@ class ReflectionTest < ActiveRecord::TestCase ) reflection_for_gps_location = AggregateReflection.new( - :gps_location, nil, { }, Customer + :gps_location, nil, {}, Customer ) - assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location) - assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance) - assert Customer.reflect_on_all_aggregations.include?(reflection_for_address) + assert_includes Customer.reflect_on_all_aggregations, reflection_for_gps_location + assert_includes Customer.reflect_on_all_aggregations, reflection_for_balance + assert_includes Customer.reflect_on_all_aggregations, reflection_for_address assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address) diff --git a/activerecord/test/cases/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb index bc3b1de697..278dac8171 100644 --- a/activerecord/test/cases/relation/merging_test.rb +++ b/activerecord/test/cases/relation/merging_test.rb @@ -86,9 +86,9 @@ class RelationMergingTest < ActiveRecord::TestCase merged = left.merge(right) assert_equal expected, merged.bound_attributes - assert !merged.to_sql.include?("omg") - assert merged.to_sql.include?("wtf") - assert merged.to_sql.include?("bbq") + assert_not_includes merged.to_sql, "omg" + assert_includes merged.to_sql, "wtf" + assert_includes merged.to_sql, "bbq" end def test_merging_reorders_bind_params diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb index ca5d187819..2cbbc775ce 100644 --- a/activerecord/test/cases/relation/mutation_test.rb +++ b/activerecord/test/cases/relation/mutation_test.rb @@ -71,7 +71,7 @@ module ActiveRecord test "#references!" do assert relation.references!(:foo).equal?(relation) - assert relation.references_values.include?("foo") + assert_includes relation.references_values, "foo" end test "extending!" do @@ -90,7 +90,7 @@ module ActiveRecord assert_equal [], relation.extending_values end - (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with, :uniq]).each do |method| + (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with]).each do |method| test "##{method}!" do assert relation.public_send("#{method}!", :foo).equal?(relation) assert_equal :foo, relation.public_send("#{method}_value") @@ -140,7 +140,7 @@ module ActiveRecord test "create_with!" do assert relation.create_with!(foo: "bar").equal?(relation) - assert_equal({foo: "bar"}, relation.create_with_value) + assert_equal({ foo: "bar" }, relation.create_with_value) end test "test_merge!" do @@ -161,22 +161,6 @@ module ActiveRecord test "distinct!" do relation.distinct! :foo assert_equal :foo, relation.distinct_value - - assert_deprecated do - assert_equal :foo, relation.uniq_value # deprecated access - end - end - - test "uniq! was replaced by distinct!" do - assert_deprecated(/use distinct! instead/) do - relation.uniq! :foo - end - - assert_deprecated(/use distinct_value instead/) do - assert_equal :foo, relation.uniq_value # deprecated access - end - - assert_equal :foo, relation.distinct_value end end end diff --git a/activerecord/test/cases/relation/or_test.rb b/activerecord/test/cases/relation/or_test.rb index 4efc742d5a..abb7ca72dd 100644 --- a/activerecord/test/cases/relation/or_test.rb +++ b/activerecord/test/cases/relation/or_test.rb @@ -61,8 +61,8 @@ module ActiveRecord def test_or_when_grouping groups = Post.where("id < 10").group("body").select("body, COUNT(*) AS c") - expected = groups.having("COUNT(*) > 1 OR body like 'Such%'").to_a.map {|o| [o.body, o.c] } - assert_equal expected, groups.having("COUNT(*) > 1").or(groups.having("body like 'Such%'")).to_a.map {|o| [o.body, o.c] } + expected = groups.having("COUNT(*) > 1 OR body like 'Such%'").to_a.map { |o| [o.body, o.c] } + assert_equal expected, groups.having("COUNT(*) > 1").or(groups.having("body like 'Such%'")).to_a.map { |o| [o.body, o.c] } end def test_or_with_named_scope @@ -79,7 +79,7 @@ module ActiveRecord expected = Post.where("id = 1 or id = 2").to_a p = Post.where("id = 1") p.load - assert_equal p.loaded?, true + assert_equal true, p.loaded? assert_equal expected, p.or(Post.where("id = 2")).to_a end diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb index 3d93cb7bce..a96d1ae5b5 100644 --- a/activerecord/test/cases/relation/where_chain_test.rb +++ b/activerecord/test/cases/relation/where_chain_test.rb @@ -26,7 +26,7 @@ module ActiveRecord def test_association_not_eq expected = Arel::Nodes::Grouping.new(Comment.arel_table[@name].not_eq(Arel::Nodes::BindParam.new)) - relation = Post.joins(:comments).where.not(comments: {title: "hello"}) + relation = Post.joins(:comments).where.not(comments: { title: "hello" }) assert_equal(expected.to_sql, relation.where_clause.ast.to_sql) end diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index ad9008ea4d..ed8ffddcf5 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -4,10 +4,10 @@ require "models/binary" require "models/cake_designer" require "models/car" require "models/chef" +require "models/post" require "models/comment" require "models/edge" require "models/essay" -require "models/post" require "models/price_estimate" require "models/topic" require "models/treasure" @@ -64,12 +64,12 @@ module ActiveRecord end def test_belongs_to_array_value_where - assert_equal Post.where(author_id: [1,2]).to_sql, Post.where(author: [1,2]).to_sql + assert_equal Post.where(author_id: [1, 2]).to_sql, Post.where(author: [1, 2]).to_sql end def test_belongs_to_nested_relation_where - expected = Post.where(author_id: Author.where(id: [1,2])).to_sql - actual = Post.where(author: Author.where(id: [1,2])).to_sql + expected = Post.where(author_id: Author.where(id: [1, 2])).to_sql + actual = Post.where(author: Author.where(id: [1, 2])).to_sql assert_equal expected, actual end @@ -87,7 +87,7 @@ module ActiveRecord def test_belongs_to_nested_where_with_relation author = authors(:david) - expected = Author.where(id: author ).joins(:posts) + expected = Author.where(id: author).joins(:posts) actual = Author.where(posts: { author_id: Author.where(id: author.id) }).joins(:posts) assert_equal expected.to_a, actual.to_a @@ -127,8 +127,8 @@ module ActiveRecord end def test_polymorphic_nested_relation_where - expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: Treasure.where(id: [1,2])) - actual = PriceEstimate.where(estimate_of: Treasure.where(id: [1,2])) + expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: Treasure.where(id: [1, 2])) + actual = PriceEstimate.where(estimate_of: Treasure.where(id: [1, 2])) assert_equal expected.to_sql, actual.to_sql end @@ -196,7 +196,7 @@ module ActiveRecord end def test_where_error - assert_raises(ActiveRecord::StatementInvalid) do + assert_nothing_raised do Post.where(id: { "posts.author_id" => 10 }).first end end diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 0802afac5a..d5af0cc9a5 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -40,9 +40,10 @@ module ActiveRecord def test_initialize_single_values relation = Relation.new(FakeKlass, :b, nil) - (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |method| + (Relation::SINGLE_VALUE_METHODS - [:create_with, :readonly]).each do |method| assert_nil relation.send("#{method}_value"), method.to_s end + assert_equal false, relation.readonly_value value = relation.create_with_value assert_equal({}, value) assert_predicate value, :frozen? @@ -70,7 +71,7 @@ module ActiveRecord def test_has_values relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) relation.where! 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 @@ -108,8 +109,8 @@ module ActiveRecord def test_create_with_value_with_wheres relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) relation.where! relation.table[:id].eq(10) - relation.create_with_value = {hello: "world"} - assert_equal({hello: "world", id: 10}, relation.scope_for_create) + relation.create_with_value = { hello: "world" } + assert_equal({ hello: "world", id: 10 }, relation.scope_for_create) end # FIXME: is this really wanted or expected behavior? @@ -120,7 +121,7 @@ module ActiveRecord relation.where! relation.table[:id].eq(10) assert_equal({}, relation.scope_for_create) - relation.create_with_value = {hello: "world"} + relation.create_with_value = { hello: "world" } assert_equal({}, relation.scope_for_create) end @@ -156,9 +157,9 @@ module ActiveRecord test "merging a hash into a relation" do relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) - relation = relation.merge where: {name: :lol}, readonly: true + relation = relation.merge where: { name: :lol }, readonly: true - assert_equal({"name"=>:lol}, relation.where_clause.to_h) + assert_equal({ "name" => :lol }, relation.where_clause.to_h) assert_equal true, relation.readonly_value end @@ -223,7 +224,7 @@ module ActiveRecord def test_relation_merging_with_merged_joins_as_symbols special_comments_with_ratings = SpecialComment.joins(:ratings) posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) - assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length + assert_equal({ 2 => 1, 4 => 3, 5 => 1 }, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count) end def test_relation_merging_with_joins_as_join_dependency_pick_proper_parent @@ -273,7 +274,7 @@ module ActiveRecord join_string = "LEFT OUTER JOIN #{Rating.quoted_table_name} ON #{SpecialComment.quoted_table_name}.id = #{Rating.quoted_table_name}.comment_id" special_comments_with_ratings = SpecialComment.joins join_string posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) - assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length + assert_equal({ 2 => 1, 4 => 3, 5 => 1 }, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count) end class EnsureRoundTripTypeCasting < ActiveRecord::Type::Value @@ -309,10 +310,10 @@ module ActiveRecord def skip_if_sqlite3_version_includes_quoting_bug if sqlite3_version_includes_quoting_bug? skip <<-ERROR.squish - You are using an outdated version of SQLite3 which has a bug in - quoted column names. Please update SQLite3 and rebuild the sqlite3 - ruby gem - ERROR + You are using an outdated version of SQLite3 which has a bug in + quoted column names. Please update SQLite3 and rebuild the sqlite3 + ruby gem + ERROR end end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 8652ef1081..9519fec0c4 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -184,14 +184,14 @@ class RelationTest < ActiveRecord::TestCase def test_select_with_subquery_in_from_does_not_use_original_table_name relation = Comment.group(:type).select("COUNT(post_id) AS post_count, type") - subquery = Comment.from(relation).select("type","post_count") - assert_equal(relation.map(&:post_count).sort,subquery.map(&:post_count).sort) + subquery = Comment.from(relation).select("type", "post_count") + assert_equal(relation.map(&:post_count).sort, subquery.map(&:post_count).sort) end def test_group_with_subquery_in_from_does_not_use_original_table_name relation = Comment.group(:type).select("COUNT(post_id) AS post_count,type") subquery = Comment.from(relation).group("type").average("post_count") - assert_equal(relation.map(&:post_count).sort,subquery.values.sort) + assert_equal(relation.map(&:post_count).sort, subquery.values.sort) end def test_finding_with_conditions @@ -240,6 +240,15 @@ class RelationTest < ActiveRecord::TestCase assert_raises(ActiveRecord::IrreversibleOrderError) do Topic.order("concat(author_name, title)").reverse_order end + assert_raises(ActiveRecord::IrreversibleOrderError) do + Topic.order("concat(lower(author_name), title)").reverse_order + end + assert_raises(ActiveRecord::IrreversibleOrderError) do + Topic.order("concat(author_name, lower(title))").reverse_order + end + assert_raises(ActiveRecord::IrreversibleOrderError) do + Topic.order("concat(lower(author_name), title, length(title)").reverse_order + end end def test_reverse_order_with_nulls_first_or_last @@ -282,7 +291,7 @@ class RelationTest < ActiveRecord::TestCase assert_includes Topic.order(id: "DESC").to_sql, "DESC" assert_includes Topic.order(id: "desc").to_sql, "DESC" assert_includes Topic.order(id: :DESC).to_sql, "DESC" - assert_includes Topic.order(id: :desc).to_sql,"DESC" + assert_includes Topic.order(id: :desc).to_sql, "DESC" end def test_raising_exception_on_invalid_hash_params @@ -356,7 +365,7 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_sanitized_order - query = Tag.order(["field(id, ?)", [1,3,2]]).to_sql + query = Tag.order(["field(id, ?)", [1, 3, 2]]).to_sql assert_match(/field\(id, 1,3,2\)/, query) query = Tag.order(["field(id, ?)", []]).to_sql @@ -384,7 +393,7 @@ class RelationTest < ActiveRecord::TestCase end def test_select_with_block - even_ids = Developer.all.select {|d| d.id % 2 == 0 }.map(&:id) + even_ids = Developer.all.select { |d| d.id % 2 == 0 }.map(&:id) assert_equal [2, 4, 6, 8, 10], even_ids.sort end @@ -433,7 +442,7 @@ class RelationTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert_equal 0, Developer.none.count assert_equal 0, Developer.none.calculate(:count, nil) - assert_equal nil, Developer.none.calculate(:average, "salary") + assert_nil Developer.none.calculate(:average, "salary") end end @@ -449,55 +458,55 @@ class RelationTest < ActiveRecord::TestCase def test_null_relation_sum ac = Aircraft.new assert_equal Hash.new, ac.engines.group(:id).sum(:id) - assert_equal 0, ac.engines.count + assert_equal 0, ac.engines.count ac.save assert_equal Hash.new, ac.engines.group(:id).sum(:id) - assert_equal 0, ac.engines.count + assert_equal 0, ac.engines.count end def test_null_relation_count ac = Aircraft.new assert_equal Hash.new, ac.engines.group(:id).count - assert_equal 0, ac.engines.count + assert_equal 0, ac.engines.count ac.save assert_equal Hash.new, ac.engines.group(:id).count - assert_equal 0, ac.engines.count + assert_equal 0, ac.engines.count end def test_null_relation_size ac = Aircraft.new assert_equal Hash.new, ac.engines.group(:id).size - assert_equal 0, ac.engines.size + assert_equal 0, ac.engines.size ac.save assert_equal Hash.new, ac.engines.group(:id).size - assert_equal 0, ac.engines.size + assert_equal 0, ac.engines.size end def test_null_relation_average ac = Aircraft.new assert_equal Hash.new, ac.engines.group(:car_id).average(:id) - assert_equal nil, ac.engines.average(:id) + assert_nil ac.engines.average(:id) ac.save assert_equal Hash.new, ac.engines.group(:car_id).average(:id) - assert_equal nil, ac.engines.average(:id) + assert_nil ac.engines.average(:id) end def test_null_relation_minimum ac = Aircraft.new assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id) - assert_equal nil, ac.engines.minimum(:id) + assert_nil ac.engines.minimum(:id) ac.save assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id) - assert_equal nil, ac.engines.minimum(:id) + assert_nil ac.engines.minimum(:id) end def test_null_relation_maximum ac = Aircraft.new assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id) - assert_equal nil, ac.engines.maximum(:id) + assert_nil ac.engines.maximum(:id) ac.save assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id) - assert_equal nil, ac.engines.maximum(:id) + assert_nil ac.engines.maximum(:id) end def test_null_relation_in_where_condition @@ -521,12 +530,12 @@ class RelationTest < ActiveRecord::TestCase assert_equal 3, developers_on_project_one.length developer_names = developers_on_project_one.map(&:name) - assert developer_names.include?("David") - assert developer_names.include?("Jamis") + assert_includes developer_names, "David" + assert_includes developer_names, "Jamis" end def test_find_on_hash_conditions - assert_equal Topic.all.merge!(where: {approved: false}).to_a, Topic.where(approved: false).to_a + assert_equal Topic.all.merge!(where: { approved: false }).to_a, Topic.where(approved: false).to_a end def test_joins_with_string_array @@ -739,11 +748,11 @@ class RelationTest < ActiveRecord::TestCase posts = Post.preload(:comments) post = posts.find { |p| p.id == 1 } assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) posts = Post.preload(:last_comment) post = posts.find { |p| p.id == 1 } @@ -776,7 +785,6 @@ class RelationTest < ActiveRecord::TestCase expected_taggings = taggings(:welcome_general, :thinking_general) assert_no_queries do - assert_equal expected_taggings, author.taggings.distinct.sort_by(&:id) assert_equal expected_taggings, author.taggings.uniq.sort_by(&:id) end @@ -832,15 +840,6 @@ class RelationTest < ActiveRecord::TestCase assert_equal author, authors.first end - class Mary < Author; end - - def test_find_by_classname - Author.create!(name: Mary.name) - assert_deprecated do - assert_equal 1, Author.where(name: Mary).size - end - end - def test_find_by_id_with_list_of_ar author = Author.first authors = Author.find_by_id([author]) @@ -970,7 +969,7 @@ class RelationTest < ActiveRecord::TestCase assert ! davids.exists?(42) assert ! davids.exists?(davids.new.id) - fake = Author.where(name: "fake author") + fake = Author.where(name: "fake author") assert ! fake.exists? assert ! fake.exists?(authors(:david).id) end @@ -1005,12 +1004,6 @@ class RelationTest < ActiveRecord::TestCase assert davids.loaded? end - def test_destroy_all_with_conditions_is_deprecated - assert_deprecated do - assert_difference("Author.count", -1) { Author.destroy_all(name: "David") } - end - end - def test_delete_all davids = Author.where(name: "David") @@ -1018,12 +1011,6 @@ class RelationTest < ActiveRecord::TestCase assert ! davids.loaded? end - def test_delete_all_with_conditions_is_deprecated - assert_deprecated do - assert_difference("Author.count", -1) { Author.delete_all(name: "David") } - end - end - def test_delete_all_loaded davids = Author.where(name: "David") @@ -1225,8 +1212,8 @@ class RelationTest < ActiveRecord::TestCase assert posts.any? # Uses COUNT() assert ! posts.where(id: nil).any? - assert posts.any? {|p| p.id > 0 } - assert ! posts.any? {|p| p.id <= 0 } + assert posts.any? { |p| p.id > 0 } + assert ! posts.any? { |p| p.id <= 0 } end assert posts.loaded? @@ -1237,8 +1224,8 @@ class RelationTest < ActiveRecord::TestCase assert_queries(2) do assert posts.many? # Uses COUNT() - assert posts.many? {|p| p.id > 0 } - assert ! posts.many? {|p| p.id < 2 } + assert posts.many? { |p| p.id > 0 } + assert ! posts.many? { |p| p.id < 2 } end assert posts.loaded? @@ -1260,8 +1247,8 @@ class RelationTest < ActiveRecord::TestCase assert ! posts.loaded? assert_queries(1) do - assert posts.none? {|p| p.id < 0 } - assert ! posts.none? {|p| p.id == 1 } + assert posts.none? { |p| p.id < 0 } + assert ! posts.none? { |p| p.id == 1 } end assert posts.loaded? @@ -1276,8 +1263,8 @@ class RelationTest < ActiveRecord::TestCase assert ! posts.loaded? assert_queries(1) do - assert ! posts.one? {|p| p.id < 3 } - assert posts.one? {|p| p.id == 1 } + assert ! posts.one? { |p| p.id < 3 } + assert posts.one? { |p| p.id == 1 } end assert posts.loaded? @@ -1363,11 +1350,11 @@ class RelationTest < ActiveRecord::TestCase end def test_first_or_create_with_array - several_green_birds = Bird.where(color: "green").first_or_create([{name: "parrot"}, {name: "parakeet"}]) + several_green_birds = Bird.where(color: "green").first_or_create([{ name: "parrot" }, { name: "parakeet" }]) assert_kind_of Array, several_green_birds several_green_birds.each { |bird| assert bird.persisted? } - same_parrot = Bird.where(color: "green").first_or_create([{name: "hummingbird"}, {name: "macaw"}]) + same_parrot = Bird.where(color: "green").first_or_create([{ name: "hummingbird" }, { name: "macaw" }]) assert_kind_of Bird, same_parrot assert_equal several_green_birds.first, same_parrot end @@ -1411,17 +1398,17 @@ class RelationTest < ActiveRecord::TestCase end def test_first_or_create_with_valid_array - several_green_birds = Bird.where(color: "green").first_or_create!([{name: "parrot"}, {name: "parakeet"}]) + several_green_birds = Bird.where(color: "green").first_or_create!([{ name: "parrot" }, { name: "parakeet" }]) assert_kind_of Array, several_green_birds several_green_birds.each { |bird| assert bird.persisted? } - same_parrot = Bird.where(color: "green").first_or_create!([{name: "hummingbird"}, {name: "macaw"}]) + same_parrot = Bird.where(color: "green").first_or_create!([{ name: "hummingbird" }, { name: "macaw" }]) assert_kind_of Bird, same_parrot assert_equal several_green_birds.first, same_parrot end def test_first_or_create_with_invalid_array - assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create!([ {name: "parrot"}, {pirate_id: 1} ]) } + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create!([ { name: "parrot" }, { pirate_id: 1 } ]) } end def test_first_or_initialize @@ -1513,7 +1500,7 @@ class RelationTest < ActiveRecord::TestCase assert_equal Post.where(author_id: 1).to_a, author_posts.to_a all_posts = relation.only(:limit) - assert_equal Post.limit(1).to_a.first, all_posts.first + assert_equal Post.limit(1).to_a, all_posts.to_a end def test_anonymous_extension @@ -1555,8 +1542,8 @@ class RelationTest < ActiveRecord::TestCase end def test_unscoped_block_style - assert_equal "honda", CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name} - assert_equal "honda", FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name} + assert_equal "honda", CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name } + assert_equal "honda", FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name } end def test_intersection_with_array @@ -1646,17 +1633,11 @@ class RelationTest < ActiveRecord::TestCase assert_equal ["Foo", "Foo"], query.map(&:name) assert_sql(/DISTINCT/) do assert_equal ["Foo"], query.distinct.map(&:name) - assert_deprecated { assert_equal ["Foo"], query.uniq.map(&:name) } end assert_sql(/DISTINCT/) do assert_equal ["Foo"], query.distinct(true).map(&:name) - assert_deprecated { assert_equal ["Foo"], query.uniq(true).map(&:name) } end assert_equal ["Foo", "Foo"], query.distinct(true).distinct(false).map(&:name) - - assert_deprecated do - assert_equal ["Foo", "Foo"], query.uniq(true).uniq(false).map(&:name) - end end def test_doesnt_add_having_values_if_options_are_blank @@ -1806,7 +1787,7 @@ class RelationTest < ActiveRecord::TestCase end test "find_by returns nil if the record is missing" do - assert_equal nil, Post.all.find_by("1 = 0") + assert_nil Post.all.find_by("1 = 0") end test "find_by doesn't have implicit ordering" do @@ -1955,7 +1936,7 @@ class RelationTest < ActiveRecord::TestCase end def test_unscope_removes_binds - left = Post.where(id: Arel::Nodes::BindParam.new) + left = Post.where(id: Arel::Nodes::BindParam.new) column = Post.columns_hash["id"] left.bind_values += [[column, 20]] @@ -1964,8 +1945,8 @@ class RelationTest < ActiveRecord::TestCase end def test_merging_removes_rhs_bind_parameters - left = Post.where(id: 20) - right = Post.where(id: [1,2,3,4]) + left = Post.where(id: 20) + right = Post.where(id: [1, 2, 3, 4]) merged = left.merge(right) assert_equal [], merged.bind_values diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb index 8bbd4b3bc5..949086fda0 100644 --- a/activerecord/test/cases/result_test.rb +++ b/activerecord/test/cases/result_test.rb @@ -16,20 +16,20 @@ module ActiveRecord test "to_hash returns row_hashes" do assert_equal [ - {"col_1" => "row 1 col 1", "col_2" => "row 1 col 2"}, - {"col_1" => "row 2 col 1", "col_2" => "row 2 col 2"}, - {"col_1" => "row 3 col 1", "col_2" => "row 3 col 2"}, + { "col_1" => "row 1 col 1", "col_2" => "row 1 col 2" }, + { "col_1" => "row 2 col 1", "col_2" => "row 2 col 2" }, + { "col_1" => "row 3 col 1", "col_2" => "row 3 col 2" }, ], result.to_hash end test "first returns first row as a hash" do assert_equal( - {"col_1" => "row 1 col 1", "col_2" => "row 1 col 2"}, result.first) + { "col_1" => "row 1 col 1", "col_2" => "row 1 col 2" }, result.first) end test "last returns last row as a hash" do assert_equal( - {"col_1" => "row 3 col 1", "col_2" => "row 3 col 2"}, result.last) + { "col_1" => "row 3 col 1", "col_2" => "row 3 col 2" }, result.last) end test "each with block returns row hashes" do diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb index 464bb12ccb..23bcb0af1e 100644 --- a/activerecord/test/cases/sanitize_test.rb +++ b/activerecord/test/cases/sanitize_test.rb @@ -12,8 +12,8 @@ class SanitizeTest < ActiveRecord::TestCase 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".mb_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".mb_chars]) + 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".mb_chars]) end def test_sanitize_sql_array_handles_bind_variables diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 2ad3da94e4..bea78d2a95 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -51,6 +51,7 @@ class SchemaDumperTest < ActiveRecord::TestCase output = standard_dump assert_match %r{create_table "accounts"}, output assert_match %r{create_table "authors"}, output + assert_no_match %r{(?<=, ) do \|t\|}, output assert_no_match %r{create_table "schema_migrations"}, output assert_no_match %r{create_table "ar_internal_metadata"}, output end @@ -70,38 +71,35 @@ class SchemaDumperTest < ActiveRecord::TestCase assert_match %r{create_table "CamelCase"}, output end - def assert_line_up(lines, pattern, required = false) + def assert_no_line_up(lines, pattern) return assert(true) if lines.empty? matches = lines.map { |line| line.match(pattern) } - assert matches.all? if required matches.compact! return assert(true) if matches.empty? - assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length + line_matches = lines.map { |line| [line, line.match(pattern)] }.select { |line, match| match } + assert line_matches.all? { |line, match| + start = match.offset(0).first + line[start - 2..start - 1] == ", " + } end def column_definition_lines(output = standard_dump) - output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) } + output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map { |m| m.last.split(/\n/) } end - def test_types_line_up + def test_types_no_line_up column_definition_lines.each do |column_set| next if column_set.empty? - lengths = column_set.map do |column| - if match = column.match(/\bt\.\w+\s+(?="\w+?")/) - match[0].length - end - end.compact - - assert_equal 1, lengths.uniq.length + assert column_set.all? { |column| !column.match(/\bt\.\w+\s{2,}/) } end end - def test_arguments_line_up + def test_arguments_no_line_up column_definition_lines.each do |column_set| - assert_line_up(column_set, /default: /) - assert_line_up(column_set, /limit: /) - assert_line_up(column_set, /null: /) + assert_no_line_up(column_set, /default: /) + assert_no_line_up(column_set, /limit: /) + assert_no_line_up(column_set, /null: /) end end @@ -150,12 +148,7 @@ class SchemaDumperTest < ActiveRecord::TestCase assert_match %r{c_int_4.*limit: 4}, output end - if current_adapter?(:SQLite3Adapter) - assert_match %r{c_int_5.*limit: 5}, output - assert_match %r{c_int_6.*limit: 6}, output - assert_match %r{c_int_7.*limit: 7}, output - assert_match %r{c_int_8.*limit: 8}, output - elsif current_adapter?(:OracleAdapter) + if current_adapter?(:SQLite3Adapter, :OracleAdapter) assert_match %r{c_int_5.*limit: 5}, output assert_match %r{c_int_6.*limit: 6}, output assert_match %r{c_int_7.*limit: 7}, output @@ -186,8 +179,10 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dumps_index_columns_in_right_order index_definition = standard_dump.split(/\n/).grep(/t\.index.*company_index/).first.strip - if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) - assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index", using: :btree', index_definition + if current_adapter?(:PostgreSQLAdapter) + assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index", order: { rating: :desc }, using: :btree', index_definition + elsif current_adapter?(:Mysql2Adapter) + assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index", length: { type: 10 }, using: :btree', index_definition else assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index"', index_definition end @@ -346,7 +341,7 @@ class SchemaDumperTest < ActiveRecord::TestCase create_table("dogs") do |t| t.column :name, :string - t.column :owner_id, :integer + t.column :owner_id, :bigint t.index [:name] t.foreign_key :dog_owners, column: "owner_id" if supports_foreign_keys? end @@ -426,6 +421,13 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase t.datetime :datetime_with_default, default: "2014-06-05 07:17:04" t.time :time_with_default, default: "07:17:04" end + + if current_adapter?(:PostgreSQLAdapter) + @connection.create_table :infinity_defaults, force: true do |t| + t.float :float_with_inf_default, default: Float::INFINITY + t.float :float_with_nan_default, default: Float::NAN + end + end end teardown do @@ -441,4 +443,11 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase assert_match %r{t\.datetime\s+"datetime_with_default",\s+default: '2014-06-05 07:17:04'}, output assert_match %r{t\.time\s+"time_with_default",\s+default: '2000-01-01 07:17:04'}, output end + + def test_schema_dump_with_float_column_infinity_default + skip unless current_adapter?(:PostgreSQLAdapter) + output = dump_table_schema("infinity_defaults") + assert_match %r{t\.float\s+"float_with_inf_default",\s+default: ::Float::INFINITY}, output + assert_match %r{t\.float\s+"float_with_nan_default",\s+default: ::Float::NAN}, output + end end diff --git a/activerecord/test/cases/schema_loading_test.rb b/activerecord/test/cases/schema_loading_test.rb index 3d92a5e104..362370ac61 100644 --- a/activerecord/test/cases/schema_loading_test.rb +++ b/activerecord/test/cases/schema_loading_test.rb @@ -8,7 +8,7 @@ module SchemaLoadCounter def load_schema! self.load_schema_calls ||= 0 - self.load_schema_calls +=1 + self.load_schema_calls += 1 super end end diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb index effecfd294..3a04f4bf7d 100644 --- a/activerecord/test/cases/scoping/default_scoping_test.rb +++ b/activerecord/test/cases/scoping/default_scoping_test.rb @@ -5,7 +5,7 @@ require "models/developer" require "models/computer" require "models/vehicle" require "models/cat" -require "active_support/core_ext/regexp" +require "concurrent/atomic/cyclic_barrier" class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers, :posts, :comments @@ -51,7 +51,7 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scope_with_conditions_string assert_equal Developer.where(name: "David").map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort - assert_equal nil, DeveloperCalledDavid.create!.name + assert_nil DeveloperCalledDavid.create!.name end def test_default_scope_with_conditions_hash @@ -63,7 +63,7 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scoping_with_threads 2.times do Thread.new { - assert DeveloperOrderedBySalary.all.to_sql.include?("salary DESC") + assert_includes DeveloperOrderedBySalary.all.to_sql, "salary DESC" DeveloperOrderedBySalary.connection.close }.join end @@ -132,7 +132,7 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal expected, received expected_2 = Developer.order("salary DESC").collect(&:name) - received_2 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope({where: :name}, :select).collect(&:name) + received_2 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope({ where: :name }, :select).collect(&:name) assert_equal expected_2, received_2 expected_3 = Developer.order("salary DESC").collect(&:name) @@ -315,7 +315,7 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_create_attribute_overwrites_default_values - assert_equal nil, PoorDeveloperCalledJamis.create!(salary: nil).salary + assert_nil PoorDeveloperCalledJamis.create!(salary: nil).salary assert_equal 50000, PoorDeveloperCalledJamis.create!(name: "David").salary end @@ -368,7 +368,7 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_unscoped_with_named_scope_should_not_have_default_scope assert_equal [DeveloperCalledJamis.find(developers(:poor_jamis).id)], DeveloperCalledJamis.poor - assert DeveloperCalledJamis.unscoped.poor.include?(developers(:david).becomes(DeveloperCalledJamis)) + assert_includes DeveloperCalledJamis.unscoped.poor, developers(:david).becomes(DeveloperCalledJamis) assert_equal 11, DeveloperCalledJamis.unscoped.length assert_equal 1, DeveloperCalledJamis.poor.length @@ -438,12 +438,17 @@ class DefaultScopingTest < ActiveRecord::TestCase threads = [] assert_not_equal 1, ThreadsafeDeveloper.unscoped.count + barrier_1 = Concurrent::CyclicBarrier.new(2) + barrier_2 = Concurrent::CyclicBarrier.new(2) + threads << Thread.new do - Thread.current[:long_default_scope] = true + Thread.current[:default_scope_delay] = -> { barrier_1.wait; barrier_2.wait } assert_equal 1, ThreadsafeDeveloper.all.to_a.count ThreadsafeDeveloper.connection.close end threads << Thread.new do + Thread.current[:default_scope_delay] = -> { barrier_2.wait } + barrier_1.wait assert_equal 1, ThreadsafeDeveloper.all.to_a.count ThreadsafeDeveloper.connection.close end diff --git a/activerecord/test/cases/scoping/named_scoping_test.rb b/activerecord/test/cases/scoping/named_scoping_test.rb index 4e799d6dc0..995ff4dfc5 100644 --- a/activerecord/test/cases/scoping/named_scoping_test.rb +++ b/activerecord/test/cases/scoping/named_scoping_test.rb @@ -33,8 +33,8 @@ class NamedScopingTest < ActiveRecord::TestCase all_posts.to_a new_post = Topic.create! - assert !all_posts.include?(new_post) - assert all_posts.reload.include?(new_post) + assert_not_includes all_posts, new_post + assert_includes all_posts.reload, new_post end def test_delegates_finds_and_calculations_to_the_base_class @@ -69,9 +69,9 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified - assert !Topic.all.merge!(where: {approved: true}).to_a.empty? + assert !Topic.all.merge!(where: { approved: true }).to_a.empty? - assert_equal Topic.all.merge!(where: {approved: true}).to_a, Topic.approved + assert_equal Topic.all.merge!(where: { approved: true }).to_a, Topic.approved assert_equal Topic.where(approved: true).count, Topic.approved.count end @@ -82,7 +82,7 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_scopes_are_composable - assert_equal((approved = Topic.all.merge!(where: {approved: true}).to_a), Topic.approved) + assert_equal((approved = Topic.all.merge!(where: { approved: true }).to_a), Topic.approved) assert_equal((replied = Topic.all.merge!(where: "replies_count > 0").to_a), Topic.replied) assert !(approved == replied) assert !(approved & replied).empty? @@ -119,8 +119,8 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_scope_with_STI - assert_equal 3,Post.containing_the_letter_a.count - assert_equal 1,SpecialPost.containing_the_letter_a.count + assert_equal 3, Post.containing_the_letter_a.count + assert_equal 1, SpecialPost.containing_the_letter_a.count end def test_has_many_through_associations_have_access_to_scopes @@ -327,12 +327,12 @@ class NamedScopingTest < ActiveRecord::TestCase conflicts.each do |name| e = assert_raises(ArgumentError, "scope `#{name}` should not be allowed") do - klass.class_eval { scope name, ->{ where(approved: true) } } + klass.class_eval { scope name, -> { where(approved: true) } } end assert_match(/You tried to define a scope named \"#{name}\" on the model/, e.message) e = assert_raises(ArgumentError, "scope `#{name}` should not be allowed") do - subklass.class_eval { scope name, ->{ where(approved: true) } } + subklass.class_eval { scope name, -> { where(approved: true) } } end assert_match(/You tried to define a scope named \"#{name}\" on the model/, e.message) end @@ -340,12 +340,12 @@ class NamedScopingTest < ActiveRecord::TestCase non_conflicts.each do |name| assert_nothing_raised do silence_warnings do - klass.class_eval { scope name, ->{ where(approved: true) } } + klass.class_eval { scope name, -> { where(approved: true) } } end end assert_nothing_raised do - subklass.class_eval { scope name, ->{ where(approved: true) } } + subklass.class_eval { scope name, -> { where(approved: true) } } end end end @@ -431,12 +431,12 @@ class NamedScopingTest < ActiveRecord::TestCase assert_equal 4, Topic.approved.count assert_queries(5) do - Topic.approved.find_each(batch_size: 1) {|t| assert t.approved? } + Topic.approved.find_each(batch_size: 1) { |t| assert t.approved? } end assert_queries(3) do Topic.approved.find_in_batches(batch_size: 2) do |group| - group.each {|t| assert t.approved? } + group.each { |t| assert t.approved? } end end end @@ -462,7 +462,7 @@ class NamedScopingTest < ActiveRecord::TestCase [:public_method, :protected_method, :private_method].each do |reserved_method| assert Topic.respond_to?(reserved_method, true) ActiveRecord::Base.logger.expects(:warn) - silence_warnings { Topic.scope(reserved_method, -> { }) } + silence_warnings { Topic.scope(reserved_method, -> {}) } end end diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index a46123f451..a1ae57fdbb 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -28,7 +28,7 @@ class RelationScopingTest < ActiveRecord::TestCase def test_scope_breaks_caching_on_collections author = authors :david ids = author.reload.special_posts_with_default_scope.map(&:id) - assert_equal [1,5,6], ids.sort + assert_equal [1, 5, 6], ids.sort scoped_posts = SpecialPostWithDefaultScope.unscoped do author = authors :david author.reload.special_posts_with_default_scope.to_a @@ -133,8 +133,8 @@ class RelationScopingTest < ActiveRecord::TestCase scoped_developers = Developer.includes(:projects).scoping do Developer.where("projects.id" => 2).to_a end - assert scoped_developers.include?(developers(:david)) - assert !scoped_developers.include?(developers(:jamis)) + assert_includes scoped_developers, developers(:david) + assert_not_includes scoped_developers, developers(:jamis) assert_equal 1, scoped_developers.size end @@ -143,8 +143,8 @@ class RelationScopingTest < ActiveRecord::TestCase Developer.where("developers_projects.project_id = 2").to_a end - assert scoped_developers.include?(developers(:david)) - assert !scoped_developers.include?(developers(:jamis)) + assert_includes scoped_developers, developers(:david) + assert_not_includes scoped_developers, developers(:jamis) assert_equal 1, scoped_developers.size assert_equal developers(:david).attributes, scoped_developers.first.attributes end @@ -155,7 +155,7 @@ class RelationScopingTest < ActiveRecord::TestCase end assert_equal 1, new_comment.post_id - assert Post.find(1).comments.include?(new_comment) + assert_includes Post.find(1).comments, new_comment end def test_scoped_create_with_create_with @@ -164,7 +164,7 @@ class RelationScopingTest < ActiveRecord::TestCase end assert_equal 1, new_comment.post_id - assert Post.find(1).comments.include?(new_comment) + assert_includes Post.find(1).comments, new_comment end def test_scoped_create_with_create_with_has_higher_priority @@ -173,7 +173,7 @@ class RelationScopingTest < ActiveRecord::TestCase end assert_equal 1, new_comment.post_id - assert Post.find(1).comments.include?(new_comment) + assert_includes Post.find(1).comments, new_comment end def test_ensure_that_method_scoping_is_correctly_restored @@ -277,7 +277,7 @@ class NestedRelationScopingTest < ActiveRecord::TestCase assert_equal "David", Developer.first.name Developer.unscoped.where("name = 'Maiha'") do - assert_equal nil, Developer.first + assert_nil Developer.first end # ensure that scoping is restored diff --git a/activerecord/test/cases/secure_token_test.rb b/activerecord/test/cases/secure_token_test.rb index eda0229c26..7b9cbee40a 100644 --- a/activerecord/test/cases/secure_token_test.rb +++ b/activerecord/test/cases/secure_token_test.rb @@ -27,6 +27,6 @@ class SecureTokenTest < ActiveRecord::TestCase @user.token = "custom-secure-token" @user.save - assert_equal @user.token, "custom-secure-token" + assert_equal "custom-secure-token", @user.token end end diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index ceb0d5441b..a469da0a5b 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -107,7 +107,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_serialized_time_attribute - myobj = Time.local(2008,1,1,1,0) + myobj = Time.local(2008, 1, 1, 1, 0) topic = Topic.create("content" => myobj).reload assert_equal(myobj, topic.content) end @@ -157,6 +157,13 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal(settings, Topic.find(topic.id).content) end + def test_where_by_serialized_attribute_with_hash + settings = { "color" => "green" } + Topic.serialize(:content, Hash) + topic = Topic.create!(content: settings) + assert_equal topic, Topic.where(content: settings).take + end + def test_serialized_default_class Topic.serialize(:content, Hash) topic = Topic.new @@ -178,14 +185,14 @@ class SerializedAttributeTest < ActiveRecord::TestCase topic = Topic.new(content: true) assert topic.save topic = topic.reload - assert_equal topic.content, true + assert_equal true, topic.content end def test_serialized_boolean_value_false topic = Topic.new(content: false) assert topic.save topic = topic.reload - assert_equal topic.content, false + assert_equal false, topic.content end def test_serialize_with_coder @@ -204,7 +211,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase topic.save! topic.reload assert_kind_of some_class, topic.content - assert_equal topic.content, some_class.new("my value") + assert_equal some_class.new("my value"), topic.content end def test_serialize_attribute_via_select_method_when_time_zone_available diff --git a/activerecord/test/cases/suppressor_test.rb b/activerecord/test/cases/suppressor_test.rb index 64f39d8574..a7d16b7cdb 100644 --- a/activerecord/test/cases/suppressor_test.rb +++ b/activerecord/test/cases/suppressor_test.rb @@ -64,7 +64,7 @@ class SuppressorTest < ActiveRecord::TestCase def test_suppresses_when_nested_multiple_times assert_no_difference -> { Notification.count } do Notification.suppress do - Notification.suppress { } + Notification.suppress {} Notification.create Notification.create! Notification.new.save diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb index 0519c70ac7..f7c53b5801 100644 --- a/activerecord/test/cases/tasks/database_tasks_test.rb +++ b/activerecord/test/cases/tasks/database_tasks_test.rb @@ -24,13 +24,13 @@ module ActiveRecord sqlite3: :sqlite_tasks } - class DatabaseTasksUtilsTask< ActiveRecord::TestCase + class DatabaseTasksUtilsTask < ActiveRecord::TestCase def test_raises_an_error_when_called_with_protected_environment ActiveRecord::Migrator.stubs(:current_version).returns(1) protected_environments = ActiveRecord::Base.protected_environments.dup current_env = ActiveRecord::Migrator.current_environment - assert !protected_environments.include?(current_env) + assert_not_includes protected_environments, current_env # Assert no error ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! @@ -61,15 +61,15 @@ module ActiveRecord instance = klazz.new klazz.stubs(:new).returns instance - instance.expects(:structure_dump).with("awesome-file.sql") + instance.expects(:structure_dump).with("awesome-file.sql", nil) ActiveRecord::Tasks::DatabaseTasks.register_task(/foo/, klazz) - ActiveRecord::Tasks::DatabaseTasks.structure_dump({"adapter" => :foo}, "awesome-file.sql") + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :foo }, "awesome-file.sql") end def test_unregistered_task assert_raise(ActiveRecord::Tasks::DatabaseNotSupported) do - ActiveRecord::Tasks::DatabaseTasks.structure_dump({"adapter" => :bar}, "awesome-file.sql") + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :bar }, "awesome-file.sql") end end end @@ -85,9 +85,19 @@ module ActiveRecord end end + class DatabaseTasksDumpSchemaCacheTest < ActiveRecord::TestCase + def test_dump_schema_cache + path = "/tmp/my_schema_cache.yml" + ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, path) + assert File.file?(path) + ensure + FileUtils.rm_rf(path) + end + end + class DatabaseTasksCreateAllTest < ActiveRecord::TestCase def setup - @configurations = {"development" => {"database" => "my-db"}} + @configurations = { "development" => { "database" => "my-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) end @@ -145,9 +155,9 @@ module ActiveRecord class DatabaseTasksCreateCurrentTest < ActiveRecord::TestCase def setup @configurations = { - "development" => {"database" => "dev-db"}, - "test" => {"database" => "test-db"}, - "production" => {"database" => "prod-db"} + "development" => { "database" => "dev-db" }, + "test" => { "database" => "test-db" }, + "production" => { "database" => "prod-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) @@ -213,7 +223,7 @@ module ActiveRecord class DatabaseTasksDropAllTest < ActiveRecord::TestCase def setup - @configurations = {development: {"database" => "my-db"}} + @configurations = { development: { "database" => "my-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) end @@ -271,9 +281,9 @@ module ActiveRecord class DatabaseTasksDropCurrentTest < ActiveRecord::TestCase def setup @configurations = { - "development" => {"database" => "dev-db"}, - "test" => {"database" => "test-db"}, - "production" => {"database" => "prod-db"} + "development" => { "database" => "dev-db" }, + "test" => { "database" => "test-db" }, + "production" => { "database" => "prod-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) @@ -358,9 +368,9 @@ module ActiveRecord class DatabaseTasksPurgeCurrentTest < ActiveRecord::TestCase def test_purges_current_environment_database configurations = { - "development" => {"database" => "dev-db"}, - "test" => {"database" => "test-db"}, - "production" => {"database" => "prod-db"} + "development" => { "database" => "dev-db" }, + "test" => { "database" => "test-db" }, + "production" => { "database" => "prod-db" } } ActiveRecord::Base.stubs(:configurations).returns(configurations) @@ -374,7 +384,7 @@ module ActiveRecord class DatabaseTasksPurgeAllTest < ActiveRecord::TestCase def test_purge_all_local_configurations - configurations = {development: {"database" => "my-db"}} + configurations = { development: { "database" => "my-db" } } ActiveRecord::Base.stubs(:configurations).returns(configurations) ActiveRecord::Tasks::DatabaseTasks.expects(:purge). @@ -411,8 +421,8 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_dump") do - eval("@#{v}").expects(:structure_dump).with("awesome-file.sql") - ActiveRecord::Tasks::DatabaseTasks.structure_dump({"adapter" => k}, "awesome-file.sql") + eval("@#{v}").expects(:structure_dump).with("awesome-file.sql", nil) + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => k }, "awesome-file.sql") end end end @@ -422,8 +432,8 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_load") do - eval("@#{v}").expects(:structure_load).with("awesome-file.sql") - ActiveRecord::Tasks::DatabaseTasks.structure_load({"adapter" => k}, "awesome-file.sql") + eval("@#{v}").expects(:structure_load).with("awesome-file.sql", nil) + ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => k }, "awesome-file.sql") end end end @@ -443,7 +453,7 @@ module ActiveRecord end class DatabaseTasksCheckSchemaFileSpecifiedFormatsTest < ActiveRecord::TestCase - {ruby: "schema.rb", sql: "structure.sql"}.each_pair do |fmt, filename| + { ruby: "schema.rb", sql: "structure.sql" }.each_pair do |fmt, filename| define_method("test_check_schema_file_for_#{fmt}_format") do ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns("/tmp") assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_file(fmt) diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index dbe935808e..f30e0958c3 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -59,7 +59,7 @@ if current_adapter?(:Mysql2Adapter) def test_when_database_created_successfully_outputs_info_to_stdout ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stdout.string, "Created database 'my-app-db'\n" + assert_equal "Created database 'my-app-db'\n", $stdout.string end def test_create_when_database_exists_outputs_info_to_stderr @@ -69,7 +69,7 @@ if current_adapter?(:Mysql2Adapter) ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stderr.string, "Database 'my-app-db' already exists\n" + assert_equal "Database 'my-app-db' already exists\n", $stderr.string end end @@ -205,7 +205,7 @@ if current_adapter?(:Mysql2Adapter) def test_when_database_dropped_successfully_outputs_info_to_stdout ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal $stdout.string, "Dropped database 'my-app-db'\n" + assert_equal "Dropped database 'my-app-db'\n", $stdout.string end end @@ -294,6 +294,17 @@ if current_adapter?(:Mysql2Adapter) ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) end + def test_structure_dump_with_extra_flags + filename = "awesome-file.sql" + expected_command = ["mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--noop", "test-db"] + + assert_called_with(Kernel, :system, expected_command, returns: true) do + with_structure_dump_flags(["--noop"]) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + end + end + end + def test_warn_when_external_structure_dump_command_execution_fails filename = "awesome-file.sql" Kernel.expects(:system) @@ -323,6 +334,15 @@ if current_adapter?(:Mysql2Adapter) @configuration.merge("sslca" => "ca.crt"), filename) end + + private + def with_structure_dump_flags(flags) + old = ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags + ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = flags + yield + ensure + ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = old + end end class MySQLStructureLoadTest < ActiveRecord::TestCase @@ -335,11 +355,23 @@ if current_adapter?(:Mysql2Adapter) def test_structure_load filename = "awesome-file.sql" - Kernel.expects(:system).with("mysql", "--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}, "--database", "test-db") - .returns(true) + expected_command = ["mysql", "--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}, "--database", "test-db", "--noop"] - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + assert_called_with(Kernel, :system, expected_command, returns: true) do + with_structure_load_flags(["--noop"]) do + ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + end + end end + + private + def with_structure_load_flags(flags) + old = ActiveRecord::Tasks::DatabaseTasks.structure_load_flags + ActiveRecord::Tasks::DatabaseTasks.structure_load_flags = flags + yield + ensure + ActiveRecord::Tasks::DatabaseTasks.structure_load_flags = old + end end end end diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index b8c8ec88f0..a23100c32a 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -74,7 +74,7 @@ if current_adapter?(:PostgreSQLAdapter) def test_when_database_created_successfully_outputs_info_to_stdout ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stdout.string, "Created database 'my-app-db'\n" + assert_equal "Created database 'my-app-db'\n", $stdout.string end def test_create_when_database_exists_outputs_info_to_stderr @@ -84,7 +84,7 @@ if current_adapter?(:PostgreSQLAdapter) ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stderr.string, "Database 'my-app-db' already exists\n" + assert_equal "Database 'my-app-db' already exists\n", $stderr.string end end @@ -126,7 +126,7 @@ if current_adapter?(:PostgreSQLAdapter) def test_when_database_dropped_successfully_outputs_info_to_stdout ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal $stdout.string, "Dropped database 'my-app-db'\n" + assert_equal "Dropped database 'my-app-db'\n", $stdout.string end end @@ -236,6 +236,16 @@ if current_adapter?(:PostgreSQLAdapter) ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) end + def test_structure_dump_with_extra_flags + expected_command = ["pg_dump", "-s", "-x", "-O", "-f", @filename, "--noop", "my-app-db"] + + assert_called_with(Kernel, :system, expected_command, returns: true) do + with_structure_dump_flags(["--noop"]) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + end + end + end + def test_structure_dump_with_schema_search_path @configuration["schema_search_path"] = "foo,bar" @@ -263,7 +273,6 @@ if current_adapter?(:PostgreSQLAdapter) end private - def with_dump_schemas(value, &block) old_dump_schemas = ActiveRecord::Base.dump_schemas ActiveRecord::Base.dump_schemas = value @@ -271,6 +280,14 @@ if current_adapter?(:PostgreSQLAdapter) ensure ActiveRecord::Base.dump_schemas = old_dump_schemas end + + def with_structure_dump_flags(flags) + old = ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags + ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = flags + yield + ensure + ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = old + end end class PostgreSQLStructureLoadTest < ActiveRecord::TestCase @@ -293,12 +310,32 @@ if current_adapter?(:PostgreSQLAdapter) ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) end + def test_structure_load_with_extra_flags + filename = "awesome-file.sql" + expected_command = ["psql", "-v", "ON_ERROR_STOP=1", "-q", "-f", filename, "--noop", @configuration["database"]] + + assert_called_with(Kernel, :system, expected_command, returns: true) do + with_structure_load_flags(["--noop"]) do + ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + end + end + end + def test_structure_load_accepts_path_with_spaces filename = "awesome file.sql" Kernel.expects(:system).with("psql", "-v", "ON_ERROR_STOP=1", "-q", "-f", filename, @configuration["database"]).returns(true) ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) end + + private + def with_structure_load_flags(flags) + old = ActiveRecord::Tasks::DatabaseTasks.structure_load_flags + ActiveRecord::Tasks::DatabaseTasks.structure_load_flags = flags + yield + ensure + ActiveRecord::Tasks::DatabaseTasks.structure_load_flags = old + end end end end diff --git a/activerecord/test/cases/tasks/sqlite_rake_test.rb b/activerecord/test/cases/tasks/sqlite_rake_test.rb index 141048bfe7..0d917f3f6c 100644 --- a/activerecord/test/cases/tasks/sqlite_rake_test.rb +++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb @@ -34,7 +34,7 @@ if current_adapter?(:SQLite3Adapter) def test_when_db_created_successfully_outputs_info_to_stdout ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal $stdout.string, "Created database '#{@database}'\n" + assert_equal "Created database '#{@database}'\n", $stdout.string end def test_db_create_when_file_exists @@ -42,7 +42,7 @@ if current_adapter?(:SQLite3Adapter) ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal $stderr.string, "Database '#{@database}' already exists\n" + assert_equal "Database '#{@database}' already exists\n", $stderr.string end def test_db_create_with_file_does_nothing @@ -128,7 +128,7 @@ if current_adapter?(:SQLite3Adapter) def test_when_db_dropped_successfully_outputs_info_to_stdout ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" - assert_equal $stdout.string, "Dropped database '#{@database}'\n" + assert_equal "Dropped database '#{@database}'\n", $stdout.string end end diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index b4f5226f2b..31b11c19f7 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -1,13 +1,28 @@ require "active_support/test_case" +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" require "active_support/testing/stream" -require "active_support/core_ext/regexp" +require "active_record/fixtures" + +require "cases/validations_repair_helper" module ActiveRecord # = Active Record Test Case # # Defines some test assertions to test against SQL queries. class TestCase < ActiveSupport::TestCase #:nodoc: + include ActiveSupport::Testing::MethodCallAssertions include ActiveSupport::Testing::Stream + include ActiveRecord::TestFixtures + include ActiveRecord::ValidationsRepairHelper + + self.fixture_path = FIXTURES_ROOT + self.use_instantiated_fixtures = false + self.use_transactional_tests = true + + def create_fixtures(*fixture_set_names, &block) + ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block) + end def teardown SQLCounter.clear_log @@ -24,7 +39,7 @@ module ActiveRecord ensure failed_patterns = [] patterns_to_match.each do |pattern| - failed_patterns << pattern unless SQLCounter.log_all.any?{ |sql| pattern === sql } + failed_patterns << pattern unless SQLCounter.log_all.any? { |sql| pattern === sql } end assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}" end @@ -48,11 +63,11 @@ module ActiveRecord assert_queries(0, options, &block) end - def assert_column(model, column_name, msg=nil) + def assert_column(model, column_name, msg = nil) assert has_column?(model, column_name), msg end - def assert_no_column(model, column_name, msg=nil) + def assert_no_column(model, column_name, msg = nil) assert_not has_column?(model, column_name), msg end @@ -109,12 +124,9 @@ module ActiveRecord end def call(name, start, finish, message_id, values) - sql = values[:sql] - - # FIXME: this seems bad. we should probably have a better way to indicate - # the query was cached - return if "CACHE" == values[:name] + return if values[:cached] + sql = values[:sql] self.class.log_all << sql self.class.log << sql unless ignore.match?(sql) end diff --git a/activerecord/test/cases/test_fixtures_test.rb b/activerecord/test/cases/test_fixtures_test.rb index 14a5faa85e..58d3bea3a2 100644 --- a/activerecord/test/cases/test_fixtures_test.rb +++ b/activerecord/test/cases/test_fixtures_test.rb @@ -3,28 +3,10 @@ require "cases/helper" class TestFixturesTest < ActiveRecord::TestCase setup do @klass = Class.new - @klass.send(:include, ActiveRecord::TestFixtures) - end - - def test_deprecated_use_transactional_fixtures= - assert_deprecated "use use_transactional_tests= instead" do - @klass.use_transactional_fixtures = true - end - end - - def test_use_transactional_tests_prefers_use_transactional_fixtures - ActiveSupport::Deprecation.silence do - @klass.use_transactional_fixtures = false - end - - assert_equal false, @klass.use_transactional_tests + @klass.include(ActiveRecord::TestFixtures) end def test_use_transactional_tests_defaults_to_true - ActiveSupport::Deprecation.silence do - @klass.use_transactional_fixtures = nil - end - assert_equal true, @klass.use_transactional_tests end diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index 519d9db601..7766a74612 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -430,39 +430,24 @@ class TimestampTest < ActiveRecord::TestCase assert_not_equal person.born_at, nil end - def test_timestamp_attributes_for_create - toy = Toy.first - assert_equal [:created_at, :created_on], toy.send(:timestamp_attributes_for_create) - end - - def test_timestamp_attributes_for_update - toy = Toy.first - assert_equal [:updated_at, :updated_on], toy.send(:timestamp_attributes_for_update) - end - - def test_all_timestamp_attributes - toy = Toy.first - assert_equal [:created_at, :created_on, :updated_at, :updated_on], toy.send(:all_timestamp_attributes) - end - def test_timestamp_attributes_for_create_in_model toy = Toy.first - assert_equal [:created_at], toy.send(:timestamp_attributes_for_create_in_model) + assert_equal ["created_at"], toy.send(:timestamp_attributes_for_create_in_model) end def test_timestamp_attributes_for_update_in_model toy = Toy.first - assert_equal [:updated_at], toy.send(:timestamp_attributes_for_update_in_model) + assert_equal ["updated_at"], toy.send(:timestamp_attributes_for_update_in_model) end def test_all_timestamp_attributes_in_model toy = Toy.first - assert_equal [:created_at, :updated_at], toy.send(:all_timestamp_attributes_in_model) + assert_equal ["created_at", "updated_at"], toy.send(:all_timestamp_attributes_in_model) end def test_index_is_created_for_both_timestamps ActiveRecord::Base.connection.create_table(:foos, force: true) do |t| - t.timestamps(:foos, null: true, index: true) + t.timestamps null: true, index: true end indexes = ActiveRecord::Base.connection.indexes("foos") diff --git a/activerecord/test/cases/touch_later_test.rb b/activerecord/test/cases/touch_later_test.rb index 697447a4f3..d1e8c649d9 100644 --- a/activerecord/test/cases/touch_later_test.rb +++ b/activerecord/test/cases/touch_later_test.rb @@ -24,6 +24,15 @@ class TouchLaterTest < ActiveRecord::TestCase assert_not invoice.changed? end + def test_touch_later_respects_no_touching_policy + time = Time.now.utc - 25.days + topic = Topic.create!(updated_at: time, created_at: time) + Topic.no_touching do + topic.touch_later + end + assert_equal time.to_i, topic.updated_at.to_i + end + def test_touch_later_update_the_attributes time = Time.now.utc - 25.days topic = Topic.create!(updated_at: time, created_at: time) diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 6a7d48871c..391bbe8877 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -68,17 +68,17 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def do_before_commit(on) blocks = @before_commit[on] if defined?(@before_commit) - blocks.each{|b| b.call(self)} if blocks + blocks.each { |b| b.call(self) } if blocks end def do_after_commit(on) blocks = @after_commit[on] if defined?(@after_commit) - blocks.each{|b| b.call(self)} if blocks + blocks.each { |b| b.call(self) } if blocks end def do_after_rollback(on) blocks = @after_rollback[on] if defined?(@after_rollback) - blocks.each{|b| b.call(self)} if blocks + blocks.each { |b| b.call(self) } if blocks end end @@ -101,8 +101,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_call_after_commit_after_transaction_commits - @first.after_commit_block{|r| r.history << :after_commit} - @first.after_rollback_block{|r| r.history << :after_rollback} + @first.after_commit_block { |r| r.history << :after_commit } + @first.after_rollback_block { |r| r.history << :after_rollback } @first.save! assert_equal [:after_commit], @first.history @@ -155,7 +155,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_commit_on_top_level_transactions - @first.after_commit_block{|r| r.history << :after_commit} + @first.after_commit_block { |r| r.history << :after_commit } assert @first.history.empty? @first.transaction do @@ -168,8 +168,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_call_after_rollback_after_transaction_rollsback - @first.after_commit_block{|r| r.history << :after_commit} - @first.after_rollback_block{|r| r.history << :after_rollback} + @first.after_commit_block { |r| r.history << :after_commit } + @first.after_rollback_block { |r| r.history << :after_rollback } Topic.transaction do @first.save! @@ -243,16 +243,16 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint - def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end - def @first.commits(i=0); @commits ||= 0; @commits += i if i; end - @first.after_rollback_block{|r| r.rollbacks(1)} - @first.after_commit_block{|r| r.commits(1)} + def @first.rollbacks(i = 0); @rollbacks ||= 0; @rollbacks += i if i; end + def @first.commits(i = 0); @commits ||= 0; @commits += i if i; end + @first.after_rollback_block { |r| r.rollbacks(1) } + @first.after_commit_block { |r| r.commits(1) } second = TopicWithCallbacks.find(3) - def second.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end - def second.commits(i=0); @commits ||= 0; @commits += i if i; end - second.after_rollback_block{|r| r.rollbacks(1)} - second.after_commit_block{|r| r.commits(1)} + def second.rollbacks(i = 0); @rollbacks ||= 0; @rollbacks += i if i; end + def second.commits(i = 0); @commits ||= 0; @commits += i if i; end + second.after_rollback_block { |r| r.rollbacks(1) } + second.after_commit_block { |r| r.commits(1) } Topic.transaction do @first.save! @@ -269,11 +269,11 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails - def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end - def @first.commits(i=0); @commits ||= 0; @commits += i if i; end + def @first.rollbacks(i = 0); @rollbacks ||= 0; @rollbacks += i if i; end + def @first.commits(i = 0); @commits ||= 0; @commits += i if i; end - @first.after_rollback_block{|r| r.rollbacks(1)} - @first.after_commit_block{|r| r.commits(1)} + @first.after_rollback_block { |r| r.rollbacks(1) } + @first.after_commit_block { |r| r.commits(1) } Topic.transaction do @first.save @@ -292,7 +292,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_after_commit_callback_should_not_swallow_errors - @first.after_commit_block{ fail "boom" } + @first.after_commit_block { fail "boom" } assert_raises(RuntimeError) do Topic.transaction do @first.save! @@ -303,8 +303,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def test_after_commit_callback_when_raise_should_not_restore_state first = TopicWithCallbacks.new second = TopicWithCallbacks.new - first.after_commit_block{ fail "boom" } - second.after_commit_block{ fail "boom" } + first.after_commit_block { fail "boom" } + second.after_commit_block { fail "boom" } begin Topic.transaction do @@ -322,7 +322,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def test_after_rollback_callback_should_not_swallow_errors_when_set_to_raise error_class = Class.new(StandardError) - @first.after_rollback_block{ raise error_class } + @first.after_rollback_block { raise error_class } assert_raises(error_class) do Topic.transaction do @first.save! @@ -336,8 +336,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase first = TopicWithCallbacks.new second = TopicWithCallbacks.new - first.after_rollback_block{ raise error_class } - second.after_rollback_block{ raise error_class } + first.after_rollback_block { raise error_class } + second.after_rollback_block { raise error_class } begin Topic.transaction do @@ -449,6 +449,51 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase end end +class CallbacksOnDestroyUpdateActionRaceTest < ActiveRecord::TestCase + class TopicWithHistory < ActiveRecord::Base + self.table_name = :topics + + def self.clear_history + @@history = [] + end + + def self.history + @@history ||= [] + end + end + + class TopicWithCallbacksOnDestroy < TopicWithHistory + after_commit(on: :destroy) { |record| record.class.history << :destroy } + end + + class TopicWithCallbacksOnUpdate < TopicWithHistory + after_commit(on: :update) { |record| record.class.history << :update } + end + + def test_trigger_once_on_multiple_deletions + TopicWithCallbacksOnDestroy.clear_history + topic = TopicWithCallbacksOnDestroy.new + topic.save + topic_clone = TopicWithCallbacksOnDestroy.find(topic.id) + topic.destroy + topic_clone.destroy + + assert_equal [:destroy], TopicWithCallbacksOnDestroy.history + end + + def test_trigger_on_update_where_row_was_deleted + TopicWithCallbacksOnUpdate.clear_history + topic = TopicWithCallbacksOnUpdate.new + topic.save + topic_clone = TopicWithCallbacksOnUpdate.find(topic.id) + topic.destroy + topic_clone.author_name = "Test Author" + topic_clone.save + + assert_equal [], TopicWithCallbacksOnUpdate.history + end +end + class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase class TopicWithoutTransactionalEnrollmentCallbacks < ActiveRecord::Base self.table_name = :topics diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb index f177f0644a..58abfadaf4 100644 --- a/activerecord/test/cases/transaction_isolation_test.rb +++ b/activerecord/test/cases/transaction_isolation_test.rb @@ -9,7 +9,7 @@ unless ActiveRecord::Base.connection.supports_transaction_isolation? test "setting the isolation level raises an error" do assert_raises(ActiveRecord::TransactionIsolationError) do - Tag.transaction(isolation: :serializable) { } + Tag.transaction(isolation: :serializable) {} end end end @@ -90,7 +90,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? test "setting isolation when joining a transaction raises an error" do Tag.transaction do assert_raises(ActiveRecord::TransactionIsolationError) do - Tag.transaction(isolation: :serializable) { } + Tag.transaction(isolation: :serializable) {} end end end @@ -98,7 +98,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? test "setting isolation when starting a nested transaction raises error" do Tag.transaction do assert_raises(ActiveRecord::TransactionIsolationError) do - Tag.transaction(requires_new: true, isolation: :serializable) { } + Tag.transaction(requires_new: true, isolation: :serializable) {} end end end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index c8963ada63..9b1cca8583 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -98,7 +98,7 @@ class TransactionTest < ActiveRecord::TestCase end Topic.transaction do - @first.approved = true + @first.approved = true @first.save! end @@ -160,7 +160,7 @@ class TransactionTest < ActiveRecord::TestCase assert !@first.approved Topic.transaction do - @first.approved = true + @first.approved = true @first.save! end assert !Topic.find(@first.id).approved?, "Should not commit the approved flag" @@ -443,16 +443,16 @@ class TransactionTest < ActiveRecord::TestCase def test_using_named_savepoints Topic.transaction do - @first.approved = true + @first.approved = true @first.save! Topic.connection.create_savepoint("first") - @first.approved = false + @first.approved = false @first.save! Topic.connection.rollback_to_savepoint("first") assert @first.reload.approved? - @first.approved = false + @first.approved = false @first.save! Topic.connection.release_savepoint("first") assert_not @first.reload.approved? @@ -493,7 +493,7 @@ class TransactionTest < ActiveRecord::TestCase def test_rollback_when_commit_raises assert_called(Topic.connection, :begin_db_transaction) do - Topic.connection.stub(:commit_db_transaction, ->{ raise("OH NOES") }) do + Topic.connection.stub(:commit_db_transaction, -> { raise("OH NOES") }) do assert_called(Topic.connection, :rollback_db_transaction) do e = assert_raise RuntimeError do @@ -511,9 +511,10 @@ class TransactionTest < ActiveRecord::TestCase topic = Topic.new(title: "test") topic.freeze e = assert_raise(RuntimeError) { topic.save } - assert_match(/frozen/i, e.message) # Not good enough, but we can't do much - # about it since there is no specific error - # for frozen objects. + # Not good enough, but we can't do much + # about it since there is no specific error + # for frozen objects. + assert_match(/frozen/i, e.message) assert !topic.persisted?, "not persisted" assert_nil topic.id assert topic.frozen?, "not frozen" @@ -630,11 +631,11 @@ class TransactionTest < ActiveRecord::TestCase assert_nothing_raised do Topic.reset_column_information Topic.connection.add_column("topics", "stuff", :string) - assert Topic.column_names.include?("stuff") + assert_includes Topic.column_names, "stuff" Topic.reset_column_information Topic.connection.remove_column("topics", "stuff") - assert !Topic.column_names.include?("stuff") + assert_not_includes Topic.column_names, "stuff" end if Topic.connection.supports_ddl_transactions? @@ -692,7 +693,7 @@ class TransactionTest < ActiveRecord::TestCase klass = Class.new(ActiveRecord::Base) do self.table_name = "transaction_without_primary_keys" - after_commit { } # necessary to trigger the has_transactional_callbacks branch + after_commit {} # necessary to trigger the has_transactional_callbacks branch end assert_no_difference(-> { klass.count }) do diff --git a/activerecord/test/cases/type/date_time_test.rb b/activerecord/test/cases/type/date_time_test.rb index bc4900e1c2..6848619ece 100644 --- a/activerecord/test/cases/type/date_time_test.rb +++ b/activerecord/test/cases/type/date_time_test.rb @@ -3,7 +3,7 @@ require "models/task" module ActiveRecord module Type - class IntegerTest < ActiveRecord::TestCase + class DateTimeTest < ActiveRecord::TestCase def test_datetime_seconds_precision_applied_to_timestamp skip "This test is invalid if subsecond precision isn't supported" unless subsecond_precision_supported? p = Task.create!(starting: ::Time.now) diff --git a/activerecord/test/cases/type/unsigned_integer_test.rb b/activerecord/test/cases/type/unsigned_integer_test.rb new file mode 100644 index 0000000000..1cd4dbc2c5 --- /dev/null +++ b/activerecord/test/cases/type/unsigned_integer_test.rb @@ -0,0 +1,17 @@ +require "cases/helper" + +module ActiveRecord + module Type + class UnsignedIntegerTest < ActiveRecord::TestCase + test "unsigned int max value is in range" do + assert_equal(4294967295, UnsignedInteger.new.serialize(4294967295)) + end + + test "minus value is out of range" do + assert_raises(ActiveModel::RangeError) do + UnsignedInteger.new.serialize(-1) + end + end + end + end +end diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb index 66d6ecb928..f5ceb27d97 100644 --- a/activerecord/test/cases/validations/association_validation_test.rb +++ b/activerecord/test/cases/validations/association_validation_test.rb @@ -26,7 +26,7 @@ class AssociationValidationTest < ActiveRecord::TestCase def test_validates_associated_one Reply.validates :topic, associated: true - Topic.validates_presence_of( :content ) + Topic.validates_presence_of(:content) r = Reply.new("title" => "A reply", "content" => "with content!") r.topic = Topic.create("title" => "uhohuhoh") assert !r.valid? diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb index d73d287073..a57065ba75 100644 --- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb @@ -47,7 +47,7 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase test "RecordInvalid exception translation falls back to the :errors namespace" do reset_i18n_load_path do - I18n.backend.store_translations "en", errors: {messages: {record_invalid: "fallback message"}} + I18n.backend.store_translations "en", errors: { messages: { record_invalid: "fallback message" } } topic = Topic.new topic.errors.add(:title, :blank) assert_equal "fallback message", ActiveRecord::RecordInvalid.new(topic).message @@ -56,28 +56,28 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase test "translation for 'taken' can be overridden" do reset_i18n_load_path do - I18n.backend.store_translations "en", errors: {attributes: {title: {taken: "Custom taken message" }}} + I18n.backend.store_translations "en", errors: { attributes: { title: { taken: "Custom taken message" } } } assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end test "translation for 'taken' can be overridden in activerecord scope" do reset_i18n_load_path do - I18n.backend.store_translations "en", activerecord: {errors: {messages: {taken: "Custom taken message" }}} + I18n.backend.store_translations "en", activerecord: { errors: { messages: { taken: "Custom taken message" } } } assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end test "translation for 'taken' can be overridden in activerecord model scope" do reset_i18n_load_path do - I18n.backend.store_translations "en", activerecord: {errors: {models: {topic: {taken: "Custom taken message" }}}} + I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { taken: "Custom taken message" } } } } assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end test "translation for 'taken' can be overridden in activerecord attributes scope" do reset_i18n_load_path do - I18n.backend.store_translations "en", activerecord: {errors: {models: {topic: {attributes: {title: {taken: "Custom taken message" }}}}}} + I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { attributes: { title: { taken: "Custom taken message" } } } } } } assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index cbb5362f3f..fd88a3ea67 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -12,7 +12,7 @@ class I18nValidationTest < ActiveRecord::TestCase @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations("en", errors: {messages: {custom: nil}}) + I18n.backend.store_translations("en", errors: { messages: { custom: nil } }) end teardown do @@ -36,13 +36,13 @@ class I18nValidationTest < ActiveRecord::TestCase # are used to generate tests to keep things DRY # COMMON_CASES = [ - # [ case, validation_options, generate_message_options] + # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], - [ "given custom message", {message: "custom"}, {message: "custom"}], - [ "given if condition", {if: lambda { true }}, {}], - [ "given unless condition", {unless: lambda { false }}, {}], - [ "given option that is not reserved", {format: "jpg"}, {format: "jpg" }], - [ "given on condition", {on: [:create, :update] }, {}] + [ "given custom message", { message: "custom" }, { message: "custom" }], + [ "given if condition", { if: lambda { true } }, {}], + [ "given unless condition", { unless: lambda { false } }, {}], + [ "given option that is not reserved", { format: "jpg" }, { format: "jpg" }], + [ "given on condition", { on: [:create, :update] }, {}] ] COMMON_CASES.each do |name, validation_options, generate_message_options| @@ -65,8 +65,8 @@ class I18nValidationTest < ActiveRecord::TestCase end def test_validates_associated_finds_custom_model_key_translation - I18n.backend.store_translations "en", activerecord: {errors: {models: {topic: {attributes: {replies: {invalid: "custom message"}}}}}} - I18n.backend.store_translations "en", activerecord: {errors: {messages: {invalid: "global message"}}} + I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { attributes: { replies: { invalid: "custom message" } } } } } } + I18n.backend.store_translations "en", activerecord: { errors: { messages: { invalid: "global message" } } } Topic.validates_associated :replies replied_topic.valid? @@ -74,7 +74,7 @@ class I18nValidationTest < ActiveRecord::TestCase end def test_validates_associated_finds_global_default_translation - I18n.backend.store_translations "en", activerecord: {errors: {messages: {invalid: "global message"}}} + I18n.backend.store_translations "en", activerecord: { errors: { messages: { invalid: "global message" } } } Topic.validates_associated :replies replied_topic.valid? diff --git a/activerecord/test/cases/validations/length_validation_test.rb b/activerecord/test/cases/validations/length_validation_test.rb index 4fcb3e2eb6..ba45c6dcc1 100644 --- a/activerecord/test/cases/validations/length_validation_test.rb +++ b/activerecord/test/cases/validations/length_validation_test.rb @@ -54,7 +54,7 @@ class LengthValidationTest < ActiveRecord::TestCase assert owner.save pet_count = Pet.count - assert_not owner.update_attributes pets_attributes: [ {_destroy: 1, id: pet.id} ] + assert_not owner.update_attributes pets_attributes: [ { _destroy: 1, id: pet.id } ] assert_not owner.valid? assert owner.errors[:pets].any? assert_equal pet_count, Pet.count diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 44b4e28777..6d22638592 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -6,6 +6,9 @@ require "models/guid" require "models/event" require "models/dashboard" require "models/uuid_item" +require "models/author" +require "models/person" +require "models/essay" class Wizard < ActiveRecord::Base self.abstract_class = true @@ -163,6 +166,19 @@ class UniquenessValidationTest < ActiveRecord::TestCase assert !r2.valid?, "Saving r2 first time" end + def test_validate_uniqueness_with_polymorphic_object_scope + Essay.validates_uniqueness_of(:name, scope: :writer) + + a = Author.create(name: "Sergey") + p = Person.create(first_name: "Sergey") + + e1 = a.essays.create(name: "Essay") + assert e1.valid?, "Saving e1" + + e2 = p.essays.create(name: "Essay") + assert e2.valid?, "Saving e2" + end + def test_validate_uniqueness_with_composed_attribute_scope r1 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world" assert r1.valid?, "Saving r1" diff --git a/activerecord/test/cases/view_test.rb b/activerecord/test/cases/view_test.rb index 5f85c5ff8b..d055968a56 100644 --- a/activerecord/test/cases/view_test.rb +++ b/activerecord/test/cases/view_test.rb @@ -11,20 +11,21 @@ module ViewBehavior end class Ebook < ActiveRecord::Base + self.table_name = "ebooks'" self.primary_key = "id" end def setup super @connection = ActiveRecord::Base.connection - create_view "ebooks", <<-SQL + create_view "ebooks'", <<-SQL SELECT id, name, status FROM books WHERE format = 'ebook' SQL end def teardown super - drop_view "ebooks" + drop_view "ebooks'" end def test_reading @@ -44,8 +45,7 @@ module ViewBehavior def test_table_exists view_name = Ebook.table_name - # TODO: switch this assertion around once we changed #tables to not return views. - ActiveSupport::Deprecation.silence { assert @connection.table_exists?(view_name), "'#{view_name}' table should exist" } + assert_not @connection.table_exists?(view_name), "'#{view_name}' table should not exist" end def test_views_ara_valid_data_sources @@ -60,21 +60,26 @@ module ViewBehavior end def test_attributes - assert_equal({"id" => 2, "name" => "Ruby for Rails", "status" => 0}, + assert_equal({ "id" => 2, "name" => "Ruby for Rails", "status" => 0 }, Ebook.first.attributes) end def test_does_not_assume_id_column_as_primary_key model = Class.new(ActiveRecord::Base) do - self.table_name = "ebooks" + self.table_name = "ebooks'" end assert_nil model.primary_key end def test_does_not_dump_view_as_table - schema = dump_table_schema "ebooks" - assert_no_match %r{create_table "ebooks"}, schema + schema = dump_table_schema "ebooks'" + assert_no_match %r{create_table "ebooks'"}, schema end + + private + def quote_table_name(name) + @connection.quote_table_name(name) + end end if ActiveRecord::Base.connection.supports_views? @@ -83,11 +88,11 @@ if ActiveRecord::Base.connection.supports_views? private def create_view(name, query) - @connection.execute "CREATE VIEW #{name} AS #{query}" + @connection.execute "CREATE VIEW #{quote_table_name(name)} AS #{query}" end def drop_view(name) - @connection.execute "DROP VIEW #{name}" if @connection.view_exists? name + @connection.execute "DROP VIEW #{quote_table_name(name)}" if @connection.view_exists? name end end @@ -100,9 +105,9 @@ if ActiveRecord::Base.connection.supports_views? setup do @connection = ActiveRecord::Base.connection @connection.execute <<-SQL - CREATE VIEW paperbacks - AS SELECT name, status FROM books WHERE format = 'paperback' - SQL + CREATE VIEW paperbacks + AS SELECT name, status FROM books WHERE format = 'paperback' + SQL end teardown do @@ -125,8 +130,7 @@ if ActiveRecord::Base.connection.supports_views? def test_table_exists view_name = Paperback.table_name - # TODO: switch this assertion around once we changed #tables to not return views. - ActiveSupport::Deprecation.silence { assert @connection.table_exists?(view_name), "'#{view_name}' table should exist" } + assert_not @connection.table_exists?(view_name), "'#{view_name}' table should not exist" end def test_column_definitions @@ -135,7 +139,7 @@ if ActiveRecord::Base.connection.supports_views? end def test_attributes - assert_equal({"name" => "Agile Web Development with Rails", "status" => 2}, + assert_equal({ "name" => "Agile Web Development with Rails", "status" => 2 }, Paperback.first.attributes) end @@ -149,7 +153,7 @@ if ActiveRecord::Base.connection.supports_views? end end -# sqlite dose not support CREATE, INSERT, and DELETE for VIEW + # sqlite dose not support CREATE, INSERT, and DELETE for VIEW if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) class UpdateableViewTest < ActiveRecord::TestCase self.use_transactional_tests = false @@ -162,9 +166,9 @@ if ActiveRecord::Base.connection.supports_views? setup do @connection = ActiveRecord::Base.connection @connection.execute <<-SQL - CREATE VIEW printed_books - AS SELECT id, name, status, format FROM books WHERE format = 'paperback' - SQL + CREATE VIEW printed_books + AS SELECT id, name, status, format FROM books WHERE format = 'paperback' + SQL end teardown do @@ -196,8 +200,8 @@ if ActiveRecord::Base.connection.supports_views? end end end - end # end fo `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)` -end # end fo `if ActiveRecord::Base.connection.supports_views?` + end # end of `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)` +end # end of `if ActiveRecord::Base.connection.supports_views?` if ActiveRecord::Base.connection.respond_to?(:supports_materialized_views?) && ActiveRecord::Base.connection.supports_materialized_views? @@ -206,11 +210,11 @@ if ActiveRecord::Base.connection.respond_to?(:supports_materialized_views?) && private def create_view(name, query) - @connection.execute "CREATE MATERIALIZED VIEW #{name} AS #{query}" + @connection.execute "CREATE MATERIALIZED VIEW #{quote_table_name(name)} AS #{query}" end def drop_view(name) - @connection.execute "DROP MATERIALIZED VIEW #{name}" if @connection.view_exists? name + @connection.execute "DROP MATERIALIZED VIEW #{quote_table_name(name)}" if @connection.view_exists? name end end end diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb index ade6e6095b..1571b31329 100644 --- a/activerecord/test/cases/yaml_serialization_test.rb +++ b/activerecord/test/cases/yaml_serialization_test.rb @@ -22,8 +22,8 @@ class YamlSerializationTest < ActiveRecord::TestCase end def test_roundtrip_serialized_column - topic = Topic.new(content: {omg: :lol}) - assert_equal({omg: :lol}, YAML.load(YAML.dump(topic)).content) + topic = Topic.new(content: { omg: :lol }) + assert_equal({ omg: :lol }, YAML.load(YAML.dump(topic)).content) end def test_psych_roundtrip @@ -95,7 +95,7 @@ class YamlSerializationTest < ActiveRecord::TestCase topic = YAML.load(yaml_fixture("rails_4_1")) assert topic.new_record? - assert_equal nil, topic.id + assert_nil topic.id assert_equal "The First Topic", topic.title assert_equal({ omg: :lol }, topic.content) end |