diff options
Diffstat (limited to 'activerecord/test')
39 files changed, 1328 insertions, 672 deletions
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 79642f5871..59b99351d1 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -304,6 +304,8 @@ module ActiveRecord class AdapterForeignKeyTest < ActiveRecord::TestCase self.use_transactional_tests = false + fixtures :fk_test_has_pk + def setup @connection = ActiveRecord::Base.connection end @@ -322,7 +324,7 @@ module ActiveRecord assert_not_nil error.cause end - def test_foreign_key_violations_are_translated_to_specific_exception + def test_foreign_key_violations_on_insert_are_translated_to_specific_exception error = assert_raises(ActiveRecord::InvalidForeignKey) do insert_into_fk_test_has_fk end @@ -330,6 +332,16 @@ module ActiveRecord assert_not_nil error.cause end + def test_foreign_key_violations_on_delete_are_translated_to_specific_exception + insert_into_fk_test_has_fk fk_id: 1 + + error = assert_raises(ActiveRecord::InvalidForeignKey) do + @connection.execute "DELETE FROM fk_test_has_pk WHERE pk_id = 1" + end + + assert_not_nil error.cause + end + def test_disable_referential_integrity assert_nothing_raised do @connection.disable_referential_integrity do @@ -342,14 +354,13 @@ module ActiveRecord end private - - def insert_into_fk_test_has_fk + def insert_into_fk_test_has_fk(fk_id: 0) # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method if @connection.prefetch_primary_key? id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id")) - @connection.execute "INSERT INTO fk_test_has_fk (id,fk_id) VALUES (#{id_value},0)" + @connection.execute "INSERT INTO fk_test_has_fk (id,fk_id) VALUES (#{id_value},#{fk_id})" else - @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)" + @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (#{fk_id})" end end end diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 976c5dde58..6fc9df5083 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -157,15 +157,19 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase end def test_indexes_in_create - ActiveRecord::Base.connection.stubs(:data_source_exists?).with(:temp).returns(false) - ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false) + assert_called_with( + ActiveRecord::Base.connection, + :data_source_exists?, + [:temp], + returns: false + ) do + expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`)) AS SELECT id, name, zip FROM a_really_complicated_query" + actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| + t.index :zip + end - expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`)) AS SELECT id, name, zip FROM a_really_complicated_query" - actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t| - t.index :zip + assert_equal expected, actual end - - assert_equal expected, actual end private diff --git a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb index fa54f39992..00a075e063 100644 --- a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +++ b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb @@ -45,9 +45,10 @@ class Mysql2DatetimePrecisionQuotingTest < ActiveRecord::Mysql2TestCase end def stub_version(full_version_string) - @connection.stubs(:full_version).returns(full_version_string) - @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) - yield + @connection.stub(:full_version, full_version_string) do + @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) + yield + end ensure @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) end diff --git a/activerecord/test/cases/adapters/postgresql/partitions_test.rb b/activerecord/test/cases/adapters/postgresql/partitions_test.rb new file mode 100644 index 0000000000..0ac9ca1200 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/partitions_test.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "cases/helper" + +class PostgreSQLPartitionsTest < ActiveRecord::PostgreSQLTestCase + def setup + @connection = ActiveRecord::Base.connection + end + + def teardown + @connection.drop_table "partitioned_events", if_exists: true + end + + def test_partitions_table_exists + skip unless ActiveRecord::Base.connection.postgresql_version >= 100000 + @connection.create_table :partitioned_events, force: true, id: false, + options: "partition by range (issued_at)" do |t| + t.timestamp :issued_at + end + assert @connection.table_exists?("partitioned_events") + end +end diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb index 1c85ff5674..40b58e86bf 100644 --- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb @@ -62,4 +62,30 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase assert_equal "'2000-01-01 12:30:00.999999'", @conn.quote(type.serialize(value)) end + + def test_quoted_time_dst_utc + with_env_tz "America/New_York" do + with_timezone_config default: :utc do + t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30") + + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getutc.to_s(:db).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ") + + assert_equal expected, @conn.quoted_time(t) + end + end + end + + def test_quoted_time_dst_local + with_env_tz "America/New_York" do + with_timezone_config default: :local do + t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30") + + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getlocal.to_s(:db).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ") + + assert_equal expected, @conn.quoted_time(t) + end + end + end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index ad155c7492..d1d4d545a3 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -504,6 +504,39 @@ module ActiveRecord assert_deprecated { @conn.valid_alter_table_type?(:string) } end + def test_db_is_not_readonly_when_readonly_option_is_false + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + readonly: false + + assert_not_predicate conn.raw_connection, :readonly? + end + + def test_db_is_not_readonly_when_readonly_option_is_unspecified + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3" + + assert_not_predicate conn.raw_connection, :readonly? + end + + def test_db_is_readonly_when_readonly_option_is_true + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + readonly: true + + assert_predicate conn.raw_connection, :readonly? + end + + def test_writes_are_not_permitted_to_readonly_databases + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + readonly: true + + assert_raises(ActiveRecord::StatementInvalid, /SQLite3::ReadOnlyException/) do + conn.execute("CREATE TABLE test(id integer)") + end + end + private def assert_logged(logs) diff --git a/activerecord/test/cases/arel/attributes/math_test.rb b/activerecord/test/cases/arel/attributes/math_test.rb index f3aabe4f60..41eea217c0 100644 --- a/activerecord/test/cases/arel/attributes/math_test.rb +++ b/activerecord/test/cases/arel/attributes/math_test.rb @@ -6,35 +6,35 @@ module Arel module Attributes class MathTest < Arel::Spec %i[* /].each do |math_operator| - it "average should be compatiable with #{math_operator}" do + it "average should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].average.public_send(math_operator, 2)).to_sql.must_be_like %{ AVG("users"."id") #{math_operator} 2 } end - it "count should be compatiable with #{math_operator}" do + it "count should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].count.public_send(math_operator, 2)).to_sql.must_be_like %{ COUNT("users"."id") #{math_operator} 2 } end - it "maximum should be compatiable with #{math_operator}" do + it "maximum should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].maximum.public_send(math_operator, 2)).to_sql.must_be_like %{ MAX("users"."id") #{math_operator} 2 } end - it "minimum should be compatiable with #{math_operator}" do + it "minimum should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].minimum.public_send(math_operator, 2)).to_sql.must_be_like %{ MIN("users"."id") #{math_operator} 2 } end - it "attribute node should be compatiable with #{math_operator}" do + it "attribute node should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].public_send(math_operator, 2)).to_sql.must_be_like %{ "users"."id" #{math_operator} 2 @@ -43,35 +43,35 @@ module Arel end %i[+ - & | ^ << >>].each do |math_operator| - it "average should be compatiable with #{math_operator}" do + it "average should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].average.public_send(math_operator, 2)).to_sql.must_be_like %{ (AVG("users"."id") #{math_operator} 2) } end - it "count should be compatiable with #{math_operator}" do + it "count should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].count.public_send(math_operator, 2)).to_sql.must_be_like %{ (COUNT("users"."id") #{math_operator} 2) } end - it "maximum should be compatiable with #{math_operator}" do + it "maximum should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].maximum.public_send(math_operator, 2)).to_sql.must_be_like %{ (MAX("users"."id") #{math_operator} 2) } end - it "minimum should be compatiable with #{math_operator}" do + it "minimum should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].minimum.public_send(math_operator, 2)).to_sql.must_be_like %{ (MIN("users"."id") #{math_operator} 2) } end - it "attribute node should be compatiable with #{math_operator}" do + it "attribute node should be compatible with #{math_operator}" do table = Arel::Table.new :users (table[:id].public_send(math_operator, 2)).to_sql.must_be_like %{ ("users"."id" #{math_operator} 2) diff --git a/activerecord/test/cases/arel/insert_manager_test.rb b/activerecord/test/cases/arel/insert_manager_test.rb index ae10ccf56c..2376ad8d37 100644 --- a/activerecord/test/cases/arel/insert_manager_test.rb +++ b/activerecord/test/cases/arel/insert_manager_test.rb @@ -220,7 +220,6 @@ module Arel end describe "select" do - it "accepts a select query in place of a VALUES clause" do table = Table.new :users @@ -238,7 +237,6 @@ module Arel INSERT INTO "users" ("id", "name") (SELECT 1, "aaron") } end - end end end diff --git a/activerecord/test/cases/arel/select_manager_test.rb b/activerecord/test/cases/arel/select_manager_test.rb index f318577b94..c17487ae88 100644 --- a/activerecord/test/cases/arel/select_manager_test.rb +++ b/activerecord/test/cases/arel/select_manager_test.rb @@ -244,8 +244,6 @@ module Arel @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].gt(99)) - - end it "should union two managers" do @@ -266,7 +264,6 @@ module Arel ( SELECT * FROM "users" WHERE "users"."age" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."age" > 99 ) } end - end describe "intersect" do @@ -279,11 +276,9 @@ module Arel @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].lt(99)) - - end - it "should interect two managers" do + it "should intersect two managers" do # FIXME should this intersect "managers" or "statements" ? # FIXME this probably shouldn't return a node node = @m1.intersect @m2 @@ -293,7 +288,6 @@ module Arel ( SELECT * FROM "users" WHERE "users"."age" > 18 INTERSECT SELECT * FROM "users" WHERE "users"."age" < 99 ) } end - end describe "except" do @@ -318,7 +312,6 @@ module Arel ( SELECT * FROM "users" WHERE "users"."age" BETWEEN 18 AND 60 EXCEPT SELECT * FROM "users" WHERE "users"."age" BETWEEN 40 AND 99 ) } end - end describe "with" do @@ -647,7 +640,6 @@ module Arel end describe "joins" do - it "returns inner join sql" do table = Table.new :users aliaz = table.alias @@ -1002,7 +994,6 @@ module Arel end describe "update" do - it "creates an update statement" do table = Table.new :users manager = Arel::SelectManager.new @@ -1075,7 +1066,6 @@ module Arel UPDATE "users" SET "id" = 1 WHERE "users"."id" IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42) } end - end describe "project" do @@ -1097,7 +1087,6 @@ module Arel manager.project "*" manager.to_sql.must_be_like %{ SELECT * } end - end describe "projections" do diff --git a/activerecord/test/cases/arel/visitors/postgres_test.rb b/activerecord/test/cases/arel/visitors/postgres_test.rb index ba9cfcfc64..f7f2c76b6f 100644 --- a/activerecord/test/cases/arel/visitors/postgres_test.rb +++ b/activerecord/test/cases/arel/visitors/postgres_test.rb @@ -215,7 +215,7 @@ module Arel } end - it "should know how to generate paranthesis when supplied with many Dimensions" do + it "should know how to generate parenthesis when supplied with many Dimensions" do dim1 = Arel::Nodes::GroupingElement.new(@table[:name]) dim2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) node = Arel::Nodes::Cube.new([dim1, dim2]) @@ -241,7 +241,7 @@ module Arel } end - it "should know how to generate paranthesis when supplied with many Dimensions" do + it "should know how to generate parenthesis when supplied with many Dimensions" do group1 = Arel::Nodes::GroupingElement.new(@table[:name]) group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) node = Arel::Nodes::GroupingSet.new([group1, group2]) @@ -267,7 +267,7 @@ module Arel } end - it "should know how to generate paranthesis when supplied with many Dimensions" do + it "should know how to generate parenthesis when supplied with many Dimensions" do group1 = Arel::Nodes::GroupingElement.new(@table[:name]) group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) node = Arel::Nodes::RollUp.new([group1, group2]) diff --git a/activerecord/test/cases/arel/visitors/to_sql_test.rb b/activerecord/test/cases/arel/visitors/to_sql_test.rb index ce836eded7..e8ac50bfa3 100644 --- a/activerecord/test/cases/arel/visitors/to_sql_test.rb +++ b/activerecord/test/cases/arel/visitors/to_sql_test.rb @@ -427,7 +427,7 @@ module Arel compile(node).must_equal %(("products"."price" - 7)) end - it "should handle Concatination" do + it "should handle Concatenation" do table = Table.new(:users) node = table[:name].concat(table[:name]) compile(node).must_equal %("users"."name" || "users"."name") diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 8be663e3dc..5b8d4722af 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -123,6 +123,24 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal memberships(:membership_of_boring_club), member.current_membership end + def test_loading_associations_dont_leak_instance_state + assertions = ->(firm) { + assert_equal companies(:first_firm), firm + + assert_predicate firm.association(:readonly_account), :loaded? + assert_predicate firm.association(:accounts), :loaded? + + assert_equal accounts(:signals37), firm.readonly_account + assert_equal [accounts(:signals37)], firm.accounts + + assert_predicate firm.readonly_account, :readonly? + assert firm.accounts.none?(&:readonly?) + } + + assertions.call(Firm.preload(:readonly_account, :accounts).first) + assertions.call(Firm.eager_load(:readonly_account, :accounts).first) + end + def test_with_ordering list = Post.all.merge!(includes: :comments, order: "posts.id DESC").to_a [:other_by_mary, :other_by_bob, :misc_by_mary, :misc_by_bob, :eager_other, 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 5d9735d98a..f414fbf64b 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 @@ -697,24 +697,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_join_table_alias - # FIXME: `references` has no impact on the aliases generated for the join - # query. The fact that we pass `:developers_projects_join` to `references` - # and that the SQL string contains `developers_projects_join` is merely a - # coincidence. assert_equal( 3, - Developer.references(:developers_projects_join).merge( - includes: { projects: :developers }, - where: "projects_developers_projects_join.joined_on IS NOT NULL" - ).to_a.size + Developer.includes(projects: :developers).where.not("projects_developers_projects_join.joined_on": nil).to_a.size ) end def test_join_with_group - # FIXME: `references` has no impact on the aliases generated for the join - # query. The fact that we pass `:developers_projects_join` to `references` - # and that the SQL string contains `developers_projects_join` is merely a - # coincidence. group = Developer.columns.inject([]) do |g, c| g << "developers.#{c.name}" g << "developers_projects_2.#{c.name}" @@ -723,10 +712,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", - group: group.join(",") - ).to_a.size + Developer.includes(projects: :developers).where.not("projects_developers_projects_join.joined_on": nil).group(group.join(",")).to_a.size ) end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 434d32846c..0bfd46a522 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -163,19 +163,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "10", keyboard.read_attribute_before_type_cast(:key_number) end - # Syck calls respond_to? before actually calling initialize. - test "respond_to? with an allocated object" do - klass = Class.new(ActiveRecord::Base) do - self.table_name = "topics" - end - - topic = klass.allocate - assert_not_respond_to topic, "nothingness" - assert_not_respond_to topic, :nothingness - assert_respond_to topic, "title" - assert_respond_to topic, :title - end - # IRB inspects the return value of MyModel.allocate. test "allocated objects can be inspected" do topic = Topic.allocate diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index b9ba51c730..253c3099d6 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -476,4 +476,31 @@ class CallbacksTest < ActiveRecord::TestCase child.save assert child.after_save_called end + + def test_before_save_doesnt_allow_on_option + exception = assert_raises ArgumentError do + Class.new(ActiveRecord::Base) do + before_save(on: :create) {} + end + end + assert_equal "Unknown key: :on. Valid keys are: :if, :unless, :prepend", exception.message + end + + def test_around_save_doesnt_allow_on_option + exception = assert_raises ArgumentError do + Class.new(ActiveRecord::Base) do + around_save(on: :create) {} + end + end + assert_equal "Unknown key: :on. Valid keys are: :if, :unless, :prepend", exception.message + end + + def test_after_save_doesnt_allow_on_option + exception = assert_raises ArgumentError do + Class.new(ActiveRecord::Base) do + after_save(on: :create) {} + end + end + assert_equal "Unknown key: :on. Valid keys are: :if, :unless, :prepend", exception.message + end end diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index 1c96aaabe2..0f957d41cf 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -106,21 +106,31 @@ if current_adapter?(:Mysql2Adapter) class MysqlDefaultExpressionTest < ActiveRecord::TestCase include SchemaDumpingHelper - if ActiveRecord::Base.connection.version >= "5.6.0" + if subsecond_precision_supported? test "schema dump datetime includes default expression" do output = dump_table_schema("datetime_defaults") - assert_match %r/t\.datetime\s+"modified_datetime",\s+default: -> { "CURRENT_TIMESTAMP" }/, output + assert_match %r/t\.datetime\s+"modified_datetime",\s+default: -> { "CURRENT_TIMESTAMP(?:\(\))?" }/i, output end - end - test "schema dump timestamp includes default expression" do - output = dump_table_schema("timestamp_defaults") - assert_match %r/t\.timestamp\s+"modified_timestamp",\s+default: -> { "CURRENT_TIMESTAMP" }/, output - end + test "schema dump datetime includes precise default expression" do + output = dump_table_schema("datetime_defaults") + assert_match %r/t\.datetime\s+"precise_datetime",.+default: -> { "CURRENT_TIMESTAMP\(6\)" }/i, output + end - test "schema dump timestamp without default expression" do - output = dump_table_schema("timestamp_defaults") - assert_match %r/t\.timestamp\s+"nullable_timestamp"$/, output + test "schema dump timestamp includes default expression" do + output = dump_table_schema("timestamp_defaults") + assert_match %r/t\.timestamp\s+"modified_timestamp",\s+default: -> { "CURRENT_TIMESTAMP(?:\(\))?" }/i, output + end + + test "schema dump timestamp includes precise default expression" do + output = dump_table_schema("timestamp_defaults") + assert_match %r/t\.timestamp\s+"precise_timestamp",.+default: -> { "CURRENT_TIMESTAMP\(6\)" }/i, output + end + + test "schema dump timestamp without default expression" do + output = dump_table_schema("timestamp_defaults") + assert_match %r/t\.timestamp\s+"nullable_timestamp"$/, output + end end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 39ffe12ec6..e73c88dd5d 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -463,6 +463,7 @@ class FinderTest < ActiveRecord::TestCase expected = topics(:first) expected.touch # PostgreSQL changes the default order if no order clause is used assert_equal expected, Topic.first + assert_equal expected, Topic.limit(5).first end def test_model_class_responds_to_first_bang @@ -485,6 +486,7 @@ class FinderTest < ActiveRecord::TestCase expected = topics(:second) expected.touch # PostgreSQL changes the default order if no order clause is used assert_equal expected, Topic.second + assert_equal expected, Topic.limit(5).second end def test_model_class_responds_to_second_bang @@ -507,6 +509,7 @@ class FinderTest < ActiveRecord::TestCase expected = topics(:third) expected.touch # PostgreSQL changes the default order if no order clause is used assert_equal expected, Topic.third + assert_equal expected, Topic.limit(5).third end def test_model_class_responds_to_third_bang @@ -529,6 +532,7 @@ class FinderTest < ActiveRecord::TestCase expected = topics(:fourth) expected.touch # PostgreSQL changes the default order if no order clause is used assert_equal expected, Topic.fourth + assert_equal expected, Topic.limit(5).fourth end def test_model_class_responds_to_fourth_bang @@ -551,6 +555,7 @@ class FinderTest < ActiveRecord::TestCase expected = topics(:fifth) expected.touch # PostgreSQL changes the default order if no order clause is used assert_equal expected, Topic.fifth + assert_equal expected, Topic.limit(5).fifth end def test_model_class_responds_to_fifth_bang @@ -713,6 +718,14 @@ class FinderTest < ActiveRecord::TestCase assert_equal comments.limit(2).to_a.first(3), comments.limit(2).first(3) end + def test_first_have_determined_order_by_default + expected = [companies(:second_client), companies(:another_client)] + clients = Client.where(name: expected.map(&:name)) + + assert_equal expected, clients.first(2) + assert_equal expected, clients.limit(5).first(2) + end + def test_take_and_first_and_last_with_integer_should_return_an_array assert_kind_of Array, Topic.take(5) assert_kind_of Array, Topic.first(5) diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index ee88bd8144..c65523d8c1 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "cases/helper" +require "support/connection_helper" require "models/admin" require "models/admin/account" require "models/admin/randomly_named_c1" @@ -32,6 +33,8 @@ require "models/treasure" require "tempfile" class FixturesTest < ActiveRecord::TestCase + include ConnectionHelper + self.use_instantiated_fixtures = true self.use_transactional_tests = false @@ -114,9 +117,96 @@ class FixturesTest < ActiveRecord::TestCase end end end + + def test_bulk_insert_with_a_multi_statement_query_in_a_nested_transaction + fixtures = { + "traffic_lights" => [ + { "location" => "US", "state" => ["NY"], "long_state" => ["a"] }, + ] + } + + assert_difference "TrafficLight.count" do + ActiveRecord::Base.transaction do + conn = ActiveRecord::Base.connection + assert_equal 1, conn.open_transactions + conn.insert_fixtures_set(fixtures) + assert_equal 1, conn.open_transactions + end + end + end end if current_adapter?(:Mysql2Adapter) + def test_bulk_insert_with_multi_statements_enabled + run_without_connection do |orig_connection| + ActiveRecord::Base.establish_connection( + orig_connection.merge(flags: %w[MULTI_STATEMENTS]) + ) + + fixtures = { + "traffic_lights" => [ + { "location" => "US", "state" => ["NY"], "long_state" => ["a"] }, + ] + } + + ActiveRecord::Base.connection.stub(:supports_set_server_option?, false) do + assert_nothing_raised do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + + assert_difference "TrafficLight.count" do + ActiveRecord::Base.transaction do + conn = ActiveRecord::Base.connection + assert_equal 1, conn.open_transactions + conn.insert_fixtures_set(fixtures) + assert_equal 1, conn.open_transactions + end + end + + assert_nothing_raised do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + end + end + end + + def test_bulk_insert_with_multi_statements_disabled + run_without_connection do |orig_connection| + ActiveRecord::Base.establish_connection( + orig_connection.merge(flags: []) + ) + + fixtures = { + "traffic_lights" => [ + { "location" => "US", "state" => ["NY"], "long_state" => ["a"] }, + ] + } + + ActiveRecord::Base.connection.stub(:supports_set_server_option?, false) do + assert_raises(ActiveRecord::StatementInvalid) do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + + assert_difference "TrafficLight.count" do + conn = ActiveRecord::Base.connection + conn.insert_fixtures_set(fixtures) + end + + assert_raises(ActiveRecord::StatementInvalid) do + conn = ActiveRecord::Base.connection + conn.execute("SELECT 1; SELECT 2;") + conn.raw_connection.abandon_results! + end + end + end + end + def test_insert_fixtures_set_raises_an_error_when_max_allowed_packet_is_smaller_than_fixtures_set_size conn = ActiveRecord::Base.connection mysql_margin = 2 @@ -128,10 +218,10 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size - mysql_margin) - - error = assert_raises(ActiveRecord::ActiveRecordError) { conn.insert_fixtures_set(fixtures) } - assert_match(/Fixtures set is too large #{packet_size}\./, error.message) + conn.stub(:max_allowed_packet, packet_size - mysql_margin) do + error = assert_raises(ActiveRecord::ActiveRecordError) { conn.insert_fixtures_set(fixtures) } + assert_match(/Fixtures set is too large #{packet_size}\./, error.message) + end end def test_insert_fixture_set_when_max_allowed_packet_is_bigger_than_fixtures_set_size @@ -143,10 +233,10 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size) - - assert_difference "TrafficLight.count" do - conn.insert_fixtures_set(fixtures) + conn.stub(:max_allowed_packet, packet_size) do + assert_difference "TrafficLight.count" do + conn.insert_fixtures_set(fixtures) + end end end @@ -164,12 +254,13 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size) + conn.stub(:max_allowed_packet, packet_size) do + conn.insert_fixtures_set(fixtures) - conn.insert_fixtures_set(fixtures) - assert_equal 2, subscriber.events.size - assert_operator subscriber.events.first.bytesize, :<, packet_size - assert_operator subscriber.events.second.bytesize, :<, packet_size + assert_equal 2, subscriber.events.size + assert_operator subscriber.events.first.bytesize, :<, packet_size + assert_operator subscriber.events.second.bytesize, :<, packet_size + end ensure ActiveSupport::Notifications.unsubscribe(subscription) end @@ -188,10 +279,10 @@ class FixturesTest < ActiveRecord::TestCase ] } - conn.stubs(:max_allowed_packet).returns(packet_size) - - assert_difference ["TrafficLight.count", "Comment.count"], +1 do - conn.insert_fixtures_set(fixtures) + conn.stub(:max_allowed_packet, packet_size) do + assert_difference ["TrafficLight.count", "Comment.count"], +1 do + conn.insert_fixtures_set(fixtures) + end end assert_equal 1, subscriber.events.size ensure @@ -833,44 +924,58 @@ class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase self.use_instantiated_fixtures = false def test_transaction_created_on_connection_notification - connection = stub(transaction_open?: false) - connection.expects(:begin_transaction).with(joinable: false) - pool = connection.stubs(:pool).returns(ActiveRecord::ConnectionAdapters::ConnectionPool.new(ActiveRecord::Base.connection_pool.spec)) - pool.stubs(:lock_thread=).with(false) - fire_connection_notification(connection) + connection = Class.new do + attr_accessor :pool + + def transaction_open?; end + def begin_transaction(*args); end + def rollback_transaction(*args); end + end.new + + connection.pool = Class.new do + def lock_thread=(lock_thread); end + end.new + + assert_called_with(connection, :begin_transaction, [joinable: false]) do + fire_connection_notification(connection) + end end def test_notification_established_transactions_are_rolled_back - # Mocha is not thread-safe so define our own stub to test connection = Class.new do attr_accessor :rollback_transaction_called attr_accessor :pool + def transaction_open?; true; end def begin_transaction(*args); end def rollback_transaction(*args) @rollback_transaction_called = true end end.new + connection.pool = Class.new do - def lock_thread=(lock_thread); false; end + def lock_thread=(lock_thread); end end.new + fire_connection_notification(connection) teardown_fixtures + assert(connection.rollback_transaction_called, "Expected <mock connection>#rollback_transaction to be called but was not") end private def fire_connection_notification(connection) - ActiveRecord::Base.connection_handler.stubs(:retrieve_connection).with("book").returns(connection) - message_bus = ActiveSupport::Notifications.instrumenter - payload = { - spec_name: "book", - config: nil, - connection_id: connection.object_id - } + assert_called_with(ActiveRecord::Base.connection_handler, :retrieve_connection, ["book"], returns: connection) do + message_bus = ActiveSupport::Notifications.instrumenter + payload = { + spec_name: "book", + config: nil, + connection_id: connection.object_id + } - message_bus.instrument("!connection.active_record", payload) {} + message_bus.instrument("!connection.active_record", payload) {} + end end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 4a0ad0442a..3d3189900f 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -91,7 +91,6 @@ class InheritanceTest < ActiveRecord::TestCase end ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise e }) do - exception = assert_raises NameError do Company.send :compute_type, "InvalidModel" end diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index e2742ed33e..f0126fdb0d 100644 --- a/activerecord/test/cases/log_subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -177,11 +177,25 @@ class LogSubscriberTest < ActiveRecord::TestCase logger = TestDebugLogSubscriber.new logger.sql(Event.new(0, sql: "hi mom!")) + assert_equal 2, @logger.logged(:debug).size assert_match(/↳/, @logger.logged(:debug).last) ensure ActiveRecord::Base.verbose_query_logs = false end + def test_verbose_query_with_ignored_callstack + ActiveRecord::Base.verbose_query_logs = true + + logger = TestDebugLogSubscriber.new + def logger.extract_query_source_location(*); nil; end + + logger.sql(Event.new(0, sql: "hi mom!")) + assert_equal 1, @logger.logged(:debug).size + assert_no_match(/↳/, @logger.logged(:debug).last) + ensure + ActiveRecord::Base.verbose_query_logs = false + end + def test_verbose_query_logs_disabled_by_default logger = TestDebugLogSubscriber.new logger.sql(Event.new(0, sql: "hi mom!")) diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 32af90caef..aa519fd332 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -669,7 +669,6 @@ module NestedAttributesOnACollectionAssociationTests def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models @child_1.stub(:id, "ABC1X") do @child_2.stub(:id, "ABC2X") do - @pirate.attributes = { association_getter => [ { id: @child_1.id, name: "Grace OMalley" }, @@ -1095,3 +1094,15 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR assert_equal ["Ship name can't be blank"], part.errors.full_messages end end + +class TestNestedAttributesWithExtend < ActiveRecord::TestCase + setup do + Pirate.accepts_nested_attributes_for :treasures + end + + def test_extend_affects_nested_attributes + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + pirate.treasures_attributes = [{ id: nil }] + assert_equal "from extension", pirate.treasures[0].name + end +end diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index 60dac91ec9..4ed7469039 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -305,6 +305,7 @@ class PrimaryKeyAnyTypeTest < ActiveRecord::TestCase test "schema dump primary key includes type and options" do schema = dump_table_schema "barcodes" assert_match %r{create_table "barcodes", primary_key: "code", id: :string, limit: 42}, schema + assert_no_match %r{t\.index \["code"\]}, schema end if current_adapter?(:Mysql2Adapter) && subsecond_precision_supported? diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 1c05571f1b..69be091869 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -482,7 +482,6 @@ class QueryCacheTest < ActiveRecord::TestCase assert_not ActiveRecord::Base.connection.query_cache_enabled }.join }.call({}) - end end diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 92eb0c814f..723fccc8d9 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -71,8 +71,8 @@ module ActiveRecord with_timezone_config default: :utc do t = Time.now.change(usec: 0) - expected = t.getutc.change(year: 2000, month: 1, day: 1) - expected = expected.to_s(:db).sub("2000-01-01 ", "") + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getutc.to_s(:db).slice(11..-1) assert_equal expected, @quoter.quoted_time(t) end @@ -89,6 +89,32 @@ module ActiveRecord end end + def test_quoted_time_dst_utc + with_env_tz "America/New_York" do + with_timezone_config default: :utc do + t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30") + + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getutc.to_s(:db).slice(11..-1) + + assert_equal expected, @quoter.quoted_time(t) + end + end + end + + def test_quoted_time_dst_local + with_env_tz "America/New_York" do + with_timezone_config default: :local do + t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30") + + expected = t.change(year: 2000, month: 1, day: 1) + expected = expected.getlocal.to_s(:db).slice(11..-1) + + assert_equal expected, @quoter.quoted_time(t) + end + end + end + def test_quoted_time_crazy with_timezone_config default: :asdfasdf do t = Time.now.change(usec: 0) diff --git a/activerecord/test/cases/relation/select_test.rb b/activerecord/test/cases/relation/select_test.rb index 0577e6bfdb..dec8a6925d 100644 --- a/activerecord/test/cases/relation/select_test.rb +++ b/activerecord/test/cases/relation/select_test.rb @@ -7,7 +7,7 @@ module ActiveRecord class SelectTest < ActiveRecord::TestCase fixtures :posts - def test_select_with_nil_agrument + def test_select_with_nil_argument expected = Post.select(:title).to_sql assert_equal expected, Post.select(nil).select(:title).to_sql end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 952d2dd5d9..5412ab5def 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -30,7 +30,9 @@ class RelationTest < ActiveRecord::TestCase class TopicWithCallbacks < ActiveRecord::Base self.table_name = :topics + cattr_accessor :topic_count before_update { |topic| topic.author_name = "David" if topic.author_name.blank? } + after_update { |topic| topic.class.topic_count = topic.class.count } end def test_do_not_double_quote_string_id @@ -1576,6 +1578,8 @@ class RelationTest < ActiveRecord::TestCase topics = TopicWithCallbacks.where(id: [topic1.id, topic2.id]) topics.update(title: "adequaterecord") + assert_equal TopicWithCallbacks.count, TopicWithCallbacks.topic_count + assert_equal "adequaterecord", topic1.reload.title assert_equal "adequaterecord", topic2.reload.title # Testing that the before_update callbacks have run diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb index db52c108ac..68fcafb682 100644 --- a/activerecord/test/cases/result_test.rb +++ b/activerecord/test/cases/result_test.rb @@ -12,6 +12,11 @@ module ActiveRecord ]) end + test "includes_column?" do + assert result.includes_column?("col_1") + assert_not result.includes_column?("foo") + end + test "length" do assert_equal 3, result.length end diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 15f4cea1a6..75b68b521c 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -297,29 +297,33 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_includes_extensions connection = ActiveRecord::Base.connection - connection.stubs(:extensions).returns(["hstore"]) - output = perform_schema_dump - assert_match "# These are extensions that must be enabled", output - assert_match %r{enable_extension "hstore"}, output - - connection.stubs(:extensions).returns([]) - output = perform_schema_dump - assert_no_match "# These are extensions that must be enabled", output - assert_no_match %r{enable_extension}, output + connection.stub(:extensions, ["hstore"]) do + output = perform_schema_dump + assert_match "# These are extensions that must be enabled", output + assert_match %r{enable_extension "hstore"}, output + end + + connection.stub(:extensions, []) do + output = perform_schema_dump + assert_no_match "# These are extensions that must be enabled", output + assert_no_match %r{enable_extension}, output + end end def test_schema_dump_includes_extensions_in_alphabetic_order connection = ActiveRecord::Base.connection - connection.stubs(:extensions).returns(["hstore", "uuid-ossp", "xml2"]) - output = perform_schema_dump - enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten - assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + connection.stub(:extensions, ["hstore", "uuid-ossp", "xml2"]) do + output = perform_schema_dump + enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten + assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + end - connection.stubs(:extensions).returns(["uuid-ossp", "xml2", "hstore"]) - output = perform_schema_dump - enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten - assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + connection.stub(:extensions, ["uuid-ossp", "xml2", "hstore"]) do + output = perform_schema_dump + enabled_extensions = output.scan(%r{enable_extension "(.+)"}).flatten + assert_equal ["hstore", "uuid-ossp", "xml2"], enabled_extensions + end end end diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index f18f1ed981..544adc9b39 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -254,6 +254,11 @@ class RelationScopingTest < ActiveRecord::TestCase end end + def test_scoping_works_in_the_scope_block + expected = SpecialPostWithDefaultScope.unscoped.to_a + assert_equal expected, SpecialPostWithDefaultScope.unscoped_all + end + def test_circular_joins_with_scoping_does_not_crash posts = Post.joins(comments: :post).scoping do Post.first(10) diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb index 60c7cb1bb4..a6efe3fa5e 100644 --- a/activerecord/test/cases/tasks/database_tasks_test.rb +++ b/activerecord/test/cases/tasks/database_tasks_test.rb @@ -6,10 +6,18 @@ require "active_record/tasks/database_tasks" module ActiveRecord module DatabaseTasksSetupper def setup - @mysql_tasks, @postgresql_tasks, @sqlite_tasks = stub, stub, stub - ActiveRecord::Tasks::MySQLDatabaseTasks.stubs(:new).returns @mysql_tasks - ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stubs(:new).returns @postgresql_tasks - ActiveRecord::Tasks::SQLiteDatabaseTasks.stubs(:new).returns @sqlite_tasks + @mysql_tasks, @postgresql_tasks, @sqlite_tasks = Array.new( + 3, + Class.new do + def create; end + def drop; end + def purge; end + def charset; end + def collation; end + def structure_dump(*); end + def structure_load(*); end + end.new + ) $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr @@ -18,6 +26,16 @@ module ActiveRecord def teardown $stdout, $stderr = @original_stdout, @original_stderr end + + def with_stubbed_new + ActiveRecord::Tasks::MySQLDatabaseTasks.stub(:new, @mysql_tasks) do + ActiveRecord::Tasks::PostgreSQLDatabaseTasks.stub(:new, @postgresql_tasks) do + ActiveRecord::Tasks::SQLiteDatabaseTasks.stub(:new, @sqlite_tasks) do + yield + end + end + end + end end ADAPTERS_TASKS = { @@ -37,6 +55,7 @@ module ActiveRecord ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! ActiveRecord::Base.protected_environments = [current_env] + assert_raise(ActiveRecord::ProtectedEnvironmentError) do ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! end @@ -62,11 +81,12 @@ module ActiveRecord end def test_raises_an_error_if_no_migrations_have_been_made - ActiveRecord::InternalMetadata.stubs(:table_exists?).returns(false) - ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1) + ActiveRecord::InternalMetadata.stub(:table_exists?, false) do + ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1) - assert_raise(ActiveRecord::NoEnvironmentInSchemaError) do - ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! + assert_raise(ActiveRecord::NoEnvironmentInSchemaError) do + ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! + end end end end @@ -79,11 +99,11 @@ module ActiveRecord end instance = klazz.new - klazz.stubs(:new).returns instance - - assert_called_with(instance, :structure_dump, ["awesome-file.sql", nil]) do - ActiveRecord::Tasks::DatabaseTasks.register_task(/foo/, klazz) - ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :foo }, "awesome-file.sql") + klazz.stub(:new, instance) do + assert_called_with(instance, :structure_dump, ["awesome-file.sql", nil]) do + ActiveRecord::Tasks::DatabaseTasks.register_task(/foo/, klazz) + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :foo }, "awesome-file.sql") + end end end @@ -99,8 +119,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_create") do - eval("@#{v}").expects(:create) - ActiveRecord::Tasks::DatabaseTasks.create "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :create) do + ActiveRecord::Tasks::DatabaseTasks.create "adapter" => k + end + end end end end @@ -120,59 +143,89 @@ module ActiveRecord def setup @configurations = { "development" => { "database" => "my-db" } } - ActiveRecord::Base.stubs(:configurations).returns(@configurations) - # To refrain from connecting to a newly created empty DB in sqlite3_mem tests - ActiveRecord::Base.connection_handler.stubs(:establish_connection) + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end + + def teardown + $stdout, $stderr = @original_stdout, @original_stderr end def test_ignores_configurations_without_databases - @configurations["development"].merge!("database" => nil) + @configurations["development"]["database"] = nil - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations_establish_connection do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_ignores_remote_databases - @configurations["development"].merge!("host" => "my.server.tld") - $stderr.stubs(:puts).returns(nil) + @configurations["development"]["host"] = "my.server.tld" - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations_establish_connection do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_warning_for_remote_databases - @configurations["development"].merge!("host" => "my.server.tld") + @configurations["development"]["host"] = "my.server.tld" - assert_called_with($stderr, :puts, ["This task only modifies local databases. my-db is on a remote host."]) do + with_stubbed_configurations_establish_connection do ActiveRecord::Tasks::DatabaseTasks.create_all + + assert_match "This task only modifies local databases. my-db is on a remote host.", + $stderr.string end end def test_creates_configurations_with_local_ip - @configurations["development"].merge!("host" => "127.0.0.1") + @configurations["development"]["host"] = "127.0.0.1" - assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations_establish_connection do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_creates_configurations_with_local_host - @configurations["development"].merge!("host" => "localhost") + @configurations["development"]["host"] = "localhost" - assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations_establish_connection do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end def test_creates_configurations_with_blank_hosts - @configurations["development"].merge!("host" => nil) + @configurations["development"]["host"] = nil - assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do - ActiveRecord::Tasks::DatabaseTasks.create_all + with_stubbed_configurations_establish_connection do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :create) do + ActiveRecord::Tasks::DatabaseTasks.create_all + end end end + + private + + def with_stubbed_configurations_establish_connection + ActiveRecord::Base.stub(:configurations, @configurations) do + # To refrain from connecting to a newly created empty DB in + # sqlite3_mem tests + ActiveRecord::Base.connection_handler.stub( + :establish_connection, + nil + ) do + yield + end + end + end end class DatabaseTasksCreateCurrentTest < ActiveRecord::TestCase @@ -182,70 +235,94 @@ module ActiveRecord "test" => { "database" => "test-db" }, "production" => { "url" => "prod-db-url" } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_creates_current_environment_database - assert_called_with( - ActiveRecord::Tasks::DatabaseTasks, - :create, - ["database" => "test-db"], - ) do - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("test") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + ["database" => "test-db"], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("test") + ) + end end end def test_creates_current_environment_database_with_url - assert_called_with( - ActiveRecord::Tasks::DatabaseTasks, - :create, - ["url" => "prod-db-url"], - ) do - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("production") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + ["url" => "prod-db-url"], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("production") + ) + end end end def test_creates_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_creates_test_and_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ], + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end def test_establishes_connection_for_the_given_environments - ActiveRecord::Tasks::DatabaseTasks.stubs(:create).returns true + ActiveRecord::Tasks::DatabaseTasks.stub(:create, nil) do + assert_called_with(ActiveRecord::Base, :establish_connection, [:development]) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end + end - ActiveRecord::Base.expects(:establish_connection).with(:development) + private - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) - end + def with_stubbed_configurations_establish_connection + ActiveRecord::Base.stub(:configurations, @configurations) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class DatabaseTasksCreateCurrentThreeTierTest < ActiveRecord::TestCase @@ -255,78 +332,108 @@ module ActiveRecord "test" => { "primary" => { "database" => "test-db" }, "secondary" => { "database" => "secondary-test-db" } }, "production" => { "primary" => { "url" => "prod-db-url" }, "secondary" => { "url" => "secondary-prod-db-url" } } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_creates_current_environment_database - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("test") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("test") + ) + end + end end def test_creates_current_environment_database_with_url - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("url" => "prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("url" => "secondary-prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("production") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["url" => "prod-db-url"], + ["url" => "secondary-prod-db-url"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("production") + ) + end + end end def test_creates_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_creates_test_and_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) + + with_stubbed_configurations_establish_connection do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :create, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end def test_establishes_connection_for_the_given_environments_config - ActiveRecord::Tasks::DatabaseTasks.stubs(:create).returns true + ActiveRecord::Tasks::DatabaseTasks.stub(:create, nil) do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [:development] + ) do + ActiveRecord::Tasks::DatabaseTasks.create_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end + end - ActiveRecord::Base.expects(:establish_connection).with(:development) + private - ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new("development") - ) - end + def with_stubbed_configurations_establish_connection + ActiveRecord::Base.stub(:configurations, @configurations) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class DatabaseTasksDropTest < ActiveRecord::TestCase @@ -334,8 +441,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_drop") do - eval("@#{v}").expects(:drop) - ActiveRecord::Tasks::DatabaseTasks.drop "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop "adapter" => k + end + end end end end @@ -344,59 +454,72 @@ module ActiveRecord def setup @configurations = { development: { "database" => "my-db" } } - ActiveRecord::Base.stubs(:configurations).returns(@configurations) + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end + + def teardown + $stdout, $stderr = @original_stdout, @original_stderr end def test_ignores_configurations_without_databases - @configurations[:development].merge!("database" => nil) + @configurations[:development]["database"] = nil - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_ignores_remote_databases - @configurations[:development].merge!("host" => "my.server.tld") - $stderr.stubs(:puts).returns(nil) + @configurations[:development]["host"] = "my.server.tld" - assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_not_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_warning_for_remote_databases - @configurations[:development].merge!("host" => "my.server.tld") + @configurations[:development]["host"] = "my.server.tld" - assert_called_with( - $stderr, - :puts, - ["This task only modifies local databases. my-db is on a remote host."], - ) do + ActiveRecord::Base.stub(:configurations, @configurations) do ActiveRecord::Tasks::DatabaseTasks.drop_all + + assert_match "This task only modifies local databases. my-db is on a remote host.", + $stderr.string end end def test_drops_configurations_with_local_ip - @configurations[:development].merge!("host" => "127.0.0.1") + @configurations[:development]["host"] = "127.0.0.1" - assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_drops_configurations_with_local_host - @configurations[:development].merge!("host" => "localhost") + @configurations[:development]["host"] = "localhost" - assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end def test_drops_configurations_with_blank_hosts - @configurations[:development].merge!("host" => nil) + @configurations[:development]["host"] = nil - assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do - ActiveRecord::Tasks::DatabaseTasks.drop_all + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called(ActiveRecord::Tasks::DatabaseTasks, :drop) do + ActiveRecord::Tasks::DatabaseTasks.drop_all + end end end end @@ -408,50 +531,65 @@ module ActiveRecord "test" => { "database" => "test-db" }, "production" => { "url" => "prod-db-url" } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) end def test_drops_current_environment_database - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("test") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with(ActiveRecord::Tasks::DatabaseTasks, :drop, + ["database" => "test-db"]) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("test") + ) + end + end end def test_drops_current_environment_database_with_url - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("url" => "prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("production") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with(ActiveRecord::Tasks::DatabaseTasks, :drop, + ["url" => "prod-db-url"]) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("production") + ) + end + end end def test_drops_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_drops_testand_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end @@ -464,64 +602,81 @@ module ActiveRecord "test" => { "primary" => { "database" => "test-db" }, "secondary" => { "database" => "secondary-test-db" } }, "production" => { "primary" => { "url" => "prod-db-url" }, "secondary" => { "url" => "secondary-prod-db-url" } } } - - ActiveRecord::Base.stubs(:configurations).returns(@configurations) end def test_drops_current_environment_database - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("test") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("test") + ) + end + end end def test_drops_current_environment_database_with_url - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("url" => "prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("url" => "secondary-prod-db-url") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("production") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["url" => "prod-db-url"], + ["url" => "secondary-prod-db-url"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("production") + ) + end + end end def test_drops_test_and_development_databases_when_env_was_not_specified - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end end def test_drops_testand_development_databases_when_rails_env_is_development old_env = ENV["RAILS_ENV"] ENV["RAILS_ENV"] = "development" - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-dev-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "test-db") - ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with("database" => "secondary-test-db") - - ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new("development") - ) + + ActiveRecord::Base.stub(:configurations, @configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :drop, + [ + ["database" => "dev-db"], + ["database" => "secondary-dev-db"], + ["database" => "test-db"], + ["database" => "secondary-test-db"] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop_current( + ActiveSupport::StringInquirer.new("development") + ) + end + end ensure ENV["RAILS_ENV"] = old_env end @@ -649,10 +804,10 @@ module ActiveRecord end def test_migrate_raise_error_on_failed_check_target_version - ActiveRecord::Tasks::DatabaseTasks.stubs(:check_target_version).raises("foo") - - e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate } - assert_equal "foo", e.message + ActiveRecord::Tasks::DatabaseTasks.stub(:check_target_version, -> { raise "foo" }) do + e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate } + assert_equal "foo", e.message + end end def test_migrate_clears_schema_cache_afterward @@ -667,8 +822,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_purge") do - eval("@#{v}").expects(:purge) - ActiveRecord::Tasks::DatabaseTasks.purge "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :purge) do + ActiveRecord::Tasks::DatabaseTasks.purge "adapter" => k + end + end end end end @@ -680,13 +838,16 @@ module ActiveRecord "test" => { "database" => "test-db" }, "production" => { "database" => "prod-db" } } - ActiveRecord::Base.stubs(:configurations).returns(configurations) - - ActiveRecord::Tasks::DatabaseTasks.expects(:purge). - with("database" => "prod-db") - - assert_called_with(ActiveRecord::Base, :establish_connection, [:production]) do - ActiveRecord::Tasks::DatabaseTasks.purge_current("production") + ActiveRecord::Base.stub(:configurations, configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :purge, + ["database" => "prod-db"] + ) do + assert_called_with(ActiveRecord::Base, :establish_connection, [:production]) do + ActiveRecord::Tasks::DatabaseTasks.purge_current("production") + end + end end end end @@ -694,12 +855,15 @@ module ActiveRecord class DatabaseTasksPurgeAllTest < ActiveRecord::TestCase def test_purge_all_local_configurations configurations = { development: { "database" => "my-db" } } - ActiveRecord::Base.stubs(:configurations).returns(configurations) - - ActiveRecord::Tasks::DatabaseTasks.expects(:purge). - with("database" => "my-db") - - ActiveRecord::Tasks::DatabaseTasks.purge_all + ActiveRecord::Base.stub(:configurations, configurations) do + assert_called_with( + ActiveRecord::Tasks::DatabaseTasks, + :purge, + ["database" => "my-db"] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge_all + end + end end end @@ -708,8 +872,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_charset") do - eval("@#{v}").expects(:charset) - ActiveRecord::Tasks::DatabaseTasks.charset "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :charset) do + ActiveRecord::Tasks::DatabaseTasks.charset "adapter" => k + end + end end end end @@ -719,8 +886,11 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_collation") do - eval("@#{v}").expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation "adapter" => k + with_stubbed_new do + assert_called(eval("@#{v}"), :collation) do + ActiveRecord::Tasks::DatabaseTasks.collation "adapter" => k + end + end end end end @@ -832,8 +1002,14 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_dump") do - eval("@#{v}").expects(:structure_dump).with("awesome-file.sql", nil) - ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => k }, "awesome-file.sql") + with_stubbed_new do + assert_called_with( + eval("@#{v}"), :structure_dump, + ["awesome-file.sql", nil] + ) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => k }, "awesome-file.sql") + end + end end end end @@ -843,8 +1019,15 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_load") do - eval("@#{v}").expects(:structure_load).with("awesome-file.sql", nil) - ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => k }, "awesome-file.sql") + with_stubbed_new do + assert_called_with( + eval("@#{v}"), + :structure_load, + ["awesome-file.sql", nil] + ) do + ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => k }, "awesome-file.sql") + end + end end end end @@ -859,16 +1042,18 @@ module ActiveRecord class DatabaseTasksCheckSchemaFileDefaultsTest < ActiveRecord::TestCase def test_check_schema_file_defaults - ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns("/tmp") - assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_file + ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do + assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_file + end end end class DatabaseTasksCheckSchemaFileSpecifiedFormatsTest < ActiveRecord::TestCase { 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) + ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do + assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_file(fmt) + end end end end diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index 6cddfaefeb..eeb4222d97 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -7,15 +7,11 @@ if current_adapter?(:Mysql2Adapter) module ActiveRecord class MysqlDBCreateTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def create_database(*); end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -25,59 +21,97 @@ if current_adapter?(:Mysql2Adapter) end def test_establishes_connection_without_database - ActiveRecord::Base.expects(:establish_connection). - with("adapter" => "mysql2", "database" => nil) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [ + [ "adapter" => "mysql2", "database" => nil ], + [ "adapter" => "mysql2", "database" => "my-app-db" ], + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_creates_database_with_no_default_options - @connection.expects(:create_database). - with("my-app-db", {}) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :create_database, ["my-app-db", {}]) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_creates_database_with_given_encoding - @connection.expects(:create_database). - with("my-app-db", charset: "latin1") - - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("encoding" => "latin1") + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :create_database, ["my-app-db", charset: "latin1"]) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("encoding" => "latin1") + end + end end def test_creates_database_with_given_collation - @connection.expects(:create_database). - with("my-app-db", collation: "latin1_swedish_ci") - - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("collation" => "latin1_swedish_ci") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + ["my-app-db", collation: "latin1_swedish_ci"] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("collation" => "latin1_swedish_ci") + end + end end def test_establishes_connection_to_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [ + ["adapter" => "mysql2", "database" => nil], + [@configuration] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_when_database_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal "Created database 'my-app-db'\n", $stdout.string + assert_equal "Created database 'my-app-db'\n", $stdout.string + end end def test_create_when_database_exists_outputs_info_to_stderr - ActiveRecord::Base.connection.stubs(:create_database).raises( - ActiveRecord::Tasks::DatabaseAlreadyExists - ) + with_stubbed_connection_establish_connection do + ActiveRecord::Base.connection.stub( + :create_database, + proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists } + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + + assert_equal "Database 'my-app-db' already exists\n", $stderr.string + end + end + end - ActiveRecord::Tasks::DatabaseTasks.create @configuration + private - assert_equal "Database 'my-app-db' already exists\n", $stderr.string - end + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end + end end class MysqlDBCreateWithInvalidPermissionsTest < ActiveRecord::TestCase def setup - @connection = stub("Connection", create_database: true) @error = Mysql2::Error.new("Invalid permissions") @configuration = { "adapter" => "mysql2", @@ -85,10 +119,6 @@ if current_adapter?(:Mysql2Adapter) "username" => "pat", "password" => "wossname" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).raises(@error) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -98,23 +128,21 @@ if current_adapter?(:Mysql2Adapter) end def test_raises_error - assert_raises(Mysql2::Error) do - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:establish_connection, -> * { raise @error }) do + assert_raises(Mysql2::Error, "Invalid permissions") do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end end end end class MySQLDBDropTest < ActiveRecord::TestCase def setup - @connection = stub(drop_database: true) + @connection = Class.new { def drop_database(name); end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -124,91 +152,122 @@ if current_adapter?(:Mysql2Adapter) end def test_establishes_connection_to_mysql_database - ActiveRecord::Base.expects(:establish_connection).with @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Base.expects(:establish_connection).with @configuration - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end end def test_drops_database - @connection.expects(:drop_database).with("my-app-db") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :drop_database, ["my-app-db"]) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end + end end def test_when_database_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal "Dropped database 'my-app-db'\n", $stdout.string + assert_equal "Dropped database 'my-app-db'\n", $stdout.string + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end + end end class MySQLPurgeTest < ActiveRecord::TestCase def setup - @connection = stub(recreate_database: true) + @connection = Class.new { def recreate_database(*); end }.new @configuration = { "adapter" => "mysql2", "database" => "test-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_establishes_connection_to_the_appropriate_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + with_stubbed_connection_establish_connection do + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end end def test_recreates_database_with_no_default_options - @connection.expects(:recreate_database). - with("test-db", {}) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection_establish_connection do + assert_called_with(@connection, :recreate_database, ["test-db", {}]) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end end def test_recreates_database_with_the_given_options - @connection.expects(:recreate_database). - with("test-db", charset: "latin", collation: "latin1_swedish_ci") - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( - "encoding" => "latin", "collation" => "latin1_swedish_ci") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :recreate_database, + ["test-db", charset: "latin", collation: "latin1_swedish_ci"] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( + "encoding" => "latin", "collation" => "latin1_swedish_ci") + end + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end + end end class MysqlDBCharsetTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def charset; end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_charset - @connection.expects(:charset) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :charset) do + ActiveRecord::Tasks::DatabaseTasks.charset @configuration + end + end end end class MysqlDBCollationTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def collation; end }.new @configuration = { "adapter" => "mysql2", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_collation - @connection.expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called_with(@connection, :collation) do + ActiveRecord::Tasks::DatabaseTasks.collation @configuration + end + end end end @@ -245,15 +304,15 @@ if current_adapter?(:Mysql2Adapter) def test_structure_dump_with_ignore_tables filename = "awesome-file.sql" - ActiveRecord::SchemaDumper.expects(:ignore_tables).returns(["foo", "bar"]) - - assert_called_with( - Kernel, - :system, - ["mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--ignore-table=test-db.foo", "--ignore-table=test-db.bar", "test-db"], - returns: true - ) do - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + ActiveRecord::SchemaDumper.stub(:ignore_tables, ["foo", "bar"]) do + assert_called_with( + Kernel, + :system, + ["mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "--ignore-table=test-db.foo", "--ignore-table=test-db.bar", "test-db"], + returns: true + ) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + end end end diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index a1a3700f07..00005e7a0d 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -7,15 +7,11 @@ if current_adapter?(:PostgreSQLAdapter) module ActiveRecord class PostgreSQLDBCreateTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def create_database(*); end }.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -25,82 +21,141 @@ if current_adapter?(:PostgreSQLAdapter) end def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - "adapter" => "postgresql", - "database" => "postgres", - "schema_search_path" => "public" - ) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [ + [ + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ], + [ + "adapter" => "postgresql", + "database" => "my-app-db" + ] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_creates_database_with_default_encoding - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "utf8")) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + ["my-app-db", @configuration.merge("encoding" => "utf8")] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_creates_database_with_given_encoding - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "latin")) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration. - merge("encoding" => "latin") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + ["my-app-db", @configuration.merge("encoding" => "latin")] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration. + merge("encoding" => "latin") + end + end end def test_creates_database_with_given_collation_and_ctype - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "utf8", "collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8")) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration. - merge("collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8") + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :create_database, + [ + "my-app-db", + @configuration.merge( + "encoding" => "utf8", + "collation" => "ja_JP.UTF8", + "ctype" => "ja_JP.UTF8" + ) + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration. + merge("collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8") + end + end end def test_establishes_connection_to_new_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [ + [ + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ], + [ + @configuration + ] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end + end end def test_db_create_with_error_prints_message - ActiveRecord::Base.stubs(:establish_connection).raises(Exception) - - $stderr.stubs(:puts).returns(true) - $stderr.expects(:puts). - with("Couldn't create database for #{@configuration.inspect}") - - assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration } + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.stub(:establish_connection, -> * { raise Exception }) do + assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration } + assert_match "Couldn't create database for #{@configuration.inspect}", $stderr.string + end + end end def test_when_database_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal "Created database 'my-app-db'\n", $stdout.string + assert_equal "Created database 'my-app-db'\n", $stdout.string + end end def test_create_when_database_exists_outputs_info_to_stderr - ActiveRecord::Base.connection.stubs(:create_database).raises( - ActiveRecord::Tasks::DatabaseAlreadyExists - ) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Base.connection.stub( + :create_database, + proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists } + ) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal "Database 'my-app-db' already exists\n", $stderr.string + assert_equal "Database 'my-app-db' already exists\n", $stderr.string + end + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class PostgreSQLDBDropTest < ActiveRecord::TestCase def setup - @connection = stub(drop_database: true) + @connection = Class.new { def drop_database(*); end }.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -110,125 +165,192 @@ if current_adapter?(:PostgreSQLAdapter) end def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - "adapter" => "postgresql", - "database" => "postgres", - "schema_search_path" => "public" - ) - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end end def test_drops_database - @connection.expects(:drop_database).with("my-app-db") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + assert_called_with( + @connection, + :drop_database, + ["my-app-db"] + ) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end + end end def test_when_database_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + with_stubbed_connection_establish_connection do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal "Dropped database 'my-app-db'\n", $stdout.string + assert_equal "Dropped database 'my-app-db'\n", $stdout.string + end end + + private + + def with_stubbed_connection_establish_connection + ActiveRecord::Base.stub(:connection, @connection) do + ActiveRecord::Base.stub(:establish_connection, nil) do + yield + end + end + end end class PostgreSQLPurgeTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true, drop_database: true) + @connection = Class.new do + def create_database(*); end + def drop_database(*); end + end.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:clear_active_connections!).returns(true) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_clears_active_connections - ActiveRecord::Base.expects(:clear_active_connections!) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called(ActiveRecord::Base, :clear_active_connections!) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end + end end def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - "adapter" => "postgresql", - "database" => "postgres", - "schema_search_path" => "public" - ) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [ + [ + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ], + [ + "adapter" => "postgresql", + "database" => "my-app-db" + ] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end end def test_drops_database - @connection.expects(:drop_database).with("my-app-db") - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called_with(@connection, :drop_database, ["my-app-db"]) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end + end end def test_creates_database - @connection.expects(:create_database). - with("my-app-db", @configuration.merge("encoding" => "utf8")) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called_with( + @connection, + :create_database, + ["my-app-db", @configuration.merge("encoding" => "utf8")] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end + end end def test_establishes_connection - ActiveRecord::Base.expects(:establish_connection).with(@configuration) - - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + with_stubbed_connection do + assert_called_with( + ActiveRecord::Base, + :establish_connection, + [ + [ + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ], + [ + @configuration + ] + ] + ) do + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end + end end + + private + + def with_stubbed_connection + ActiveRecord::Base.stub(:connection, @connection) do + yield + end + end end class PostgreSQLDBCharsetTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new do + def create_database(*); end + def encoding; end + end.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_charset - @connection.expects(:encoding) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :encoding) do + ActiveRecord::Tasks::DatabaseTasks.charset @configuration + end + end end end class PostgreSQLDBCollationTest < ActiveRecord::TestCase def setup - @connection = stub(create_database: true) + @connection = Class.new { def collation; end }.new @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_collation - @connection.expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation @configuration + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :collation) do + ActiveRecord::Tasks::DatabaseTasks.collation @configuration + end + end end end class PostgreSQLStructureDumpTest < ActiveRecord::TestCase def setup - @connection = stub(schema_search_path: nil, structure_dump: true) @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } @filename = "/tmp/awesome-file.sql" FileUtils.touch(@filename) - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def teardown @@ -247,12 +369,12 @@ if current_adapter?(:PostgreSQLAdapter) end def test_structure_dump_header_comments_removed - Kernel.stubs(:system).returns(true) - File.write(@filename, "-- header comment\n\n-- more header comment\n statement \n-- lower comment\n") - - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + Kernel.stub(:system, true) do + File.write(@filename, "-- header comment\n\n-- more header comment\n statement \n-- lower comment\n") + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) - assert_equal [" statement \n", "-- lower comment\n"], File.readlines(@filename).first(2) + assert_equal [" statement \n", "-- lower comment\n"], File.readlines(@filename).first(2) + end end def test_structure_dump_with_extra_flags @@ -358,14 +480,10 @@ if current_adapter?(:PostgreSQLAdapter) class PostgreSQLStructureLoadTest < ActiveRecord::TestCase def setup - @connection = stub @configuration = { "adapter" => "postgresql", "database" => "my-app-db" } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_structure_load diff --git a/activerecord/test/cases/tasks/sqlite_rake_test.rb b/activerecord/test/cases/tasks/sqlite_rake_test.rb index d368a7a6ee..7eb062b456 100644 --- a/activerecord/test/cases/tasks/sqlite_rake_test.rb +++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb @@ -9,16 +9,10 @@ if current_adapter?(:SQLite3Adapter) class SqliteDBCreateTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @connection = stub :connection @configuration = { "adapter" => "sqlite3", "database" => @database } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr end @@ -28,63 +22,62 @@ if current_adapter?(:SQLite3Adapter) end def test_db_checks_database_exists - File.expects(:exist?).with(@database).returns(false) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + ActiveRecord::Base.stub(:establish_connection, nil) do + assert_called_with(File, :exist?, [@database], returns: false) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end + end end def test_when_db_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + ActiveRecord::Base.stub(:establish_connection, nil) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal "Created database '#{@database}'\n", $stdout.string + assert_equal "Created database '#{@database}'\n", $stdout.string + end end def test_db_create_when_file_exists - File.stubs(:exist?).returns(true) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + File.stub(:exist?, true) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal "Database '#{@database}' already exists\n", $stderr.string + assert_equal "Database '#{@database}' already exists\n", $stderr.string + end end def test_db_create_with_file_does_nothing - File.stubs(:exist?).returns(true) - $stderr.stubs(:puts).returns(nil) + File.stub(:exist?, true) do + ActiveRecord::Base.expects(:establish_connection).never - ActiveRecord::Base.expects(:establish_connection).never - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end end def test_db_create_establishes_a_connection - ActiveRecord::Base.expects(:establish_connection).with(@configuration) - - ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + assert_called_with(ActiveRecord::Base, :establish_connection, [@configuration]) do + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end end def test_db_create_with_error_prints_message - ActiveRecord::Base.stubs(:establish_connection).raises(Exception) - - $stderr.stubs(:puts).returns(true) - $stderr.expects(:puts). - with("Couldn't create database for #{@configuration.inspect}") - - assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" } + ActiveRecord::Base.stub(:establish_connection, proc { raise Exception }) do + assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" } + assert_match "Couldn't create database for #{@configuration.inspect}", $stderr.string + end end end class SqliteDBDropTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @path = stub(to_s: "/absolute/path", absolute?: true) @configuration = { "adapter" => "sqlite3", "database" => @database } - - Pathname.stubs(:new).returns(@path) - File.stubs(:join).returns("/former/relative/path") - FileUtils.stubs(:rm).returns(true) + @path = Class.new do + def to_s; "/absolute/path" end + def absolute?; true end + end.new $stdout, @original_stdout = StringIO.new, $stdout $stderr, @original_stderr = StringIO.new, $stderr @@ -95,77 +88,76 @@ if current_adapter?(:SQLite3Adapter) end def test_creates_path_from_database - Pathname.expects(:new).with(@database).returns(@path) - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + assert_called_with(Pathname, :new, [@database], returns: @path) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end end def test_removes_file_with_absolute_path - File.stubs(:exist?).returns(true) - @path.stubs(:absolute?).returns(true) - - FileUtils.expects(:rm).with("/absolute/path") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + Pathname.stub(:new, @path) do + assert_called_with(FileUtils, :rm, ["/absolute/path"]) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end + end end def test_generates_absolute_path_with_given_root - @path.stubs(:absolute?).returns(false) - - File.expects(:join).with("/rails/root", @path). - returns("/former/relative/path") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + Pathname.stub(:new, @path) do + @path.stub(:absolute?, false) do + assert_called_with(File, :join, ["/rails/root", @path], + returns: "/former/relative/path" + ) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end + end + end end def test_removes_file_with_relative_path - File.stubs(:exist?).returns(true) - @path.stubs(:absolute?).returns(false) - - FileUtils.expects(:rm).with("/former/relative/path") - - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + File.stub(:join, "/former/relative/path") do + @path.stub(:absolute?, false) do + assert_called_with(FileUtils, :rm, ["/former/relative/path"]) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end + end + end end def test_when_db_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + FileUtils.stub(:rm, nil) do + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" - assert_equal "Dropped database '#{@database}'\n", $stdout.string + assert_equal "Dropped database '#{@database}'\n", $stdout.string + end end end class SqliteDBCharsetTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @connection = stub :connection + @connection = Class.new { def encoding; end }.new @configuration = { "adapter" => "sqlite3", "database" => @database } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_charset - @connection.expects(:encoding) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration, "/rails/root" + ActiveRecord::Base.stub(:connection, @connection) do + assert_called(@connection, :encoding) do + ActiveRecord::Tasks::DatabaseTasks.charset @configuration, "/rails/root" + end + end end end class SqliteDBCollationTest < ActiveRecord::TestCase def setup @database = "db_create.sqlite3" - @connection = stub :connection @configuration = { "adapter" => "sqlite3", "database" => @database } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) end def test_db_retrieves_collation diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 5b685ca564..46463ac414 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -573,7 +573,6 @@ class TransactionTest < ActiveRecord::TestCase assert_called(Topic.connection, :begin_db_transaction) do Topic.connection.stub(:commit_db_transaction, -> { raise("OH NOES") }) do assert_called(Topic.connection, :rollback_db_transaction) do - e = assert_raise RuntimeError do Topic.transaction do # do nothing diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index c8617d1cfe..fd5083e597 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -17,7 +17,13 @@ class Pirate < ActiveRecord::Base after_remove: proc { |p, pa| p.ship_log << "after_removing_proc_parrot_#{pa.id}" } has_and_belongs_to_many :autosaved_parrots, class_name: "Parrot", autosave: true - has_many :treasures, as: :looter + module PostTreasuresExtension + def build(attributes = {}) + super({ name: "from extension" }.merge(attributes)) + end + end + + has_many :treasures, as: :looter, extend: PostTreasuresExtension has_many :treasure_estimates, through: :treasures, source: :price_estimates has_one :ship diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 54eb5e6783..640cdb33b4 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -253,6 +253,7 @@ class SpecialPostWithDefaultScope < ActiveRecord::Base self.inheritance_column = :disabled self.table_name = "posts" default_scope { where(id: [1, 5, 6]) } + scope :unscoped_all, -> { unscoped { all } } end class PostThatLoadsCommentsInAnAfterSaveHook < ActiveRecord::Base diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb index e634e9e6b1..8371ba9528 100644 --- a/activerecord/test/schema/mysql2_specific_schema.rb +++ b/activerecord/test/schema/mysql2_specific_schema.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true ActiveRecord::Schema.define do - - if ActiveRecord::Base.connection.version >= "5.6.0" + if subsecond_precision_supported? create_table :datetime_defaults, force: true do |t| t.datetime :modified_datetime, default: -> { "CURRENT_TIMESTAMP" } + t.datetime :precise_datetime, precision: 6, default: -> { "CURRENT_TIMESTAMP(6)" } end - end - create_table :timestamp_defaults, force: true do |t| - t.timestamp :nullable_timestamp - t.timestamp :modified_timestamp, default: -> { "CURRENT_TIMESTAMP" } + create_table :timestamp_defaults, force: true do |t| + t.timestamp :nullable_timestamp + t.timestamp :modified_timestamp, default: -> { "CURRENT_TIMESTAMP" } + t.timestamp :precise_timestamp, precision: 6, default: -> { "CURRENT_TIMESTAMP(6)" } + end end create_table :binary_fields, force: true do |t| diff --git a/activerecord/test/schema/oracle_specific_schema.rb b/activerecord/test/schema/oracle_specific_schema.rb index e236571caa..bc1e45ca80 100644 --- a/activerecord/test/schema/oracle_specific_schema.rb +++ b/activerecord/test/schema/oracle_specific_schema.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true ActiveRecord::Schema.define do - execute "drop table test_oracle_defaults" rescue nil execute "drop sequence test_oracle_defaults_seq" rescue nil execute "drop sequence companies_nonstd_seq" rescue nil @@ -38,5 +37,4 @@ create sequence test_oracle_defaults_seq minvalue 10000 ) SQL execute "create sequence defaults_seq minvalue 10000" - end diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb index f15178d695..975824ed51 100644 --- a/activerecord/test/schema/postgresql_specific_schema.rb +++ b/activerecord/test/schema/postgresql_specific_schema.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true ActiveRecord::Schema.define do - enable_extension!("uuid-ossp", ActiveRecord::Base.connection) enable_extension!("pgcrypto", ActiveRecord::Base.connection) if ActiveRecord::Base.connection.supports_pgcrypto_uuid? |