diff options
Diffstat (limited to 'activemodel/test/cases/validations')
16 files changed, 872 insertions, 638 deletions
diff --git a/activemodel/test/cases/validations/absence_validation_test.rb b/activemodel/test/cases/validations/absence_validation_test.rb index 9cbc77dfb5..8bc4f4723a 100644 --- a/activemodel/test/cases/validations/absence_validation_test.rb +++ b/activemodel/test/cases/validations/absence_validation_test.rb @@ -1,7 +1,9 @@ -require 'cases/helper' -require 'models/topic' -require 'models/person' -require 'models/custom_reader' +# frozen_string_literal: true + +require "cases/helper" +require "models/topic" +require "models/person" +require "models/custom_reader" class AbsenceValidationTest < ActiveModel::TestCase teardown do @@ -15,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? + t.content = "something" + 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 @@ -32,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 @@ -41,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 @@ -49,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 d3995ad5af..7662f996ae 100644 --- a/activemodel/test/cases/validations/acceptance_validation_test.rb +++ b/activemodel/test/cases/validations/acceptance_validation_test.rb @@ -1,11 +1,12 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' -require 'models/reply' -require 'models/person' +require "cases/helper" -class AcceptanceValidationTest < ActiveModel::TestCase +require "models/topic" +require "models/reply" +require "models/person" +class AcceptanceValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -14,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? + t = Topic.new("title" => "We should be confirmed", "terms_of_service" => "") + 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? + t = Topic.new("title" => "We should be confirmed", "eula" => "") + 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 @@ -70,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 @@ -82,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 75eb18e795..ff3cf61746 100644 --- a/activemodel/test/cases/validations/callbacks_test.rb +++ b/activemodel/test/cases/validations/callbacks_test.rb @@ -1,4 +1,6 @@ -require 'cases/helper' +# frozen_string_literal: true + +require "cases/helper" class Dog include ActiveModel::Validations @@ -15,37 +17,37 @@ class DogWithMethodCallbacks < Dog before_validation :set_before_validation_marker after_validation :set_after_validation_marker - def set_before_validation_marker; self.history << 'before_validation_marker'; end - def set_after_validation_marker; self.history << 'after_validation_marker' ; end + def set_before_validation_marker; history << "before_validation_marker"; end + def set_after_validation_marker; history << "after_validation_marker" ; end end class DogValidatorsAreProc < Dog - before_validation { self.history << 'before_validation_marker' } - after_validation { self.history << 'after_validation_marker' } + before_validation { history << "before_validation_marker" } + after_validation { history << "after_validation_marker" } end class DogWithTwoValidators < Dog - before_validation { self.history << 'before_validation_marker1' } - before_validation { self.history << 'before_validation_marker2' } + before_validation { history << "before_validation_marker1" } + before_validation { history << "before_validation_marker2" } end -class DogDeprecatedBeforeValidatorReturningFalse < Dog +class DogBeforeValidatorReturningFalse < Dog before_validation { false } - before_validation { self.history << 'before_validation_marker2' } + before_validation { history << "before_validation_marker2" } end class DogBeforeValidatorThrowingAbort < Dog before_validation { throw :abort } - before_validation { self.history << 'before_validation_marker2' } + before_validation { history << "before_validation_marker2" } end class DogAfterValidatorReturningFalse < Dog after_validation { false } - after_validation { self.history << 'after_validation_marker' } + after_validation { history << "after_validation_marker" } end class DogWithMissingName < Dog - before_validation { self.history << 'before_validation_marker' } + before_validation { history << "before_validation_marker" } validates_presence_of :name end @@ -53,8 +55,20 @@ class DogValidatorWithOnCondition < Dog before_validation :set_before_validation_marker, on: :create after_validation :set_after_validation_marker, on: :create - def set_before_validation_marker; self.history << 'before_validation_marker'; end - def set_after_validation_marker; self.history << 'after_validation_marker' ; end + def set_before_validation_marker; history << "before_validation_marker"; end + 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 @@ -64,16 +78,14 @@ class DogValidatorWithIfCondition < Dog after_validation :set_after_validation_marker1, if: -> { true } after_validation :set_after_validation_marker2, if: -> { false } - def set_before_validation_marker1; self.history << 'before_validation_marker1'; end - def set_before_validation_marker2; self.history << 'before_validation_marker2' ; end + def set_before_validation_marker1; history << "before_validation_marker1"; end + def set_before_validation_marker2; history << "before_validation_marker2" ; end - def set_after_validation_marker1; self.history << 'after_validation_marker1'; end - def set_after_validation_marker2; self.history << 'after_validation_marker2' ; end + def set_after_validation_marker1; history << "after_validation_marker1"; end + def set_after_validation_marker2; history << "after_validation_marker2" ; end end - class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase - def test_if_condition_is_respected_for_before_validation d = DogValidatorWithIfCondition.new d.valid? @@ -98,22 +110,53 @@ 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? - assert_equal ['before_validation_marker', 'after_validation_marker'], d.history + assert_equal ["before_validation_marker", "after_validation_marker"], d.history end def test_before_validation_and_after_validation_callbacks_should_be_called_with_proc d = DogValidatorsAreProc.new d.valid? - assert_equal ['before_validation_marker', 'after_validation_marker'], d.history + assert_equal ["before_validation_marker", "after_validation_marker"], d.history end def test_before_validation_and_after_validation_callbacks_should_be_called_in_declared_order d = DogWithTwoValidators.new d.valid? - assert_equal ['before_validation_marker1', 'before_validation_marker2'], d.history + assert_equal ["before_validation_marker1", "before_validation_marker2"], d.history end def test_further_callbacks_should_not_be_called_if_before_validation_throws_abort @@ -123,26 +166,23 @@ class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase assert_equal false, output end - def test_deprecated_further_callbacks_should_not_be_called_if_before_validation_returns_false - d = DogDeprecatedBeforeValidatorReturningFalse.new - assert_deprecated do - output = d.valid? - assert_equal [], d.history - assert_equal false, output - end + def test_further_callbacks_should_be_called_if_before_validation_returns_false + d = DogBeforeValidatorReturningFalse.new + output = d.valid? + assert_equal ["before_validation_marker2"], d.history + assert_equal true, output end def test_further_callbacks_should_be_called_if_after_validation_returns_false d = DogAfterValidatorReturningFalse.new d.valid? - assert_equal ['after_validation_marker'], d.history + assert_equal ["after_validation_marker"], d.history end def test_validation_test_should_be_done d = DogWithMissingName.new output = d.valid? - assert_equal ['before_validation_marker'], d.history + assert_equal ["before_validation_marker"], d.history assert_equal false, output end - end diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb index 296d3b4407..1704db9a48 100644 --- a/activemodel/test/cases/validations/conditional_validation_test.rb +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -1,9 +1,10 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' +require "cases/helper" -class ConditionalValidationTest < ActiveModel::TestCase +require "models/topic" +class ConditionalValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -12,67 +13,63 @@ 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_unless_validation_using_method_true - # When the method returns true - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true) + 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.valid? - assert_empty t.errors[:title] + assert_predicate t, :invalid? + assert_predicate t.errors[:title], :any? + assert_equal ["hoo 5"], t.errors["title"] end - def test_if_validation_using_method_false - # When the method returns false - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true_but_its_not) + def test_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.valid? - assert_empty t.errors[:title] + assert_predicate t, :invalid? + assert_predicate t.errors[:title], :any? + assert_equal ["hoo 5"], t.errors["title"] end - def test_unless_validation_using_method_false - # When the method returns false - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true_but_its_not) + def test_unless_validation_using_method_true + # When the method returns true + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") - assert t.invalid? - assert t.errors[:title].any? - assert_equal ["hoo 5"], t.errors["title"] + assert_predicate t, :valid? + assert_empty t.errors[:title] end - def test_if_validation_using_string_true - # When the evaluated string returns true - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: "a = 1; a == 1") + 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.invalid? - assert t.errors[:title].any? - assert_equal ["hoo 5"], t.errors["title"] + assert_predicate t, :valid? + assert_empty t.errors[:title] end - def test_unless_validation_using_string_true - # When the evaluated string returns true - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: "a = 1; a == 1") + 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 - def test_if_validation_using_string_false - # When the evaluated string returns false - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: "false") + def test_if_validation_using_method_false + # When the method returns false + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_false) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") - assert t.valid? + assert_predicate t, :valid? assert_empty t.errors[:title] end - def test_unless_validation_using_string_false - # When the evaluated string returns false - Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: "false") + def test_unless_validation_using_method_false + # When the method returns false + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_false) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") - assert t.invalid? - assert t.errors[:title].any? + assert_predicate t, :invalid? + assert_predicate t.errors[:title], :any? assert_equal ["hoo 5"], t.errors["title"] end @@ -81,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 @@ -91,48 +88,41 @@ 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 def test_if_validation_using_block_false # When the block returns false Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", - if: Proc.new { |r| r.title != "uhohuhoh"}) + 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 def test_unless_validation_using_block_false # When the block returns false Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", - unless: Proc.new { |r| r.title != "uhohuhoh"} ) + 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 - # previous implementation of validates_presence_of eval'd the - # string with the wrong binding, this regression test is to - # ensure that it works correctly - def test_validation_with_if_as_string - Topic.validates_presence_of(:title) - Topic.validates_presence_of(:author_name, if: "title.to_s.match('important')") - - t = Topic.new - assert t.invalid?, "A topic without a title should not be valid" - assert_empty t.errors[:author_name], "A topic without an 'important' title should not require an author" - - t.title = "Just a title" - assert t.valid?, "A topic with a basic title should be valid" - - t.title = "A very important title" - assert t.invalid?, "A topic with an important title, but without an author, should not be valid" - assert t.errors[:author_name].any?, "A topic with an 'important' title should require an author" + def test_validation_using_conbining_if_true_and_unless_true_conditions + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true, unless: :condition_is_true) + t = Topic.new("title" => "uhohuhoh", "content" => "whatever") + assert_predicate t, :valid? + assert_empty t.errors[:title] + end - t.author_name = "Hubert J. Farnsworth" - assert t.valid?, "A topic with an important title and author should be valid" + def test_validation_using_conbining_if_true_and_unless_false_conditions + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true, unless: :condition_is_false) + t = Topic.new("title" => "uhohuhoh", "content" => "whatever") + assert_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 c56bf1c0ad..8603a8ac5c 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -1,10 +1,11 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' +require "cases/helper" -class ConfirmationValidationTest < ActiveModel::TestCase +require "models/topic" +require "models/person" +class ConfirmationValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -13,27 +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? + t = Topic.new("title" => "We should be confirmed", "title_confirmation" => "") + 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_predicate t, :valid? + + t.approved_confirmation = false + assert_predicate t, :invalid? + + t.approved_confirmation = true + assert_predicate t, :valid? end def test_validates_confirmation_of_for_ruby_class @@ -41,12 +55,12 @@ 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 @@ -56,15 +70,14 @@ class ConfirmationValidationTest < ActiveModel::TestCase @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', { + I18n.backend.store_translations("en", errors: { messages: { confirmation: "doesn't match %{attribute}" } }, - activemodel: { attributes: { topic: { title: 'Test Title'} } } - }) + activemodel: { attributes: { topic: { title: "Test Title" } } }) Topic.validates_confirmation_of(:title) - t = Topic.new("title" => "We should be confirmed","title_confirmation" => "") - assert t.invalid? + 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 @@ -109,13 +122,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 005bc15df5..50bd47065c 100644 --- a/activemodel/test/cases/validations/exclusion_validation_test.rb +++ b/activemodel/test/cases/validations/exclusion_validation_test.rb @@ -1,11 +1,12 @@ -require 'cases/helper' -require 'active_support/core_ext/numeric/time' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' +require "cases/helper" +require "active_support/core_ext/numeric/time" -class ExclusionValidationTest < ActiveModel::TestCase +require "models/topic" +require "models/person" +class ExclusionValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -13,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 @@ -23,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 @@ -34,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 @@ -43,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 @@ -59,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 @@ -91,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 @@ -101,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 86bbbe6ebe..2a7088b3e8 100644 --- a/activemodel/test/cases/validations/format_validation_test.rb +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -1,10 +1,11 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' +require "cases/helper" -class PresenceValidationTest < ActiveModel::TestCase +require "models/topic" +require "models/person" +class FormatValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -15,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 @@ -41,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" @@ -57,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? + t = Topic.new(title: "Invalid title") + assert_predicate t, :invalid? assert_equal ["can't be Invalid title"], t.errors[:title] end @@ -73,7 +74,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validate_format_of_with_multiline_regexp_and_option - assert_nothing_raised(ArgumentError) do + assert_nothing_raised do Topic.validates_format_of(:title, with: /^Valid Title$/, multiline: true) end end @@ -108,40 +109,40 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_with_lambda - Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\z/ : /\A\S+\z/ } t = Topic.new t.title = "digit" 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 - Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\z/ : /\A\S+\z/ } t = Topic.new t.title = "characters" 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 - Person.validates_format_of :karma, with: /\A\d+\Z/ + Person.validates_format_of :karma, with: /\A\d+\z/ 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_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index da63df9152..d3e44945db 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "cases/helper" -require 'models/person' +require "models/person" class I18nGenerateMessageValidationTest < ActiveModel::TestCase def setup @@ -10,29 +12,29 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase # validates_inclusion_of: generate_message(attr_name, :inclusion, message: custom_message, value: value) def test_generate_message_inclusion_with_default_message - assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, value: 'title') + assert_equal "is not included in the list", @person.errors.generate_message(:title, :inclusion, value: "title") end def test_generate_message_inclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :inclusion, message: "custom message %{value}", value: "title") end # validates_exclusion_of: generate_message(attr_name, :exclusion, message: custom_message, value: value) def test_generate_message_exclusion_with_default_message - assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, value: 'title') + assert_equal "is reserved", @person.errors.generate_message(:title, :exclusion, value: "title") end def test_generate_message_exclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :exclusion, message: "custom message %{value}", value: "title") end # validates_format_of: generate_message(attr_name, :invalid, message: custom_message, value: value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, value: 'title') + assert_equal "is invalid", @person.errors.generate_message(:title, :invalid, value: "title") end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :invalid, message: "custom message %{value}", value: "title") end # validates_confirmation_of: generate_message(attr_name, :confirmation, message: custom_message) @@ -41,7 +43,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_confirmation_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :confirmation, message: "custom message") end # validates_acceptance_of: generate_message(attr_name, :accepted, message: custom_message) @@ -50,7 +52,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_accepted_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :accepted, message: "custom message") end # add_on_empty: generate_message(attr, :empty, message: custom_message) @@ -59,7 +61,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_empty_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :empty, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :empty, message: "custom message") end # validates_presence_of: generate_message(attr, :blank, message: custom_message) @@ -68,7 +70,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_blank_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :blank, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :blank, message: "custom message") end # validates_length_of: generate_message(attr, :too_long, message: custom_message, count: option_value.end) @@ -81,7 +83,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_too_long_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, message: 'custom message %{count}', count: 10) + assert_equal "custom message 10", @person.errors.generate_message(:title, :too_long, message: "custom message %{count}", count: 10) end # validates_length_of: generate_message(attr, :too_short, default: custom_message, count: option_value.begin) @@ -94,7 +96,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_too_short_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, message: 'custom message %{count}', count: 10) + assert_equal "custom message 10", @person.errors.generate_message(:title, :too_short, message: "custom message %{count}", count: 10) end # validates_length_of: generate_message(attr, :wrong_length, message: custom_message, count: option_value) @@ -107,44 +109,44 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_wrong_length_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, message: 'custom message %{count}', count: 10) + assert_equal "custom message 10", @person.errors.generate_message(:title, :wrong_length, message: "custom message %{count}", count: 10) end # validates_numericality_of: generate_message(attr_name, :not_a_number, value: raw_value, message: custom_message) def test_generate_message_not_a_number_with_default_message - assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, value: 'title') + assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, value: "title") end def test_generate_message_not_a_number_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :not_a_number, message: "custom message %{value}", value: "title") end # validates_numericality_of: generate_message(attr_name, option, value: raw_value, default: custom_message) def test_generate_message_greater_than_with_default_message - assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, value: 'title', count: 10) + assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, value: "title", count: 10) end def test_generate_message_greater_than_or_equal_to_with_default_message - assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, value: 'title', count: 10) + assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, value: "title", count: 10) end def test_generate_message_equal_to_with_default_message - assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, value: 'title', count: 10) + assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, value: "title", count: 10) end def test_generate_message_less_than_with_default_message - assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, value: 'title', count: 10) + assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, value: "title", count: 10) end def test_generate_message_less_than_or_equal_to_with_default_message - assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, value: 'title', count: 10) + assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, value: "title", count: 10) end def test_generate_message_odd_with_default_message - assert_equal "must be odd", @person.errors.generate_message(:title, :odd, value: 'title', count: 10) + assert_equal "must be odd", @person.errors.generate_message(:title, :odd, value: "title", count: 10) end def test_generate_message_even_with_default_message - assert_equal "must be even", @person.errors.generate_message(:title, :even, value: 'title', count: 10) + assert_equal "must be even", @person.errors.generate_message(:title, :even, value: "title", count: 10) end end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 09d7226b5a..ccb565c5bd 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require "cases/helper" -require 'models/person' +require "models/person" class I18nValidationTest < ActiveModel::TestCase - def setup Person.clear_validators! @person = Person.new @@ -10,7 +11,10 @@ class I18nValidationTest < ActiveModel::TestCase @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: { custom: nil } }) + 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 @@ -18,48 +22,161 @@ 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 - I18n.backend.store_translations('en', errors: { - messages: { too_short: '猫舌' } }) + I18n.backend.store_translations("en", errors: { + messages: { too_short: "猫舌" } }) Person.validates_length_of :title, within: 3..5 @person.valid? - assert_equal ['Title 猫舌'], @person.errors.full_messages + assert_equal ["Title 猫舌"], @person.errors.full_messages end 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 + @person.errors.add(:name, "not found") + 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 def test_errors_full_messages_uses_format - I18n.backend.store_translations('en', errors: { format: "Field %{attribute} %{message}" }) - @person.errors.add('name', 'empty') + I18n.backend.store_translations("en", errors: { format: "Field %{attribute} %{message}" }) + @person.errors.add("name", "empty") 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 # are used to generate tests to keep things DRY # COMMON_CASES = [ - # [ case, validation_options, generate_message_options] + # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], [ "given custom message", { message: "custom" }, { message: "custom" }], - [ "given if condition", { if: lambda { true }}, {}], - [ "given unless condition", { unless: lambda { false }}, {}], + [ "given if condition", { if: lambda { true } }, {}], + [ "given unless condition", { unless: lambda { false } }, {}], [ "given option that is not reserved", { format: "jpg" }, { format: "jpg" }] ] COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_confirmation_of on generated message #{name}" do Person.validates_confirmation_of :title, validation_options - @person.title_confirmation = 'foo' - call = [:title_confirmation, :confirmation, generate_message_options.merge(attribute: 'Title')] + @person.title_confirmation = "foo" + call = [:title_confirmation, :confirmation, generate_message_options.merge(attribute: "Title")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -99,7 +216,7 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :too_long generated message #{name}" do Person.validates_length_of :title, validation_options.merge(within: 3..5) - @person.title = 'this title is too long' + @person.title = "this title is too long" call = [:title, :too_long, generate_message_options.merge(count: 5)] assert_called_with(@person.errors, :generate_message, call) do @person.valid? @@ -120,8 +237,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_format_of on generated message #{name}" do Person.validates_format_of :title, validation_options.merge(with: /\A[1-9][0-9]*\z/) - @person.title = '72x' - call = [:title, :invalid, generate_message_options.merge(value: '72x')] + @person.title = "72x" + call = [:title, :invalid, generate_message_options.merge(value: "72x")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -131,8 +248,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_inclusion_of on generated message #{name}" do Person.validates_inclusion_of :title, validation_options.merge(in: %w(a b c)) - @person.title = 'z' - call = [:title, :inclusion, generate_message_options.merge(value: 'z')] + @person.title = "z" + call = [:title, :inclusion, generate_message_options.merge(value: "z")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -142,8 +259,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_inclusion_of using :within on generated message #{name}" do Person.validates_inclusion_of :title, validation_options.merge(within: %w(a b c)) - @person.title = 'z' - call = [:title, :inclusion, generate_message_options.merge(value: 'z')] + @person.title = "z" + call = [:title, :inclusion, generate_message_options.merge(value: "z")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -153,8 +270,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_exclusion_of generated message #{name}" do Person.validates_exclusion_of :title, validation_options.merge(in: %w(a b c)) - @person.title = 'a' - call = [:title, :exclusion, generate_message_options.merge(value: 'a')] + @person.title = "a" + call = [:title, :exclusion, generate_message_options.merge(value: "a")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -164,8 +281,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_exclusion_of using :within generated message #{name}" do Person.validates_exclusion_of :title, validation_options.merge(within: %w(a b c)) - @person.title = 'a' - call = [:title, :exclusion, generate_message_options.merge(value: 'a')] + @person.title = "a" + call = [:title, :exclusion, generate_message_options.merge(value: "a")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -175,8 +292,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of generated message #{name}" do Person.validates_numericality_of :title, validation_options - @person.title = 'a' - call = [:title, :not_a_number, generate_message_options.merge(value: 'a')] + @person.title = "a" + call = [:title, :not_a_number, generate_message_options.merge(value: "a")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -186,8 +303,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of for :only_integer on generated message #{name}" do Person.validates_numericality_of :title, validation_options.merge(only_integer: true) - @person.title = '0.0' - call = [:title, :not_an_integer, generate_message_options.merge(value: '0.0')] + @person.title = "0.0" + call = [:title, :not_an_integer, generate_message_options.merge(value: "0.0")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -225,35 +342,35 @@ class I18nValidationTest < ActiveModel::TestCase end test "#{validation} finds custom model key translation when #{error_type}" do - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => 'custom message' } } } } } } - I18n.backend.store_translations 'en', errors: { messages: { error_type => 'global message'}} + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => "custom message" } } } } } } + I18n.backend.store_translations "en", errors: { messages: { error_type => "global message" } } yield(@person, {}) @person.valid? - assert_equal ['custom message'], @person.errors[attribute] + assert_equal ["custom message"], @person.errors[attribute] end test "#{validation} finds custom model key translation with interpolation when #{error_type}" do - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => 'custom message with %{extra}' } } } } } } - I18n.backend.store_translations 'en', errors: { messages: {error_type => 'global message'} } + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => "custom message with %{extra}" } } } } } } + I18n.backend.store_translations "en", errors: { messages: { error_type => "global message" } } yield(@person, { extra: "extra information" }) @person.valid? - assert_equal ['custom message with extra information'], @person.errors[attribute] + assert_equal ["custom message with extra information"], @person.errors[attribute] end test "#{validation} finds global default key translation when #{error_type}" do - I18n.backend.store_translations 'en', errors: { messages: {error_type => 'global message'} } + I18n.backend.store_translations "en", errors: { messages: { error_type => "global message" } } yield(@person, {}) @person.valid? - assert_equal ['global message'], @person.errors[attribute] + assert_equal ["global message"], @person.errors[attribute] end end set_expectations_for_validation "validates_confirmation_of", :confirmation do |person, options_to_merge| Person.validates_confirmation_of :title, options_to_merge - person.title_confirmation = 'foo' + person.title_confirmation = "foo" end set_expectations_for_validation "validates_acceptance_of", :accepted do |person, options_to_merge| @@ -287,17 +404,17 @@ class I18nValidationTest < ActiveModel::TestCase set_expectations_for_validation "validates_exclusion_of", :exclusion do |person, options_to_merge| Person.validates_exclusion_of :title, options_to_merge.merge(in: %w(a b c)) - person.title = 'a' + person.title = "a" end set_expectations_for_validation "validates_numericality_of", :not_a_number do |person, options_to_merge| Person.validates_numericality_of :title, options_to_merge - person.title = 'a' + person.title = "a" end set_expectations_for_validation "validates_numericality_of", :not_an_integer do |person, options_to_merge| Person.validates_numericality_of :title, options_to_merge.merge(only_integer: true) - person.title = '1.0' + person.title = "1.0" end set_expectations_for_validation "validates_numericality_of", :odd do |person, options_to_merge| @@ -311,7 +428,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validations_with_message_symbol_must_translate - I18n.backend.store_translations 'en', errors: { messages: { custom_error: "I am a custom error" } } + I18n.backend.store_translations "en", errors: { messages: { custom_error: "I am a custom error" } } Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? @@ -319,7 +436,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validates_with_message_symbol_must_translate_per_attribute - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { title: { custom_error: "I am a custom error" } } } } } } + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { attributes: { title: { custom_error: "I am a custom error" } } } } } } Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? @@ -327,7 +444,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validates_with_message_symbol_must_translate_per_model - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { custom_error: "I am a custom error" } } } } + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { custom_error: "I am a custom error" } } } } Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb index 55d1fb4dcb..daad76759f 100644 --- a/activemodel/test/cases/validations/inclusion_validation_test.rb +++ b/activemodel/test/cases/validations/inclusion_validation_test.rb @@ -1,95 +1,110 @@ -require 'cases/helper' -require 'active_support/all' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' +require "cases/helper" +require "active_support/all" -class InclusionValidationTest < ActiveModel::TestCase +require "models/topic" +require "models/person" +class InclusionValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end 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? + Topic.validates_inclusion_of(:title, in: "aaa".."bbb") + 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 - Topic.validates_inclusion_of(:created_at, in: 1.year.ago..Time.now) - 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? + range_begin = 1.year.ago + range_end = Time.now + Topic.validates_inclusion_of(:created_at, in: range_begin..range_end) + 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 - Topic.validates_inclusion_of(:created_at, in: 1.year.until(Date.today)..Date.today) - 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? + range_begin = 1.year.until(Date.today) + range_end = Date.today + Topic.validates_inclusion_of(:created_at, in: range_begin..range_end) + 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 - Topic.validates_inclusion_of(:created_at, in: 1.year.until(DateTime.current)..DateTime.current) - 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? + range_begin = 1.year.until(DateTime.current) + range_end = DateTime.current + Topic.validates_inclusion_of(:created_at, in: range_begin..range_end) + 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) } assert_raise(ArgumentError) { Topic.validates_inclusion_of(:title, in: 0) } - assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of(:title, in: "hi!") } - assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of(:title, in: {}) } - assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of(:title, in: []) } + assert_nothing_raised { Topic.validates_inclusion_of(:title, in: "hi!") } + assert_nothing_raised { Topic.validates_inclusion_of(:title, in: {}) } + assert_nothing_raised { Topic.validates_inclusion_of(:title, in: []) } end 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 @@ -97,26 +112,26 @@ 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 def test_validates_inclusion_of_with_lambda - Topic.validates_inclusion_of :title, in: lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } + Topic.validates_inclusion_of :title, in: lambda { |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } 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 @@ -129,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 @@ -139,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 ee901b75fb..774a2cde74 100644 --- a/activemodel/test/cases/validations/length_validation_test.rb +++ b/activemodel/test/cases/validations/length_validation_test.rb @@ -1,7 +1,9 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' +require "cases/helper" + +require "models/topic" +require "models/person" class LengthValidationTest < ActiveModel::TestCase def teardown @@ -9,160 +11,160 @@ class LengthValidationTest < ActiveModel::TestCase end def test_validates_length_of_with_allow_nil - Topic.validates_length_of( :title, is: 5, allow_nil: true ) + 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 ) + 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? + t.content = "mad" + 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? + t = Topic.new("title" => "abc", "content" => "abcd") + 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 - bigmin = 2 ** 30 - bigmax = 2 ** 32 + bigmin = 2**30 + bigmax = 2**32 bigrange = bigmin...bigmax assert_nothing_raised do Topic.validates_length_of :title, is: bigmin + 5 @@ -183,77 +185,77 @@ class LengthValidationTest < ActiveModel::TestCase end def test_validates_length_of_custom_errors_for_minimum_with_message - Topic.validates_length_of( :title, minimum: 5, message: "boo %{count}" ) + 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}" ) + 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}" ) + 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}" ) + 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 def test_validates_length_of_custom_errors_for_both_too_short_and_too_long - Topic.validates_length_of :title, minimum: 3, maximum: 5, too_short: 'too short', too_long: 'too long' + 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_equal ['too short'], t.errors['title'] + t = Topic.new(title: "a") + 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_equal ['too long'], t.errors['title'] + t = Topic.new(title: "aaaaaa") + 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}" ) + 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}" ) + 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 @@ -261,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 @@ -273,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 @@ -285,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? + t.content = "12三" + assert_predicate t, :valid? end def test_optionally_validates_length_of_using_within_utf8 @@ -310,60 +312,23 @@ 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 - def test_validates_length_of_with_block - assert_deprecated do - Topic.validates_length_of( - :content, - minimum: 5, - too_short: "Your essay must be at least %{count} words.", - tokenizer: lambda {|str| str.scan(/\w+/) }, - ) - end - t = Topic.new(content: "this content should be long enough") - assert t.valid? - - t.content = "not long enough" - assert t.invalid? - assert t.errors[:content].any? - assert_equal ["Your essay must be at least 5 words."], t.errors[:content] - end - - - def test_validates_length_of_with_symbol - assert_deprecated do - Topic.validates_length_of( - :content, - minimum: 5, - too_short: "Your essay must be at least %{count} words.", - tokenizer: :my_word_tokenizer, - ) - end - t = Topic.new(content: "this content should be long enough") - assert t.valid? - - t.content = "not long enough" - assert t.invalid? - assert t.errors[:content].any? - assert_equal ["Your essay must be at least 5 words."], t.errors[:content] - end - - def test_validates_length_of_for_fixnum + def test_validates_length_of_for_integer 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 @@ -371,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 @@ -385,64 +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 } ) + Topic.validates_length_of(:title, is: 5, if: Proc.new { false }) + + 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_predicate t, :valid? + + t.title = "notvalid" + 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_predicate t, :valid? + end - assert Topic.new("title" => "david").valid? - assert Topic.new("title" => "david2").invalid? + def test_validates_length_of_using_proc_as_maximum_with_model_method + Topic.send(:define_method, :max_title_length, lambda { 5 }) + Topic.validates_length_of :title, maximum: Proc.new(&:max_title_length) + + t = Topic.new("title" => "valid", "content" => "whatever") + assert_predicate t, :valid? + + t.title = "notvalid" + 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_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 04ec74bad3..ca3c3bc40d 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -1,13 +1,14 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' +require "cases/helper" -require 'bigdecimal' -require 'active_support/core_ext/big_decimal' +require "models/topic" +require "models/person" -class NumericalityValidationTest < ActiveModel::TestCase +require "bigdecimal" +require "active_support/core_ext/big_decimal" +class NumericalityValidationTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -19,9 +20,9 @@ class NumericalityValidationTest < ActiveModel::TestCase INTEGER_STRINGS = %w(0 +0 -0 10 +10 -10 0090 -090) FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS INTEGERS = [0, 10, -10] + INTEGER_STRINGS - BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) } + BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal(bd) } JUNK = ["not a number", "42 not a number", "0xdeadbeef", "0xinvalidhex", "0Xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"] - INFINITY = [1.0/0.0] + INFINITY = [1.0 / 0.0] def test_default_validates_numericality_of Topic.validates_numericality_of :approved @@ -36,6 +37,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!(NIL + FLOATS + INTEGERS + BIGDECIMAL + INFINITY) end + def test_validates_numericality_of_with_blank_allowed + Topic.validates_numericality_of :approved, allow_blank: true + + invalid!(JUNK) + valid!(NIL + BLANK + FLOATS + INTEGERS + BIGDECIMAL + INFINITY) + end + def test_validates_numericality_of_with_integer_only Topic.validates_numericality_of :approved, only_integer: true @@ -51,7 +59,7 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_of_with_integer_only_and_symbol_as_value - Topic.validates_numericality_of :approved, only_integer: :condition_is_true_but_its_not + Topic.validates_numericality_of :approved, only_integer: :condition_is_false invalid!(NIL + BLANK + JUNK) valid!(FLOATS + INTEGERS + BIGDECIMAL + INFINITY) @@ -68,84 +76,119 @@ class NumericalityValidationTest < ActiveModel::TestCase def test_validates_numericality_with_greater_than Topic.validates_numericality_of :approved, greater_than: 10 - invalid!([-10, 10], 'must be greater than 10') + invalid!([-10, 10], "must be greater than 10") valid!([11]) end def test_validates_numericality_with_greater_than_using_differing_numeric_types - Topic.validates_numericality_of :approved, greater_than: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, greater_than: BigDecimal("97.18") - invalid!([-97.18, BigDecimal.new('97.18'), BigDecimal('-97.18')], 'must be greater than 97.18') - valid!([97.18, 98, BigDecimal.new('98')]) # Notice the 97.18 as a float is greater than 97.18 as a BigDecimal due to floating point precision + invalid!([-97.18, BigDecimal("97.18"), BigDecimal("-97.18")], "must be greater than 97.18") + valid!([97.19, 98, BigDecimal("98"), BigDecimal("97.19")]) + end + + def test_validates_numericality_with_greater_than_using_string_value + Topic.validates_numericality_of :approved, greater_than: 10 + + invalid!(["-10", "9", "9.9", "10"], "must be greater than 10") + valid!(["10.1", "11"]) end def test_validates_numericality_with_greater_than_or_equal Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 - invalid!([-9, 9], 'must be greater than or equal to 10') + invalid!([-9, 9], "must be greater than or equal to 10") valid!([10]) end def test_validates_numericality_with_greater_than_or_equal_using_differing_numeric_types - Topic.validates_numericality_of :approved, greater_than_or_equal_to: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, greater_than_or_equal_to: BigDecimal("97.18") + + invalid!([-97.18, 97.17, 97, BigDecimal("97.17"), BigDecimal("-97.18")], "must be greater than or equal to 97.18") + valid!([97.18, 98, BigDecimal("97.19")]) + end + + def test_validates_numericality_with_greater_than_or_equal_using_string_value + Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 - invalid!([-97.18, 97.17, 97, BigDecimal.new('97.17'), BigDecimal.new('-97.18')], 'must be greater than or equal to 97.18') - valid!([97.18, 98, BigDecimal.new('97.19')]) + invalid!(["-10", "9", "9.9"], "must be greater than or equal to 10") + valid!(["10", "10.1", "11"]) end def test_validates_numericality_with_equal_to Topic.validates_numericality_of :approved, equal_to: 10 - invalid!([-10, 11] + INFINITY, 'must be equal to 10') + invalid!([-10, 11] + INFINITY, "must be equal to 10") valid!([10]) end def test_validates_numericality_with_equal_to_using_differing_numeric_types - Topic.validates_numericality_of :approved, equal_to: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, equal_to: BigDecimal("97.18") + + invalid!([-97.18], "must be equal to 97.18") + valid!([BigDecimal("97.18")]) + end - invalid!([-97.18, 97.18], 'must be equal to 97.18') - valid!([BigDecimal.new('97.18')]) + def test_validates_numericality_with_equal_to_using_string_value + Topic.validates_numericality_of :approved, equal_to: 10 + + invalid!(["-10", "9", "9.9", "10.1", "11"], "must be equal to 10") + valid!(["10"]) end def test_validates_numericality_with_less_than Topic.validates_numericality_of :approved, less_than: 10 - invalid!([10], 'must be less than 10') + invalid!([10], "must be less than 10") valid!([-9, 9]) end def test_validates_numericality_with_less_than_using_differing_numeric_types - Topic.validates_numericality_of :approved, less_than: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, less_than: BigDecimal("97.18") - invalid!([97.18, BigDecimal.new('97.18')], 'must be less than 97.18') - valid!([-97.0, 97.0, -97, 97, BigDecimal.new('-97'), BigDecimal.new('97')]) + invalid!([97.18, BigDecimal("97.18")], "must be less than 97.18") + valid!([-97.0, 97.0, -97, 97, BigDecimal("-97"), BigDecimal("97")]) + end + + def test_validates_numericality_with_less_than_using_string_value + Topic.validates_numericality_of :approved, less_than: 10 + + invalid!(["10", "10.1", "11"], "must be less than 10") + valid!(["-10", "9", "9.9"]) end def test_validates_numericality_with_less_than_or_equal_to Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 - invalid!([11], 'must be less than or equal to 10') + invalid!([11], "must be less than or equal to 10") valid!([-10, 10]) end def test_validates_numericality_with_less_than_or_equal_to_using_differing_numeric_types - Topic.validates_numericality_of :approved, less_than_or_equal_to: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, less_than_or_equal_to: BigDecimal("97.18") + + invalid!([97.19, 98], "must be less than or equal to 97.18") + valid!([-97.18, BigDecimal("-97.18"), BigDecimal("97.18")]) + end + + def test_validates_numericality_with_less_than_or_equal_using_string_value + Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 - invalid!([97.18, 98], 'must be less than or equal to 97.18') - valid!([-97.18, BigDecimal.new('-97.18'), BigDecimal.new('97.18')]) + invalid!(["10.1", "11"], "must be less than or equal to 10") + valid!(["-10", "9", "9.9", "10"]) end def test_validates_numericality_with_odd Topic.validates_numericality_of :approved, odd: true - invalid!([-2, 2], 'must be odd') + invalid!([-2, 2], "must be odd") valid!([-1, 1]) end def test_validates_numericality_with_even Topic.validates_numericality_of :approved, even: true - invalid!([-1, 1], 'must be even') + invalid!([-1, 1], "must be even") valid!([-2, 2]) end @@ -163,6 +206,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([-1, 42]) end + def test_validates_numericality_with_other_than_using_string_value + Topic.validates_numericality_of :approved, other_than: 0 + + invalid!(["0", "0.0"]) + valid!(["-1", "1.1", "42"]) + end + def test_validates_numericality_with_proc Topic.send(:define_method, :min_approved, lambda { 5 }) Topic.validates_numericality_of :approved, greater_than_or_equal_to: Proc.new(&:min_approved) @@ -187,13 +237,13 @@ class NumericalityValidationTest < ActiveModel::TestCase 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 @@ -202,45 +252,64 @@ 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_predicate topic, :invalid? + end + def test_validates_numericality_with_invalid_args - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, greater_than_or_equal_to: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, less_than_or_equal_to: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, greater_than: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, less_than: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, equal_to: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, greater_than_or_equal_to: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, less_than_or_equal_to: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, greater_than: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, less_than: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, equal_to: "foo" } end private - def invalid!(values, error = nil) - with_each_topic_approved_value(values) do |topic, value| - assert topic.invalid?, "#{value.inspect} not rejected as a number" - assert topic.errors[:approved].any?, "FAILED for #{value.inspect}" - assert_equal error, topic.errors[:approved].first if error + def invalid!(values, error = nil) + with_each_topic_approved_value(values) do |topic, value| + assert topic.invalid?, "#{value.inspect} not rejected as a number" + assert topic.errors[:approved].any?, "FAILED for #{value.inspect}" + assert_equal error, topic.errors[:approved].first if error + end end - end - def valid!(values) - with_each_topic_approved_value(values) do |topic, value| - assert topic.valid?, "#{value.inspect} not accepted as a number with validation error: #{topic.errors[:approved].first}" + def valid!(values) + with_each_topic_approved_value(values) do |topic, value| + assert topic.valid?, "#{value.inspect} not accepted as a number with validation error: #{topic.errors[:approved].first}" + end end - end - def with_each_topic_approved_value(values) - topic = Topic.new(title: "numeric test", content: "whatever") - values.each do |value| - topic.approved = value - yield topic, value + def with_each_topic_approved_value(values) + topic = Topic.new(title: "numeric test", content: "whatever") + values.each do |value| + topic.approved = value + yield topic, value + end end - end end diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb index 59b9db0795..c3eca41070 100644 --- a/activemodel/test/cases/validations/presence_validation_test.rb +++ b/activemodel/test/cases/validations/presence_validation_test.rb @@ -1,11 +1,12 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' -require 'models/person' -require 'models/custom_reader' +require "cases/helper" -class PresenceValidationTest < ActiveModel::TestCase +require "models/topic" +require "models/person" +require "models/custom_reader" +class PresenceValidationTest < ActiveModel::TestCase teardown do Topic.clear_validators! Person.clear_validators! @@ -16,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 = " " + 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 @@ -42,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 @@ -50,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 @@ -77,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 04101f3545..ae5a875c24 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -1,8 +1,10 @@ -require 'cases/helper' -require 'models/person' -require 'models/topic' -require 'models/person_with_validator' -require 'validators/namespace/email_validator' +# frozen_string_literal: true + +require "cases/helper" +require "models/person" +require "models/topic" +require "models/person_with_validator" +require "validators/namespace/email_validator" class ValidatesTest < ActiveModel::TestCase setup :reset_callbacks @@ -17,106 +19,112 @@ 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 Person.validates :title, numericality: true person = Person.new person.valid? - assert_equal ['is not a number'], person.errors[:title] + assert_equal ["is not a number"], person.errors[:title] end def test_validates_with_attribute_specified_as_string Person.validates "title", numericality: true person = Person.new person.valid? - assert_equal ['is not a number'], person.errors[:title] + assert_equal ["is not a number"], person.errors[:title] person = Person.new person.title = 123 - assert person.valid? + assert_predicate person, :valid? end def test_validates_with_built_in_validation_and_options - Person.validates :salary, numericality: { message: 'my custom message' } + Person.validates :salary, numericality: { message: "my custom message" } person = Person.new person.valid? - assert_equal ['my custom message'], person.errors[:salary] + assert_equal ["my custom message"], person.errors[:salary] end def test_validates_with_validator_class Person.validates :karma, email: true person = Person.new person.valid? - assert_equal ['is not an email'], person.errors[:karma] + assert_equal ["is not an email"], person.errors[:karma] end def test_validates_with_namespaced_validator_class - Person.validates :karma, :'namespace/email' => true + Person.validates :karma, 'namespace/email': true person = Person.new person.valid? - assert_equal ['is not an email'], person.errors[:karma] + assert_equal ["is not an email"], person.errors[:karma] end def test_validates_with_if_as_local_conditions - Person.validates :karma, presence: true, email: { unless: :condition_is_true } + Person.validates :karma, presence: true, email: { if: :condition_is_false } person = Person.new person.valid? assert_equal ["can't be blank"], person.errors[:karma] end def test_validates_with_if_as_shared_conditions - Person.validates :karma, presence: true, email: true, if: :condition_is_true + Person.validates :karma, presence: true, email: true, if: :condition_is_false + person = Person.new + assert_predicate person, :valid? + end + + def test_validates_with_unless_as_local_conditions + Person.validates :karma, presence: true, email: { unless: :condition_is_true } person = Person.new person.valid? - assert_equal ["can't be blank", "is not an email"], person.errors[:karma].sort + assert_equal ["can't be blank"], person.errors[:karma] end def test_validates_with_unless_shared_conditions 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_equal ['is invalid'], person.errors[:karma] + 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_equal ['is not included in the list'], person.errors[:gender] + 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_equal ['is too short (minimum is 6 characters)'], person.errors[:karma] - person.karma = 'something' - assert person.valid? + assert_predicate person, :invalid? + assert_equal ["is too short (minimum is 6 characters)"], person.errors[:karma] + person.karma = "something" + assert_predicate person, :valid? end def test_validates_with_validator_class_and_options - Person.validates :karma, email: { message: 'my custom message' } + Person.validates :karma, email: { message: "my custom message" } person = Person.new person.valid? - assert_equal ['my custom message'], person.errors[:karma] + assert_equal ["my custom message"], person.errors[:karma] end def test_validates_with_unknown_validator @@ -127,14 +135,14 @@ class ValidatesTest < ActiveModel::TestCase PersonWithValidator.validates :title, presence: true person = PersonWithValidator.new person.valid? - assert_equal ['Local validator'], person.errors[:title] + assert_equal ["Local validator"], person.errors[:title] end def test_validates_with_included_validator_and_options - PersonWithValidator.validates :title, presence: { custom: ' please' } + PersonWithValidator.validates :title, presence: { custom: " please" } person = PersonWithValidator.new person.valid? - assert_equal ['Local validator please'], person.errors[:title] + assert_equal ["Local validator please"], person.errors[:title] end def test_validates_with_included_validator_and_wildcard_shortcut @@ -143,15 +151,15 @@ class ValidatesTest < ActiveModel::TestCase person = PersonWithValidator.new person.title = "Ms. Pacman" person.valid? - assert_equal ['does not appear to be like Mr.'], person.errors[:title] + assert_equal ["does not appear to be like Mr."], person.errors[:title] end def test_defining_extra_default_keys_for_validates - Topic.validates :title, confirmation: true, message: 'Y U NO CONFIRM' + Topic.validates :title, confirmation: true, message: "Y U NO CONFIRM" topic = Topic.new topic.title = "What's happening" topic.title_confirmation = "Not this" - assert !topic.valid? - assert_equal ['Y U NO CONFIRM'], topic.errors[:title_confirmation] + assert_not_predicate topic, :valid? + assert_equal ["Y U NO CONFIRM"], topic.errors[:title_confirmation] end end diff --git a/activemodel/test/cases/validations/validations_context_test.rb b/activemodel/test/cases/validations/validations_context_test.rb index b901a1523e..024eb1882f 100644 --- a/activemodel/test/cases/validations/validations_context_test.rb +++ b/activemodel/test/cases/validations/validations_context_test.rb @@ -1,6 +1,8 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' +require "cases/helper" + +require "models/topic" class ValidationsContextTest < ActiveModel::TestCase def teardown @@ -38,7 +40,7 @@ class ValidationsContextTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors, on: :create) topic = Topic.new assert topic.invalid?(:create), "Validation does run on create if 'on' is set to create" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with a class that adds errors on multiple contexts and validating a new model" do @@ -48,10 +50,10 @@ class ValidationsContextTest < ActiveModel::TestCase assert topic.valid?, "Validation ran with no context given when 'on' is set to context1 and context2" assert topic.invalid?(:context1), "Validation did not run on context1 when 'on' is set to context1 and context2" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE assert topic.invalid?(:context2), "Validation did not run on context2 when 'on' is set to context1 and context2" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with a class that validating a model for a multiple contexts" do @@ -62,7 +64,7 @@ class ValidationsContextTest < ActiveModel::TestCase assert topic.valid?, "Validation ran with no context given when 'on' is set to context1 and context2" assert topic.invalid?([:context1, :context2]), "Validation did not run on context1 when 'on' is set to context1 and context2" - assert topic.errors[:base].include?(ERROR_MESSAGE) - assert topic.errors[:base].include?(ANOTHER_ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE + assert_includes topic.errors[:base], ANOTHER_ERROR_MESSAGE end end diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb index 03c7943308..8239792c79 100644 --- a/activemodel/test/cases/validations/with_validation_test.rb +++ b/activemodel/test/cases/validations/with_validation_test.rb @@ -1,9 +1,10 @@ -require 'cases/helper' +# frozen_string_literal: true -require 'models/topic' +require "cases/helper" -class ValidatesWithTest < ActiveModel::TestCase +require "models/topic" +class ValidatesWithTest < ActiveModel::TestCase def teardown Topic.clear_validators! end @@ -52,7 +53,7 @@ class ValidatesWithTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors) topic = Topic.new assert topic.invalid?, "A class that adds errors causes the record to be invalid" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with a class that returns valid" do @@ -64,60 +65,35 @@ class ValidatesWithTest < ActiveModel::TestCase test "with multiple classes" do Topic.validates_with(ValidatorThatAddsErrors, OtherValidatorThatAddsErrors) topic = Topic.new - assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) - assert topic.errors[:base].include?(OTHER_ERROR_MESSAGE) - end - - test "with if statements that return false" do - Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 2") - topic = Topic.new - assert topic.valid? - end - - test "with if statements that return true" do - Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 1") - topic = Topic.new - assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) - end - - test "with unless statements that return true" do - Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 1") - topic = Topic.new - assert topic.valid? - end - - test "with unless statements that returns false" do - Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 2") - topic = Topic.new - assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_predicate topic, :invalid? + assert_includes topic.errors[:base], ERROR_MESSAGE + assert_includes topic.errors[:base], OTHER_ERROR_MESSAGE end test "passes all configuration options to the validator class" do topic = Topic.new validator = Minitest::Mock.new - validator.expect(:new, validator, [{foo: :bar, if: "1 == 1", class: Topic}]) + validator.expect(:new, validator, [{ foo: :bar, if: :condition_is_true, class: Topic }]) validator.expect(:validate, nil, [topic]) validator.expect(:is_a?, false, [Symbol]) + validator.expect(:is_a?, false, [String]) - Topic.validates_with(validator, if: "1 == 1", foo: :bar) - assert topic.valid? + Topic.validates_with(validator, if: :condition_is_true, foo: :bar) + 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 topic.errors[:base].include?(ERROR_MESSAGE) + 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 @@ -137,37 +113,37 @@ 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_equal ['is missing'], topic.errors[:title] + assert_not_predicate topic, :valid? + assert_equal ["is missing"], topic.errors[:title] end test "optionally pass in the attribute being validated when validating with an instance method" do Topic.validates :title, :content, with: :my_validation_with_arg topic = Topic.new title: "foo" - assert !topic.valid? - assert topic.errors[:title].empty? - assert_equal ['is missing'], topic.errors[:content] + assert_not_predicate topic, :valid? + assert_empty topic.errors[:title] + assert_equal ["is missing"], topic.errors[:content] end end |