aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/test')
-rw-r--r--activemodel/test/cases/attribute_assignment_test.rb17
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb94
-rw-r--r--activemodel/test/cases/attribute_set_test.rb37
-rw-r--r--activemodel/test/cases/attribute_test.rb22
-rw-r--r--activemodel/test/cases/attributes_dirty_test.rb40
-rw-r--r--activemodel/test/cases/attributes_test.rb29
-rw-r--r--activemodel/test/cases/callbacks_test.rb14
-rw-r--r--activemodel/test/cases/dirty_test.rb79
-rw-r--r--activemodel/test/cases/errors_test.rb141
-rw-r--r--activemodel/test/cases/helper.rb18
-rw-r--r--activemodel/test/cases/naming_test.rb2
-rw-r--r--activemodel/test/cases/railtie_test.rb20
-rw-r--r--activemodel/test/cases/secure_password_test.rb51
-rw-r--r--activemodel/test/cases/serialization_test.rb7
-rw-r--r--activemodel/test/cases/serializers/json_serialization_test.rb52
-rw-r--r--activemodel/test/cases/type/boolean_test.rb4
-rw-r--r--activemodel/test/cases/type/date_test.rb5
-rw-r--r--activemodel/test/cases/type/date_time_test.rb11
-rw-r--r--activemodel/test/cases/type/decimal_test.rb5
-rw-r--r--activemodel/test/cases/type/float_test.rb5
-rw-r--r--activemodel/test/cases/type/integer_test.rb13
-rw-r--r--activemodel/test/cases/type/string_test.rb12
-rw-r--r--activemodel/test/cases/type/time_test.rb16
-rw-r--r--activemodel/test/cases/validations/absence_validation_test.rb18
-rw-r--r--activemodel/test/cases/validations/acceptance_validation_test.rb26
-rw-r--r--activemodel/test/cases/validations/callbacks_test.rb43
-rw-r--r--activemodel/test/cases/validations/conditional_validation_test.rb42
-rw-r--r--activemodel/test/cases/validations/confirmation_validation_test.rb60
-rw-r--r--activemodel/test/cases/validations/exclusion_validation_test.rb36
-rw-r--r--activemodel/test/cases/validations/format_validation_test.rb36
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb118
-rw-r--r--activemodel/test/cases/validations/inclusion_validation_test.rb88
-rw-r--r--activemodel/test/cases/validations/length_validation_test.rb198
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb50
-rw-r--r--activemodel/test/cases/validations/presence_validation_test.rb20
-rw-r--r--activemodel/test/cases/validations/validates_test.rb24
-rw-r--r--activemodel/test/cases/validations/with_validation_test.rb28
-rw-r--r--activemodel/test/cases/validations_test.rb56
-rw-r--r--activemodel/test/models/topic.rb14
-rw-r--r--activemodel/test/models/user.rb3
-rw-r--r--activemodel/test/models/visitor.rb3
41 files changed, 1006 insertions, 551 deletions
diff --git a/activemodel/test/cases/attribute_assignment_test.rb b/activemodel/test/cases/attribute_assignment_test.rb
index 5ecf0a69c4..30e8419685 100644
--- a/activemodel/test/cases/attribute_assignment_test.rb
+++ b/activemodel/test/cases/attribute_assignment_test.rb
@@ -18,10 +18,7 @@ class AttributeAssignmentTest < ActiveModel::TestCase
raise ErrorFromAttributeWriter
end
- # TODO Change this to private once we've dropped Ruby 2.2 support.
- # Workaround for Ruby 2.2 "private attribute?" warning.
- protected
-
+ private
attr_writer :metadata
end
@@ -71,6 +68,14 @@ class AttributeAssignmentTest < ActiveModel::TestCase
assert_equal "world", model.description
end
+ test "simple assignment alias" do
+ model = Model.new
+
+ model.attributes = { name: "hello", description: "world" }
+ assert_equal "hello", model.name
+ assert_equal "world", model.description
+ end
+
test "assign non-existing attribute" do
model = Model.new
error = assert_raises(ActiveModel::UnknownAttributeError) do
@@ -95,9 +100,11 @@ class AttributeAssignmentTest < ActiveModel::TestCase
end
test "an ArgumentError is raised if a non-hash-like object is passed" do
- assert_raises(ArgumentError) do
+ err = assert_raises(ArgumentError) do
Model.new(1)
end
+
+ assert_equal("When assigning attributes, you must pass a hash as an argument, Integer passed.", err.message)
end
test "forbidden attributes cannot be used for mass assignment" do
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index d2837ec894..ebb6cc542d 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -106,14 +106,12 @@ class AttributeMethodsTest < ActiveModel::TestCase
end
test "#define_attribute_method generates attribute method" do
- begin
- ModelWithAttributes.define_attribute_method(:foo)
+ ModelWithAttributes.define_attribute_method(:foo)
- assert_respond_to ModelWithAttributes.new, :foo
- assert_equal "value of foo", ModelWithAttributes.new.foo
- ensure
- ModelWithAttributes.undefine_attribute_methods
- end
+ assert_respond_to ModelWithAttributes.new, :foo
+ assert_equal "value of foo", ModelWithAttributes.new.foo
+ ensure
+ ModelWithAttributes.undefine_attribute_methods
end
test "#define_attribute_method does not generate attribute method if already defined in attribute module" do
@@ -140,36 +138,30 @@ class AttributeMethodsTest < ActiveModel::TestCase
end
test "#define_attribute_method generates attribute method with invalid identifier characters" do
- begin
- ModelWithWeirdNamesAttributes.define_attribute_method(:'a?b')
+ ModelWithWeirdNamesAttributes.define_attribute_method(:'a?b')
- assert_respond_to ModelWithWeirdNamesAttributes.new, :'a?b'
- assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send("a?b")
- ensure
- ModelWithWeirdNamesAttributes.undefine_attribute_methods
- end
+ assert_respond_to ModelWithWeirdNamesAttributes.new, :'a?b'
+ assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send("a?b")
+ ensure
+ ModelWithWeirdNamesAttributes.undefine_attribute_methods
end
test "#define_attribute_methods works passing multiple arguments" do
- begin
- ModelWithAttributes.define_attribute_methods(:foo, :baz)
+ ModelWithAttributes.define_attribute_methods(:foo, :baz)
- assert_equal "value of foo", ModelWithAttributes.new.foo
- assert_equal "value of baz", ModelWithAttributes.new.baz
- ensure
- ModelWithAttributes.undefine_attribute_methods
- end
+ assert_equal "value of foo", ModelWithAttributes.new.foo
+ assert_equal "value of baz", ModelWithAttributes.new.baz
+ ensure
+ ModelWithAttributes.undefine_attribute_methods
end
test "#define_attribute_methods generates attribute methods" do
- begin
- ModelWithAttributes.define_attribute_methods(:foo)
+ ModelWithAttributes.define_attribute_methods(:foo)
- assert_respond_to ModelWithAttributes.new, :foo
- assert_equal "value of foo", ModelWithAttributes.new.foo
- ensure
- ModelWithAttributes.undefine_attribute_methods
- end
+ assert_respond_to ModelWithAttributes.new, :foo
+ assert_equal "value of foo", ModelWithAttributes.new.foo
+ ensure
+ ModelWithAttributes.undefine_attribute_methods
end
test "#alias_attribute generates attribute_aliases lookup hash" do
@@ -182,45 +174,39 @@ class AttributeMethodsTest < ActiveModel::TestCase
end
test "#define_attribute_methods generates attribute methods with spaces in their names" do
- begin
- ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
- assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
- assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.send(:'foo bar')
- ensure
- ModelWithAttributesWithSpaces.undefine_attribute_methods
- end
+ assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
+ assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.send(:'foo bar')
+ ensure
+ ModelWithAttributesWithSpaces.undefine_attribute_methods
end
test "#alias_attribute works with attributes with spaces in their names" do
- begin
- ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
- ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar')
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
+ ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar')
- assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar
- ensure
- ModelWithAttributesWithSpaces.undefine_attribute_methods
- end
+ assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar
+ ensure
+ ModelWithAttributesWithSpaces.undefine_attribute_methods
end
test "#alias_attribute works with attributes named as a ruby keyword" do
- begin
- ModelWithRubyKeywordNamedAttributes.define_attribute_methods([:begin, :end])
- ModelWithRubyKeywordNamedAttributes.alias_attribute(:from, :begin)
- ModelWithRubyKeywordNamedAttributes.alias_attribute(:to, :end)
-
- assert_equal "value of begin", ModelWithRubyKeywordNamedAttributes.new.from
- assert_equal "value of end", ModelWithRubyKeywordNamedAttributes.new.to
- ensure
- ModelWithRubyKeywordNamedAttributes.undefine_attribute_methods
- end
+ ModelWithRubyKeywordNamedAttributes.define_attribute_methods([:begin, :end])
+ ModelWithRubyKeywordNamedAttributes.alias_attribute(:from, :begin)
+ ModelWithRubyKeywordNamedAttributes.alias_attribute(:to, :end)
+
+ assert_equal "value of begin", ModelWithRubyKeywordNamedAttributes.new.from
+ assert_equal "value of end", ModelWithRubyKeywordNamedAttributes.new.to
+ ensure
+ ModelWithRubyKeywordNamedAttributes.undefine_attribute_methods
end
test "#undefine_attribute_methods removes attribute methods" do
ModelWithAttributes.define_attribute_methods(:foo)
ModelWithAttributes.undefine_attribute_methods
- assert !ModelWithAttributes.new.respond_to?(:foo)
+ assert_not_respond_to ModelWithAttributes.new, :foo
assert_raises(NoMethodError) { ModelWithAttributes.new.foo }
end
@@ -255,7 +241,7 @@ class AttributeMethodsTest < ActiveModel::TestCase
m = ModelWithAttributes2.new
m.attributes = { "private_method" => "<3", "protected_method" => "O_o" }
- assert !m.respond_to?(:private_method)
+ assert_not_respond_to m, :private_method
assert m.respond_to?(:private_method, true)
c = ClassWithProtected.new
diff --git a/activemodel/test/cases/attribute_set_test.rb b/activemodel/test/cases/attribute_set_test.rb
index 6e522d6c80..62feb9074e 100644
--- a/activemodel/test/cases/attribute_set_test.rb
+++ b/activemodel/test/cases/attribute_set_test.rb
@@ -74,8 +74,8 @@ module ActiveModel
clone.freeze
- assert clone.frozen?
- assert_not attributes.frozen?
+ assert_predicate clone, :frozen?
+ assert_not_predicate attributes, :frozen?
end
test "to_hash returns a hash of the type cast values" do
@@ -105,8 +105,8 @@ module ActiveModel
test "known columns are built with uninitialized attributes" do
attributes = attributes_with_uninitialized_key
- assert attributes[:foo].initialized?
- assert_not attributes[:bar].initialized?
+ assert_predicate attributes[:foo], :initialized?
+ assert_not_predicate attributes[:bar], :initialized?
end
test "uninitialized attributes are not included in the attributes hash" do
@@ -169,7 +169,7 @@ module ActiveModel
assert attributes.key?(:foo)
assert_equal [:foo], attributes.keys
- assert attributes[:foo].initialized?
+ assert_predicate attributes[:foo], :initialized?
end
class MyType
@@ -209,11 +209,6 @@ module ActiveModel
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")
@@ -222,6 +217,22 @@ module ActiveModel
assert_equal({ foo: "1" }, attributes.to_hash)
end
+ test "marshalling dump/load legacy materialized attribute hash" do
+ builder = AttributeSet::Builder.new(foo: Type::String.new)
+ attributes = builder.build_from_database(foo: "1")
+
+ attributes.instance_variable_get(:@attributes).instance_eval do
+ class << self
+ def marshal_dump
+ materialize
+ end
+ end
+ end
+
+ attributes = Marshal.load(Marshal.dump(attributes))
+ 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")
@@ -253,5 +264,11 @@ module ActiveModel
assert_equal attributes, attributes2
assert_not_equal attributes2, attributes3
end
+
+ private
+ 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
end
end
diff --git a/activemodel/test/cases/attribute_test.rb b/activemodel/test/cases/attribute_test.rb
index 14d86cef97..20c02e689c 100644
--- a/activemodel/test/cases/attribute_test.rb
+++ b/activemodel/test/cases/attribute_test.rb
@@ -78,7 +78,7 @@ module ActiveModel
end
test "duping dups the value" do
- @type.expect(:deserialize, "type cast".dup, ["a value"])
+ @type.expect(:deserialize, +"type cast", ["a value"])
attribute = Attribute.from_database(nil, "a value", @type)
value_from_orig = attribute.value
@@ -175,33 +175,33 @@ module ActiveModel
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?
+ assert_not_predicate 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?
+ assert_predicate 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?
+ assert_not_predicate 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?
+ assert_predicate 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?
+ assert_not_predicate unchanged, :changed?
end
test "an attribute can not be mutated if it has not been read,
@@ -209,15 +209,15 @@ module ActiveModel
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?
+ assert_not_predicate 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?
+ assert_predicate attribute, :changed_in_place?
+ assert_predicate attribute, :changed?
end
test "an attribute can forget its changes" do
@@ -226,7 +226,7 @@ module ActiveModel
forgotten = changed.forgetting_assignment
assert changed.changed? # sanity check
- refute forgotten.changed?
+ assert_not_predicate forgotten, :changed?
end
test "with_value_from_user validates the value" do
@@ -246,7 +246,7 @@ module ActiveModel
end
test "with_type preserves mutations" do
- attribute = Attribute.from_database(:foo, "".dup, Type::Value.new)
+ attribute = Attribute.from_database(:foo, +"", Type::Value.new)
attribute.value << "1"
assert_equal 1, attribute.with_type(Type::Integer.new).value
diff --git a/activemodel/test/cases/attributes_dirty_test.rb b/activemodel/test/cases/attributes_dirty_test.rb
index 83a86371e0..f9693a23cd 100644
--- a/activemodel/test/cases/attributes_dirty_test.rb
+++ b/activemodel/test/cases/attributes_dirty_test.rb
@@ -25,11 +25,11 @@ class AttributesDirtyTest < ActiveModel::TestCase
end
test "setting attribute will result in change" do
- assert !@model.changed?
- assert !@model.name_changed?
+ assert_not_predicate @model, :changed?
+ assert_not_predicate @model, :name_changed?
@model.name = "Ringo"
- assert @model.changed?
- assert @model.name_changed?
+ assert_predicate @model, :changed?
+ assert_predicate @model, :name_changed?
end
test "list of changed attribute keys" do
@@ -39,7 +39,7 @@ class AttributesDirtyTest < ActiveModel::TestCase
end
test "changes to attribute values" do
- assert !@model.changes["name"]
+ assert_not @model.changes["name"]
@model.name = "John"
assert_equal [nil, "John"], @model.changes["name"]
end
@@ -71,35 +71,35 @@ class AttributesDirtyTest < ActiveModel::TestCase
test "attribute mutation" do
@model.name = "Yam"
@model.save
- assert !@model.name_changed?
+ assert_not_predicate @model, :name_changed?
@model.name.replace("Hadad")
- assert @model.name_changed?
+ assert_predicate @model, :name_changed?
end
test "resetting attribute" do
@model.name = "Bob"
@model.restore_name!
assert_nil @model.name
- assert !@model.name_changed?
+ assert_not_predicate @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?
+ assert_predicate @model, :color_changed?
@model.save
- assert !@model.color_changed?
- assert !@model.changed?
+ assert_not_predicate @model, :color_changed?
+ assert_not_predicate @model, :changed?
@model.color = "red"
- assert !@model.color_changed?
- assert !@model.changed?
+ assert_not_predicate @model, :color_changed?
+ assert_not_predicate @model, :changed?
end
test "saving should reset model's changed status" do
@model.name = "Alf"
- assert @model.changed?
+ assert_predicate @model, :changed?
@model.save
- assert !@model.changed?
- assert !@model.name_changed?
+ assert_not_predicate @model, :changed?
+ assert_not_predicate @model, :name_changed?
end
test "saving should preserve previous changes" do
@@ -118,7 +118,7 @@ class AttributesDirtyTest < ActiveModel::TestCase
test "saving should preserve model's previous changed status" do
@model.name = "Jericho Cane"
@model.save
- assert @model.name_previously_changed?
+ assert_predicate @model, :name_previously_changed?
end
test "previous value is preserved when changed after save" do
@@ -143,7 +143,7 @@ class AttributesDirtyTest < ActiveModel::TestCase
test "using attribute_will_change! with a symbol" do
@model.size = 1
- assert @model.size_changed?
+ assert_predicate @model, :size_changed?
end
test "reload should reset all changes" do
@@ -170,7 +170,7 @@ class AttributesDirtyTest < ActiveModel::TestCase
@model.restore_attributes
- assert_not @model.changed?
+ assert_not_predicate @model, :changed?
assert_equal "Dmitry", @model.name
assert_equal "Red", @model.color
end
@@ -184,7 +184,7 @@ class AttributesDirtyTest < ActiveModel::TestCase
@model.restore_attributes(["name"])
- assert @model.changed?
+ assert_predicate @model, :changed?
assert_equal "Dmitry", @model.name
assert_equal "White", @model.color
end
diff --git a/activemodel/test/cases/attributes_test.rb b/activemodel/test/cases/attributes_test.rb
index e43bf15335..5483fb101d 100644
--- a/activemodel/test/cases/attributes_test.rb
+++ b/activemodel/test/cases/attributes_test.rb
@@ -47,6 +47,26 @@ module ActiveModel
assert_equal true, data.boolean_field
end
+ test "reading attributes" do
+ data = ModelForAttributesTest.new(
+ integer_field: 1.1,
+ string_field: 1.1,
+ decimal_field: 1.1,
+ boolean_field: 1.1
+ )
+
+ expected_attributes = {
+ integer_field: 1,
+ string_field: "1.1",
+ decimal_field: BigDecimal("1.1"),
+ string_with_default: "default string",
+ date_field: Date.new(2016, 1, 1),
+ boolean_field: true
+ }.stringify_keys
+
+ assert_equal expected_attributes, data.attributes
+ end
+
test "nonexistent attribute" do
assert_raise ActiveModel::UnknownAttributeError do
ModelForAttributesTest.new(nonexistent: "nonexistent")
@@ -64,5 +84,14 @@ module ActiveModel
assert_equal "4.4", data.integer_field
end
+
+ test "attributes with proc defaults can be marshalled" do
+ data = ModelForAttributesTest.new
+ attributes = data.instance_variable_get(:@attributes)
+ round_tripped = Marshal.load(Marshal.dump(data))
+ new_attributes = round_tripped.instance_variable_get(:@attributes)
+
+ assert_equal attributes, new_attributes
+ end
end
end
diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb
index a5d29d0f22..0711dc56ca 100644
--- a/activemodel/test/cases/callbacks_test.rb
+++ b/activemodel/test/cases/callbacks_test.rb
@@ -85,21 +85,21 @@ class CallbacksTest < ActiveModel::TestCase
end
test "only selects which types of callbacks should be created" do
- assert !ModelCallbacks.respond_to?(:before_initialize)
- assert !ModelCallbacks.respond_to?(:around_initialize)
+ assert_not_respond_to ModelCallbacks, :before_initialize
+ assert_not_respond_to ModelCallbacks, :around_initialize
assert_respond_to ModelCallbacks, :after_initialize
end
test "only selects which types of callbacks should be created from an array list" do
assert_respond_to ModelCallbacks, :before_multiple
assert_respond_to ModelCallbacks, :around_multiple
- assert !ModelCallbacks.respond_to?(:after_multiple)
+ assert_not_respond_to ModelCallbacks, :after_multiple
end
test "no callbacks should be created" do
- assert !ModelCallbacks.respond_to?(:before_empty)
- assert !ModelCallbacks.respond_to?(:around_empty)
- assert !ModelCallbacks.respond_to?(:after_empty)
+ assert_not_respond_to ModelCallbacks, :before_empty
+ assert_not_respond_to ModelCallbacks, :around_empty
+ assert_not_respond_to ModelCallbacks, :after_empty
end
class Violin
@@ -112,7 +112,7 @@ class CallbacksTest < ActiveModel::TestCase
def callback1; history << "callback1"; end
def callback2; history << "callback2"; end
def create
- run_callbacks(:create) {}
+ run_callbacks(:create) { }
self
end
end
diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb
index dfe041ff50..0edbbffa86 100644
--- a/activemodel/test/cases/dirty_test.rb
+++ b/activemodel/test/cases/dirty_test.rb
@@ -5,41 +5,37 @@ require "cases/helper"
class DirtyTest < ActiveModel::TestCase
class DirtyModel
include ActiveModel::Dirty
- define_attribute_methods :name, :color, :size
+ define_attribute_methods :name, :color, :size, :status
def initialize
@name = nil
@color = nil
@size = nil
+ @status = "initialized"
end
- def name
- @name
- end
+ attr_reader :name, :color, :size, :status
def name=(val)
name_will_change!
@name = val
end
- def color
- @color
- end
-
def color=(val)
color_will_change! unless val == @color
@color = val
end
- def size
- @size
- end
-
def size=(val)
attribute_will_change!(:size) unless val == @size
@size = val
end
+ def status=(val)
+ status_will_change! unless val == @status
+ @status = val
+ end
+
def save
changes_applied
end
@@ -54,11 +50,11 @@ class DirtyTest < ActiveModel::TestCase
end
test "setting attribute will result in change" do
- assert !@model.changed?
- assert !@model.name_changed?
+ assert_not_predicate @model, :changed?
+ assert_not_predicate @model, :name_changed?
@model.name = "Ringo"
- assert @model.changed?
- assert @model.name_changed?
+ assert_predicate @model, :changed?
+ assert_predicate @model, :name_changed?
end
test "list of changed attribute keys" do
@@ -68,7 +64,7 @@ class DirtyTest < ActiveModel::TestCase
end
test "changes to attribute values" do
- assert !@model.changes["name"]
+ assert_not @model.changes["name"]
@model.name = "John"
assert_equal [nil, "John"], @model.changes["name"]
end
@@ -98,83 +94,94 @@ class DirtyTest < ActiveModel::TestCase
end
test "attribute mutation" do
- @model.instance_variable_set("@name", "Yam".dup)
- assert !@model.name_changed?
+ @model.instance_variable_set("@name", +"Yam")
+ assert_not_predicate @model, :name_changed?
@model.name.replace("Hadad")
- assert !@model.name_changed?
+ assert_not_predicate @model, :name_changed?
@model.name_will_change!
@model.name.replace("Baal")
- assert @model.name_changed?
+ assert_predicate @model, :name_changed?
end
test "resetting attribute" do
@model.name = "Bob"
@model.restore_name!
assert_nil @model.name
- assert !@model.name_changed?
+ assert_not_predicate @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?
+ assert_predicate @model, :color_changed?
@model.save
- assert !@model.color_changed?
- assert !@model.changed?
+ assert_not_predicate @model, :color_changed?
+ assert_not_predicate @model, :changed?
@model.color = "red"
- assert !@model.color_changed?
- assert !@model.changed?
+ assert_not_predicate @model, :color_changed?
+ assert_not_predicate @model, :changed?
end
test "saving should reset model's changed status" do
@model.name = "Alf"
- assert @model.changed?
+ assert_predicate @model, :changed?
@model.save
- assert !@model.changed?
- assert !@model.name_changed?
+ assert_not_predicate @model, :changed?
+ assert_not_predicate @model, :name_changed?
end
test "saving should preserve previous changes" do
@model.name = "Jericho Cane"
+ @model.status = "waiting"
@model.save
assert_equal [nil, "Jericho Cane"], @model.previous_changes["name"]
+ assert_equal ["initialized", "waiting"], @model.previous_changes["status"]
end
test "setting new attributes should not affect previous changes" do
@model.name = "Jericho Cane"
+ @model.status = "waiting"
@model.save
@model.name = "DudeFella ManGuy"
+ @model.status = "finished"
assert_equal [nil, "Jericho Cane"], @model.name_previous_change
+ assert_equal ["initialized", "waiting"], @model.previous_changes["status"]
end
test "saving should preserve model's previous changed status" do
@model.name = "Jericho Cane"
@model.save
- assert @model.name_previously_changed?
+ assert_predicate @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.status = "waiting"
+ assert_equal({ "name" => nil, "status" => "initialized" }, @model.changed_attributes)
@model.save
@model.name = "John"
- assert_equal({ "name" => "Paul" }, @model.changed_attributes)
+ @model.status = "finished"
+ assert_equal({ "name" => "Paul", "status" => "waiting" }, @model.changed_attributes)
end
test "changing the same attribute multiple times retains the correct original value" do
@model.name = "Otto"
+ @model.status = "waiting"
@model.save
@model.name = "DudeFella ManGuy"
@model.name = "Mr. Manfredgensonton"
+ @model.status = "processing"
+ @model.status = "finished"
assert_equal ["Otto", "Mr. Manfredgensonton"], @model.name_change
+ assert_equal ["waiting", "finished"], @model.status_change
assert_equal @model.name_was, "Otto"
end
test "using attribute_will_change! with a symbol" do
@model.size = 1
- assert @model.size_changed?
+ assert_predicate @model, :size_changed?
end
test "reload should reset all changes" do
@@ -201,7 +208,7 @@ class DirtyTest < ActiveModel::TestCase
@model.restore_attributes
- assert_not @model.changed?
+ assert_not_predicate @model, :changed?
assert_equal "Dmitry", @model.name
assert_equal "Red", @model.color
end
@@ -215,7 +222,7 @@ class DirtyTest < ActiveModel::TestCase
@model.restore_attributes(["name"])
- assert @model.changed?
+ assert_predicate @model, :changed?
assert_equal "Dmitry", @model.name
assert_equal "White", @model.color
end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index d5c282b620..947f9bf99b 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require "cases/helper"
-require "active_support/core_ext/string/strip"
require "yaml"
class ErrorsTest < ActiveModel::TestCase
@@ -83,7 +82,7 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal 1, person.errors.count
person.errors.clear
- assert person.errors.empty?
+ assert_empty person.errors
end
test "error access is indifferent" do
@@ -128,8 +127,8 @@ class ErrorsTest < ActiveModel::TestCase
test "detecting whether there are errors with empty?, blank?, include?" do
person = Person.new
person.errors[:foo]
- assert person.errors.empty?
- assert person.errors.blank?
+ assert_empty person.errors
+ assert_predicate person.errors, :blank?
assert_not_includes person.errors, :foo
end
@@ -186,6 +185,12 @@ class ErrorsTest < ActiveModel::TestCase
assert person.errors.added?(:name, :blank)
end
+ test "added? returns true when string attribute is used with a symbol message" do
+ person = Person.new
+ person.errors.add(:name, :blank)
+ assert person.errors.added?("name", :blank)
+ end
+
test "added? handles proc messages" do
person = Person.new
message = Proc.new { "cannot be blank" }
@@ -204,30 +209,118 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add(:name, "cannot be blank")
person.errors.add(:name, "is invalid")
assert person.errors.added?(:name, "cannot be blank")
+ assert person.errors.added?(:name, "is invalid")
+ assert_not person.errors.added?(:name, "incorrect")
end
test "added? returns false when no errors are present" do
person = Person.new
- assert !person.errors.added?(:name)
+ assert_not person.errors.added?(:name)
end
test "added? returns false when checking a nonexisting error and other errors are present for the given attribute" do
person = Person.new
person.errors.add(:name, "is invalid")
- assert !person.errors.added?(:name, "cannot be blank")
+ assert_not person.errors.added?(:name, "cannot be blank")
end
- test "added? returns false when checking for an error, but not providing message arguments" do
+ test "added? returns false when checking for an error, but not providing message argument" do
person = Person.new
person.errors.add(:name, "cannot be blank")
- assert !person.errors.added?(:name)
+ assert_not person.errors.added?(:name)
+ end
+
+ test "added? returns false when checking for an error with an incorrect or missing option" do
+ person = Person.new
+ person.errors.add :name, :too_long, count: 25
+
+ assert person.errors.added? :name, :too_long, count: 25
+ assert person.errors.added? :name, "is too long (maximum is 25 characters)"
+ assert_not person.errors.added? :name, :too_long, count: 24
+ assert_not person.errors.added? :name, :too_long
+ assert_not person.errors.added? :name, "is too long"
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)
+ assert_not person.errors.added?(:name, :used)
+ assert person.errors.added?(:name, :wrong)
+ end
+
+ test "of_kind? returns false when checking for an error, but not providing message argument" do
+ person = Person.new
+ person.errors.add(:name, "cannot be blank")
+ assert_not person.errors.of_kind?(:name)
+ end
+
+ test "of_kind? returns false when checking a nonexisting error and other errors are present for the given attribute" do
+ person = Person.new
+ person.errors.add(:name, "is invalid")
+ assert_not person.errors.of_kind?(:name, "cannot be blank")
+ end
+
+ test "of_kind? returns false when no errors are present" do
+ person = Person.new
+ assert_not person.errors.of_kind?(:name)
+ end
+
+ test "of_kind? matches the given message when several errors are present for the same attribute" do
+ person = Person.new
+ person.errors.add(:name, "cannot be blank")
+ person.errors.add(:name, "is invalid")
+ assert person.errors.of_kind?(:name, "cannot be blank")
+ assert person.errors.of_kind?(:name, "is invalid")
+ assert_not person.errors.of_kind?(:name, "incorrect")
+ end
+
+ test "of_kind? defaults message to :invalid" do
+ person = Person.new
+ person.errors.add(:name)
+ assert person.errors.of_kind?(:name)
+ end
+
+ test "of_kind? handles proc messages" do
+ person = Person.new
+ message = Proc.new { "cannot be blank" }
+ person.errors.add(:name, message)
+ assert person.errors.of_kind?(:name, message)
+ end
+
+ test "of_kind? returns true when string attribute is used with a symbol message" do
+ person = Person.new
+ person.errors.add(:name, :blank)
+ assert person.errors.of_kind?("name", :blank)
+ end
+
+ test "of_kind? handles symbol message" do
+ person = Person.new
+ person.errors.add(:name, :blank)
+ assert person.errors.of_kind?(:name, :blank)
+ end
+
+ test "of_kind? detects indifferent if a specific error was added to the object" do
+ person = Person.new
+ person.errors.add(:name, "cannot be blank")
+ assert person.errors.of_kind?(:name, "cannot be blank")
+ assert person.errors.of_kind?("name", "cannot be blank")
+ end
+
+ test "of_kind? ignores options" do
+ person = Person.new
+ person.errors.add :name, :too_long, count: 25
+
+ assert person.errors.of_kind? :name, :too_long
+ assert person.errors.of_kind? :name, "is too long (maximum is 25 characters)"
+ end
+
+ test "of_kind? 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_not person.errors.of_kind?(:name, :used)
+ assert person.errors.of_kind?(:name, :wrong)
end
test "size calculates the number of error messages" do
@@ -320,7 +413,7 @@ class ErrorsTest < ActiveModel::TestCase
test "generate_message works without i18n_scope" do
person = Person.new
- assert !Person.respond_to?(:i18n_scope)
+ assert_not_respond_to Person, :i18n_scope
assert_nothing_raised {
person.errors.generate_message(:name, :blank)
}
@@ -371,7 +464,7 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal 1, person.errors.details.count
person.errors.clear
- assert person.errors.details.empty?
+ assert_empty person.errors.details
end
test "copy errors" do
@@ -396,6 +489,30 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal({ name: [{ error: :blank }, { error: :invalid }] }, person.errors.details)
end
+ test "slice! removes all errors except the given keys" do
+ person = Person.new
+ person.errors.add(:name, "cannot be nil")
+ person.errors.add(:age, "cannot be nil")
+ person.errors.add(:gender, "cannot be nil")
+ person.errors.add(:city, "cannot be nil")
+
+ person.errors.slice!(:age, "gender")
+
+ assert_equal [:age, :gender], person.errors.keys
+ end
+
+ test "slice! returns the deleted errors" do
+ person = Person.new
+ person.errors.add(:name, "cannot be nil")
+ person.errors.add(:age, "cannot be nil")
+ person.errors.add(:gender, "cannot be nil")
+ person.errors.add(:city, "cannot be nil")
+
+ removed_errors = person.errors.slice!(:age, "gender")
+
+ assert_equal({ name: ["cannot be nil"], city: ["cannot be nil"] }, removed_errors)
+ end
+
test "errors are marshalable" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)
@@ -406,7 +523,7 @@ class ErrorsTest < ActiveModel::TestCase
end
test "errors are backward compatible with the Rails 4.2 format" do
- yaml = <<-CODE.strip_heredoc
+ yaml = <<~CODE
--- !ruby/object:ActiveModel::Errors
base: &1 !ruby/object:ErrorsTest::Person
errors: !ruby/object:ActiveModel::Errors
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 91fb9d0a7c..138b1d1bb9 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -14,12 +14,14 @@ require "active_support/testing/method_call_assertions"
class ActiveModel::TestCase < ActiveSupport::TestCase
include ActiveSupport::Testing::MethodCallAssertions
- # Skips the current run on Rubinius using Minitest::Assertions#skip
- private def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
- end
- # Skips the current run on JRuby using Minitest::Assertions#skip
- private def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
- end
+ private
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
end
diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb
index 009f1f47af..4693da434c 100644
--- a/activemodel/test/cases/naming_test.rb
+++ b/activemodel/test/cases/naming_test.rb
@@ -248,7 +248,7 @@ class NamingHelpersTest < ActiveModel::TestCase
def test_uncountable
assert uncountable?(@uncountable), "Expected 'sheep' to be uncountable"
- assert !uncountable?(@klass), "Expected 'contact' to be countable"
+ assert_not uncountable?(@klass), "Expected 'contact' to be countable"
end
def test_uncountable_route_key
diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb
index ff5022e960..ab60285e2a 100644
--- a/activemodel/test/cases/railtie_test.rb
+++ b/activemodel/test/cases/railtie_test.rb
@@ -31,4 +31,24 @@ class RailtieTest < ActiveModel::TestCase
assert_equal true, ActiveModel::SecurePassword.min_cost
end
+
+ test "i18n full message defaults to false" do
+ @app.initialize!
+
+ assert_equal false, ActiveModel::Errors.i18n_full_message
+ end
+
+ test "i18n full message can be disabled" do
+ @app.config.active_model.i18n_full_message = false
+ @app.initialize!
+
+ assert_equal false, ActiveModel::Errors.i18n_full_message
+ end
+
+ test "i18n full message can be enabled" do
+ @app.config.active_model.i18n_full_message = true
+ @app.initialize!
+
+ assert_equal true, ActiveModel::Errors.i18n_full_message
+ end
end
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index d19e81a119..bbf443290b 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -49,14 +49,14 @@ class SecurePasswordTest < ActiveModel::TestCase
test "create a new user with validation and a blank password" do
@user.password = ""
- assert !@user.valid?(:create), "user should be invalid"
+ assert_not @user.valid?(:create), "user should be invalid"
assert_equal 1, @user.errors.count
assert_equal ["can't be blank"], @user.errors[:password]
end
test "create a new user with validation and a nil password" do
@user.password = nil
- assert !@user.valid?(:create), "user should be invalid"
+ assert_not @user.valid?(:create), "user should be invalid"
assert_equal 1, @user.errors.count
assert_equal ["can't be blank"], @user.errors[:password]
end
@@ -64,7 +64,7 @@ class SecurePasswordTest < ActiveModel::TestCase
test "create a new user with validation and password length greater than 72" do
@user.password = "a" * 73
@user.password_confirmation = "a" * 73
- assert !@user.valid?(:create), "user should be invalid"
+ assert_not @user.valid?(:create), "user should be invalid"
assert_equal 1, @user.errors.count
assert_equal ["is too long (maximum is 72 characters)"], @user.errors[:password]
end
@@ -72,7 +72,7 @@ class SecurePasswordTest < ActiveModel::TestCase
test "create a new user with validation and a blank password confirmation" do
@user.password = "password"
@user.password_confirmation = ""
- assert !@user.valid?(:create), "user should be invalid"
+ assert_not @user.valid?(:create), "user should be invalid"
assert_equal 1, @user.errors.count
assert_equal ["doesn't match Password"], @user.errors[:password_confirmation]
end
@@ -86,7 +86,7 @@ class SecurePasswordTest < ActiveModel::TestCase
test "create a new user with validation and an incorrect password confirmation" do
@user.password = "password"
@user.password_confirmation = "something else"
- assert !@user.valid?(:create), "user should be invalid"
+ assert_not @user.valid?(:create), "user should be invalid"
assert_equal 1, @user.errors.count
assert_equal ["doesn't match Password"], @user.errors[:password_confirmation]
end
@@ -125,7 +125,7 @@ class SecurePasswordTest < ActiveModel::TestCase
test "updating an existing user with validation and a nil password" do
@existing_user.password = nil
- assert !@existing_user.valid?(:update), "user should be invalid"
+ assert_not @existing_user.valid?(:update), "user should be invalid"
assert_equal 1, @existing_user.errors.count
assert_equal ["can't be blank"], @existing_user.errors[:password]
end
@@ -133,7 +133,7 @@ class SecurePasswordTest < ActiveModel::TestCase
test "updating an existing user with validation and password length greater than 72" do
@existing_user.password = "a" * 73
@existing_user.password_confirmation = "a" * 73
- assert !@existing_user.valid?(:update), "user should be invalid"
+ assert_not @existing_user.valid?(:update), "user should be invalid"
assert_equal 1, @existing_user.errors.count
assert_equal ["is too long (maximum is 72 characters)"], @existing_user.errors[:password]
end
@@ -141,7 +141,7 @@ class SecurePasswordTest < ActiveModel::TestCase
test "updating an existing user with validation and a blank password confirmation" do
@existing_user.password = "password"
@existing_user.password_confirmation = ""
- assert !@existing_user.valid?(:update), "user should be invalid"
+ assert_not @existing_user.valid?(:update), "user should be invalid"
assert_equal 1, @existing_user.errors.count
assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation]
end
@@ -155,21 +155,21 @@ class SecurePasswordTest < ActiveModel::TestCase
test "updating an existing user with validation and an incorrect password confirmation" do
@existing_user.password = "password"
@existing_user.password_confirmation = "something else"
- assert !@existing_user.valid?(:update), "user should be invalid"
+ assert_not @existing_user.valid?(:update), "user should be invalid"
assert_equal 1, @existing_user.errors.count
assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation]
end
test "updating an existing user with validation and a blank password digest" do
@existing_user.password_digest = ""
- assert !@existing_user.valid?(:update), "user should be invalid"
+ assert_not @existing_user.valid?(:update), "user should be invalid"
assert_equal 1, @existing_user.errors.count
assert_equal ["can't be blank"], @existing_user.errors[:password]
end
test "updating an existing user with validation and a nil password digest" do
@existing_user.password_digest = nil
- assert !@existing_user.valid?(:update), "user should be invalid"
+ assert_not @existing_user.valid?(:update), "user should be invalid"
assert_equal 1, @existing_user.errors.count
assert_equal ["can't be blank"], @existing_user.errors[:password]
end
@@ -186,9 +186,16 @@ class SecurePasswordTest < ActiveModel::TestCase
test "authenticate" do
@user.password = "secret"
+ @user.recovery_password = "42password"
- assert !@user.authenticate("wrong")
- assert @user.authenticate("secret")
+ assert_equal false, @user.authenticate("wrong")
+ assert_equal @user, @user.authenticate("secret")
+
+ assert_equal false, @user.authenticate_password("wrong")
+ assert_equal @user, @user.authenticate_password("secret")
+
+ assert_equal false, @user.authenticate_recovery_password("wrong")
+ assert_equal @user, @user.authenticate_recovery_password("42password")
end
test "Password digest cost defaults to bcrypt default cost when min_cost is false" do
@@ -199,16 +206,14 @@ class SecurePasswordTest < ActiveModel::TestCase
end
test "Password digest cost honors bcrypt cost attribute when min_cost is false" do
- begin
- original_bcrypt_cost = BCrypt::Engine.cost
- ActiveModel::SecurePassword.min_cost = false
- BCrypt::Engine.cost = 5
-
- @user.password = "secret"
- assert_equal BCrypt::Engine.cost, @user.password_digest.cost
- ensure
- BCrypt::Engine.cost = original_bcrypt_cost
- end
+ original_bcrypt_cost = BCrypt::Engine.cost
+ ActiveModel::SecurePassword.min_cost = false
+ BCrypt::Engine.cost = 5
+
+ @user.password = "secret"
+ assert_equal BCrypt::Engine.cost, @user.password_digest.cost
+ ensure
+ BCrypt::Engine.cost = original_bcrypt_cost
end
test "Password digest cost can be set to bcrypt min cost to speed up tests" do
diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb
index 9002982e7f..6826d2bbd1 100644
--- a/activemodel/test/cases/serialization_test.rb
+++ b/activemodel/test/cases/serialization_test.rb
@@ -174,4 +174,11 @@ class SerializationTest < ActiveModel::TestCase
{ "name" => "Sue", "email" => "sue@example.com", "gender" => "female" }] }
assert_equal expected, @user.serializable_hash(include: [{ address: { only: "street" } }, :friends])
end
+
+ def test_all_includes_with_options
+ expected = { "email" => "david@example.com", "gender" => "male", "name" => "David",
+ "address" => { "street" => "123 Lane" },
+ "friends" => [{ "name" => "Joe" }, { "name" => "Sue" }] }
+ assert_equal expected, @user.serializable_hash(include: [address: { only: "street" }, friends: { only: "name" }])
+ end
end
diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb
index aae98c9fe4..84efc8de0d 100644
--- a/activemodel/test/cases/serializers/json_serialization_test.rb
+++ b/activemodel/test/cases/serializers/json_serialization_test.rb
@@ -26,20 +26,18 @@ class JsonSerializationTest < ActiveModel::TestCase
end
test "should include root in json if include_root_in_json is true" do
- begin
- original_include_root_in_json = Contact.include_root_in_json
- Contact.include_root_in_json = true
- json = @contact.to_json
-
- assert_match %r{^\{"contact":\{}, json
- assert_match %r{"name":"Konata Izumi"}, json
- assert_match %r{"age":16}, json
- assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})
- assert_match %r{"awesome":true}, json
- assert_match %r{"preferences":\{"shows":"anime"\}}, json
- ensure
- Contact.include_root_in_json = original_include_root_in_json
- end
+ original_include_root_in_json = Contact.include_root_in_json
+ Contact.include_root_in_json = true
+ json = @contact.to_json
+
+ assert_match %r{^\{"contact":\{}, json
+ assert_match %r{"name":"Konata Izumi"}, json
+ assert_match %r{"age":16}, json
+ assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})
+ assert_match %r{"awesome":true}, json
+ assert_match %r{"preferences":\{"shows":"anime"\}}, json
+ ensure
+ Contact.include_root_in_json = original_include_root_in_json
end
test "should include root in json (option) even if the default is set to false" do
@@ -129,20 +127,22 @@ class JsonSerializationTest < ActiveModel::TestCase
assert_equal :name, options[:except]
end
+ test "as_json should serialize timestamps" do
+ assert_equal "2006-08-01T00:00:00.000Z", @contact.as_json["created_at"]
+ end
+
test "as_json should return a hash if include_root_in_json is true" do
- begin
- original_include_root_in_json = Contact.include_root_in_json
- Contact.include_root_in_json = true
- json = @contact.as_json
-
- assert_kind_of Hash, json
- assert_kind_of Hash, json["contact"]
- %w(name age created_at awesome preferences).each do |field|
- assert_equal @contact.send(field), json["contact"][field]
- end
- ensure
- Contact.include_root_in_json = original_include_root_in_json
+ original_include_root_in_json = Contact.include_root_in_json
+ Contact.include_root_in_json = true
+ json = @contact.as_json
+
+ assert_kind_of Hash, json
+ assert_kind_of Hash, json["contact"]
+ %w(name age created_at awesome preferences).each do |field|
+ assert_equal @contact.send(field).as_json, json["contact"][field]
end
+ ensure
+ Contact.include_root_in_json = original_include_root_in_json
end
test "from_json should work without a root (class attribute)" do
diff --git a/activemodel/test/cases/type/boolean_test.rb b/activemodel/test/cases/type/boolean_test.rb
index 2d33579595..2de0f53640 100644
--- a/activemodel/test/cases/type/boolean_test.rb
+++ b/activemodel/test/cases/type/boolean_test.rb
@@ -7,8 +7,8 @@ module ActiveModel
class BooleanTest < ActiveModel::TestCase
def test_type_cast_boolean
type = Type::Boolean.new
- assert type.cast("").nil?
- assert type.cast(nil).nil?
+ assert_predicate type.cast(""), :nil?
+ assert_predicate type.cast(nil), :nil?
assert type.cast(true)
assert type.cast(1)
diff --git a/activemodel/test/cases/type/date_test.rb b/activemodel/test/cases/type/date_test.rb
index c50a549d3d..2dd1a55616 100644
--- a/activemodel/test/cases/type/date_test.rb
+++ b/activemodel/test/cases/type/date_test.rb
@@ -12,8 +12,11 @@ module ActiveModel
assert_nil type.cast(" ")
assert_nil type.cast("ABC")
- date_string = ::Time.now.utc.strftime("%F")
+ now = ::Time.now.utc
+ values_hash = { 1 => now.year, 2 => now.mon, 3 => now.mday }
+ date_string = now.strftime("%F")
assert_equal date_string, type.cast(date_string).strftime("%F")
+ assert_equal date_string, type.cast(values_hash).strftime("%F")
end
def test_returns_correct_year
diff --git a/activemodel/test/cases/type/date_time_test.rb b/activemodel/test/cases/type/date_time_test.rb
index 60f62becc2..74b47d1b4d 100644
--- a/activemodel/test/cases/type/date_time_test.rb
+++ b/activemodel/test/cases/type/date_time_test.rb
@@ -25,6 +25,17 @@ module ActiveModel
end
end
+ def test_hash_to_time
+ type = Type::DateTime.new
+ assert_equal ::Time.utc(2018, 10, 15, 0, 0, 0), type.cast(1 => 2018, 2 => 10, 3 => 15)
+ end
+
+ def test_hash_with_wrong_keys
+ type = Type::DateTime.new
+ error = assert_raises(ArgumentError) { type.cast(a: 1) }
+ assert_equal "Provided hash {:a=>1} doesn't contain necessary keys: [1, 2, 3]", error.message
+ end
+
private
def with_timezone_config(default:)
diff --git a/activemodel/test/cases/type/decimal_test.rb b/activemodel/test/cases/type/decimal_test.rb
index c0cf6ce590..be60c4f7fa 100644
--- a/activemodel/test/cases/type/decimal_test.rb
+++ b/activemodel/test/cases/type/decimal_test.rb
@@ -57,9 +57,12 @@ module ActiveModel
def test_changed?
type = Decimal.new
- assert type.changed?(5.0, 5.0, "5.0wibble")
+ assert type.changed?(0.0, 0, "wibble")
+ assert type.changed?(5.0, 0, "wibble")
+ assert_not type.changed?(5.0, 5.0, "5.0wibble")
assert_not type.changed?(5.0, 5.0, "5.0")
assert_not type.changed?(-5.0, -5.0, "-5.0")
+ assert_not type.changed?(5.0, 5.0, "0.5e+1")
end
def test_scale_is_applied_before_precision_to_prevent_rounding_errors
diff --git a/activemodel/test/cases/type/float_test.rb b/activemodel/test/cases/type/float_test.rb
index 28318e06f8..230a8dda32 100644
--- a/activemodel/test/cases/type/float_test.rb
+++ b/activemodel/test/cases/type/float_test.rb
@@ -21,9 +21,12 @@ module ActiveModel
def test_changing_float
type = Type::Float.new
- assert type.changed?(5.0, 5.0, "5wibble")
+ assert type.changed?(0.0, 0, "wibble")
+ assert type.changed?(5.0, 0, "wibble")
+ assert_not type.changed?(5.0, 5.0, "5wibble")
assert_not type.changed?(5.0, 5.0, "5")
assert_not type.changed?(5.0, 5.0, "5.0")
+ assert_not type.changed?(500.0, 500.0, "0.5E+4")
assert_not type.changed?(nil, nil, nil)
end
end
diff --git a/activemodel/test/cases/type/integer_test.rb b/activemodel/test/cases/type/integer_test.rb
index 8c5d18c9b3..9bd0110099 100644
--- a/activemodel/test/cases/type/integer_test.rb
+++ b/activemodel/test/cases/type/integer_test.rb
@@ -50,12 +50,23 @@ module ActiveModel
assert_equal 7200, type.cast(2.hours)
end
+ test "casting empty string" do
+ type = Type::Integer.new
+ assert_nil type.cast("")
+ assert_nil type.serialize("")
+ assert_equal 0, type.deserialize("")
+ end
+
test "changed?" do
type = Type::Integer.new
- assert type.changed?(5, 5, "5wibble")
+ assert type.changed?(0, 0, "wibble")
+ assert type.changed?(5, 0, "wibble")
+ assert_not type.changed?(5, 5, "5wibble")
assert_not type.changed?(5, 5, "5")
assert_not type.changed?(5, 5, "5.0")
+ assert_not type.changed?(5, 5, "+5")
+ assert_not type.changed?(5, 5, "+5.0")
assert_not type.changed?(-5, -5, "-5")
assert_not type.changed?(-5, -5, "-5.0")
assert_not type.changed?(nil, nil, nil)
diff --git a/activemodel/test/cases/type/string_test.rb b/activemodel/test/cases/type/string_test.rb
index 825c8bb246..9cc530e8db 100644
--- a/activemodel/test/cases/type/string_test.rb
+++ b/activemodel/test/cases/type/string_test.rb
@@ -12,14 +12,22 @@ module ActiveModel
assert_equal "123", type.cast(123)
end
+ test "type casting for database" do
+ type = Type::String.new
+ object, array, hash = Object.new, [true], { a: :b }
+ assert_equal object, type.serialize(object)
+ assert_equal array, type.serialize(array)
+ assert_equal hash, type.serialize(hash)
+ end
+
test "cast strings are mutable" do
type = Type::String.new
- s = "foo".dup
+ s = +"foo"
assert_equal false, type.cast(s).frozen?
assert_equal false, s.frozen?
- f = "foo".freeze
+ f = -"foo"
assert_equal false, type.cast(f).frozen?
assert_equal true, f.frozen?
end
diff --git a/activemodel/test/cases/type/time_test.rb b/activemodel/test/cases/type/time_test.rb
index f7102d1e97..5c6271241d 100644
--- a/activemodel/test/cases/type/time_test.rb
+++ b/activemodel/test/cases/type/time_test.rb
@@ -16,6 +16,22 @@ module ActiveModel
assert_equal ::Time.utc(2000, 1, 1, 16, 45, 54), type.cast("2015-06-13T19:45:54+03:00")
assert_equal ::Time.utc(1999, 12, 31, 21, 7, 8), type.cast("06:07:08+09:00")
+ assert_equal ::Time.utc(2000, 1, 1, 16, 45, 54), type.cast(4 => 16, 5 => 45, 6 => 54)
+ end
+
+ def test_user_input_in_time_zone
+ ::Time.use_zone("Pacific Time (US & Canada)") do
+ type = Type::Time.new
+ assert_nil type.user_input_in_time_zone(nil)
+ assert_nil type.user_input_in_time_zone("")
+ assert_nil type.user_input_in_time_zone("ABC")
+
+ offset = ::Time.zone.formatted_offset
+ time_string = "2015-02-09T19:45:54#{offset}"
+
+ assert_equal 19, type.user_input_in_time_zone(time_string).hour
+ assert_equal offset, type.user_input_in_time_zone(time_string).formatted_offset
+ end
end
end
end
diff --git a/activemodel/test/cases/validations/absence_validation_test.rb b/activemodel/test/cases/validations/absence_validation_test.rb
index 801577474a..8bc4f4723a 100644
--- a/activemodel/test/cases/validations/absence_validation_test.rb
+++ b/activemodel/test/cases/validations/absence_validation_test.rb
@@ -17,16 +17,16 @@ class AbsenceValidationTest < ActiveModel::TestCase
t = Topic.new
t.title = "foo"
t.content = "bar"
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be blank"], t.errors[:title]
assert_equal ["must be blank"], t.errors[:content]
t.title = ""
t.content = "something"
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be blank"], t.errors[:content]
assert_equal [], t.errors[:title]
t.content = ""
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_absence_of_with_array_arguments
@@ -34,7 +34,7 @@ class AbsenceValidationTest < ActiveModel::TestCase
t = Topic.new
t.title = "foo"
t.content = "bar"
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be blank"], t.errors[:title]
assert_equal ["must be blank"], t.errors[:content]
end
@@ -43,7 +43,7 @@ class AbsenceValidationTest < ActiveModel::TestCase
Person.validates_absence_of :karma, message: "This string contains 'single' and \"double\" quotes"
p = Person.new
p.karma = "good"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal "This string contains 'single' and \"double\" quotes", p.errors[:karma].last
end
@@ -51,19 +51,19 @@ class AbsenceValidationTest < ActiveModel::TestCase
Person.validates_absence_of :karma
p = Person.new
p.karma = "good"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["must be blank"], p.errors[:karma]
p.karma = nil
- assert p.valid?
+ assert_predicate p, :valid?
end
def test_validates_absence_of_for_ruby_class_with_custom_reader
CustomReader.validates_absence_of :karma
p = CustomReader.new
p[:karma] = "excellent"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["must be blank"], p.errors[:karma]
p[:karma] = ""
- assert p.valid?
+ assert_predicate p, :valid?
end
end
diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb
index c5f54b1868..7662f996ae 100644
--- a/activemodel/test/cases/validations/acceptance_validation_test.rb
+++ b/activemodel/test/cases/validations/acceptance_validation_test.rb
@@ -15,54 +15,54 @@ class AcceptanceValidationTest < ActiveModel::TestCase
Topic.validates_acceptance_of(:terms_of_service)
t = Topic.new("title" => "We should not be confirmed")
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_terms_of_service_agreement
Topic.validates_acceptance_of(:terms_of_service)
t = Topic.new("title" => "We should be confirmed", "terms_of_service" => "")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be accepted"], t.errors[:terms_of_service]
t.terms_of_service = "1"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_eula
Topic.validates_acceptance_of(:eula, message: "must be abided")
t = Topic.new("title" => "We should be confirmed", "eula" => "")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be abided"], t.errors[:eula]
t.eula = "1"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_terms_of_service_agreement_with_accept_value
Topic.validates_acceptance_of(:terms_of_service, accept: "I agree.")
t = Topic.new("title" => "We should be confirmed", "terms_of_service" => "")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be accepted"], t.errors[:terms_of_service]
t.terms_of_service = "I agree."
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_terms_of_service_agreement_with_multiple_accept_values
Topic.validates_acceptance_of(:terms_of_service, accept: [1, "I concur."])
t = Topic.new("title" => "We should be confirmed", "terms_of_service" => "")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["must be accepted"], t.errors[:terms_of_service]
t.terms_of_service = 1
- assert t.valid?
+ assert_predicate t, :valid?
t.terms_of_service = "I concur."
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_acceptance_of_for_ruby_class
@@ -71,11 +71,11 @@ class AcceptanceValidationTest < ActiveModel::TestCase
p = Person.new
p.karma = ""
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["must be accepted"], p.errors[:karma]
p.karma = "1"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
@@ -83,6 +83,6 @@ class AcceptanceValidationTest < ActiveModel::TestCase
def test_validates_acceptance_of_true
Topic.validates_acceptance_of(:terms_of_service)
- assert Topic.new(terms_of_service: true).valid?
+ assert_predicate Topic.new(terms_of_service: true), :valid?
end
end
diff --git a/activemodel/test/cases/validations/callbacks_test.rb b/activemodel/test/cases/validations/callbacks_test.rb
index d3a9a17a05..ff3cf61746 100644
--- a/activemodel/test/cases/validations/callbacks_test.rb
+++ b/activemodel/test/cases/validations/callbacks_test.rb
@@ -59,6 +59,18 @@ class DogValidatorWithOnCondition < Dog
def set_after_validation_marker; history << "after_validation_marker" ; end
end
+class DogValidatorWithOnMultipleCondition < Dog
+ before_validation :set_before_validation_marker_on_context_a, on: :context_a
+ before_validation :set_before_validation_marker_on_context_b, on: :context_b
+ after_validation :set_after_validation_marker_on_context_a, on: :context_a
+ after_validation :set_after_validation_marker_on_context_b, on: :context_b
+
+ def set_before_validation_marker_on_context_a; history << "before_validation_marker on context_a"; end
+ def set_before_validation_marker_on_context_b; history << "before_validation_marker on context_b"; end
+ def set_after_validation_marker_on_context_a; history << "after_validation_marker on context_a" ; end
+ def set_after_validation_marker_on_context_b; history << "after_validation_marker on context_b" ; end
+end
+
class DogValidatorWithIfCondition < Dog
before_validation :set_before_validation_marker1, if: -> { true }
before_validation :set_before_validation_marker2, if: -> { false }
@@ -98,6 +110,37 @@ class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase
assert_equal [], d.history
end
+ def test_on_multiple_condition_is_respected_for_validation_with_matching_context
+ d = DogValidatorWithOnMultipleCondition.new
+ d.valid?(:context_a)
+ assert_equal ["before_validation_marker on context_a", "after_validation_marker on context_a"], d.history
+
+ d = DogValidatorWithOnMultipleCondition.new
+ d.valid?(:context_b)
+ assert_equal ["before_validation_marker on context_b", "after_validation_marker on context_b"], d.history
+
+ d = DogValidatorWithOnMultipleCondition.new
+ d.valid?([:context_a, :context_b])
+ assert_equal([
+ "before_validation_marker on context_a",
+ "before_validation_marker on context_b",
+ "after_validation_marker on context_a",
+ "after_validation_marker on context_b"
+ ], d.history)
+ end
+
+ def test_on_multiple_condition_is_respected_for_validation_without_matching_context
+ d = DogValidatorWithOnMultipleCondition.new
+ d.valid?(:save)
+ assert_equal [], d.history
+ end
+
+ def test_on_multiple_condition_is_respected_for_validation_without_context
+ d = DogValidatorWithOnMultipleCondition.new
+ d.valid?
+ assert_equal [], d.history
+ end
+
def test_before_validation_and_after_validation_callbacks_should_be_called
d = DogWithMethodCallbacks.new
d.valid?
diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb
index caea8b65ef..1704db9a48 100644
--- a/activemodel/test/cases/validations/conditional_validation_test.rb
+++ b/activemodel/test/cases/validations/conditional_validation_test.rb
@@ -13,24 +13,24 @@ class ConditionalValidationTest < ActiveModel::TestCase
# When the method returns true
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true)
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
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_predicate t, :invalid?
+ assert_predicate 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_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 5"], t.errors["title"]
end
@@ -38,21 +38,21 @@ class ConditionalValidationTest < ActiveModel::TestCase
# When the method returns true
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true)
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
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_predicate 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_predicate t, :valid?
assert_empty t.errors[:title]
end
@@ -60,7 +60,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
# 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_predicate t, :valid?
assert_empty t.errors[:title]
end
@@ -68,8 +68,8 @@ class ConditionalValidationTest < ActiveModel::TestCase
# 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?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 5"], t.errors["title"]
end
@@ -78,8 +78,8 @@ class ConditionalValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}",
if: Proc.new { |r| r.content.size > 4 })
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 5"], t.errors["title"]
end
@@ -88,7 +88,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}",
unless: Proc.new { |r| r.content.size > 4 })
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
assert_empty t.errors[:title]
end
@@ -97,7 +97,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}",
if: Proc.new { |r| r.title != "uhohuhoh" })
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
assert_empty t.errors[:title]
end
@@ -106,23 +106,23 @@ class ConditionalValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}",
unless: Proc.new { |r| r.title != "uhohuhoh" })
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate 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_predicate 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_predicate t, :invalid?
+ assert_predicate 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 8b2c65289b..7bf15e4bee 100644
--- a/activemodel/test/cases/validations/confirmation_validation_test.rb
+++ b/activemodel/test/cases/validations/confirmation_validation_test.rb
@@ -14,40 +14,40 @@ class ConfirmationValidationTest < ActiveModel::TestCase
Topic.validates_confirmation_of(:title)
t = Topic.new(author_name: "Plutarch")
- assert t.valid?
+ assert_predicate t, :valid?
t.title_confirmation = "Parallel Lives"
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title_confirmation = nil
t.title = "Parallel Lives"
- assert t.valid?
+ assert_predicate t, :valid?
t.title_confirmation = "Parallel Lives"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_title_confirmation
Topic.validates_confirmation_of(:title)
t = Topic.new("title" => "We should be confirmed", "title_confirmation" => "")
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title_confirmation = "We should be confirmed"
- assert t.valid?
+ assert_predicate 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?
+ assert_predicate t, :valid?
t.approved_confirmation = false
- assert t.invalid?
+ assert_predicate t, :invalid?
t.approved_confirmation = true
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_confirmation_of_for_ruby_class
@@ -55,35 +55,33 @@ class ConfirmationValidationTest < ActiveModel::TestCase
p = Person.new
p.karma_confirmation = "None"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["doesn't match Karma"], p.errors[:karma_confirmation]
p.karma = "None"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
def test_title_confirmation_with_i18n_attribute
- begin
- @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend
- I18n.load_path.clear
- I18n.backend = I18n::Backend::Simple.new
- I18n.backend.store_translations("en",
- errors: { messages: { confirmation: "doesn't match %{attribute}" } },
- activemodel: { attributes: { topic: { title: "Test Title" } } })
-
- Topic.validates_confirmation_of(:title)
-
- t = Topic.new("title" => "We should be confirmed", "title_confirmation" => "")
- assert t.invalid?
- assert_equal ["doesn't match Test Title"], t.errors[:title_confirmation]
- ensure
- I18n.load_path.replace @old_load_path
- I18n.backend = @old_backend
- I18n.backend.reload!
- end
+ @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend
+ I18n.load_path.clear
+ I18n.backend = I18n::Backend::Simple.new
+ I18n.backend.store_translations("en",
+ errors: { messages: { confirmation: "doesn't match %{attribute}" } },
+ activemodel: { attributes: { topic: { title: "Test Title" } } })
+
+ Topic.validates_confirmation_of(:title)
+
+ t = Topic.new("title" => "We should be confirmed", "title_confirmation" => "")
+ assert_predicate t, :invalid?
+ assert_equal ["doesn't match Test Title"], t.errors[:title_confirmation]
+ ensure
+ I18n.load_path.replace @old_load_path
+ I18n.backend = @old_backend
+ I18n.backend.reload!
end
test "does not override confirmation reader if present" do
@@ -122,13 +120,13 @@ class ConfirmationValidationTest < ActiveModel::TestCase
Topic.validates_confirmation_of(:title, case_sensitive: true)
t = Topic.new(title: "title", title_confirmation: "Title")
- assert t.invalid?
+ assert_predicate t, :invalid?
end
def test_title_confirmation_with_case_sensitive_option_false
Topic.validates_confirmation_of(:title, case_sensitive: false)
t = Topic.new(title: "title", title_confirmation: "Title")
- assert t.valid?
+ assert_predicate t, :valid?
end
end
diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb
index 68d611e904..50bd47065c 100644
--- a/activemodel/test/cases/validations/exclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/exclusion_validation_test.rb
@@ -14,8 +14,8 @@ class ExclusionValidationTest < ActiveModel::TestCase
def test_validates_exclusion_of
Topic.validates_exclusion_of(:title, in: %w( abe monkey ))
- assert Topic.new("title" => "something", "content" => "abc").valid?
- assert Topic.new("title" => "monkey", "content" => "abc").invalid?
+ assert_predicate Topic.new("title" => "something", "content" => "abc"), :valid?
+ assert_predicate Topic.new("title" => "monkey", "content" => "abc"), :invalid?
end
def test_validates_exclusion_of_with_formatted_message
@@ -24,8 +24,8 @@ class ExclusionValidationTest < ActiveModel::TestCase
assert Topic.new("title" => "something", "content" => "abc")
t = Topic.new("title" => "monkey")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["option monkey is restricted"], t.errors[:title]
end
@@ -35,8 +35,8 @@ class ExclusionValidationTest < ActiveModel::TestCase
assert Topic.new("title" => "something", "content" => "abc")
t = Topic.new("title" => "monkey")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
end
def test_validates_exclusion_of_for_ruby_class
@@ -44,12 +44,12 @@ class ExclusionValidationTest < ActiveModel::TestCase
p = Person.new
p.karma = "abe"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is reserved"], p.errors[:karma]
p.karma = "Lifo"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
@@ -60,26 +60,26 @@ class ExclusionValidationTest < ActiveModel::TestCase
t = Topic.new
t.title = "elephant"
t.author_name = "sikachu"
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title = "wasabi"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_exclusion_of_with_range
Topic.validates_exclusion_of :content, in: ("a".."g")
- assert Topic.new(content: "g").invalid?
- assert Topic.new(content: "h").valid?
+ assert_predicate Topic.new(content: "g"), :invalid?
+ assert_predicate Topic.new(content: "h"), :valid?
end
def test_validates_exclusion_of_with_time_range
Topic.validates_exclusion_of :created_at, in: 6.days.ago..2.days.ago
- assert Topic.new(created_at: 5.days.ago).invalid?
- assert Topic.new(created_at: 3.days.ago).invalid?
- assert Topic.new(created_at: 7.days.ago).valid?
- assert Topic.new(created_at: 1.day.ago).valid?
+ assert_predicate Topic.new(created_at: 5.days.ago), :invalid?
+ assert_predicate Topic.new(created_at: 3.days.ago), :invalid?
+ assert_predicate Topic.new(created_at: 7.days.ago), :valid?
+ assert_predicate Topic.new(created_at: 1.day.ago), :valid?
end
def test_validates_inclusion_of_with_symbol
@@ -92,7 +92,7 @@ class ExclusionValidationTest < ActiveModel::TestCase
%w(abe)
end
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is reserved"], p.errors[:karma]
p = Person.new
@@ -102,7 +102,7 @@ class ExclusionValidationTest < ActiveModel::TestCase
%w()
end
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb
index 3ddda2154a..2a7088b3e8 100644
--- a/activemodel/test/cases/validations/format_validation_test.rb
+++ b/activemodel/test/cases/validations/format_validation_test.rb
@@ -5,7 +5,7 @@ require "cases/helper"
require "models/topic"
require "models/person"
-class PresenceValidationTest < ActiveModel::TestCase
+class FormatValidationTest < ActiveModel::TestCase
def teardown
Topic.clear_validators!
end
@@ -16,22 +16,22 @@ class PresenceValidationTest < ActiveModel::TestCase
t = Topic.new("title" => "i'm incorrect", "content" => "Validation macros rule!")
assert t.invalid?, "Shouldn't be valid"
assert_equal ["is bad data"], t.errors[:title]
- assert t.errors[:content].empty?
+ assert_empty t.errors[:content]
t.title = "Validation macros rule!"
- assert t.valid?
- assert t.errors[:title].empty?
+ assert_predicate t, :valid?
+ assert_empty t.errors[:title]
assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
end
def test_validate_format_with_allow_blank
Topic.validates_format_of(:title, with: /\AValidation\smacros \w+!\z/, allow_blank: true)
- assert Topic.new("title" => "Shouldn't be valid").invalid?
- assert Topic.new("title" => "").valid?
- assert Topic.new("title" => nil).valid?
- assert Topic.new("title" => "Validation macros rule!").valid?
+ assert_predicate Topic.new("title" => "Shouldn't be valid"), :invalid?
+ assert_predicate Topic.new("title" => ""), :valid?
+ assert_predicate Topic.new("title" => nil), :valid?
+ assert_predicate Topic.new("title" => "Validation macros rule!"), :valid?
end
# testing ticket #3142
@@ -42,7 +42,7 @@ class PresenceValidationTest < ActiveModel::TestCase
assert t.invalid?, "Shouldn't be valid"
assert_equal ["is bad data"], t.errors[:title]
- assert t.errors[:content].empty?
+ assert_empty t.errors[:content]
t.title = "-11"
assert t.invalid?, "Shouldn't be valid"
@@ -58,14 +58,14 @@ class PresenceValidationTest < ActiveModel::TestCase
t.title = "1"
- assert t.valid?
- assert t.errors[:title].empty?
+ assert_predicate t, :valid?
+ assert_empty t.errors[:title]
end
def test_validate_format_with_formatted_message
Topic.validates_format_of(:title, with: /\AValid Title\z/, message: "can't be %{value}")
t = Topic.new(title: "Invalid title")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["can't be Invalid title"], t.errors[:title]
end
@@ -114,10 +114,10 @@ class PresenceValidationTest < ActiveModel::TestCase
t = Topic.new
t.title = "digit"
t.content = "Pixies"
- assert t.invalid?
+ assert_predicate t, :invalid?
t.content = "1234"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_format_of_without_lambda
@@ -126,10 +126,10 @@ class PresenceValidationTest < ActiveModel::TestCase
t = Topic.new
t.title = "characters"
t.content = "1234"
- assert t.invalid?
+ assert_predicate t, :invalid?
t.content = "Pixies"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_format_of_for_ruby_class
@@ -137,12 +137,12 @@ class PresenceValidationTest < ActiveModel::TestCase
p = Person.new
p.karma = "Pixies"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is invalid"], p.errors[:karma]
p.karma = "1234"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index 9cfe189d0e..ccb565c5bd 100644
--- a/activemodel/test/cases/validations/i18n_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_validation_test.rb
@@ -12,6 +12,9 @@ class I18nValidationTest < ActiveModel::TestCase
I18n.load_path.clear
I18n.backend = I18n::Backend::Simple.new
I18n.backend.store_translations("en", errors: { messages: { custom: nil } })
+
+ @original_i18n_full_message = ActiveModel::Errors.i18n_full_message
+ ActiveModel::Errors.i18n_full_message = true
end
def teardown
@@ -19,6 +22,7 @@ class I18nValidationTest < ActiveModel::TestCase
I18n.load_path.replace @old_load_path
I18n.backend = @old_backend
I18n.backend.reload!
+ ActiveModel::Errors.i18n_full_message = @original_i18n_full_message
end
def test_full_message_encoding
@@ -31,7 +35,7 @@ class I18nValidationTest < ActiveModel::TestCase
def test_errors_full_messages_translates_human_attribute_name_for_model_attributes
@person.errors.add(:name, "not found")
- assert_called_with(Person, :human_attribute_name, [:name, default: "Name"], returns: "Person's name") do
+ assert_called_with(Person, :human_attribute_name, ["name", default: "Name"], returns: "Person's name") do
assert_equal ["Person's name not found"], @person.errors.full_messages
end
end
@@ -42,6 +46,118 @@ class I18nValidationTest < ActiveModel::TestCase
assert_equal ["Field Name empty"], @person.errors.full_messages
end
+ def test_errors_full_messages_doesnt_use_attribute_format_without_config
+ ActiveModel::Errors.i18n_full_message = false
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } })
+
+ person = Person.new
+ assert_equal "Name cannot be blank", person.errors.full_message(:name, "cannot be blank")
+ assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
+ end
+
+ def test_errors_full_messages_uses_attribute_format
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } })
+
+ person = Person.new
+ assert_equal "cannot be blank", person.errors.full_message(:name, "cannot be blank")
+ assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
+ end
+
+ def test_errors_full_messages_uses_model_format
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { person: { format: "%{message}" } } } })
+
+ person = Person.new
+ assert_equal "cannot be blank", person.errors.full_message(:name, "cannot be blank")
+ assert_equal "cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
+ end
+
+ def test_errors_full_messages_uses_deeply_nested_model_attributes_format
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
+
+ person = Person.new
+ assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.street', "cannot be blank")
+ assert_equal "Contacts/addresses country cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank")
+ end
+
+ def test_errors_full_messages_uses_deeply_nested_model_model_format
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } })
+
+ person = Person.new
+ assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.street', "cannot be blank")
+ assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank")
+ end
+
+ def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_attributes_format
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
+
+ person = Person.new
+ assert_equal "cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank")
+ assert_equal "Contacts/addresses country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank")
+ end
+
+ def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_model_format
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } })
+
+ person = Person.new
+ assert_equal "cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank")
+ assert_equal "cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank")
+ end
+
+ def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_i18n_attribute_name
+ ActiveModel::Errors.i18n_full_message = true
+
+ I18n.backend.store_translations("en", activemodel: {
+ attributes: { 'person/contacts/addresses': { country: "Country" } }
+ })
+
+ person = Person.new
+ assert_equal "Contacts/addresses street cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank")
+ assert_equal "Country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank")
+ end
+
+ def test_errors_full_messages_with_indexed_deeply_nested_attributes_without_i18n_config
+ ActiveModel::Errors.i18n_full_message = false
+
+ I18n.backend.store_translations("en", activemodel: {
+ errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
+
+ person = Person.new
+ assert_equal "Contacts[0]/addresses[0] street cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank")
+ assert_equal "Contacts[0]/addresses[0] country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank")
+ end
+
+ def test_errors_full_messages_with_i18n_attribute_name_without_i18n_config
+ ActiveModel::Errors.i18n_full_message = false
+
+ I18n.backend.store_translations("en", activemodel: {
+ attributes: { 'person/contacts[0]/addresses[0]': { country: "Country" } }
+ })
+
+ person = Person.new
+ assert_equal "Contacts[0]/addresses[0] street cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank")
+ assert_equal "Country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank")
+ end
+
# ActiveModel::Validations
# A set of common cases for ActiveModel::Validations message generation that
diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb
index 94df0649a9..daad76759f 100644
--- a/activemodel/test/cases/validations/inclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/inclusion_validation_test.rb
@@ -13,61 +13,61 @@ class InclusionValidationTest < ActiveModel::TestCase
def test_validates_inclusion_of_range
Topic.validates_inclusion_of(:title, in: "aaa".."bbb")
- assert Topic.new("title" => "bbc", "content" => "abc").invalid?
- assert Topic.new("title" => "aa", "content" => "abc").invalid?
- assert Topic.new("title" => "aaab", "content" => "abc").invalid?
- assert Topic.new("title" => "aaa", "content" => "abc").valid?
- assert Topic.new("title" => "abc", "content" => "abc").valid?
- assert Topic.new("title" => "bbb", "content" => "abc").valid?
+ assert_predicate Topic.new("title" => "bbc", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => "aa", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => "aaab", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => "aaa", "content" => "abc"), :valid?
+ assert_predicate Topic.new("title" => "abc", "content" => "abc"), :valid?
+ assert_predicate Topic.new("title" => "bbb", "content" => "abc"), :valid?
end
def test_validates_inclusion_of_time_range
range_begin = 1.year.ago
range_end = Time.now
Topic.validates_inclusion_of(:created_at, in: range_begin..range_end)
- assert Topic.new(title: "aaa", created_at: 2.years.ago).invalid?
- assert Topic.new(title: "aaa", created_at: 3.months.ago).valid?
- assert Topic.new(title: "aaa", created_at: 37.weeks.from_now).invalid?
- assert Topic.new(title: "aaa", created_at: range_begin).valid?
- assert Topic.new(title: "aaa", created_at: range_end).valid?
+ assert_predicate Topic.new(title: "aaa", created_at: 2.years.ago), :invalid?
+ assert_predicate Topic.new(title: "aaa", created_at: 3.months.ago), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: 37.weeks.from_now), :invalid?
+ assert_predicate Topic.new(title: "aaa", created_at: range_begin), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: range_end), :valid?
end
def test_validates_inclusion_of_date_range
range_begin = 1.year.until(Date.today)
range_end = Date.today
Topic.validates_inclusion_of(:created_at, in: range_begin..range_end)
- assert Topic.new(title: "aaa", created_at: 2.years.until(Date.today)).invalid?
- assert Topic.new(title: "aaa", created_at: 3.months.until(Date.today)).valid?
- assert Topic.new(title: "aaa", created_at: 37.weeks.since(Date.today)).invalid?
- assert Topic.new(title: "aaa", created_at: 1.year.until(Date.today)).valid?
- assert Topic.new(title: "aaa", created_at: Date.today).valid?
- assert Topic.new(title: "aaa", created_at: range_begin).valid?
- assert Topic.new(title: "aaa", created_at: range_end).valid?
+ assert_predicate Topic.new(title: "aaa", created_at: 2.years.until(Date.today)), :invalid?
+ assert_predicate Topic.new(title: "aaa", created_at: 3.months.until(Date.today)), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: 37.weeks.since(Date.today)), :invalid?
+ assert_predicate Topic.new(title: "aaa", created_at: 1.year.until(Date.today)), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: Date.today), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: range_begin), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: range_end), :valid?
end
def test_validates_inclusion_of_date_time_range
range_begin = 1.year.until(DateTime.current)
range_end = DateTime.current
Topic.validates_inclusion_of(:created_at, in: range_begin..range_end)
- assert Topic.new(title: "aaa", created_at: 2.years.until(DateTime.current)).invalid?
- assert Topic.new(title: "aaa", created_at: 3.months.until(DateTime.current)).valid?
- assert Topic.new(title: "aaa", created_at: 37.weeks.since(DateTime.current)).invalid?
- assert Topic.new(title: "aaa", created_at: range_begin).valid?
- assert Topic.new(title: "aaa", created_at: range_end).valid?
+ assert_predicate Topic.new(title: "aaa", created_at: 2.years.until(DateTime.current)), :invalid?
+ assert_predicate Topic.new(title: "aaa", created_at: 3.months.until(DateTime.current)), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: 37.weeks.since(DateTime.current)), :invalid?
+ assert_predicate Topic.new(title: "aaa", created_at: range_begin), :valid?
+ assert_predicate Topic.new(title: "aaa", created_at: range_end), :valid?
end
def test_validates_inclusion_of
Topic.validates_inclusion_of(:title, in: %w( a b c d e f g ))
- assert Topic.new("title" => "a!", "content" => "abc").invalid?
- assert Topic.new("title" => "a b", "content" => "abc").invalid?
- assert Topic.new("title" => nil, "content" => "def").invalid?
+ assert_predicate Topic.new("title" => "a!", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => "a b", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => nil, "content" => "def"), :invalid?
t = Topic.new("title" => "a", "content" => "I know you are but what am I?")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "uhoh"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is not included in the list"], t.errors[:title]
assert_raise(ArgumentError) { Topic.validates_inclusion_of(:title, in: nil) }
@@ -81,30 +81,30 @@ class InclusionValidationTest < ActiveModel::TestCase
def test_validates_inclusion_of_with_allow_nil
Topic.validates_inclusion_of(:title, in: %w( a b c d e f g ), allow_nil: true)
- assert Topic.new("title" => "a!", "content" => "abc").invalid?
- assert Topic.new("title" => "", "content" => "abc").invalid?
- assert Topic.new("title" => nil, "content" => "abc").valid?
+ assert_predicate Topic.new("title" => "a!", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => "", "content" => "abc"), :invalid?
+ assert_predicate Topic.new("title" => nil, "content" => "abc"), :valid?
end
def test_validates_inclusion_of_with_formatted_message
Topic.validates_inclusion_of(:title, in: %w( a b c d e f g ), message: "option %{value} is not in the list")
- assert Topic.new("title" => "a", "content" => "abc").valid?
+ assert_predicate Topic.new("title" => "a", "content" => "abc"), :valid?
t = Topic.new("title" => "uhoh", "content" => "abc")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["option uhoh is not in the list"], t.errors[:title]
end
def test_validates_inclusion_of_with_within_option
Topic.validates_inclusion_of(:title, within: %w( a b c d e f g ))
- assert Topic.new("title" => "a", "content" => "abc").valid?
+ assert_predicate Topic.new("title" => "a", "content" => "abc"), :valid?
t = Topic.new("title" => "uhoh", "content" => "abc")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
end
def test_validates_inclusion_of_for_ruby_class
@@ -112,12 +112,12 @@ class InclusionValidationTest < ActiveModel::TestCase
p = Person.new
p.karma = "Lifo"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is not included in the list"], p.errors[:karma]
p.karma = "monkey"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
@@ -128,10 +128,10 @@ class InclusionValidationTest < ActiveModel::TestCase
t = Topic.new
t.title = "wasabi"
t.author_name = "sikachu"
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title = "elephant"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_inclusion_of_with_symbol
@@ -144,7 +144,7 @@ class InclusionValidationTest < ActiveModel::TestCase
%w()
end
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is not included in the list"], p.errors[:karma]
p = Person.new
@@ -154,7 +154,7 @@ class InclusionValidationTest < ActiveModel::TestCase
%w(Lifo)
end
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb
index 42f76f3e3c..37e10f783c 100644
--- a/activemodel/test/cases/validations/length_validation_test.rb
+++ b/activemodel/test/cases/validations/length_validation_test.rb
@@ -13,153 +13,153 @@ class LengthValidationTest < ActiveModel::TestCase
def test_validates_length_of_with_allow_nil
Topic.validates_length_of(:title, is: 5, allow_nil: true)
- assert Topic.new("title" => "ab").invalid?
- assert Topic.new("title" => "").invalid?
- assert Topic.new("title" => nil).valid?
- assert Topic.new("title" => "abcde").valid?
+ assert_predicate Topic.new("title" => "ab"), :invalid?
+ assert_predicate Topic.new("title" => ""), :invalid?
+ assert_predicate Topic.new("title" => nil), :valid?
+ assert_predicate Topic.new("title" => "abcde"), :valid?
end
def test_validates_length_of_with_allow_blank
Topic.validates_length_of(:title, is: 5, allow_blank: true)
- assert Topic.new("title" => "ab").invalid?
- assert Topic.new("title" => "").valid?
- assert Topic.new("title" => nil).valid?
- assert Topic.new("title" => "abcde").valid?
+ assert_predicate Topic.new("title" => "ab"), :invalid?
+ assert_predicate Topic.new("title" => ""), :valid?
+ assert_predicate Topic.new("title" => nil), :valid?
+ assert_predicate Topic.new("title" => "abcde"), :valid?
end
def test_validates_length_of_using_minimum
Topic.validates_length_of :title, minimum: 5
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "not"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too short (minimum is 5 characters)"], t.errors[:title]
t.title = ""
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too short (minimum is 5 characters)"], t.errors[:title]
t.title = nil
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too short (minimum is 5 characters)"], t.errors["title"]
end
def test_validates_length_of_using_maximum_should_allow_nil
Topic.validates_length_of :title, maximum: 10
t = Topic.new
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_optionally_validates_length_of_using_minimum
Topic.validates_length_of :title, minimum: 5, allow_nil: true
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = nil
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_maximum
Topic.validates_length_of :title, maximum: 5
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "notvalid"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too long (maximum is 5 characters)"], t.errors[:title]
t.title = ""
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_optionally_validates_length_of_using_maximum
Topic.validates_length_of :title, maximum: 5, allow_nil: true
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = nil
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_within
Topic.validates_length_of(:title, :content, within: 3..5)
t = Topic.new("title" => "a!", "content" => "I'm ooooooooh so very long")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["is too short (minimum is 3 characters)"], t.errors[:title]
assert_equal ["is too long (maximum is 5 characters)"], t.errors[:content]
t.title = nil
t.content = nil
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["is too short (minimum is 3 characters)"], t.errors[:title]
assert_equal ["is too short (minimum is 3 characters)"], t.errors[:content]
t.title = "abe"
t.content = "mad"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_within_with_exclusive_range
Topic.validates_length_of(:title, within: 4...10)
t = Topic.new("title" => "9 chars!!")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "Now I'm 10"
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["is too long (maximum is 9 characters)"], t.errors[:title]
t.title = "Four"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_optionally_validates_length_of_using_within
Topic.validates_length_of :title, :content, within: 3..5, allow_nil: true
t = Topic.new("title" => "abc", "content" => "abcd")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = nil
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_is
Topic.validates_length_of :title, is: 5
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "notvalid"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is the wrong length (should be 5 characters)"], t.errors[:title]
t.title = ""
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title = nil
- assert t.invalid?
+ assert_predicate t, :invalid?
end
def test_optionally_validates_length_of_using_is
Topic.validates_length_of :title, is: 5, allow_nil: true
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = nil
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_bignum
@@ -187,45 +187,45 @@ class LengthValidationTest < ActiveModel::TestCase
def test_validates_length_of_custom_errors_for_minimum_with_message
Topic.validates_length_of(:title, minimum: 5, message: "boo %{count}")
t = Topic.new("title" => "uhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["boo 5"], t.errors[:title]
end
def test_validates_length_of_custom_errors_for_minimum_with_too_short
Topic.validates_length_of(:title, minimum: 5, too_short: "hoo %{count}")
t = Topic.new("title" => "uhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 5"], t.errors[:title]
end
def test_validates_length_of_custom_errors_for_maximum_with_message
Topic.validates_length_of(:title, maximum: 5, message: "boo %{count}")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["boo 5"], t.errors[:title]
end
def test_validates_length_of_custom_errors_for_in
Topic.validates_length_of(:title, in: 10..20, message: "hoo %{count}")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 10"], t.errors["title"]
t = Topic.new("title" => "uhohuhohuhohuhohuhohuhohuhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 20"], t.errors["title"]
end
def test_validates_length_of_custom_errors_for_maximum_with_too_long
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 5"], t.errors["title"]
end
@@ -233,29 +233,29 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of :title, minimum: 3, maximum: 5, too_short: "too short", too_long: "too long"
t = Topic.new(title: "a")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["too short"], t.errors["title"]
t = Topic.new(title: "aaaaaa")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["too long"], t.errors["title"]
end
def test_validates_length_of_custom_errors_for_is_with_message
Topic.validates_length_of(:title, is: 5, message: "boo %{count}")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["boo 5"], t.errors["title"]
end
def test_validates_length_of_custom_errors_for_is_with_wrong_length
Topic.validates_length_of(:title, is: 5, wrong_length: "hoo %{count}")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["hoo 5"], t.errors["title"]
end
@@ -263,11 +263,11 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of :title, minimum: 5
t = Topic.new("title" => "一二三四五", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "一二三四"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too short (minimum is 5 characters)"], t.errors["title"]
end
@@ -275,11 +275,11 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of :title, maximum: 5
t = Topic.new("title" => "一二三四五", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "一二34五六"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too long (maximum is 5 characters)"], t.errors["title"]
end
@@ -287,12 +287,12 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:title, :content, within: 3..5)
t = Topic.new("title" => "一二", "content" => "12三四五六七")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["is too short (minimum is 3 characters)"], t.errors[:title]
assert_equal ["is too long (maximum is 5 characters)"], t.errors[:content]
t.title = "一二三"
t.content = "12三"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_optionally_validates_length_of_using_within_utf8
@@ -312,11 +312,11 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of :title, is: 5
t = Topic.new("title" => "一二345", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "一二345六"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is the wrong length (should be 5 characters)"], t.errors["title"]
end
@@ -324,11 +324,11 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:approved, is: 4)
t = Topic.new("title" => "uhohuhoh", "content" => "whatever", approved: 1)
- assert t.invalid?
- assert t.errors[:approved].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:approved], :any?
t = Topic.new("title" => "uhohuhoh", "content" => "whatever", approved: 1234)
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_for_ruby_class
@@ -336,12 +336,12 @@ class LengthValidationTest < ActiveModel::TestCase
p = Person.new
p.karma = "Pix"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is too short (minimum is 5 characters)"], p.errors[:karma]
p.karma = "The Smiths"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
@@ -350,95 +350,95 @@ class LengthValidationTest < ActiveModel::TestCase
Topic.validates_length_of(:title, within: 5..Float::INFINITY)
t = Topic.new("title" => "1234")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
t.title = "12345"
- assert t.valid?
+ assert_predicate t, :valid?
Topic.validates_length_of(:author_name, maximum: Float::INFINITY)
- assert t.valid?
+ assert_predicate t, :valid?
t.author_name = "A very long author name that should still be valid." * 100
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_maximum_should_not_allow_nil_when_nil_not_allowed
Topic.validates_length_of :title, maximum: 10, allow_nil: false
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
end
def test_validates_length_of_using_maximum_should_not_allow_nil_and_empty_string_when_blank_not_allowed
Topic.validates_length_of :title, maximum: 10, allow_blank: false
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title = ""
- assert t.invalid?
+ assert_predicate t, :invalid?
end
def test_validates_length_of_using_both_minimum_and_maximum_should_not_allow_nil
Topic.validates_length_of :title, minimum: 5, maximum: 10
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
end
def test_validates_length_of_using_minimum_0_should_not_allow_nil
Topic.validates_length_of :title, minimum: 0
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title = ""
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_length_of_using_is_0_should_not_allow_nil
Topic.validates_length_of :title, is: 0
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
t.title = ""
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_validates_with_diff_in_option
Topic.validates_length_of(:title, is: 5)
Topic.validates_length_of(:title, is: 5, if: Proc.new { false })
- assert Topic.new("title" => "david").valid?
- assert Topic.new("title" => "david2").invalid?
+ assert_predicate Topic.new("title" => "david"), :valid?
+ assert_predicate 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?
+ assert_predicate t, :valid?
t.title = "notvalid"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too long (maximum is 5 characters)"], t.errors[:title]
t.title = ""
- assert t.valid?
+ assert_predicate 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.define_method(:max_title_length) { 5 }
Topic.validates_length_of :title, maximum: Proc.new(&:max_title_length)
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.valid?
+ assert_predicate t, :valid?
t.title = "notvalid"
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["is too long (maximum is 5 characters)"], t.errors[:title]
t.title = ""
- assert t.valid?
+ assert_predicate 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 5413255e6b..16c44762cb 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -66,7 +66,7 @@ class NumericalityValidationTest < ActiveModel::TestCase
end
def test_validates_numericality_of_with_integer_only_and_proc_as_value
- Topic.send(:define_method, :allow_only_integers?, lambda { false })
+ Topic.define_method(:allow_only_integers?) { false }
Topic.validates_numericality_of :approved, only_integer: Proc.new(&:allow_only_integers?)
invalid!(NIL + BLANK + JUNK)
@@ -214,36 +214,36 @@ class NumericalityValidationTest < ActiveModel::TestCase
end
def test_validates_numericality_with_proc
- Topic.send(:define_method, :min_approved, lambda { 5 })
+ Topic.define_method(:min_approved) { 5 }
Topic.validates_numericality_of :approved, greater_than_or_equal_to: Proc.new(&:min_approved)
invalid!([3, 4])
valid!([5, 6])
ensure
- Topic.send(:remove_method, :min_approved)
+ Topic.remove_method :min_approved
end
def test_validates_numericality_with_symbol
- Topic.send(:define_method, :max_approved, lambda { 5 })
+ Topic.define_method(:max_approved) { 5 }
Topic.validates_numericality_of :approved, less_than_or_equal_to: :max_approved
invalid!([6])
valid!([4, 5])
ensure
- Topic.send(:remove_method, :max_approved)
+ Topic.remove_method :max_approved
end
def test_validates_numericality_with_numeric_message
Topic.validates_numericality_of :approved, less_than: 4, message: "smaller than %{count}"
topic = Topic.new("title" => "numeric test", "approved" => 10)
- assert !topic.valid?
+ assert_not_predicate topic, :valid?
assert_equal ["smaller than 4"], topic.errors[:approved]
Topic.validates_numericality_of :approved, greater_than: 4, message: "greater than %{count}"
topic = Topic.new("title" => "numeric test", "approved" => 1)
- assert !topic.valid?
+ assert_not_predicate topic, :valid?
assert_equal ["greater than 4"], topic.errors[:approved]
end
@@ -252,23 +252,46 @@ class NumericalityValidationTest < ActiveModel::TestCase
p = Person.new
p.karma = "Pix"
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["is not a number"], p.errors[:karma]
p.karma = "1234"
- assert p.valid?
+ assert_predicate p, :valid?
ensure
Person.clear_validators!
end
+ def test_validates_numericality_using_value_before_type_cast_if_possible
+ Topic.validates_numericality_of :price
+
+ topic = Topic.new(price: 50)
+
+ assert_equal "$50.00", topic.price
+ assert_equal 50, topic.price_before_type_cast
+ assert_predicate topic, :valid?
+ end
+
def test_validates_numericality_with_exponent_number
base = 10_000_000_000_000_000
Topic.validates_numericality_of :approved, less_than_or_equal_to: base
topic = Topic.new
topic.approved = (base + 1).to_s
- assert topic.invalid?
+ assert_predicate topic, :invalid?
+ end
+
+ def test_validates_numericality_with_object_acting_as_numeric
+ klass = Class.new do
+ def to_f
+ 123.54
+ end
+ end
+
+ Topic.validates_numericality_of :price
+ topic = Topic.new(price: klass.new)
+
+ assert_predicate topic, :valid?
end
def test_validates_numericality_with_invalid_args
@@ -279,6 +302,13 @@ class NumericalityValidationTest < ActiveModel::TestCase
assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, equal_to: "foo" }
end
+ def test_validates_numericality_equality_for_float_and_big_decimal
+ Topic.validates_numericality_of :approved, equal_to: BigDecimal("65.6")
+
+ invalid!([Float("65.5"), BigDecimal("65.7")], "must be equal to 65.6")
+ valid!([Float("65.6"), BigDecimal("65.6")])
+ end
+
private
def invalid!(values, error = nil)
diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb
index 22c2f0af87..c3eca41070 100644
--- a/activemodel/test/cases/validations/presence_validation_test.rb
+++ b/activemodel/test/cases/validations/presence_validation_test.rb
@@ -17,25 +17,25 @@ class PresenceValidationTest < ActiveModel::TestCase
Topic.validates_presence_of(:title, :content)
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["can't be blank"], t.errors[:title]
assert_equal ["can't be blank"], t.errors[:content]
t.title = "something"
t.content = " "
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["can't be blank"], t.errors[:content]
t.content = "like stuff"
- assert t.valid?
+ assert_predicate t, :valid?
end
def test_accepts_array_arguments
Topic.validates_presence_of %w(title content)
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["can't be blank"], t.errors[:title]
assert_equal ["can't be blank"], t.errors[:content]
end
@@ -43,7 +43,7 @@ class PresenceValidationTest < ActiveModel::TestCase
def test_validates_acceptance_of_with_custom_error_using_quotes
Person.validates_presence_of :karma, message: "This string contains 'single' and \"double\" quotes"
p = Person.new
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal "This string contains 'single' and \"double\" quotes", p.errors[:karma].last
end
@@ -51,24 +51,24 @@ class PresenceValidationTest < ActiveModel::TestCase
Person.validates_presence_of :karma
p = Person.new
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["can't be blank"], p.errors[:karma]
p.karma = "Cold"
- assert p.valid?
+ assert_predicate p, :valid?
end
def test_validates_presence_of_for_ruby_class_with_custom_reader
CustomReader.validates_presence_of :karma
p = CustomReader.new
- assert p.invalid?
+ assert_predicate p, :invalid?
assert_equal ["can't be blank"], p.errors[:karma]
p[:karma] = "Cold"
- assert p.valid?
+ assert_predicate p, :valid?
end
def test_validates_presence_of_with_allow_nil_option
@@ -78,7 +78,7 @@ class PresenceValidationTest < ActiveModel::TestCase
assert t.valid?, t.errors.full_messages
t.title = ""
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["can't be blank"], t.errors[:title]
t.title = " "
diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb
index 7f32f5dc74..ae5a875c24 100644
--- a/activemodel/test/cases/validations/validates_test.rb
+++ b/activemodel/test/cases/validations/validates_test.rb
@@ -19,7 +19,7 @@ class ValidatesTest < ActiveModel::TestCase
def test_validates_with_messages_empty
Person.validates :title, presence: { message: "" }
person = Person.new
- assert !person.valid?, "person should not be valid."
+ assert_not person.valid?, "person should not be valid."
end
def test_validates_with_built_in_validation
@@ -37,7 +37,7 @@ class ValidatesTest < ActiveModel::TestCase
person = Person.new
person.title = 123
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_built_in_validation_and_options
@@ -71,7 +71,7 @@ class ValidatesTest < ActiveModel::TestCase
def test_validates_with_if_as_shared_conditions
Person.validates :karma, presence: true, email: true, if: :condition_is_false
person = Person.new
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_unless_as_local_conditions
@@ -84,40 +84,40 @@ class ValidatesTest < ActiveModel::TestCase
def test_validates_with_unless_shared_conditions
Person.validates :karma, presence: true, email: true, unless: :condition_is_true
person = Person.new
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_allow_nil_shared_conditions
Person.validates :karma, length: { minimum: 20 }, email: true, allow_nil: true
person = Person.new
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_regexp
Person.validates :karma, format: /positive|negative/
person = Person.new
- assert person.invalid?
+ assert_predicate person, :invalid?
assert_equal ["is invalid"], person.errors[:karma]
person.karma = "positive"
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_array
Person.validates :gender, inclusion: %w(m f)
person = Person.new
- assert person.invalid?
+ assert_predicate person, :invalid?
assert_equal ["is not included in the list"], person.errors[:gender]
person.gender = "m"
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_range
Person.validates :karma, length: 6..20
person = Person.new
- assert person.invalid?
+ assert_predicate person, :invalid?
assert_equal ["is too short (minimum is 6 characters)"], person.errors[:karma]
person.karma = "something"
- assert person.valid?
+ assert_predicate person, :valid?
end
def test_validates_with_validator_class_and_options
@@ -159,7 +159,7 @@ class ValidatesTest < ActiveModel::TestCase
topic = Topic.new
topic.title = "What's happening"
topic.title_confirmation = "Not this"
- assert !topic.valid?
+ assert_not_predicate topic, :valid?
assert_equal ["Y U NO CONFIRM"], topic.errors[:title_confirmation]
end
end
diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb
index 13ef5e6a31..8239792c79 100644
--- a/activemodel/test/cases/validations/with_validation_test.rb
+++ b/activemodel/test/cases/validations/with_validation_test.rb
@@ -65,7 +65,7 @@ class ValidatesWithTest < ActiveModel::TestCase
test "with multiple classes" do
Topic.validates_with(ValidatorThatAddsErrors, OtherValidatorThatAddsErrors)
topic = Topic.new
- assert topic.invalid?
+ assert_predicate topic, :invalid?
assert_includes topic.errors[:base], ERROR_MESSAGE
assert_includes topic.errors[:base], OTHER_ERROR_MESSAGE
end
@@ -79,21 +79,21 @@ class ValidatesWithTest < ActiveModel::TestCase
validator.expect(:is_a?, false, [String])
Topic.validates_with(validator, if: :condition_is_true, foo: :bar)
- assert topic.valid?
+ assert_predicate topic, :valid?
validator.verify
end
test "validates_with with options" do
Topic.validates_with(ValidatorThatValidatesOptions, field: :first_name)
topic = Topic.new
- assert topic.invalid?
+ assert_predicate topic, :invalid?
assert_includes topic.errors[:base], ERROR_MESSAGE
end
test "validates_with each validator" do
Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content])
topic = Topic.new title: "Title", content: "Content"
- assert topic.invalid?
+ assert_predicate topic, :invalid?
assert_equal ["Value is Title"], topic.errors[:title]
assert_equal ["Value is Content"], topic.errors[:content]
end
@@ -113,28 +113,28 @@ class ValidatesWithTest < ActiveModel::TestCase
test "each validator skip nil values if :allow_nil is set to true" do
Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content], allow_nil: true)
topic = Topic.new content: ""
- assert topic.invalid?
- assert topic.errors[:title].empty?
+ assert_predicate topic, :invalid?
+ assert_empty topic.errors[:title]
assert_equal ["Value is "], topic.errors[:content]
end
test "each validator skip blank values if :allow_blank is set to true" do
Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content], allow_blank: true)
topic = Topic.new content: ""
- assert topic.valid?
- assert topic.errors[:title].empty?
- assert topic.errors[:content].empty?
+ assert_predicate topic, :valid?
+ assert_empty topic.errors[:title]
+ assert_empty topic.errors[:content]
end
test "validates_with can validate with an instance method" do
Topic.validates :title, with: :my_validation
topic = Topic.new title: "foo"
- assert topic.valid?
- assert topic.errors[:title].empty?
+ assert_predicate topic, :valid?
+ assert_empty topic.errors[:title]
topic = Topic.new
- assert !topic.valid?
+ assert_not_predicate topic, :valid?
assert_equal ["is missing"], topic.errors[:title]
end
@@ -142,8 +142,8 @@ class ValidatesWithTest < ActiveModel::TestCase
Topic.validates :title, :content, with: :my_validation_with_arg
topic = Topic.new title: "foo"
- assert !topic.valid?
- assert topic.errors[:title].empty?
+ assert_not_predicate topic, :valid?
+ assert_empty topic.errors[:title]
assert_equal ["is missing"], topic.errors[:content]
end
end
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index ab8c41bbd0..7776233db5 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -30,7 +30,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_single_attr_validation_and_error_msg
r = Reply.new
r.title = "There's no content!"
- assert r.invalid?
+ assert_predicate r, :invalid?
assert r.errors[:content].any?, "A reply without content should mark that attribute as invalid"
assert_equal ["is Empty"], r.errors["content"], "A reply without content should contain an error"
assert_equal 1, r.errors.count
@@ -38,7 +38,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_double_attr_validation_and_error_msg
r = Reply.new
- assert r.invalid?
+ assert_predicate r, :invalid?
assert r.errors[:title].any?, "A reply without title should mark that attribute as invalid"
assert_equal ["is Empty"], r.errors["title"], "A reply without title should contain an error"
@@ -111,8 +111,8 @@ class ValidationsTest < ActiveModel::TestCase
def test_errors_empty_after_errors_on_check
t = Topic.new
- assert t.errors[:id].empty?
- assert t.errors.empty?
+ assert_empty t.errors[:id]
+ assert_empty t.errors
end
def test_validates_each
@@ -122,7 +122,7 @@ class ValidationsTest < ActiveModel::TestCase
hits += 1
end
t = Topic.new("title" => "valid", "content" => "whatever")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal 4, hits
assert_equal %w(gotcha gotcha), t.errors[:title]
assert_equal %w(gotcha gotcha), t.errors[:content]
@@ -135,7 +135,7 @@ class ValidationsTest < ActiveModel::TestCase
hits += 1
end
t = CustomReader.new("title" => "valid", "content" => "whatever")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal 4, hits
assert_equal %w(gotcha gotcha), t.errors[:title]
assert_equal %w(gotcha gotcha), t.errors[:content]
@@ -146,16 +146,16 @@ class ValidationsTest < ActiveModel::TestCase
def test_validate_block
Topic.validate { errors.add("title", "will never be valid") }
t = Topic.new("title" => "Title", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["will never be valid"], t.errors["title"]
end
def test_validate_block_with_params
Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
t = Topic.new("title" => "Title", "content" => "whatever")
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
assert_equal ["will never be valid"], t.errors["title"]
end
@@ -214,7 +214,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_errors_conversions
Topic.validates_presence_of %w(title content)
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
xml = t.errors.to_xml
assert_match %r{<errors>}, xml
@@ -232,14 +232,14 @@ class ValidationsTest < ActiveModel::TestCase
Topic.validates_length_of :title, minimum: 2
t = Topic.new("title" => "")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal "can't be blank", t.errors["title"].first
Topic.validates_presence_of :title, :author_name
Topic.validate { errors.add("author_email_address", "will never be valid") }
Topic.validates_length_of :title, :content, minimum: 2
t = Topic.new title: ""
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal :title, key = t.errors.keys[0]
assert_equal "can't be blank", t.errors[key][0]
@@ -258,8 +258,8 @@ class ValidationsTest < ActiveModel::TestCase
t = Topic.new(title: "")
# If block should not fire
- assert t.valid?
- assert t.author_name.nil?
+ assert_predicate t, :valid?
+ assert_predicate t.author_name, :nil?
# If block should fire
assert t.invalid?(:update)
@@ -270,18 +270,18 @@ class ValidationsTest < ActiveModel::TestCase
Topic.validates_presence_of :title
t = Topic.new
- assert t.invalid?
- assert t.errors[:title].any?
+ assert_predicate t, :invalid?
+ assert_predicate t.errors[:title], :any?
t.title = "Things are going to change"
- assert !t.invalid?
+ assert_not_predicate t, :invalid?
end
def test_validation_with_message_as_proc
Topic.validates_presence_of(:title, message: proc { "no blanks here".upcase })
t = Topic.new
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["NO BLANKS HERE"], t.errors[:title]
end
@@ -331,13 +331,13 @@ class ValidationsTest < ActiveModel::TestCase
Topic.validates :content, length: { minimum: 10 }
topic = Topic.new
- assert topic.invalid?
+ assert_predicate topic, :invalid?
assert_equal 3, topic.errors.size
topic.title = "Some Title"
topic.author_name = "Some Author"
topic.content = "Some Content Whose Length is more than 10."
- assert topic.valid?
+ assert_predicate topic, :valid?
end
def test_validate
@@ -381,7 +381,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_strict_validation_not_fails
Topic.validates :title, strict: true, presence: true
- assert Topic.new(title: "hello").valid?
+ assert_predicate Topic.new(title: "hello"), :valid?
end
def test_strict_validation_particular_validator
@@ -414,7 +414,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_validates_with_false_hash_value
Topic.validates :title, presence: false
- assert Topic.new.valid?
+ assert_predicate Topic.new, :valid?
end
def test_strict_validation_error_message
@@ -439,19 +439,19 @@ class ValidationsTest < ActiveModel::TestCase
duped = topic.dup
duped.title = nil
- assert duped.invalid?
+ assert_predicate duped, :invalid?
topic.title = nil
duped.title = "Mathematics"
- assert topic.invalid?
- assert duped.valid?
+ assert_predicate topic, :invalid?
+ assert_predicate duped, :valid?
end
def test_validation_with_message_as_proc_that_takes_a_record_as_a_parameter
Topic.validates_presence_of(:title, message: proc { |record| "You have failed me for the last time, #{record.author_name}." })
t = Topic.new(author_name: "Admiral")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["You have failed me for the last time, Admiral."], t.errors[:title]
end
@@ -459,7 +459,7 @@ class ValidationsTest < ActiveModel::TestCase
Topic.validates_presence_of(:title, message: proc { |record, data| "#{data[:attribute]} is missing. You have failed me for the last time, #{record.author_name}." })
t = Topic.new(author_name: "Admiral")
- assert t.invalid?
+ assert_predicate t, :invalid?
assert_equal ["Title is missing. You have failed me for the last time, Admiral."], t.errors[:title]
end
end
diff --git a/activemodel/test/models/topic.rb b/activemodel/test/models/topic.rb
index b0af00ee45..db3284f833 100644
--- a/activemodel/test/models/topic.rb
+++ b/activemodel/test/models/topic.rb
@@ -3,6 +3,11 @@
class Topic
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
+ include ActiveModel::AttributeMethods
+ include ActiveSupport::NumberHelper
+
+ attribute_method_suffix "_before_type_cast"
+ define_attribute_method :price
def self._validates_default_keys
super | [ :message ]
@@ -10,6 +15,7 @@ class Topic
attr_accessor :title, :author_name, :content, :approved, :created_at
attr_accessor :after_validation_performed
+ attr_writer :price
after_validation :perform_after_validation
@@ -38,4 +44,12 @@ class Topic
def my_validation_with_arg(attr)
errors.add attr, "is missing" unless send(attr)
end
+
+ def price
+ number_to_currency @price
+ end
+
+ def attribute_before_type_cast(attr)
+ instance_variable_get(:"@#{attr}")
+ end
end
diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb
index e98fd8a0a1..bb1b187694 100644
--- a/activemodel/test/models/user.rb
+++ b/activemodel/test/models/user.rb
@@ -7,6 +7,7 @@ class User
define_model_callbacks :create
has_secure_password
+ has_secure_password :recovery_password, validations: false
- attr_accessor :password_digest
+ attr_accessor :password_digest, :recovery_password_digest
end
diff --git a/activemodel/test/models/visitor.rb b/activemodel/test/models/visitor.rb
index 9da004ffcc..96bf3ef10a 100644
--- a/activemodel/test/models/visitor.rb
+++ b/activemodel/test/models/visitor.rb
@@ -8,5 +8,6 @@ class Visitor
has_secure_password(validations: false)
- attr_accessor :password_digest, :password_confirmation
+ attr_accessor :password_digest
+ attr_reader :password_confirmation
end