diff options
Diffstat (limited to 'activerecord/test')
17 files changed, 247 insertions, 4 deletions
diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb index e3670c203d..c031178479 100644 --- a/activerecord/test/cases/adapters/postgresql/money_test.rb +++ b/activerecord/test/cases/adapters/postgresql/money_test.rb @@ -56,7 +56,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase def test_schema_dumping output = dump_table_schema("postgresql_moneys") assert_match %r{t\.money\s+"wealth",\s+scale: 2$}, output - assert_match %r{t\.money\s+"depth",\s+scale: 2,\s+default: 150\.55$}, output + assert_match %r{t\.money\s+"depth",\s+scale: 2,\s+default: "150\.55"$}, output end def test_create_and_update_money diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 9aba2b5976..35d5581aa7 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -480,6 +480,7 @@ class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCa @connection.create_table "defaults" do |t| t.text "text_col", default: "some value" t.string "string_col", default: "some value" + t.decimal "decimal_col", default: "3.14159265358979323846" end Default.reset_column_information end @@ -498,6 +499,10 @@ class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCa assert_equal "some value", Default.new.string_col, "Default of string column was not correctly parsed" end + def test_decimal_defaults_in_new_schema_when_overriding_domain + assert_equal BigDecimal.new("3.14159265358979323846"), Default.new.decimal_col, "Default of decimal column was not correctly parsed" + end + def test_bpchar_defaults_in_new_schema_when_overriding_domain @connection.execute "ALTER TABLE defaults ADD bpchar_col bpchar DEFAULT 'some value'" Default.reset_column_information diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 039cc46b0b..ebe08c618f 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -19,6 +19,8 @@ require 'models/invoice' require 'models/line_item' require 'models/column' require 'models/record' +require 'models/admin' +require 'models/admin/user' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -151,6 +153,30 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) } end + def test_raises_type_mismatch_with_namespaced_class + assert_nil defined?(Region), "This test requires that there is no top-level Region class" + + ActiveRecord::Base.connection.instance_eval do + create_table(:admin_regions) { |t| t.string :name } + add_column :admin_users, :region_id, :integer + end + Admin.const_set "RegionalUser", Class.new(Admin::User) { belongs_to(:region) } + Admin.const_set "Region", Class.new(ActiveRecord::Base) + + e = assert_raise(ActiveRecord::AssociationTypeMismatch) { + Admin::RegionalUser.new(region: 'wrong value') + } + assert_match(/^Region\([^)]+\) expected, got String\([^)]+\)$/, e.message) + ensure + Admin.send :remove_const, "Region" if Admin.const_defined?("Region") + Admin.send :remove_const, "RegionalUser" if Admin.const_defined?("RegionalUser") + + ActiveRecord::Base.connection.instance_eval do + remove_column :admin_users, :region_id if column_exists?(:admin_users, :region_id) + drop_table :admin_regions, if_exists: true + end + end + def test_natural_assignment apple = Firm.create("name" => "Apple") citibank = Account.create("credit_limit" => 10) @@ -292,9 +318,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_polymorphic_association_class sponsor = Sponsor.new assert_nil sponsor.association(:sponsorable).send(:klass) + assert_nil sponsor.sponsorable(force_reload: true) sponsor.sponsorable_type = '' # the column doesn't have to be declared NOT NULL assert_nil sponsor.association(:sponsorable).send(:klass) + assert_nil sponsor.sponsorable(force_reload: true) sponsor.sponsorable = Member.new :name => "Bert" assert_equal Member, sponsor.association(:sponsorable).send(:klass) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index cb4681109c..aa10817527 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -671,4 +671,14 @@ class CalculationsTest < ActiveRecord::TestCase developer.ratings.includes(comment: :post).where(posts: { id: 1 }).count end end + + def test_sum_uses_enumerable_version_when_block_is_given + block_called = false + relation = Client.all.load + + assert_no_queries do + assert_equal 0, relation.sum { block_called = true; 0 } + end + assert block_called + end end diff --git a/activerecord/test/cases/explain_subscriber_test.rb b/activerecord/test/cases/explain_subscriber_test.rb index 8de2ddb10d..2dee8a26a5 100644 --- a/activerecord/test/cases/explain_subscriber_test.rb +++ b/activerecord/test/cases/explain_subscriber_test.rb @@ -48,6 +48,11 @@ if ActiveRecord::Base.connection.supports_explain? assert queries.empty? end + def test_collects_cte_queries + SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'with s as (values(3)) select 1 from s') + assert_equal 1, queries.size + end + teardown do ActiveRecord::ExplainRegistry.reset end diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb index 5fc7702dfa..ab3f584350 100644 --- a/activerecord/test/cases/migration/columns_test.rb +++ b/activerecord/test/cases/migration/columns_test.rb @@ -267,6 +267,13 @@ module ActiveRecord assert_nil TestModel.new.first_name end + def test_change_column_default_with_from_and_to + add_column "test_models", "first_name", :string + connection.change_column_default "test_models", "first_name", from: nil, to: "Tester" + + assert_equal "Tester", TestModel.new.first_name + end + def test_remove_column_no_second_parameter_raises_exception assert_raise(ArgumentError) { connection.remove_column("funny") } end diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 90b7c6b38a..99f1dc65b0 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -169,6 +169,16 @@ module ActiveRecord end end + def test_invert_change_column_default_with_from_and_to + change = @recorder.inverse_of :change_column_default, [:table, :column, from: "old_value", to: "new_value"] + assert_equal [:change_column_default, [:table, :column, from: "new_value", to: "old_value"]], change + end + + def test_invert_change_column_default_with_from_and_to_with_boolean + change = @recorder.inverse_of :change_column_default, [:table, :column, from: true, to: false] + assert_equal [:change_column_default, [:table, :column, from: false, to: true]], change + end + def test_invert_change_column_null add = @recorder.inverse_of :change_column_null, [:table, :column, true] assert_equal [:change_column_null, [:table, :column, false]], add diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb index 7f4790bf3e..72f2fa95f1 100644 --- a/activerecord/test/cases/migration/foreign_key_test.rb +++ b/activerecord/test/cases/migration/foreign_key_test.rb @@ -243,6 +243,37 @@ module ActiveRecord silence_stream($stdout) { migration.migrate(:down) } end + class CreateSchoolsAndClassesMigration < ActiveRecord::Migration + def change + create_table(:schools) + + create_table(:classes) do |t| + t.column :school_id, :integer + end + add_foreign_key :classes, :schools + end + end + + def test_add_foreign_key_with_prefix + ActiveRecord::Base.table_name_prefix = 'p_' + migration = CreateSchoolsAndClassesMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("p_classes").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + ActiveRecord::Base.table_name_prefix = nil + end + + def test_add_foreign_key_with_suffix + ActiveRecord::Base.table_name_suffix = '_s' + migration = CreateSchoolsAndClassesMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("classes_s").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + ActiveRecord::Base.table_name_suffix = nil + end + end end end diff --git a/activerecord/test/cases/reload_models_test.rb b/activerecord/test/cases/reload_models_test.rb index 0d16a3526f..431fbf1297 100644 --- a/activerecord/test/cases/reload_models_test.rb +++ b/activerecord/test/cases/reload_models_test.rb @@ -3,7 +3,7 @@ require 'models/owner' require 'models/pet' class ReloadModelsTest < ActiveRecord::TestCase - fixtures :pets + fixtures :pets, :owners def test_has_one_with_reload pet = Pet.find_by_name('parrot') diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 51170c533b..feb1c29656 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -239,7 +239,7 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_includes_decimal_options output = dump_all_table_schema([/^[^n]/]) - assert_match %r{precision: 3,[[:space:]]+scale: 2,[[:space:]]+default: 2\.78}, output + assert_match %r{precision: 3,[[:space:]]+scale: 2,[[:space:]]+default: "2\.78"}, output end if current_adapter?(:PostgreSQLAdapter) @@ -255,7 +255,7 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_allows_array_of_decimal_defaults output = standard_dump - assert_match %r{t\.decimal\s+"decimal_array_default",\s+default: \[1.23, 3.45\],\s+array: true}, output + assert_match %r{t\.decimal\s+"decimal_array_default",\s+default: \["1.23", "3.45"\],\s+array: true}, output end if ActiveRecord::Base.connection.supports_extensions? diff --git a/activerecord/test/cases/touch_later_test.rb b/activerecord/test/cases/touch_later_test.rb index 11804ff90b..49ada22529 100644 --- a/activerecord/test/cases/touch_later_test.rb +++ b/activerecord/test/cases/touch_later_test.rb @@ -2,8 +2,11 @@ require 'cases/helper' require 'models/invoice' require 'models/line_item' require 'models/topic' +require 'models/node' +require 'models/tree' class TouchLaterTest < ActiveRecord::TestCase + fixtures :nodes, :trees def test_touch_laster_raise_if_non_persisted invoice = Invoice.new @@ -90,4 +93,22 @@ class TouchLaterTest < ActiveRecord::TestCase invoice.touch_later end end + + def test_touching_three_deep + skip "Pending from #19324" + + previous_tree_updated_at = trees(:root).updated_at + previous_grandparent_updated_at = nodes(:grandparent).updated_at + previous_parent_updated_at = nodes(:parent_a).updated_at + previous_child_updated_at = nodes(:child_one_of_a).updated_at + + travel 5.seconds + + Node.create! parent: nodes(:child_one_of_a), tree: trees(:root) + + assert_not_equal nodes(:child_one_of_a).reload.updated_at, previous_child_updated_at + assert_not_equal nodes(:parent_a).reload.updated_at, previous_parent_updated_at + assert_not_equal nodes(:grandparent).reload.updated_at, previous_grandparent_updated_at + assert_not_equal trees(:root).reload.updated_at, previous_tree_updated_at + end end diff --git a/activerecord/test/cases/validations/absence_validation_test.rb b/activerecord/test/cases/validations/absence_validation_test.rb new file mode 100644 index 0000000000..dd43ee358c --- /dev/null +++ b/activerecord/test/cases/validations/absence_validation_test.rb @@ -0,0 +1,75 @@ +require "cases/helper" +require 'models/face' +require 'models/interest' +require 'models/man' +require 'models/topic' + +class AbsenceValidationTest < ActiveRecord::TestCase + def test_non_association + boy_klass = Class.new(Man) do + def self.name; "Boy" end + validates_absence_of :name + end + + assert boy_klass.new.valid? + assert_not boy_klass.new(name: "Alex").valid? + end + + def test_has_one_marked_for_destruction + boy_klass = Class.new(Man) do + def self.name; "Boy" end + validates_absence_of :face + end + + boy = boy_klass.new(face: Face.new) + assert_not boy.valid?, "should not be valid if has_one association is present" + assert_equal 1, boy.errors[:face].size, "should only add one error" + + boy.face.mark_for_destruction + assert boy.valid?, "should be valid if association is marked for destruction" + end + + def test_has_many_marked_for_destruction + boy_klass = Class.new(Man) do + def self.name; "Boy" end + validates_absence_of :interests + end + boy = boy_klass.new + boy.interests << [i1 = Interest.new, i2 = Interest.new] + assert_not boy.valid?, "should not be valid if has_many association is present" + + i1.mark_for_destruction + assert_not boy.valid?, "should not be valid if has_many association is present" + + i2.mark_for_destruction + assert boy.valid? + end + + def test_does_not_call_to_a_on_associations + boy_klass = Class.new(Man) do + def self.name; "Boy" end + validates_absence_of :face + end + + face_with_to_a = Face.new + def face_with_to_a.to_a; ['(/)', '(\)']; end + + assert_nothing_raised { boy_klass.new(face: face_with_to_a).valid? } + end + + def test_does_not_validate_if_parent_record_is_validate_false + repair_validations(Interest) do + Interest.validates_absence_of(:topic) + interest = Interest.new(topic: Topic.new(title: "Math")) + interest.save!(validate: false) + assert interest.persisted? + + man = Man.new(interest_ids: [interest.id]) + man.save! + + assert_equal man.interests.size, 1 + assert interest.valid? + assert man.valid? + end + end +end diff --git a/activerecord/test/fixtures/nodes.yml b/activerecord/test/fixtures/nodes.yml new file mode 100644 index 0000000000..b8bb8216ee --- /dev/null +++ b/activerecord/test/fixtures/nodes.yml @@ -0,0 +1,29 @@ +grandparent: + id: 1 + tree_id: 1 + name: Grand Parent + +parent_a: + id: 2 + tree_id: 1 + parent_id: 1 + name: Parent A + +parent_b: + id: 3 + tree_id: 1 + parent_id: 1 + name: Parent B + +child_one_of_a: + id: 4 + tree_id: 1 + parent_id: 2 + name: Child one + +child_two_of_b: + id: 5 + tree_id: 1 + parent_id: 2 + name: Child two + diff --git a/activerecord/test/fixtures/trees.yml b/activerecord/test/fixtures/trees.yml new file mode 100644 index 0000000000..9e030b7632 --- /dev/null +++ b/activerecord/test/fixtures/trees.yml @@ -0,0 +1,3 @@ +root: + id: 1 + name: The Root diff --git a/activerecord/test/models/node.rb b/activerecord/test/models/node.rb new file mode 100644 index 0000000000..07dd2dbccb --- /dev/null +++ b/activerecord/test/models/node.rb @@ -0,0 +1,5 @@ +class Node < ActiveRecord::Base + belongs_to :tree, touch: true + belongs_to :parent, class_name: 'Node', touch: true, optional: true + has_many :children, class_name: 'Node', foreign_key: :parent_id, dependent: :destroy +end diff --git a/activerecord/test/models/tree.rb b/activerecord/test/models/tree.rb new file mode 100644 index 0000000000..dc29cccc9c --- /dev/null +++ b/activerecord/test/models/tree.rb @@ -0,0 +1,3 @@ +class Tree < ActiveRecord::Base + has_many :nodes, dependent: :destroy +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index dffccc9326..6872b49ad9 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -867,6 +867,17 @@ ActiveRecord::Schema.define do t.string 'from' end + create_table :nodes, force: true do |t| + t.integer :tree_id + t.integer :parent_id + t.string :name + t.datetime :updated_at + end + create_table :trees, force: true do |t| + t.string :name + t.datetime :updated_at + end + create_table :hotels, force: true do |t| end create_table :departments, force: true do |t| |