diff options
Diffstat (limited to 'activemodel/test')
7 files changed, 325 insertions, 389 deletions
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb index a81584bbad..a32f11484a 100644 --- a/activemodel/test/cases/helper.rb +++ b/activemodel/test/cases/helper.rb @@ -6,6 +6,7 @@ $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) require 'config' require 'active_model' require 'active_support/core_ext/string/access' +require 'active_support/core_ext/hash/except' # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true diff --git a/activemodel/test/cases/validations/callbacks_test.rb b/activemodel/test/cases/validations/callbacks_test.rb new file mode 100644 index 0000000000..1cf09758f9 --- /dev/null +++ b/activemodel/test/cases/validations/callbacks_test.rb @@ -0,0 +1,78 @@ +# encoding: utf-8 +require 'cases/helper' + +class Dog + include ActiveModel::Validations + include ActiveModel::Validations::Callbacks + + attr_accessor :name + attr_writer :history + + def history + @history ||= [] + end +end + +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 +end + +class DogValidtorsAreProc < Dog + before_validation { self.history << 'before_validation_marker' } + after_validation { self.history << 'after_validation_marker' } +end + +class DogWithTwoValidators < Dog + before_validation { self.history << 'before_validation_marker1' } + before_validation { self.history << 'before_validation_marker2' } +end + +class DogValidatorReturningFalse < Dog + before_validation { false } + before_validation { self.history << 'before_validation_marker2' } +end + +class DogWithMissingName < Dog + before_validation { self.history << 'before_validation_marker' } + validates_presence_of :name +end + +class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase + + 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 + end + + def test_before_validation_and_after_validation_callbacks_should_be_called_with_proc + d = DogValidtorsAreProc.new + d.valid? + 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 + end + + def test_further_callbacks_should_not_be_called_if_before_validation_returns_false + d = DogValidatorReturningFalse.new + output = d.valid? + assert_equal [], d.history + assert_equal false, output + end + + def test_validation_test_should_be_done + d = DogWithMissingName.new + output = d.valid? + assert_equal ['before_validation_marker'], d.history + assert_equal false, output + end + +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 58a8d179ad..0679e67f84 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -8,131 +8,131 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase @person = Person.new end - # validates_inclusion_of: generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) + # 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, :default => nil, :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, :default => '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, :default => configuration[:message], :value => value) + # 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, :default => nil, :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, :default => '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, :default => configuration[:message], :value => value) + # 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, :default => nil, :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, :default => '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, :default => configuration[:message]) + # validates_confirmation_of: generate_message(attr_name, :confirmation, :message => custom_message) def test_generate_message_confirmation_with_default_message - assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation, :default => nil) + assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation) end def test_generate_message_confirmation_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :message => 'custom message') end - # validates_acceptance_of: generate_message(attr_name, :accepted, :default => configuration[:message]) + # validates_acceptance_of: generate_message(attr_name, :accepted, :message => custom_message) def test_generate_message_accepted_with_default_message - assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted, :default => nil) + assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted) end def test_generate_message_accepted_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :message => 'custom message') end - # add_on_empty: generate_message(attr, :empty, :default => custom_message) + # add_on_empty: generate_message(attr, :empty, :message => custom_message) def test_generate_message_empty_with_default_message - assert_equal "can't be empty", @person.errors.generate_message(:title, :empty, :default => nil) + assert_equal "can't be empty", @person.errors.generate_message(:title, :empty) end def test_generate_message_empty_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :message => 'custom message') end - # add_on_blank: generate_message(attr, :blank, :default => custom_message) + # add_on_blank: generate_message(attr, :blank, :message => custom_message) def test_generate_message_blank_with_default_message - assert_equal "can't be blank", @person.errors.generate_message(:title, :blank, :default => nil) + assert_equal "can't be blank", @person.errors.generate_message(:title, :blank) end def test_generate_message_blank_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :default => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :message => 'custom message') end - # validates_length_of: generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end) + # validates_length_of: generate_message(attr, :too_long, :message => custom_message, :count => option_value.end) def test_generate_message_too_long_with_default_message - assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :default => nil, :count => 10) + assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :count => 10) end def test_generate_message_too_long_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :default => '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 => options[:too_short], :count => option_value.begin) + # validates_length_of: generate_message(attr, :too_short, :default => custom_message, :count => option_value.begin) def test_generate_message_too_short_with_default_message - assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :default => nil, :count => 10) + assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :count => 10) end def test_generate_message_too_short_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :default => '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, key, :default => custom_message, :count => option_value) + # validates_length_of: generate_message(attr, :wrong_length, :message => custom_message, :count => option_value) def test_generate_message_wrong_length_with_default_message - assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :default => nil, :count => 10) + assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :count => 10) end def test_generate_message_wrong_length_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :default => '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, :default => configuration[:message]) + # 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, :default => nil, :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, :default => '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 => configuration[:message]) + # 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, :default => nil, :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, :default => nil, :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, :default => nil, :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, :default => nil, :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, :default => nil, :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, :default => nil, :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, :default => nil, :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 547d80f46e..e9f0e430fe 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -22,23 +22,23 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_add_on_empty_generates_message - @person.errors.expects(:generate_message).with(:title, :empty, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :empty, {}) @person.errors.add_on_empty :title end def test_errors_add_on_empty_generates_message_with_custom_default_message - @person.errors.expects(:generate_message).with(:title, :empty, {:default => 'custom'}) - @person.errors.add_on_empty :title, 'custom' + @person.errors.expects(:generate_message).with(:title, :empty, {:message => 'custom'}) + @person.errors.add_on_empty :title, :message => 'custom' end def test_errors_add_on_blank_generates_message - @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) + @person.errors.expects(:generate_message).with(:title, :blank, {}) @person.errors.add_on_blank :title end def test_errors_add_on_blank_generates_message_with_custom_default_message - @person.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) - @person.errors.add_on_blank :title, 'custom' + @person.errors.expects(:generate_message).with(:title, :blank, {:message => 'custom'}) + @person.errors.add_on_blank :title, :message => 'custom' end def test_full_message_encoding @@ -62,441 +62,272 @@ class I18nValidationTest < ActiveModel::TestCase 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] + [ "given no options", {}, {}], + [ "given custom message", {:message => "custom"}, {:message => "custom"}], + [ "given if condition", {:if => lambda { true }}, {}], + [ "given unless condition", {:unless => lambda { false }}, {}], + [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }] + ] + # validates_confirmation_of w/ mocha - def test_validates_confirmation_of_generates_message - Person.validates_confirmation_of :title - @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title, :confirmation, {:default => nil}) - @person.valid? - end - def test_validates_confirmation_of_generates_message_with_custom_default_message - Person.validates_confirmation_of :title, :message => 'custom' - @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title, :confirmation, {:default => 'custom'}) - @person.valid? + 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' + @person.errors.expects(:generate_message).with(:title, :confirmation, generate_message_options) + @person.valid? + end end # validates_acceptance_of w/ mocha - def test_validates_acceptance_of_generates_message - Person.validates_acceptance_of :title, :allow_nil => false - @person.errors.expects(:generate_message).with(:title, :accepted, {:default => nil}) - @person.valid? - end - - def test_validates_acceptance_of_generates_message_with_custom_default_message - Person.validates_acceptance_of :title, :message => 'custom', :allow_nil => false - @person.errors.expects(:generate_message).with(:title, :accepted, {:default => 'custom'}) - @person.valid? + COMMON_CASES.each do |name, validation_options, generate_message_options| + test "validates_acceptance_of on generated message #{name}" do + Person.validates_acceptance_of :title, validation_options.merge(:allow_nil => false) + @person.errors.expects(:generate_message).with(:title, :accepted, generate_message_options) + @person.valid? + end end # validates_presence_of w/ mocha - def test_validates_presence_of_generates_message - Person.validates_presence_of :title - @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) - @person.valid? - end - - def test_validates_presence_of_generates_message_with_custom_default_message - Person.validates_presence_of :title, :message => 'custom' - @person.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) - @person.valid? + COMMON_CASES.each do |name, validation_options, generate_message_options| + test "validates_presence_of on generated message #{name}" do + Person.validates_presence_of :title, validation_options + @person.errors.expects(:generate_message).with(:title, :blank, generate_message_options) + @person.valid? + end end - # validates_length_of :within w/ mocha + # validates_length_of :within too short w/ mocha - def test_validates_length_of_within_generates_message_with_title_too_short - Person.validates_length_of :title, :within => 3..5 - @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil}) - @person.valid? + COMMON_CASES.each do |name, validation_options, generate_message_options| + test "validates_length_of for :withing on generated message when too short #{name}" do + Person.validates_length_of :title, validation_options.merge(:within => 3..5) + @person.errors.expects(:generate_message).with(:title, :too_short, generate_message_options.merge(:count => 3)) + @person.valid? + end end - def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message - Person.validates_length_of :title, :within => 3..5, :too_short => 'custom' - @person.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'}) - @person.valid? - end - - def test_validates_length_of_within_generates_message_with_title_too_long - Person.validates_length_of :title, :within => 3..5 - @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) - @person.valid? - end + # validates_length_of :within too long w/ mocha - def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message - Person.validates_length_of :title, :within => 3..5, :too_long => 'custom' - @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) - @person.valid? + 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.errors.expects(:generate_message).with(:title, :too_long, generate_message_options.merge(:count => 5)) + @person.valid? + end end # validates_length_of :is w/ mocha - def test_validates_length_of_is_generates_message - Person.validates_length_of :title, :is => 5 - @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => nil}) - @person.valid? - end - - def test_validates_length_of_is_generates_message_with_custom_default_message - Person.validates_length_of :title, :is => 5, :message => 'custom' - @person.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => 'custom'}) - @person.valid? + COMMON_CASES.each do |name, validation_options, generate_message_options| + test "validates_length_of for :is on generated message #{name}" do + Person.validates_length_of :title, validation_options.merge(:is => 5) + @person.errors.expects(:generate_message).with(:title, :wrong_length, generate_message_options.merge(:count => 5)) + @person.valid? + end end # validates_format_of w/ mocha - def test_validates_format_of_generates_message - Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ - @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => nil}) - @person.valid? - end - - def test_validates_format_of_generates_message_with_custom_default_message - Person.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom' - @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => 'custom'}) - @person.valid? + 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 => /^[1-9][0-9]*$/) + @person.title = '72x' + @person.errors.expects(:generate_message).with(:title, :invalid, generate_message_options.merge(:value => '72x')) + @person.valid? + end end # validates_inclusion_of w/ mocha - def test_validates_inclusion_of_generates_message - Person.validates_inclusion_of :title, :in => %w(a b c) - @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => nil}) - @person.valid? - end - - def test_validates_inclusion_of_generates_message_with_custom_default_message - Person.validates_inclusion_of :title, :in => %w(a b c), :message => 'custom' - @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => 'custom'}) - @person.valid? + 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' + @person.errors.expects(:generate_message).with(:title, :inclusion, generate_message_options.merge(:value => 'z')) + @person.valid? + end end # validates_exclusion_of w/ mocha - def test_validates_exclusion_of_generates_message - Person.validates_exclusion_of :title, :in => %w(a b c) - @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => nil}) - @person.valid? - end - - def test_validates_exclusion_of_generates_message_with_custom_default_message - Person.validates_exclusion_of :title, :in => %w(a b c), :message => 'custom' - @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => 'custom'}) - @person.valid? + 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' + @person.errors.expects(:generate_message).with(:title, :exclusion, generate_message_options.merge(:value => 'a')) + @person.valid? + end end # validates_numericality_of without :only_integer w/ mocha - def test_validates_numericality_of_generates_message - Person.validates_numericality_of :title - @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil}) - @person.valid? - end - - def test_validates_numericality_of_generates_message_with_custom_default_message - Person.validates_numericality_of :title, :message => 'custom' - @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) - @person.valid? + 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' + @person.errors.expects(:generate_message).with(:title, :not_a_number, generate_message_options.merge(:value => 'a')) + @person.valid? + end end # validates_numericality_of with :only_integer w/ mocha - def test_validates_numericality_of_only_integer_generates_message - Person.validates_numericality_of :title, :only_integer => true - @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => nil}) - @person.valid? - end - - def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message - Person.validates_numericality_of :title, :only_integer => true, :message => 'custom' - @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => 'custom'}) - @person.valid? + 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' + @person.errors.expects(:generate_message).with(:title, :not_an_integer, generate_message_options.merge(:value => '0.0')) + @person.valid? + end end # validates_numericality_of :odd w/ mocha - def test_validates_numericality_of_odd_generates_message - Person.validates_numericality_of :title, :only_integer => true, :odd => true - @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => nil}) - @person.valid? - end - - def test_validates_numericality_of_odd_generates_message_with_custom_default_message - Person.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom' - @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => 'custom'}) - @person.valid? + COMMON_CASES.each do |name, validation_options, generate_message_options| + test "validates_numericality_of for :odd on generated message #{name}" do + Person.validates_numericality_of :title, validation_options.merge(:only_integer => true, :odd => true) + @person.title = 0 + @person.errors.expects(:generate_message).with(:title, :odd, generate_message_options.merge(:value => 0)) + @person.valid? + end end # validates_numericality_of :less_than w/ mocha - def test_validates_numericality_of_less_than_generates_message - Person.validates_numericality_of :title, :only_integer => true, :less_than => 0 - @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => nil}) - @person.valid? + COMMON_CASES.each do |name, validation_options, generate_message_options| + test "validates_numericality_of for :less_than on generated message #{name}" do + Person.validates_numericality_of :title, validation_options.merge(:only_integer => true, :less_than => 0) + @person.title = 1 + @person.errors.expects(:generate_message).with(:title, :less_than, generate_message_options.merge(:value => 1, :count => 0)) + @person.valid? + end end - def test_validates_numericality_of_less_than_odd_generates_message_with_custom_default_message - Person.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom' - @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => 'custom'}) - @person.valid? - end - # validates_confirmation_of w/o mocha + # To make things DRY this macro is defined to define 3 tests for every validation case. + def self.set_expectations_for_validation(validation, error_type, &block_that_sets_validation) + # test "validates_confirmation_of finds custom model key translation when blank" + test "#{validation} finds custom model key translation when #{error_type}" do + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {error_type => 'custom message'}}}}}} + I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}} - def test_validates_confirmation_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:confirmation => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:confirmation => 'global message'}} + yield(@person, {}) + @person.valid? + assert_equal ['custom message'], @person.errors[:title] + end - Person.validates_confirmation_of :title - @person.title_confirmation = 'foo' - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end + # test "validates_confirmation_of finds custom model key translation with interpolation when blank" + test "#{validation} finds custom model key translation with interpolation when #{error_type}" do + I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {error_type => 'custom message with %{extra}'}}}}}} + I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}} - def test_validates_confirmation_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:confirmation => 'global message'}} + yield(@person, {:extra => "extra information"}) + @person.valid? + assert_equal ['custom message with extra information'], @person.errors[:title] + end - Person.validates_confirmation_of :title - @person.title_confirmation = 'foo' - @person.valid? - assert_equal ['global message'], @person.errors[:title] - end + # test "validates_confirmation_of finds global default key translation when blank" + test "#{validation} finds global default key translation when #{error_type}" do + I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}} - # validates_acceptance_of w/o mocha - - def test_validates_acceptance_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:accepted => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:accepted => 'global message'}} - - Person.validates_acceptance_of :title, :allow_nil => false - @person.valid? - assert_equal ['custom message'], @person.errors[:title] + yield(@person, {}) + @person.valid? + assert_equal ['global message'], @person.errors[:title] + end end - def test_validates_acceptance_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:accepted => 'global message'}} + # validates_confirmation_of w/o mocha - Person.validates_acceptance_of :title, :allow_nil => false - @person.valid? - assert_equal ['global message'], @person.errors[:title] + 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' end - # validates_presence_of w/o mocha - - def test_validates_presence_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:blank => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:blank => 'global message'}} + # validates_acceptance_of w/o mocha - Person.validates_presence_of :title - @person.valid? - assert_equal ['custom message'], @person.errors[:title] + set_expectations_for_validation "validates_acceptance_of", :accepted do |person, options_to_merge| + Person.validates_acceptance_of :title, options_to_merge.merge(:allow_nil => false) end - def test_validates_presence_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:blank => 'global message'}} + # validates_presence_of w/o mocha - Person.validates_presence_of :title - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_presence_of", :blank do |person, options_to_merge| + Person.validates_presence_of :title, options_to_merge end # validates_length_of :within w/o mocha - def test_validates_length_of_within_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:too_short => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:too_short => 'global message'}} - - Person.validates_length_of :title, :within => 3..5 - @person.valid? - assert_equal ['custom message'], @person.errors[:title] + set_expectations_for_validation "validates_length_of", :too_short do |person, options_to_merge| + Person.validates_length_of :title, options_to_merge.merge(:within => 3..5) end - def test_validates_length_of_within_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:too_short => 'global message'}} - - Person.validates_length_of :title, :within => 3..5 - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_length_of", :too_long do |person, options_to_merge| + Person.validates_length_of :title, options_to_merge.merge(:within => 3..5) + person.title = "too long" end # validates_length_of :is w/o mocha - def test_validates_length_of_is_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:wrong_length => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:wrong_length => 'global message'}} - - Person.validates_length_of :title, :is => 5 - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_length_of_is_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:wrong_length => 'global message'}} - - Person.validates_length_of :title, :is => 5 - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_length_of", :wrong_length do |person, options_to_merge| + Person.validates_length_of :title, options_to_merge.merge(:is => 5) end # validates_format_of w/o mocha - def test_validates_format_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:invalid => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:invalid => 'global message'}} - - Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_format_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:invalid => 'global message'}} - - Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_format_of", :invalid do |person, options_to_merge| + Person.validates_format_of :title, options_to_merge.merge(:with => /^[1-9][0-9]*$/) end # validates_inclusion_of w/o mocha - def test_validates_inclusion_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:inclusion => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:inclusion => 'global message'}} - - Person.validates_inclusion_of :title, :in => %w(a b c) - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_inclusion_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:inclusion => 'global message'}} - - Person.validates_inclusion_of :title, :in => %w(a b c) - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_inclusion_of", :inclusion do |person, options_to_merge| + Person.validates_inclusion_of :title, options_to_merge.merge(:in => %w(a b c)) end # validates_exclusion_of w/o mocha - def test_validates_exclusion_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:exclusion => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:exclusion => 'global message'}} - - Person.validates_exclusion_of :title, :in => %w(a b c) - @person.title = 'a' - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_exclusion_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:exclusion => 'global message'}} - - Person.validates_exclusion_of :title, :in => %w(a b c) - @person.title = 'a' - @person.valid? - assert_equal ['global message'], @person.errors[:title] + 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' end # validates_numericality_of without :only_integer w/o mocha - def test_validates_numericality_of_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}} - - Person.validates_numericality_of :title - @person.title = 'a' - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_numericality_of_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true - @person.title = 'a' - @person.valid? - assert_equal ['global message'], @person.errors[:title] + 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' end # validates_numericality_of with :only_integer w/o mocha - def test_validates_numericality_of_only_integer_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_an_integer => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true - @person.title = '1.0' - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_numericality_of_only_integer_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true - @person.title = '1.0' - @person.valid? - assert_equal ['global message'], @person.errors[:title] + 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' end # validates_numericality_of :odd w/o mocha - def test_validates_numericality_of_odd_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:odd => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:odd => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true, :odd => true - @person.title = 0 - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_numericality_of_odd_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:odd => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true, :odd => true - @person.title = 0 - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_numericality_of", :odd do |person, options_to_merge| + Person.validates_numericality_of :title, options_to_merge.merge(:only_integer => true, :odd => true) + person.title = 0 end # validates_numericality_of :less_than w/o mocha - def test_validates_numericality_of_less_than_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:less_than => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {:less_than => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true, :less_than => 0 - @person.title = 1 - @person.valid? - assert_equal ['custom message'], @person.errors[:title] - end - - def test_validates_numericality_of_less_than_finds_global_default_translation - I18n.backend.store_translations 'en', :errors => {:messages => {:less_than => 'global message'}} - - Person.validates_numericality_of :title, :only_integer => true, :less_than => 0 - @person.title = 1 - @person.valid? - assert_equal ['global message'], @person.errors[:title] + set_expectations_for_validation "validates_numericality_of", :less_than do |person, options_to_merge| + Person.validates_numericality_of :title, options_to_merge.merge(:only_integer => true, :less_than => 0) + person.title = 1 end # test with validates_with diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 8e77a0222e..e1d7d40c47 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -4,6 +4,8 @@ require 'cases/helper' require 'models/topic' require 'models/person' +require 'bigdecimal' + class NumericalityValidationTest < ActiveModel::TestCase def teardown diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb index b1450586a8..510c13a7c3 100644 --- a/activemodel/test/cases/validations/presence_validation_test.rb +++ b/activemodel/test/cases/validations/presence_validation_test.rb @@ -32,7 +32,7 @@ class PresenceValidationTest < ActiveModel::TestCase assert t.valid? end - test 'accepts array arguments' do + def test_accepts_array_arguments Topic.validates_presence_of %w(title content) t = Topic.new assert t.invalid? diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index af195af080..e94d8ce88c 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -6,6 +6,9 @@ require 'models/reply' require 'models/custom_reader' require 'models/automobile' +require 'active_support/json' +require 'active_support/xml_mini' + class ValidationsTest < ActiveModel::TestCase def setup @@ -83,10 +86,9 @@ class ValidationsTest < ActiveModel::TestCase r = Reply.new r.content = "Mismatch" r.valid? - r.errors[:base] << "Reply is not dignifying" + r.errors.add(:base, "Reply is not dignifying") - errors = [] - r.errors.to_a.each { |error| errors << error } + errors = r.errors.to_a.inject([]) { |result, error| result + [error] } assert_equal ["Reply is not dignifying"], r.errors[:base] @@ -95,6 +97,22 @@ class ValidationsTest < ActiveModel::TestCase assert_equal 2, r.errors.count end + def test_errors_on_base_with_symbol_message + r = Reply.new + r.content = "Mismatch" + r.valid? + r.errors.add(:base, :invalid) + + errors = r.errors.to_a.inject([]) { |result, error| result + [error] } + + assert_equal ["is invalid"], r.errors[:base] + + assert errors.include?("Title is Empty") + assert errors.include?("is invalid") + + assert_equal 2, r.errors.count + end + def test_errors_empty_after_errors_on_check t = Topic.new assert t.errors[:id].empty? @@ -143,12 +161,18 @@ class ValidationsTest < ActiveModel::TestCase end end - def test_errors_to_xml - r = Reply.new :title => "Wrong Create" - assert r.invalid? - xml = r.errors.to_xml(:skip_instruct => true) - assert_equal "<errors>", xml.first(8) - assert xml.include?("<error>Content is Empty</error>") + def test_errors_conversions + Topic.validates_presence_of %w(title content) + t = Topic.new + assert t.invalid? + + xml = t.errors.to_xml + assert_match %r{<errors>}, xml + assert_match %r{<error>Title can't be blank</error>}, xml + assert_match %r{<error>Content can't be blank</error>}, xml + + json = t.errors.to_json + assert_equal t.errors.to_a.to_json, json end def test_validation_order |