diff options
Diffstat (limited to 'activemodel/test')
25 files changed, 616 insertions, 52 deletions
diff --git a/activemodel/test/cases/attribute_set_test.rb b/activemodel/test/cases/attribute_set_test.rb new file mode 100644 index 0000000000..6e522d6c80 --- /dev/null +++ b/activemodel/test/cases/attribute_set_test.rb @@ -0,0 +1,257 @@ +# 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 + defaults = { foo: Attribute.from_user(:foo, nil, nil) } + builder = AttributeSet::Builder.new({ foo: Type::Integer.new }, defaults) + 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 index 26b0e85db3..83a86371e0 100644 --- a/activemodel/test/cases/attributes_dirty_test.rb +++ b/activemodel/test/cases/attributes_dirty_test.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true require "cases/helper" -require "active_model/attributes" class AttributesDirtyTest < ActiveModel::TestCase class DirtyModel include ActiveModel::Model include ActiveModel::Attributes + include ActiveModel::Dirty attribute :name, :string attribute :color, :string attribute :size, :integer @@ -69,12 +69,10 @@ class AttributesDirtyTest < ActiveModel::TestCase end test "attribute mutation" do - @model.instance_variable_set("@name", "Yam".dup) + @model.name = "Yam" + @model.save assert !@model.name_changed? @model.name.replace("Hadad") - assert !@model.name_changed? - @model.name_will_change! - @model.name.replace("Baal") assert @model.name_changed? end @@ -190,4 +188,18 @@ class AttributesDirtyTest < ActiveModel::TestCase 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 index 064cba40e3..914aee1ac0 100644 --- a/activemodel/test/cases/attributes_test.rb +++ b/activemodel/test/cases/attributes_test.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "cases/helper" -require "active_model/attributes" module ActiveModel class AttributesTest < ActiveModel::TestCase @@ -13,7 +12,7 @@ module ActiveModel attribute :string_field, :string attribute :decimal_field, :decimal attribute :string_with_default, :string, default: "default string" - attribute :date_field, :string, default: -> { Date.new(2016, 1, 1) } + attribute :date_field, :date, default: -> { Date.new(2016, 1, 1) } attribute :boolean_field, :boolean end @@ -48,31 +47,6 @@ module ActiveModel assert_equal true, data.boolean_field end - test "dirty" do - data = ModelForAttributesTest.new( - integer_field: "2.3", - string_field: "Rails FTW", - decimal_field: "12.3", - boolean_field: "0" - ) - - assert_equal false, data.changed? - - data.integer_field = "2.1" - - assert_equal false, data.changed? - - data.string_with_default = "default string" - - assert_equal false, data.changed? - - data.integer_field = "5.1" - - assert_equal true, data.changed? - assert_equal true, data.integer_field_changed? - assert_equal({ "integer_field" => [2, 5] }, data.changes) - end - test "nonexistent attribute" do assert_raise ActiveModel::UnknownAttributeError do ModelForAttributesTest.new(nonexistent: "nonexistent") diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb index 2cd9e185e6..dfe041ff50 100644 --- a/activemodel/test/cases/dirty_test.rb +++ b/activemodel/test/cases/dirty_test.rb @@ -219,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 ab18af0de1..d5c282b620 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -223,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") diff --git a/activemodel/test/cases/type/big_integer_test.rb b/activemodel/test/cases/type/big_integer_test.rb index 3d29235d52..0fa0200df4 100644 --- a/activemodel/test/cases/type/big_integer_test.rb +++ b/activemodel/test/cases/type/big_integer_test.rb @@ -1,7 +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 ef4f125a3b..3221a73e49 100644 --- a/activemodel/test/cases/type/binary_test.rb +++ b/activemodel/test/cases/type/binary_test.rb @@ -1,7 +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 97b165ab48..2d33579595 100644 --- a/activemodel/test/cases/type/boolean_test.rb +++ b/activemodel/test/cases/type/boolean_test.rb @@ -1,7 +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 15c40a37b7..e8cf178612 100644 --- a/activemodel/test/cases/type/date_test.rb +++ b/activemodel/test/cases/type/date_test.rb @@ -1,7 +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 598ccf485e..60f62becc2 100644 --- a/activemodel/test/cases/type/date_time_test.rb +++ b/activemodel/test/cases/type/date_time_test.rb @@ -1,7 +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 a0acdc2736..b91d67f95f 100644 --- a/activemodel/test/cases/type/decimal_test.rb +++ b/activemodel/test/cases/type/decimal_test.rb @@ -1,7 +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 46e8b34dfe..28318e06f8 100644 --- a/activemodel/test/cases/type/float_test.rb +++ b/activemodel/test/cases/type/float_test.rb @@ -1,7 +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 72f5779dfb..751f753ddb 100644 --- a/activemodel/test/cases/type/immutable_string_test.rb +++ b/activemodel/test/cases/type/immutable_string_test.rb @@ -1,7 +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 d2e635b447..8c5d18c9b3 100644 --- a/activemodel/test/cases/type/integer_test.rb +++ b/activemodel/test/cases/type/integer_test.rb @@ -1,7 +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 f34104286c..0633ea2538 100644 --- a/activemodel/test/cases/type/registry_test.rb +++ b/activemodel/test/cases/type/registry_test.rb @@ -1,7 +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 d39389718b..825c8bb246 100644 --- a/activemodel/test/cases/type/string_test.rb +++ b/activemodel/test/cases/type/string_test.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/type/time_test.rb b/activemodel/test/cases/type/time_test.rb index 0bea95768d..f7102d1e97 100644 --- a/activemodel/test/cases/type/time_test.rb +++ b/activemodel/test/cases/type/time_test.rb @@ -1,7 +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 671343b0c8..55b5d9d584 100644 --- a/activemodel/test/cases/type/value_test.rb +++ b/activemodel/test/cases/type/value_test.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "cases/helper" -require "active_model/type" module ActiveModel module Type diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb index aa027c4128..caea8b65ef 100644 --- a/activemodel/test/cases/validations/conditional_validation_test.rb +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -18,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) @@ -26,9 +42,23 @@ class ConditionalValidationTest < ActiveModel::TestCase assert_empty t.errors[:title] end + 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_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_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) + 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] @@ -36,7 +66,7 @@ class ConditionalValidationTest < ActiveModel::TestCase 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) + 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? @@ -80,4 +110,19 @@ class ConditionalValidationTest < ActiveModel::TestCase assert t.errors[:title].any? assert_equal ["hoo 5"], t.errors["title"] end + + 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 + + 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 e84415a868..8b2c65289b 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -37,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/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 001815e28f..fbbaf8a30c 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -59,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/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb index 77cb8ebdc1..7f32f5dc74 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -62,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/models/person.rb b/activemodel/test/models/person.rb index b61fdf76b1..8dd8ceadad 100644 --- a/activemodel/test/models/person.rb +++ b/activemodel/test/models/person.rb @@ -9,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/topic.rb b/activemodel/test/models/topic.rb index 2f4e92c3b2..b0af00ee45 100644 --- a/activemodel/test/models/topic.rb +++ b/activemodel/test/models/topic.rb @@ -23,7 +23,7 @@ class Topic true end - def condition_is_true_but_its_not + def condition_is_false false end |