diff options
Diffstat (limited to 'activemodel/test')
65 files changed, 1034 insertions, 121 deletions
diff --git a/activemodel/test/cases/attribute_assignment_test.rb b/activemodel/test/cases/attribute_assignment_test.rb index fa41d1b95f..5ecf0a69c4 100644 --- a/activemodel/test/cases/attribute_assignment_test.rb +++ b/activemodel/test/cases/attribute_assignment_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/core_ext/hash/indifferent_access" require "active_support/hash_with_indifferent_access" diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb index 4767accb7c..d2837ec894 100644 --- a/activemodel/test/cases/attribute_methods_test.rb +++ b/activemodel/test/cases/attribute_methods_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" class ModelWithAttributes @@ -116,7 +118,7 @@ class AttributeMethodsTest < ActiveModel::TestCase test "#define_attribute_method does not generate attribute method if already defined in attribute module" do klass = Class.new(ModelWithAttributes) - klass.generated_attribute_methods.module_eval do + klass.send(:generated_attribute_methods).module_eval do def foo "<3" end diff --git a/activemodel/test/cases/attribute_set_test.rb b/activemodel/test/cases/attribute_set_test.rb new file mode 100644 index 0000000000..02c44c5d45 --- /dev/null +++ b/activemodel/test/cases/attribute_set_test.rb @@ -0,0 +1,256 @@ +# frozen_string_literal: true + +require "cases/helper" +require "active_model/attribute_set" + +module ActiveModel + class AttributeSetTest < ActiveModel::TestCase + test "building a new set from raw attributes" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") + + assert_equal 1, attributes[:foo].value + assert_equal 2.2, attributes[:bar].value + assert_equal :foo, attributes[:foo].name + assert_equal :bar, attributes[:bar].name + end + + test "building with custom types" do + builder = AttributeSet::Builder.new(foo: Type::Float.new) + attributes = builder.build_from_database({ foo: "3.3", bar: "4.4" }, { bar: Type::Integer.new }) + + assert_equal 3.3, attributes[:foo].value + assert_equal 4, attributes[:bar].value + end + + test "[] returns a null object" do + builder = AttributeSet::Builder.new(foo: Type::Float.new) + attributes = builder.build_from_database(foo: "3.3") + + assert_equal "3.3", attributes[:foo].value_before_type_cast + assert_nil attributes[:bar].value_before_type_cast + assert_equal :bar, attributes[:bar].name + end + + test "duping creates a new hash, but does not dup the attributes" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::String.new) + attributes = builder.build_from_database(foo: 1, bar: "foo") + + # Ensure the type cast value is cached + attributes[:foo].value + attributes[:bar].value + + duped = attributes.dup + duped.write_from_database(:foo, 2) + duped[:bar].value << "bar" + + assert_equal 1, attributes[:foo].value + assert_equal 2, duped[:foo].value + assert_equal "foobar", attributes[:bar].value + assert_equal "foobar", duped[:bar].value + end + + test "deep_duping creates a new hash and dups each attribute" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::String.new) + attributes = builder.build_from_database(foo: 1, bar: "foo") + + # Ensure the type cast value is cached + attributes[:foo].value + attributes[:bar].value + + duped = attributes.deep_dup + duped.write_from_database(:foo, 2) + duped[:bar].value << "bar" + + assert_equal 1, attributes[:foo].value + assert_equal 2, duped[:foo].value + assert_equal "foo", attributes[:bar].value + assert_equal "foobar", duped[:bar].value + end + + test "freezing cloned set does not freeze original" do + attributes = AttributeSet.new({}) + clone = attributes.clone + + clone.freeze + + assert clone.frozen? + assert_not attributes.frozen? + end + + test "to_hash returns a hash of the type cast values" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") + + assert_equal({ foo: 1, bar: 2.2 }, attributes.to_hash) + assert_equal({ foo: 1, bar: 2.2 }, attributes.to_h) + end + + test "to_hash maintains order" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) + attributes = builder.build_from_database(foo: "2.2", bar: "3.3") + + attributes[:bar] + hash = attributes.to_h + + assert_equal [[:foo, 2], [:bar, 3.3]], hash.to_a + end + + test "values_before_type_cast" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new) + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") + + assert_equal({ foo: "1.1", bar: "2.2" }, attributes.values_before_type_cast) + end + + test "known columns are built with uninitialized attributes" do + attributes = attributes_with_uninitialized_key + assert attributes[:foo].initialized? + assert_not attributes[:bar].initialized? + end + + test "uninitialized attributes are not included in the attributes hash" do + attributes = attributes_with_uninitialized_key + assert_equal({ foo: 1 }, attributes.to_hash) + end + + test "uninitialized attributes are not included in keys" do + attributes = attributes_with_uninitialized_key + assert_equal [:foo], attributes.keys + end + + test "uninitialized attributes return false for key?" do + attributes = attributes_with_uninitialized_key + assert attributes.key?(:foo) + assert_not attributes.key?(:bar) + end + + test "unknown attributes return false for key?" do + attributes = attributes_with_uninitialized_key + assert_not attributes.key?(:wibble) + end + + test "fetch_value returns the value for the given initialized attribute" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") + + assert_equal 1, attributes.fetch_value(:foo) + assert_equal 2.2, attributes.fetch_value(:bar) + end + + test "fetch_value returns nil for unknown attributes" do + attributes = attributes_with_uninitialized_key + assert_nil attributes.fetch_value(:wibble) { "hello" } + end + + test "fetch_value returns nil for unknown attributes when types has a default" do + types = Hash.new(Type::Value.new) + builder = AttributeSet::Builder.new(types) + attributes = builder.build_from_database + + assert_nil attributes.fetch_value(:wibble) { "hello" } + end + + test "fetch_value uses the given block for uninitialized attributes" do + attributes = attributes_with_uninitialized_key + value = attributes.fetch_value(:bar) { |n| n.to_s + "!" } + assert_equal "bar!", value + end + + test "fetch_value returns nil for uninitialized attributes if no block is given" do + attributes = attributes_with_uninitialized_key + assert_nil attributes.fetch_value(:bar) + end + + test "the primary_key is always initialized" do + builder = AttributeSet::Builder.new({ foo: Type::Integer.new }, :foo) + attributes = builder.build_from_database + + assert attributes.key?(:foo) + assert_equal [:foo], attributes.keys + assert attributes[:foo].initialized? + end + + class MyType + def cast(value) + return if value.nil? + value + " from user" + end + + def deserialize(value) + return if value.nil? + value + " from database" + end + + def assert_valid_value(*) + end + end + + test "write_from_database sets the attribute with database typecasting" do + builder = AttributeSet::Builder.new(foo: MyType.new) + attributes = builder.build_from_database + + assert_nil attributes.fetch_value(:foo) + + attributes.write_from_database(:foo, "value") + + assert_equal "value from database", attributes.fetch_value(:foo) + end + + test "write_from_user sets the attribute with user typecasting" do + builder = AttributeSet::Builder.new(foo: MyType.new) + attributes = builder.build_from_database + + assert_nil attributes.fetch_value(:foo) + + attributes.write_from_user(:foo, "value") + + assert_equal "value from user", attributes.fetch_value(:foo) + end + + def attributes_with_uninitialized_key + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) + builder.build_from_database(foo: "1.1") + end + + test "freezing doesn't prevent the set from materializing" do + builder = AttributeSet::Builder.new(foo: Type::String.new) + attributes = builder.build_from_database(foo: "1") + + attributes.freeze + assert_equal({ foo: "1" }, attributes.to_hash) + end + + test "#accessed_attributes returns only attributes which have been read" do + builder = AttributeSet::Builder.new(foo: Type::Value.new, bar: Type::Value.new) + attributes = builder.build_from_database(foo: "1", bar: "2") + + assert_equal [], attributes.accessed + + attributes.fetch_value(:foo) + + assert_equal [:foo], attributes.accessed + end + + test "#map returns a new attribute set with the changes applied" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new) + attributes = builder.build_from_database(foo: "1", bar: "2") + new_attributes = attributes.map do |attr| + attr.with_cast_value(attr.value + 1) + end + + assert_equal 2, new_attributes.fetch_value(:foo) + assert_equal 3, new_attributes.fetch_value(:bar) + end + + test "comparison for equality is correctly implemented" do + builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new) + attributes = builder.build_from_database(foo: "1", bar: "2") + attributes2 = builder.build_from_database(foo: "1", bar: "2") + attributes3 = builder.build_from_database(foo: "2", bar: "2") + + assert_equal attributes, attributes2 + assert_not_equal attributes2, attributes3 + end + end +end diff --git a/activemodel/test/cases/attribute_test.rb b/activemodel/test/cases/attribute_test.rb new file mode 100644 index 0000000000..14d86cef97 --- /dev/null +++ b/activemodel/test/cases/attribute_test.rb @@ -0,0 +1,255 @@ +# frozen_string_literal: true + +require "cases/helper" + +module ActiveModel + class AttributeTest < ActiveModel::TestCase + setup do + @type = Minitest::Mock.new + end + + teardown do + assert @type.verify + end + + test "from_database + read type casts from database" do + @type.expect(:deserialize, "type cast from database", ["a value"]) + attribute = Attribute.from_database(nil, "a value", @type) + + type_cast_value = attribute.value + + assert_equal "type cast from database", type_cast_value + end + + test "from_user + read type casts from user" do + @type.expect(:cast, "type cast from user", ["a value"]) + attribute = Attribute.from_user(nil, "a value", @type) + + type_cast_value = attribute.value + + assert_equal "type cast from user", type_cast_value + end + + test "reading memoizes the value" do + @type.expect(:deserialize, "from the database", ["whatever"]) + attribute = Attribute.from_database(nil, "whatever", @type) + + type_cast_value = attribute.value + second_read = attribute.value + + assert_equal "from the database", type_cast_value + assert_same type_cast_value, second_read + end + + test "reading memoizes falsy values" do + @type.expect(:deserialize, false, ["whatever"]) + attribute = Attribute.from_database(nil, "whatever", @type) + + attribute.value + attribute.value + end + + test "read_before_typecast returns the given value" do + attribute = Attribute.from_database(nil, "raw value", @type) + + raw_value = attribute.value_before_type_cast + + assert_equal "raw value", raw_value + end + + test "from_database + read_for_database type casts to and from database" do + @type.expect(:deserialize, "read from database", ["whatever"]) + @type.expect(:serialize, "ready for database", ["read from database"]) + attribute = Attribute.from_database(nil, "whatever", @type) + + serialize = attribute.value_for_database + + assert_equal "ready for database", serialize + end + + test "from_user + read_for_database type casts from the user to the database" do + @type.expect(:cast, "read from user", ["whatever"]) + @type.expect(:serialize, "ready for database", ["read from user"]) + attribute = Attribute.from_user(nil, "whatever", @type) + + serialize = attribute.value_for_database + + assert_equal "ready for database", serialize + end + + test "duping dups the value" do + @type.expect(:deserialize, "type cast".dup, ["a value"]) + attribute = Attribute.from_database(nil, "a value", @type) + + value_from_orig = attribute.value + value_from_clone = attribute.dup.value + value_from_orig << " foo" + + assert_equal "type cast foo", value_from_orig + assert_equal "type cast", value_from_clone + end + + test "duping does not dup the value if it is not dupable" do + @type.expect(:deserialize, false, ["a value"]) + attribute = Attribute.from_database(nil, "a value", @type) + + assert_same attribute.value, attribute.dup.value + end + + test "duping does not eagerly type cast if we have not yet type cast" do + attribute = Attribute.from_database(nil, "a value", @type) + attribute.dup + end + + class MyType + def cast(value) + value + " from user" + end + + def deserialize(value) + value + " from database" + end + + def assert_valid_value(*) + end + end + + test "with_value_from_user returns a new attribute with the value from the user" do + old = Attribute.from_database(nil, "old", MyType.new) + new = old.with_value_from_user("new") + + assert_equal "old from database", old.value + assert_equal "new from user", new.value + end + + test "with_value_from_database returns a new attribute with the value from the database" do + old = Attribute.from_user(nil, "old", MyType.new) + new = old.with_value_from_database("new") + + assert_equal "old from user", old.value + assert_equal "new from database", new.value + end + + test "uninitialized attributes yield their name if a block is given to value" do + block = proc { |name| name.to_s + "!" } + foo = Attribute.uninitialized(:foo, nil) + bar = Attribute.uninitialized(:bar, nil) + + assert_equal "foo!", foo.value(&block) + assert_equal "bar!", bar.value(&block) + end + + test "uninitialized attributes have no value" do + assert_nil Attribute.uninitialized(:foo, nil).value + end + + test "attributes equal other attributes with the same constructor arguments" do + first = Attribute.from_database(:foo, 1, Type::Integer.new) + second = Attribute.from_database(:foo, 1, Type::Integer.new) + assert_equal first, second + end + + test "attributes do not equal attributes with different names" do + first = Attribute.from_database(:foo, 1, Type::Integer.new) + second = Attribute.from_database(:bar, 1, Type::Integer.new) + assert_not_equal first, second + end + + test "attributes do not equal attributes with different types" do + first = Attribute.from_database(:foo, 1, Type::Integer.new) + second = Attribute.from_database(:foo, 1, Type::Float.new) + assert_not_equal first, second + end + + test "attributes do not equal attributes with different values" do + first = Attribute.from_database(:foo, 1, Type::Integer.new) + second = Attribute.from_database(:foo, 2, Type::Integer.new) + assert_not_equal first, second + end + + test "attributes do not equal attributes of other classes" do + first = Attribute.from_database(:foo, 1, Type::Integer.new) + second = Attribute.from_user(:foo, 1, Type::Integer.new) + assert_not_equal first, second + end + + test "an attribute has not been read by default" do + attribute = Attribute.from_database(:foo, 1, Type::Value.new) + assert_not attribute.has_been_read? + end + + test "an attribute has been read when its value is calculated" do + attribute = Attribute.from_database(:foo, 1, Type::Value.new) + attribute.value + assert attribute.has_been_read? + end + + test "an attribute is not changed if it hasn't been assigned or mutated" do + attribute = Attribute.from_database(:foo, 1, Type::Value.new) + + refute attribute.changed? + end + + test "an attribute is changed if it's been assigned a new value" do + attribute = Attribute.from_database(:foo, 1, Type::Value.new) + changed = attribute.with_value_from_user(2) + + assert changed.changed? + end + + test "an attribute is not changed if it's assigned the same value" do + attribute = Attribute.from_database(:foo, 1, Type::Value.new) + unchanged = attribute.with_value_from_user(1) + + refute unchanged.changed? + end + + test "an attribute can not be mutated if it has not been read, + and skips expensive calculations" do + type_which_raises_from_all_methods = Object.new + attribute = Attribute.from_database(:foo, "bar", type_which_raises_from_all_methods) + + assert_not attribute.changed_in_place? + end + + test "an attribute is changed if it has been mutated" do + attribute = Attribute.from_database(:foo, "bar", Type::String.new) + attribute.value << "!" + + assert attribute.changed_in_place? + assert attribute.changed? + end + + test "an attribute can forget its changes" do + attribute = Attribute.from_database(:foo, "bar", Type::String.new) + changed = attribute.with_value_from_user("foo") + forgotten = changed.forgetting_assignment + + assert changed.changed? # sanity check + refute forgotten.changed? + end + + test "with_value_from_user validates the value" do + type = Type::Value.new + type.define_singleton_method(:assert_valid_value) do |value| + if value == 1 + raise ArgumentError + end + end + + attribute = Attribute.from_database(:foo, 1, type) + assert_equal 1, attribute.value + assert_equal 2, attribute.with_value_from_user(2).value + assert_raises ArgumentError do + attribute.with_value_from_user(1) + end + end + + test "with_type preserves mutations" do + attribute = Attribute.from_database(:foo, "".dup, Type::Value.new) + attribute.value << "1" + + assert_equal 1, attribute.with_type(Type::Integer.new).value + end + end +end diff --git a/activemodel/test/cases/attributes_dirty_test.rb b/activemodel/test/cases/attributes_dirty_test.rb new file mode 100644 index 0000000000..83a86371e0 --- /dev/null +++ b/activemodel/test/cases/attributes_dirty_test.rb @@ -0,0 +1,205 @@ +# frozen_string_literal: true + +require "cases/helper" + +class AttributesDirtyTest < ActiveModel::TestCase + class DirtyModel + include ActiveModel::Model + include ActiveModel::Attributes + include ActiveModel::Dirty + attribute :name, :string + attribute :color, :string + attribute :size, :integer + + def save + changes_applied + end + + def reload + clear_changes_information + end + end + + setup do + @model = DirtyModel.new + end + + test "setting attribute will result in change" do + assert !@model.changed? + assert !@model.name_changed? + @model.name = "Ringo" + assert @model.changed? + assert @model.name_changed? + end + + test "list of changed attribute keys" do + assert_equal [], @model.changed + @model.name = "Paul" + assert_equal ["name"], @model.changed + end + + test "changes to attribute values" do + assert !@model.changes["name"] + @model.name = "John" + assert_equal [nil, "John"], @model.changes["name"] + end + + test "checking if an attribute has changed to a particular value" do + @model.name = "Ringo" + assert @model.name_changed?(from: nil, to: "Ringo") + assert_not @model.name_changed?(from: "Pete", to: "Ringo") + assert @model.name_changed?(to: "Ringo") + assert_not @model.name_changed?(to: "Pete") + assert @model.name_changed?(from: nil) + assert_not @model.name_changed?(from: "Pete") + end + + test "changes accessible through both strings and symbols" do + @model.name = "David" + assert_not_nil @model.changes[:name] + assert_not_nil @model.changes["name"] + end + + test "be consistent with symbols arguments after the changes are applied" do + @model.name = "David" + assert @model.attribute_changed?(:name) + @model.save + @model.name = "Rafael" + assert @model.attribute_changed?(:name) + end + + test "attribute mutation" do + @model.name = "Yam" + @model.save + assert !@model.name_changed? + @model.name.replace("Hadad") + assert @model.name_changed? + end + + test "resetting attribute" do + @model.name = "Bob" + @model.restore_name! + assert_nil @model.name + assert !@model.name_changed? + end + + test "setting color to same value should not result in change being recorded" do + @model.color = "red" + assert @model.color_changed? + @model.save + assert !@model.color_changed? + assert !@model.changed? + @model.color = "red" + assert !@model.color_changed? + assert !@model.changed? + end + + test "saving should reset model's changed status" do + @model.name = "Alf" + assert @model.changed? + @model.save + assert !@model.changed? + assert !@model.name_changed? + end + + test "saving should preserve previous changes" do + @model.name = "Jericho Cane" + @model.save + assert_equal [nil, "Jericho Cane"], @model.previous_changes["name"] + end + + test "setting new attributes should not affect previous changes" do + @model.name = "Jericho Cane" + @model.save + @model.name = "DudeFella ManGuy" + assert_equal [nil, "Jericho Cane"], @model.name_previous_change + end + + test "saving should preserve model's previous changed status" do + @model.name = "Jericho Cane" + @model.save + assert @model.name_previously_changed? + end + + test "previous value is preserved when changed after save" do + assert_equal({}, @model.changed_attributes) + @model.name = "Paul" + assert_equal({ "name" => nil }, @model.changed_attributes) + + @model.save + + @model.name = "John" + assert_equal({ "name" => "Paul" }, @model.changed_attributes) + end + + test "changing the same attribute multiple times retains the correct original value" do + @model.name = "Otto" + @model.save + @model.name = "DudeFella ManGuy" + @model.name = "Mr. Manfredgensonton" + assert_equal ["Otto", "Mr. Manfredgensonton"], @model.name_change + assert_equal @model.name_was, "Otto" + end + + test "using attribute_will_change! with a symbol" do + @model.size = 1 + assert @model.size_changed? + end + + test "reload should reset all changes" do + @model.name = "Dmitry" + @model.name_changed? + @model.save + @model.name = "Bob" + + assert_equal [nil, "Dmitry"], @model.previous_changes["name"] + assert_equal "Dmitry", @model.changed_attributes["name"] + + @model.reload + + assert_equal ActiveSupport::HashWithIndifferentAccess.new, @model.previous_changes + assert_equal ActiveSupport::HashWithIndifferentAccess.new, @model.changed_attributes + end + + test "restore_attributes should restore all previous data" do + @model.name = "Dmitry" + @model.color = "Red" + @model.save + @model.name = "Bob" + @model.color = "White" + + @model.restore_attributes + + assert_not @model.changed? + assert_equal "Dmitry", @model.name + assert_equal "Red", @model.color + end + + test "restore_attributes can restore only some attributes" do + @model.name = "Dmitry" + @model.color = "Red" + @model.save + @model.name = "Bob" + @model.color = "White" + + @model.restore_attributes(["name"]) + + assert @model.changed? + assert_equal "Dmitry", @model.name + assert_equal "White", @model.color + end + + test "changing the attribute reports a change only when the cast value changes" do + @model.size = "2.3" + @model.save + @model.size = "2.1" + + assert_equal false, @model.changed? + + @model.size = "5.1" + + assert_equal true, @model.changed? + assert_equal true, @model.size_changed? + assert_equal({ "size" => [2, 5] }, @model.changes) + end +end diff --git a/activemodel/test/cases/attributes_test.rb b/activemodel/test/cases/attributes_test.rb new file mode 100644 index 0000000000..914aee1ac0 --- /dev/null +++ b/activemodel/test/cases/attributes_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require "cases/helper" + +module ActiveModel + class AttributesTest < ActiveModel::TestCase + class ModelForAttributesTest + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :integer_field, :integer + attribute :string_field, :string + attribute :decimal_field, :decimal + attribute :string_with_default, :string, default: "default string" + attribute :date_field, :date, default: -> { Date.new(2016, 1, 1) } + attribute :boolean_field, :boolean + end + + class ChildModelForAttributesTest < ModelForAttributesTest + end + + class GrandchildModelForAttributesTest < ChildModelForAttributesTest + attribute :integer_field, :string + end + + test "properties assignment" do + data = ModelForAttributesTest.new( + integer_field: "2.3", + string_field: "Rails FTW", + decimal_field: "12.3", + boolean_field: "0" + ) + + assert_equal 2, data.integer_field + assert_equal "Rails FTW", data.string_field + assert_equal BigDecimal.new("12.3"), data.decimal_field + assert_equal "default string", data.string_with_default + assert_equal Date.new(2016, 1, 1), data.date_field + assert_equal false, data.boolean_field + + data.integer_field = 10 + data.string_with_default = nil + data.boolean_field = "1" + + assert_equal 10, data.integer_field + assert_nil data.string_with_default + assert_equal true, data.boolean_field + end + + test "nonexistent attribute" do + assert_raise ActiveModel::UnknownAttributeError do + ModelForAttributesTest.new(nonexistent: "nonexistent") + end + end + + test "children inherit attributes" do + data = ChildModelForAttributesTest.new(integer_field: "4.4") + + assert_equal 4, data.integer_field + end + + test "children can override parents" do + data = GrandchildModelForAttributesTest.new(integer_field: "4.4") + + assert_equal "4.4", data.integer_field + end + end +end diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb index f85cd7dec4..a5d29d0f22 100644 --- a/activemodel/test/cases/callbacks_test.rb +++ b/activemodel/test/cases/callbacks_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" class CallbacksTest < ActiveModel::TestCase diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index 4a93347abc..347896ed50 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/contact" require "models/helicopter" diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb index fdd18d7601..dfe041ff50 100644 --- a/activemodel/test/cases/dirty_test.rb +++ b/activemodel/test/cases/dirty_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" class DirtyTest < ActiveModel::TestCase @@ -96,7 +98,7 @@ class DirtyTest < ActiveModel::TestCase end test "attribute mutation" do - @model.instance_variable_set("@name", "Yam") + @model.instance_variable_set("@name", "Yam".dup) assert !@model.name_changed? @model.name.replace("Hadad") assert !@model.name_changed? @@ -217,4 +219,8 @@ class DirtyTest < ActiveModel::TestCase assert_equal "Dmitry", @model.name assert_equal "White", @model.color end + + test "model can be dup-ed without Attributes" do + assert @model.dup + end end diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index 43aee5a814..d5c282b620 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/core_ext/string/strip" require "yaml" @@ -221,6 +223,13 @@ class ErrorsTest < ActiveModel::TestCase assert !person.errors.added?(:name) end + test "added? returns false when checking for an error by symbol and a different error with same message is present" do + I18n.backend.store_translations("en", errors: { attributes: { name: { wrong: "is wrong", used: "is wrong" } } }) + person = Person.new + person.errors.add(:name, :wrong) + assert !person.errors.added?(:name, :used) + end + test "size calculates the number of error messages" do person = Person.new person.errors.add(:name, "cannot be blank") @@ -375,6 +384,18 @@ class ErrorsTest < ActiveModel::TestCase assert_equal [:name], person.errors.details.keys end + test "merge errors" do + errors = ActiveModel::Errors.new(Person.new) + errors.add(:name, :invalid) + + person = Person.new + person.errors.add(:name, :blank) + person.errors.merge!(errors) + + assert_equal({ name: ["can't be blank", "is invalid"] }, person.errors.messages) + assert_equal({ name: [{ error: :blank }, { error: :invalid }] }, person.errors.details) + end + test "errors are marshalable" do errors = ActiveModel::Errors.new(Person.new) errors.add(:name, :invalid) diff --git a/activemodel/test/cases/forbidden_attributes_protection_test.rb b/activemodel/test/cases/forbidden_attributes_protection_test.rb index d8cc72e662..0fd0a2f8ee 100644 --- a/activemodel/test/cases/forbidden_attributes_protection_test.rb +++ b/activemodel/test/cases/forbidden_attributes_protection_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/core_ext/hash/indifferent_access" require "models/account" diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb index eeb5c85a48..91fb9d0a7c 100644 --- a/activemodel/test/cases/helper.rb +++ b/activemodel/test/cases/helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_model" # Show backtraces for deprecated behavior for quicker cleanup. diff --git a/activemodel/test/cases/lint_test.rb b/activemodel/test/cases/lint_test.rb index 7a817d7c01..d62c80b71a 100644 --- a/activemodel/test/cases/lint_test.rb +++ b/activemodel/test/cases/lint_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" class LintTest < ActiveModel::TestCase diff --git a/activemodel/test/cases/model_test.rb b/activemodel/test/cases/model_test.rb index ba87cd1506..b24d7e3571 100644 --- a/activemodel/test/cases/model_test.rb +++ b/activemodel/test/cases/model_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" class ModelTest < ActiveModel::TestCase diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index d5cb1a62bc..009f1f47af 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/contact" require "models/sheep" diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb index a56b26b5ee..ff5022e960 100644 --- a/activemodel/test/cases/railtie_test.rb +++ b/activemodel/test/cases/railtie_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/testing/isolation" diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index 77ce86f392..d19e81a119 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/user" require "models/visitor" diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb index f78efd2f0c..9002982e7f 100644 --- a/activemodel/test/cases/serialization_test.rb +++ b/activemodel/test/cases/serialization_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/core_ext/object/instance_variables" diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index d15ba64eb0..aae98c9fe4 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/contact" require "active_support/core_ext/object/instance_variables" diff --git a/activemodel/test/cases/translation_test.rb b/activemodel/test/cases/translation_test.rb index 9972f9daea..cd75afec9e 100644 --- a/activemodel/test/cases/translation_test.rb +++ b/activemodel/test/cases/translation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/person" diff --git a/activemodel/test/cases/type/big_integer_test.rb b/activemodel/test/cases/type/big_integer_test.rb index 56002b7cc6..0fa0200df4 100644 --- a/activemodel/test/cases/type/big_integer_test.rb +++ b/activemodel/test/cases/type/big_integer_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/binary_test.rb b/activemodel/test/cases/type/binary_test.rb index e9c2ccfca4..3221a73e49 100644 --- a/activemodel/test/cases/type/binary_test.rb +++ b/activemodel/test/cases/type/binary_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/boolean_test.rb b/activemodel/test/cases/type/boolean_test.rb index 92e5aebfb7..2d33579595 100644 --- a/activemodel/test/cases/type/boolean_test.rb +++ b/activemodel/test/cases/type/boolean_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/date_test.rb b/activemodel/test/cases/type/date_test.rb index 0cc90e99d3..e8cf178612 100644 --- a/activemodel/test/cases/type/date_test.rb +++ b/activemodel/test/cases/type/date_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/date_time_test.rb b/activemodel/test/cases/type/date_time_test.rb index 75a7fc686e..60f62becc2 100644 --- a/activemodel/test/cases/type/date_time_test.rb +++ b/activemodel/test/cases/type/date_time_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/decimal_test.rb b/activemodel/test/cases/type/decimal_test.rb index c3b43725cc..b91d67f95f 100644 --- a/activemodel/test/cases/type/decimal_test.rb +++ b/activemodel/test/cases/type/decimal_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/float_test.rb b/activemodel/test/cases/type/float_test.rb index 8026d63ad5..28318e06f8 100644 --- a/activemodel/test/cases/type/float_test.rb +++ b/activemodel/test/cases/type/float_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/immutable_string_test.rb b/activemodel/test/cases/type/immutable_string_test.rb index 23e58974fb..751f753ddb 100644 --- a/activemodel/test/cases/type/immutable_string_test.rb +++ b/activemodel/test/cases/type/immutable_string_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/integer_test.rb b/activemodel/test/cases/type/integer_test.rb index a91144036b..8c5d18c9b3 100644 --- a/activemodel/test/cases/type/integer_test.rb +++ b/activemodel/test/cases/type/integer_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" require "active_support/core_ext/numeric/time" module ActiveModel diff --git a/activemodel/test/cases/type/registry_test.rb b/activemodel/test/cases/type/registry_test.rb index 927b6d0307..0633ea2538 100644 --- a/activemodel/test/cases/type/registry_test.rb +++ b/activemodel/test/cases/type/registry_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/string_test.rb b/activemodel/test/cases/type/string_test.rb index 47d412e27e..825c8bb246 100644 --- a/activemodel/test/cases/type/string_test.rb +++ b/activemodel/test/cases/type/string_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type @@ -14,7 +15,7 @@ module ActiveModel test "cast strings are mutable" do type = Type::String.new - s = "foo" + s = "foo".dup assert_equal false, type.cast(s).frozen? assert_equal false, s.frozen? diff --git a/activemodel/test/cases/type/time_test.rb b/activemodel/test/cases/type/time_test.rb index 0cc4d33caa..f7102d1e97 100644 --- a/activemodel/test/cases/type/time_test.rb +++ b/activemodel/test/cases/type/time_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/value_test.rb b/activemodel/test/cases/type/value_test.rb index d8b3e7f164..55b5d9d584 100644 --- a/activemodel/test/cases/type/value_test.rb +++ b/activemodel/test/cases/type/value_test.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/validations/absence_validation_test.rb b/activemodel/test/cases/validations/absence_validation_test.rb index 833f694c5a..801577474a 100644 --- a/activemodel/test/cases/validations/absence_validation_test.rb +++ b/activemodel/test/cases/validations/absence_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" require "models/person" diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb index fbd994e914..c5f54b1868 100644 --- a/activemodel/test/cases/validations/acceptance_validation_test.rb +++ b/activemodel/test/cases/validations/acceptance_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" diff --git a/activemodel/test/cases/validations/callbacks_test.rb b/activemodel/test/cases/validations/callbacks_test.rb index f2e4a5946d..d3a9a17a05 100644 --- a/activemodel/test/cases/validations/callbacks_test.rb +++ b/activemodel/test/cases/validations/callbacks_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" class Dog diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb index 048d27446e..caea8b65ef 100644 --- a/activemodel/test/cases/validations/conditional_validation_test.rb +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" @@ -16,6 +18,22 @@ class ConditionalValidationTest < ActiveModel::TestCase assert_equal ["hoo 5"], t.errors["title"] end + def test_if_validation_using_array_of_true_methods + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: [:condition_is_true, :condition_is_true]) + t = Topic.new("title" => "uhohuhoh", "content" => "whatever") + assert t.invalid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_unless_validation_using_array_of_false_methods + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: [:condition_is_false, :condition_is_false]) + t = Topic.new("title" => "uhohuhoh", "content" => "whatever") + assert t.invalid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + def test_unless_validation_using_method_true # When the method returns true Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true) @@ -24,59 +42,31 @@ class ConditionalValidationTest < ActiveModel::TestCase assert_empty t.errors[:title] end - def test_if_validation_using_method_false - # When the method returns false - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true_but_its_not) + def test_if_validation_using_array_of_true_and_false_methods + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: [:condition_is_true, :condition_is_false]) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert_empty t.errors[:title] end - def test_unless_validation_using_method_false - # When the method returns false - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true_but_its_not) - t = Topic.new("title" => "uhohuhoh", "content" => "whatever") - assert t.invalid? - assert t.errors[:title].any? - assert_equal ["hoo 5"], t.errors["title"] - end - - def test_if_validation_using_string_true - # When the evaluated string returns true - ActiveSupport::Deprecation.silence do - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: "a = 1; a == 1") - end - t = Topic.new("title" => "uhohuhoh", "content" => "whatever") - assert t.invalid? - assert t.errors[:title].any? - assert_equal ["hoo 5"], t.errors["title"] - end - - def test_unless_validation_using_string_true - # When the evaluated string returns true - ActiveSupport::Deprecation.silence do - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: "a = 1; a == 1") - end + def test_unless_validation_using_array_of_true_and_felse_methods + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: [:condition_is_true, :condition_is_false]) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert_empty t.errors[:title] end - def test_if_validation_using_string_false - # When the evaluated string returns false - ActiveSupport::Deprecation.silence do - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: "false") - end + def test_if_validation_using_method_false + # When the method returns false + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_false) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert_empty t.errors[:title] end - def test_unless_validation_using_string_false - # When the evaluated string returns false - ActiveSupport::Deprecation.silence do - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: "false") - end + def test_unless_validation_using_method_false + # When the method returns false + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_false) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -121,27 +111,18 @@ class ConditionalValidationTest < ActiveModel::TestCase assert_equal ["hoo 5"], t.errors["title"] end - # previous implementation of validates_presence_of eval'd the - # string with the wrong binding, this regression test is to - # ensure that it works correctly - def test_validation_with_if_as_string - Topic.validates_presence_of(:title) - ActiveSupport::Deprecation.silence do - Topic.validates_presence_of(:author_name, if: "title.to_s.match('important')") - end - - t = Topic.new - assert t.invalid?, "A topic without a title should not be valid" - assert_empty t.errors[:author_name], "A topic without an 'important' title should not require an author" - - t.title = "Just a title" - assert t.valid?, "A topic with a basic title should be valid" - - t.title = "A very important title" - assert t.invalid?, "A topic with an important title, but without an author, should not be valid" - assert t.errors[:author_name].any?, "A topic with an 'important' title should require an author" + def test_validation_using_conbining_if_true_and_unless_true_conditions + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true, unless: :condition_is_true) + t = Topic.new("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert_empty t.errors[:title] + end - t.author_name = "Hubert J. Farnsworth" - assert t.valid?, "A topic with an important title and author should be valid" + def test_validation_using_conbining_if_true_and_unless_false_conditions + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true, unless: :condition_is_false) + t = Topic.new("title" => "uhohuhoh", "content" => "whatever") + assert t.invalid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] end end diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb index 7ddf3ad273..8b2c65289b 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" @@ -35,6 +37,19 @@ class ConfirmationValidationTest < ActiveModel::TestCase assert t.valid? end + def test_validates_confirmation_of_with_boolean_attribute + Topic.validates_confirmation_of(:approved) + + t = Topic.new(approved: true, approved_confirmation: nil) + assert t.valid? + + t.approved_confirmation = false + assert t.invalid? + + t.approved_confirmation = true + assert t.valid? + end + def test_validates_confirmation_of_for_ruby_class Person.validates_confirmation_of :karma diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb index 06ae4fbecd..68d611e904 100644 --- a/activemodel/test/cases/validations/exclusion_validation_test.rb +++ b/activemodel/test/cases/validations/exclusion_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/core_ext/numeric/time" diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb index d7e6bf3707..3ddda2154a 100644 --- a/activemodel/test/cases/validations/format_validation_test.rb +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" @@ -107,7 +109,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_with_lambda - Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\z/ : /\A\S+\z/ } t = Topic.new t.title = "digit" @@ -119,7 +121,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_without_lambda - Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\z/ : /\A\S+\z/ } t = Topic.new t.title = "characters" @@ -131,7 +133,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_for_ruby_class - Person.validates_format_of :karma, with: /\A\d+\Z/ + Person.validates_format_of :karma, with: /\A\d+\z/ p = Person.new p.karma = "Pixies" diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index f049ee26e8..d3e44945db 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/person" diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index f28cfc0ef5..9cfe189d0e 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/person" diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb index 5aa43ea4a9..94df0649a9 100644 --- a/activemodel/test/cases/validations/inclusion_validation_test.rb +++ b/activemodel/test/cases/validations/inclusion_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "active_support/all" diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb index 95ee87b401..42f76f3e3c 100644 --- a/activemodel/test/cases/validations/length_validation_test.rb +++ b/activemodel/test/cases/validations/length_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" @@ -408,4 +410,35 @@ class LengthValidationTest < ActiveModel::TestCase assert Topic.new("title" => "david").valid? assert Topic.new("title" => "david2").invalid? end + + def test_validates_length_of_using_proc_as_maximum + Topic.validates_length_of :title, maximum: ->(model) { 5 } + + t = Topic.new("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = "notvalid" + assert t.invalid? + assert t.errors[:title].any? + assert_equal ["is too long (maximum is 5 characters)"], t.errors[:title] + + t.title = "" + assert t.valid? + end + + def test_validates_length_of_using_proc_as_maximum_with_model_method + Topic.send(:define_method, :max_title_length, lambda { 5 }) + Topic.validates_length_of :title, maximum: Proc.new(&:max_title_length) + + t = Topic.new("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = "notvalid" + assert t.invalid? + assert t.errors[:title].any? + assert_equal ["is too long (maximum is 5 characters)"], t.errors[:title] + + t.title = "" + assert t.valid? + end end diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index c0158e075f..fbbaf8a30c 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" @@ -57,7 +59,7 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_of_with_integer_only_and_symbol_as_value - Topic.validates_numericality_of :approved, only_integer: :condition_is_true_but_its_not + Topic.validates_numericality_of :approved, only_integer: :condition_is_false invalid!(NIL + BLANK + JUNK) valid!(FLOATS + INTEGERS + BIGDECIMAL + INFINITY) diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb index 642dd0f144..22c2f0af87 100644 --- a/activemodel/test/cases/validations/presence_validation_test.rb +++ b/activemodel/test/cases/validations/presence_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb index 011033606e..7f32f5dc74 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/person" require "models/topic" @@ -60,17 +62,23 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_if_as_local_conditions - Person.validates :karma, presence: true, email: { unless: :condition_is_true } + Person.validates :karma, presence: true, email: { if: :condition_is_false } person = Person.new person.valid? assert_equal ["can't be blank"], person.errors[:karma] end def test_validates_with_if_as_shared_conditions - Person.validates :karma, presence: true, email: true, if: :condition_is_true + Person.validates :karma, presence: true, email: true, if: :condition_is_false + person = Person.new + assert person.valid? + end + + def test_validates_with_unless_as_local_conditions + Person.validates :karma, presence: true, email: { unless: :condition_is_true } person = Person.new person.valid? - assert_equal ["can't be blank", "is not an email"], person.errors[:karma].sort + assert_equal ["can't be blank"], person.errors[:karma] end def test_validates_with_unless_shared_conditions diff --git a/activemodel/test/cases/validations/validations_context_test.rb b/activemodel/test/cases/validations/validations_context_test.rb index 25c37a572f..024eb1882f 100644 --- a/activemodel/test/cases/validations/validations_context_test.rb +++ b/activemodel/test/cases/validations/validations_context_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb index 5ce86738cd..13ef5e6a31 100644 --- a/activemodel/test/cases/validations/with_validation_test.rb +++ b/activemodel/test/cases/validations/with_validation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" @@ -68,51 +70,15 @@ class ValidatesWithTest < ActiveModel::TestCase assert_includes topic.errors[:base], OTHER_ERROR_MESSAGE end - test "with if statements that return false" do - ActiveSupport::Deprecation.silence do - Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 2") - end - topic = Topic.new - assert topic.valid? - end - - test "with if statements that return true" do - ActiveSupport::Deprecation.silence do - Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 1") - end - topic = Topic.new - assert topic.invalid? - assert_includes topic.errors[:base], ERROR_MESSAGE - end - - test "with unless statements that return true" do - ActiveSupport::Deprecation.silence do - Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 1") - end - topic = Topic.new - assert topic.valid? - end - - test "with unless statements that returns false" do - ActiveSupport::Deprecation.silence do - Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 2") - end - topic = Topic.new - assert topic.invalid? - assert_includes topic.errors[:base], ERROR_MESSAGE - end - test "passes all configuration options to the validator class" do topic = Topic.new validator = Minitest::Mock.new - validator.expect(:new, validator, [{ foo: :bar, if: "1 == 1", class: Topic }]) + validator.expect(:new, validator, [{ foo: :bar, if: :condition_is_true, class: Topic }]) validator.expect(:validate, nil, [topic]) validator.expect(:is_a?, false, [Symbol]) validator.expect(:is_a?, false, [String]) - ActiveSupport::Deprecation.silence do - Topic.validates_with(validator, if: "1 == 1", foo: :bar) - end + Topic.validates_with(validator, if: :condition_is_true, foo: :bar) assert topic.valid? validator.verify end diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 6647191205..ab8c41bbd0 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/topic" diff --git a/activemodel/test/models/account.rb b/activemodel/test/models/account.rb index eed668d38f..40408e5708 100644 --- a/activemodel/test/models/account.rb +++ b/activemodel/test/models/account.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Account include ActiveModel::ForbiddenAttributesProtection diff --git a/activemodel/test/models/blog_post.rb b/activemodel/test/models/blog_post.rb index 46eba857df..d4b02eeaa7 100644 --- a/activemodel/test/models/blog_post.rb +++ b/activemodel/test/models/blog_post.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Blog def self.use_relative_model_naming? true diff --git a/activemodel/test/models/contact.rb b/activemodel/test/models/contact.rb index 113ab0bc1f..c40a6d6f0e 100644 --- a/activemodel/test/models/contact.rb +++ b/activemodel/test/models/contact.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Contact extend ActiveModel::Naming include ActiveModel::Conversion diff --git a/activemodel/test/models/custom_reader.rb b/activemodel/test/models/custom_reader.rb index dc26bb10ff..df605e93d9 100644 --- a/activemodel/test/models/custom_reader.rb +++ b/activemodel/test/models/custom_reader.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CustomReader include ActiveModel::Validations diff --git a/activemodel/test/models/helicopter.rb b/activemodel/test/models/helicopter.rb index 933f3c463a..fe82c463d3 100644 --- a/activemodel/test/models/helicopter.rb +++ b/activemodel/test/models/helicopter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Helicopter include ActiveModel::Conversion end diff --git a/activemodel/test/models/person.rb b/activemodel/test/models/person.rb index e896e90f98..8dd8ceadad 100644 --- a/activemodel/test/models/person.rb +++ b/activemodel/test/models/person.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Person include ActiveModel::Validations extend ActiveModel::Translation @@ -7,6 +9,10 @@ class Person def condition_is_true true end + + def condition_is_false + false + end end class Person::Gender diff --git a/activemodel/test/models/person_with_validator.rb b/activemodel/test/models/person_with_validator.rb index 505ed880c1..44e78cbc29 100644 --- a/activemodel/test/models/person_with_validator.rb +++ b/activemodel/test/models/person_with_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PersonWithValidator include ActiveModel::Validations diff --git a/activemodel/test/models/reply.rb b/activemodel/test/models/reply.rb index 3fe11043d2..6bb18f95fe 100644 --- a/activemodel/test/models/reply.rb +++ b/activemodel/test/models/reply.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "models/topic" class Reply < Topic diff --git a/activemodel/test/models/sheep.rb b/activemodel/test/models/sheep.rb index 7aba055c4f..30dd9ce192 100644 --- a/activemodel/test/models/sheep.rb +++ b/activemodel/test/models/sheep.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Sheep extend ActiveModel::Naming end diff --git a/activemodel/test/models/topic.rb b/activemodel/test/models/topic.rb index 192786c096..b0af00ee45 100644 --- a/activemodel/test/models/topic.rb +++ b/activemodel/test/models/topic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Topic include ActiveModel::Validations include ActiveModel::Validations::Callbacks @@ -21,7 +23,7 @@ class Topic true end - def condition_is_true_but_its_not + def condition_is_false false end diff --git a/activemodel/test/models/track_back.rb b/activemodel/test/models/track_back.rb index 357ee37d6d..728a022db5 100644 --- a/activemodel/test/models/track_back.rb +++ b/activemodel/test/models/track_back.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Post class TrackBack def to_model diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb index 6556b1a7d9..e98fd8a0a1 100644 --- a/activemodel/test/models/user.rb +++ b/activemodel/test/models/user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class User extend ActiveModel::Callbacks include ActiveModel::SecurePassword diff --git a/activemodel/test/models/visitor.rb b/activemodel/test/models/visitor.rb index 22ad1a3c3d..9da004ffcc 100644 --- a/activemodel/test/models/visitor.rb +++ b/activemodel/test/models/visitor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Visitor extend ActiveModel::Callbacks include ActiveModel::SecurePassword diff --git a/activemodel/test/validators/email_validator.rb b/activemodel/test/validators/email_validator.rb index f733c45cf0..0c634d8659 100644 --- a/activemodel/test/validators/email_validator.rb +++ b/activemodel/test/validators/email_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) record.errors[attribute] << (options[:message] || "is not an email") unless diff --git a/activemodel/test/validators/namespace/email_validator.rb b/activemodel/test/validators/namespace/email_validator.rb index 8639045b0d..e7815d92dc 100644 --- a/activemodel/test/validators/namespace/email_validator.rb +++ b/activemodel/test/validators/namespace/email_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "validators/email_validator" module Namespace |