diff options
Diffstat (limited to 'activemodel/test/cases/validations')
11 files changed, 1958 insertions, 0 deletions
diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb new file mode 100644 index 0000000000..88e5fdb358 --- /dev/null +++ b/activemodel/test/cases/validations/acceptance_validation_test.rb @@ -0,0 +1,80 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/reply' +require 'models/developer' +require 'models/person' + +class AcceptanceValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_terms_of_service_agreement_no_acceptance + Topic.validates_acceptance_of(:terms_of_service, :on => :create) + + t = Topic.create("title" => "We should not be confirmed") + assert t.save + end + + def test_terms_of_service_agreement + Topic.validates_acceptance_of(:terms_of_service, :on => :create) + + t = Topic.create("title" => "We should be confirmed","terms_of_service" => "") + assert !t.save + assert_equal ["must be accepted"], t.errors[:terms_of_service] + + t.terms_of_service = "1" + assert t.save + end + + def test_eula + Topic.validates_acceptance_of(:eula, :message => "must be abided", :on => :create) + + t = Topic.create("title" => "We should be confirmed","eula" => "") + assert !t.save + assert_equal ["must be abided"], t.errors[:eula] + + t.eula = "1" + assert t.save + end + + def test_terms_of_service_agreement_with_accept_value + Topic.validates_acceptance_of(:terms_of_service, :on => :create, :accept => "I agree.") + + t = Topic.create("title" => "We should be confirmed", "terms_of_service" => "") + assert !t.save + assert_equal ["must be accepted"], t.errors[:terms_of_service] + + t.terms_of_service = "I agree." + assert t.save + end + + def test_validates_acceptance_of_with_custom_error_using_quotes + repair_validations(Developer) do + Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes" + d = Developer.new + d.salary = "0" + assert !d.valid? + assert_equal "This string contains 'single' and \"double\" quotes", d.errors[:salary].last + end + end + + def test_validates_acceptance_of_for_ruby_class + repair_validations(Person) do + Person.validates_acceptance_of :karma + + p = Person.new + p.karma = "" + + assert p.invalid? + assert_equal ["must be accepted"], p.errors[:karma] + + p.karma = "1" + assert p.valid? + end + end +end diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb new file mode 100644 index 0000000000..4c716d5d48 --- /dev/null +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -0,0 +1,140 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' + +class ConditionalValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_if_validation_using_method_true + # When the method returns true + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_unless_validation_using_method_true + # When the method returns true + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert !t.errors[:title].any? + 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 ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert t.errors[:title].empty? + end + + def test_unless_validation_using_method_false + # When the method returns false + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_if_validation_using_string_true + # When the evaluated string returns true + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_unless_validation_using_string_true + # When the evaluated string returns true + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert t.errors[:title].empty? + 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") + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert t.errors[:title].empty? + 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") + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_if_validation_using_block_true + # When the block returns true + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", + :if => Proc.new { |r| r.content.size > 4 } ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_unless_validation_using_block_true + # When the block returns true + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", + :unless => Proc.new { |r| r.content.size > 4 } ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert t.errors[:title].empty? + 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"} ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert t.valid? + assert t.errors[:title].empty? + 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"} ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert 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 t.errors[:author_name].empty?, "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.valid?, "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" + + t.author_name = "Hubert J. Farnsworth" + assert t.valid?, "A topic with an important title and author should be valid" + end +end diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb new file mode 100644 index 0000000000..1d6f2a6ec5 --- /dev/null +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -0,0 +1,68 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/developer' +require 'models/person' + +class ConfirmationValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_no_title_confirmation + Topic.validates_confirmation_of(:title) + + t = Topic.new(:author_name => "Plutarch") + assert t.valid? + + t.title_confirmation = "Parallel Lives" + assert !t.valid? + + t.title_confirmation = nil + t.title = "Parallel Lives" + assert t.valid? + + t.title_confirmation = "Parallel Lives" + assert t.valid? + end + + def test_title_confirmation + Topic.validates_confirmation_of(:title) + + t = Topic.create("title" => "We should be confirmed","title_confirmation" => "") + assert !t.save + + t.title_confirmation = "We should be confirmed" + assert t.save + end + + def test_validates_confirmation_of_with_custom_error_using_quotes + repair_validations(Developer) do + Developer.validates_confirmation_of :name, :message=> "confirm 'single' and \"double\" quotes" + d = Developer.new + d.name = "John" + d.name_confirmation = "Johnny" + assert !d.valid? + assert_equal ["confirm 'single' and \"double\" quotes"], d.errors[:name] + end + end + + def test_validates_confirmation_of_for_ruby_class + repair_validations(Person) do + Person.validates_confirmation_of :karma + + p = Person.new + p.karma_confirmation = "None" + assert p.invalid? + + assert_equal ["doesn't match confirmation"], p.errors[:karma] + + p.karma = "None" + assert p.valid? + end + end + +end diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb new file mode 100644 index 0000000000..584f009e84 --- /dev/null +++ b/activemodel/test/cases/validations/exclusion_validation_test.rb @@ -0,0 +1,46 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/person' + +class ExclusionValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_validates_exclusion_of + Topic.validates_exclusion_of( :title, :in => %w( abe monkey ) ) + + assert Topic.create("title" => "something", "content" => "abc").valid? + assert !Topic.create("title" => "monkey", "content" => "abc").valid? + end + + def test_validates_exclusion_of_with_formatted_message + Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" ) + + assert Topic.create("title" => "something", "content" => "abc") + + t = Topic.create("title" => "monkey") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["option monkey is restricted"], t.errors[:title] + end + + def test_validates_exclusion_of_for_ruby_class + repair_validations(Person) do + Person.validates_exclusion_of :karma, :in => %w( abe monkey ) + + p = Person.new + p.karma = "abe" + assert p.invalid? + + assert_equal ["is reserved"], p.errors[:karma] + + p.karma = "Lifo" + assert p.valid? + end + end +end diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb new file mode 100644 index 0000000000..2c06a9dd02 --- /dev/null +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -0,0 +1,98 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/developer' +require 'models/person' + +class PresenceValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_validate_format + Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data") + + t = Topic.create("title" => "i'm incorrect", "content" => "Validation macros rule!") + assert !t.valid?, "Shouldn't be valid" + assert !t.save, "Shouldn't save because it's invalid" + assert_equal ["is bad data"], t.errors[:title] + assert t.errors[:content].empty? + + t.title = "Validation macros rule!" + + assert t.save + assert t.errors[:title].empty? + + assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) } + end + + def test_validate_format_with_allow_blank + Topic.validates_format_of(:title, :with => /^Validation\smacros \w+!$/, :allow_blank=>true) + assert !Topic.create("title" => "Shouldn't be valid").valid? + assert Topic.create("title" => "").valid? + assert Topic.create("title" => nil).valid? + assert Topic.create("title" => "Validation macros rule!").valid? + end + + # testing ticket #3142 + def test_validate_format_numeric + Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data") + + t = Topic.create("title" => "72x", "content" => "6789") + assert !t.valid?, "Shouldn't be valid" + assert !t.save, "Shouldn't save because it's invalid" + assert_equal ["is bad data"], t.errors[:title] + assert t.errors[:content].empty? + + t.title = "-11" + assert !t.valid?, "Shouldn't be valid" + + t.title = "03" + assert !t.valid?, "Shouldn't be valid" + + t.title = "z44" + assert !t.valid?, "Shouldn't be valid" + + t.title = "5v7" + assert !t.valid?, "Shouldn't be valid" + + t.title = "1" + + assert t.save + assert t.errors[:title].empty? + end + + def test_validate_format_with_formatted_message + Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}") + t = Topic.create(:title => 'Invalid title') + assert_equal ["can't be Invalid title"], t.errors[:title] + end + + def test_validates_format_of_with_custom_error_using_quotes + repair_validations(Developer) do + Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "format 'single' and \"double\" quotes" + d = Developer.new + d.name = d.name_confirmation = "John 32" + assert !d.valid? + assert_equal ["format 'single' and \"double\" quotes"], d.errors[:name] + end + end + + def test_validates_format_of_for_ruby_class + repair_validations(Person) do + Person.validates_format_of :karma, :with => /\A\d+\Z/ + + p = Person.new + p.karma = "Pixies" + assert p.invalid? + + assert_equal ["is invalid"], p.errors[:karma] + + p.karma = "1234" + assert p.valid? + end + 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 new file mode 100644 index 0000000000..37bba5e95e --- /dev/null +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -0,0 +1,182 @@ +require "cases/helper" +require 'cases/tests_database' + +require 'models/person' + +class I18nGenerateMessageValidationTest < Test::Unit::TestCase + def setup + reset_callbacks Person + @person = Person.new + + @old_load_path, @old_backend = I18n.load_path, I18n.backend + I18n.load_path.clear + I18n.backend = I18n::Backend::Simple.new + + I18n.backend.store_translations :'en', { + :activemodel => { + :errors => { + :messages => { + :inclusion => "is not included in the list", + :exclusion => "is reserved", + :invalid => "is invalid", + :confirmation => "doesn't match confirmation", + :accepted => "must be accepted", + :empty => "can't be empty", + :blank => "can't be blank", + :too_long => "is too long (maximum is {{count}} characters)", + :too_short => "is too short (minimum is {{count}} characters)", + :wrong_length => "is the wrong length (should be {{count}} characters)", + :not_a_number => "is not a number", + :greater_than => "must be greater than {{count}}", + :greater_than_or_equal_to => "must be greater than or equal to {{count}}", + :equal_to => "must be equal to {{count}}", + :less_than => "must be less than {{count}}", + :less_than_or_equal_to => "must be less than or equal to {{count}}", + :odd => "must be odd", + :even => "must be even" + } + } + } + } + end + + def teardown + I18n.load_path.replace @old_load_path + I18n.backend = @old_backend + end + + def reset_callbacks(*models) + models.each do |model| + model.instance_variable_set("@validate_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + end + end + + # validates_inclusion_of: generate_message(attr_name, :inclusion, :default => configuration[: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') + 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') + end + + # validates_exclusion_of: generate_message(attr_name, :exclusion, :default => configuration[: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') + 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') + end + + # validates_associated: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + # validates_format_of: generate_message(attr_name, :invalid, :default => configuration[: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') + 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') + end + + # validates_confirmation_of: generate_message(attr_name, :confirmation, :default => configuration[:message]) + def test_generate_message_confirmation_with_default_message + assert_equal "doesn't match confirmation", @person.errors.generate_message(:title, :confirmation, :default => nil) + end + + def test_generate_message_confirmation_with_custom_message + assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :default => 'custom message') + end + + # validates_acceptance_of: generate_message(attr_name, :accepted, :default => configuration[:message]) + def test_generate_message_accepted_with_default_message + assert_equal "must be accepted", @person.errors.generate_message(:title, :accepted, :default => nil) + end + + def test_generate_message_accepted_with_custom_message + assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :default => 'custom message') + end + + # add_on_empty: generate_message(attr, :empty, :default => custom_message) + def test_generate_message_empty_with_default_message + assert_equal "can't be empty", @person.errors.generate_message(:title, :empty, :default => nil) + end + + def test_generate_message_empty_with_custom_message + assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :default => 'custom message') + end + + # add_on_blank: generate_message(attr, :blank, :default => custom_message) + def test_generate_message_blank_with_default_message + assert_equal "can't be blank", @person.errors.generate_message(:title, :blank, :default => nil) + end + + def test_generate_message_blank_with_custom_message + assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :default => 'custom message') + end + + # validates_length_of: generate_message(attr, :too_long, :default => options[:too_long], :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) + 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) + end + + # validates_length_of: generate_message(attr, :too_short, :default => options[:too_short], :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) + 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) + end + + # validates_length_of: generate_message(attr, key, :default => 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) + 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) + end + + # validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[: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') + 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') + end + + # validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => configuration[: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) + 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) + 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) + 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) + 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) + 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) + 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) + end +end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb new file mode 100644 index 0000000000..cc68d847a2 --- /dev/null +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -0,0 +1,579 @@ +require "cases/helper" +require 'cases/tests_database' + +require 'models/person' + +class I18nValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + + def setup + reset_callbacks Person + + @person = Person.new + + @old_load_path, @old_backend = I18n.load_path, I18n.backend + I18n.load_path.clear + I18n.backend = I18n::Backend::Simple.new + I18n.backend.store_translations('en', :activemodel => {:errors => {:messages => {:custom => nil}}}) + end + + def teardown + reset_callbacks Person + I18n.load_path.replace @old_load_path + I18n.backend = @old_backend + end + + def reset_callbacks(*models) + models.each do |model| + model.instance_variable_set("@validate_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + end + end + + def test_percent_s_interpolation_syntax_in_error_messages_was_deprecated + assert_not_deprecated do + default = "%s interpolation syntax was deprecated" + assert_equal default, I18n.t(:does_not_exist, :default => default, :value => 'this') + end + end + + def test_percent_d_interpolation_syntax_in_error_messages_was_deprecated + assert_not_deprecated do + default = "%d interpolation syntaxes are deprecated" + assert_equal default, I18n.t(:does_not_exist, :default => default, :count => 2) + end + end + + def test_errors_add_on_empty_generates_message + @person.errors.expects(:generate_message).with(:title, :empty, {:default => nil}) + @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' + end + + def test_errors_add_on_blank_generates_message + @person.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) + @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' + end + + # ActiveRecord::Validations + # 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? + 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? + 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? + end + + 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? + 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 + + 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? + end + + # validates_length_of :within 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? + 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 + + 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? + 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? + 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? + 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? + 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? + 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? + 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 = 'a' + @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :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 = 'a' + @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) + @person.valid? + 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? + 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? + end + + def test_validates_numericality_of_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 + + 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', :activemodel => {:errors => {:messages => {:confirmation => 'global message'}}} + + Person.validates_confirmation_of :title + @person.title_confirmation = 'foo' + @person.valid? + assert_equal ['custom message'], @person.errors[:title] + end + + def test_validates_confirmation_of_finds_global_default_translation + I18n.backend.store_translations 'en', :activemodel => {:errors => {:messages => {:confirmation => 'global message'}}} + + Person.validates_confirmation_of :title + @person.title_confirmation = 'foo' + @person.valid? + assert_equal ['global message'], @person.errors[:title] + end + + # 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', :activemodel => {:errors => {:messages => {:accepted => 'global message'}}} + + Person.validates_acceptance_of :title, :allow_nil => false + @person.valid? + assert_equal ['custom message'], @person.errors[:title] + end + + def test_validates_acceptance_of_finds_global_default_translation + I18n.backend.store_translations 'en', :activemodel => {:errors => {:messages => {:accepted => 'global message'}}} + + Person.validates_acceptance_of :title, :allow_nil => false + @person.valid? + assert_equal ['global message'], @person.errors[:title] + 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', :activemodel => {:errors => {:messages => {:blank => 'global message'}}} + + Person.validates_presence_of :title + @person.valid? + assert_equal ['custom message'], @person.errors[:title] + end + + def test_validates_presence_of_finds_global_default_translation + I18n.backend.store_translations 'en', :activemodel => {:errors => {:messages => {:blank => 'global message'}}} + + Person.validates_presence_of :title + @person.valid? + assert_equal ['global message'], @person.errors[:title] + 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', :activemodel => {:errors => {:messages => {:too_short => 'global message'}}} + + Person.validates_length_of :title, :within => 3..5 + @person.valid? + assert_equal ['custom message'], @person.errors[:title] + end + + def test_validates_length_of_within_finds_global_default_translation + I18n.backend.store_translations 'en', :activemodel => {:errors => {:messages => {:too_short => 'global message'}}} + + Person.validates_length_of :title, :within => 3..5 + @person.valid? + assert_equal ['global message'], @person.errors[:title] + 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', :activemodel => {: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', :activemodel => {:errors => {:messages => {:wrong_length => 'global message'}}} + + Person.validates_length_of :title, :is => 5 + @person.valid? + assert_equal ['global message'], @person.errors[:title] + end + + 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', :activemodel => {: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', :activemodel => {:errors => {:messages => {:wrong_length => 'global message'}}} + + Person.validates_length_of :title, :is => 5 + @person.valid? + assert_equal ['global message'], @person.errors[:title] + 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', :activemodel => {: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', :activemodel => {:errors => {:messages => {:invalid => 'global message'}}} + + Person.validates_format_of :title, :with => /^[1-9][0-9]*$/ + @person.valid? + assert_equal ['global message'], @person.errors[:title] + 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', :activemodel => {: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', :activemodel => {:errors => {:messages => {:inclusion => 'global message'}}} + + Person.validates_inclusion_of :title, :in => %w(a b c) + @person.valid? + assert_equal ['global message'], @person.errors[:title] + 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', :activemodel => {: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', :activemodel => {: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] + 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', :activemodel => {: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', :activemodel => {: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] + 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_a_number => 'custom message'}}}}}} + I18n.backend.store_translations 'en', :activemodel => {:errors => {:messages => {:not_a_number => 'global message'}}} + + Person.validates_numericality_of :title, :only_integer => true + @person.title = 'a' + @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', :activemodel => {: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] + 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', :activemodel => {: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', :activemodel => {: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] + 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', :activemodel => {: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', :activemodel => {: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] + end + + def test_validations_with_message_symbol_must_translate + I18n.backend.store_translations 'en', :activemodel => {:errors => {:messages => {:custom_error => "I am a custom error"}}} + Person.validates_presence_of :title, :message => :custom_error + @person.title = nil + @person.valid? + assert_equal ["I am a custom error"], @person.errors[:title] + 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"}}}}}} + Person.validates_presence_of :title, :message => :custom_error + @person.title = nil + @person.valid? + assert_equal ["I am a custom error"], @person.errors[:title] + 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"}}}} + Person.validates_presence_of :title, :message => :custom_error + @person.title = nil + @person.valid? + assert_equal ["I am a custom error"], @person.errors[:title] + end + + def test_validates_with_message_string + Person.validates_presence_of :title, :message => "I am a custom error" + @person.title = nil + @person.valid? + assert_equal ["I am a custom error"], @person.errors[:title] + end + +end
\ No newline at end of file diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb new file mode 100644 index 0000000000..bc1b0365d2 --- /dev/null +++ b/activemodel/test/cases/validations/inclusion_validation_test.rb @@ -0,0 +1,80 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/developer' +require 'models/person' + +class InclusionValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_validates_inclusion_of + Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) ) + + assert !Topic.create("title" => "a!", "content" => "abc").valid? + assert !Topic.create("title" => "a b", "content" => "abc").valid? + assert !Topic.create("title" => nil, "content" => "def").valid? + + t = Topic.create("title" => "a", "content" => "I know you are but what am I?") + assert t.valid? + t.title = "uhoh" + assert !t.valid? + assert 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 => [] ) } + 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.create("title" => "a!", "content" => "abc").valid? + assert !Topic.create("title" => "", "content" => "abc").valid? + assert Topic.create("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.create("title" => "a", "content" => "abc").valid? + + t = Topic.create("title" => "uhoh", "content" => "abc") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["option uhoh is not in the list"], t.errors[:title] + end + + def test_validates_inclusion_of_with_custom_error_using_quotes + repair_validations(Developer) do + Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes" + d = Developer.new + d.salary = "90,000" + assert !d.valid? + assert_equal "This string contains 'single' and \"double\" quotes", d.errors[:salary].last + end + end + + def test_validates_inclusion_of_for_ruby_class + repair_validations(Person) do + Person.validates_inclusion_of :karma, :in => %w( abe monkey ) + + p = Person.new + p.karma = "Lifo" + assert p.invalid? + + assert_equal ["is not included in the list"], p.errors[:karma] + + p.karma = "monkey" + assert p.valid? + end + end +end diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb new file mode 100644 index 0000000000..4a2f72feab --- /dev/null +++ b/activemodel/test/cases/validations/length_validation_test.rb @@ -0,0 +1,449 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/developer' +require 'models/person' + +class LengthValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_validates_length_of_with_allow_nil + Topic.validates_length_of( :title, :is => 5, :allow_nil=>true ) + + assert !Topic.create("title" => "ab").valid? + assert !Topic.create("title" => "").valid? + assert Topic.create("title" => nil).valid? + assert Topic.create("title" => "abcde").valid? + end + + def test_validates_length_of_with_allow_blank + Topic.validates_length_of( :title, :is => 5, :allow_blank=>true ) + + assert !Topic.create("title" => "ab").valid? + assert Topic.create("title" => "").valid? + assert Topic.create("title" => nil).valid? + assert Topic.create("title" => "abcde").valid? + end + + def test_validates_length_of_using_minimum + Topic.validates_length_of :title, :minimum => 5 + + t = Topic.create("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = "not" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is too short (minimum is 5 characters)"], t.errors[:title] + + t.title = "" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is too short (minimum is 5 characters)"], t.errors[:title] + + t.title = nil + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is too short (minimum is 5 characters)"], t.errors["title"] + end + + def test_optionally_validates_length_of_using_minimum + Topic.validates_length_of :title, :minimum => 5, :allow_nil => true + + t = Topic.create("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = nil + assert t.valid? + end + + def test_validates_length_of_using_maximum + Topic.validates_length_of :title, :maximum => 5 + + t = Topic.create("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = "notvalid" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is too long (maximum is 5 characters)"], t.errors[:title] + + t.title = "" + assert t.valid? + + t.title = nil + assert !t.valid? + end + + def test_optionally_validates_length_of_using_maximum + Topic.validates_length_of :title, :maximum => 5, :allow_nil => true + + t = Topic.create("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = nil + assert 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.valid? + 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.valid? + 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? + end + + def test_optionally_validates_length_of_using_within + Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true + + t = Topic.create('title' => 'abc', 'content' => 'abcd') + assert t.valid? + + t.title = nil + assert t.valid? + end + + def test_optionally_validates_length_of_using_within_on_create + Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}" + + t = Topic.create("title" => "thisisnotvalid", "content" => "whatever") + assert !t.save + assert t.errors[:title].any? + assert_equal ["my string is too long: 10"], t.errors[:title] + + t.title = "butthisis" + assert t.save + + t.title = "few" + assert t.save + + t.content = "andthisislong" + assert t.save + + t.content = t.title = "iamfine" + assert t.save + end + + def test_optionally_validates_length_of_using_within_on_update + Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}" + + t = Topic.create("title" => "vali", "content" => "whatever") + assert !t.save + assert t.errors[:title].any? + + t.title = "not" + assert !t.save + assert t.errors[:title].any? + assert_equal ["my string is too short: 5"], t.errors[:title] + + t.title = "valid" + t.content = "andthisistoolong" + assert !t.save + assert t.errors[:content].any? + + t.content = "iamfine" + assert t.save + end + + def test_validates_length_of_using_is + Topic.validates_length_of :title, :is => 5 + + t = Topic.create("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = "notvalid" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is the wrong length (should be 5 characters)"], t.errors[:title] + + t.title = "" + assert !t.valid? + + t.title = nil + assert !t.valid? + end + + def test_optionally_validates_length_of_using_is + Topic.validates_length_of :title, :is => 5, :allow_nil => true + + t = Topic.create("title" => "valid", "content" => "whatever") + assert t.valid? + + t.title = nil + assert t.valid? + end + + def test_validates_length_of_using_bignum + bigmin = 2 ** 30 + bigmax = 2 ** 32 + bigrange = bigmin...bigmax + assert_nothing_raised do + Topic.validates_length_of :title, :is => bigmin + 5 + Topic.validates_length_of :title, :within => bigrange + Topic.validates_length_of :title, :in => bigrange + Topic.validates_length_of :title, :minimum => bigmin + Topic.validates_length_of :title, :maximum => bigmax + end + end + + def test_validates_length_of_nasty_params + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :minimum=>9) } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :is=>9) } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") } + assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") } + end + + def test_validates_length_of_custom_errors_for_minimum_with_message + Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" ) + t = Topic.create("title" => "uhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["boo 5"], t.errors[:title] + end + + def test_validates_length_of_custom_errors_for_minimum_with_too_short + Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" ) + t = Topic.create("title" => "uhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors[:title] + end + + def test_validates_length_of_custom_errors_for_maximum_with_message + Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert 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.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 10"], t.errors["title"] + + t = Topic.create("title" => "uhohuhohuhohuhohuhohuhohuhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 20"], t.errors["title"] + end + + def test_validates_length_of_custom_errors_for_maximum_with_too_long + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_validates_length_of_custom_errors_for_is_with_message + Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["boo 5"], t.errors["title"] + end + + def test_validates_length_of_custom_errors_for_is_with_wrong_length + Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" ) + t = Topic.create("title" => "uhohuhoh", "content" => "whatever") + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["hoo 5"], t.errors["title"] + end + + def test_validates_length_of_using_minimum_utf8 + with_kcode('UTF8') do + Topic.validates_length_of :title, :minimum => 5 + + t = Topic.create("title" => "一二三四五", "content" => "whatever") + assert t.valid? + + t.title = "一二三四" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is too short (minimum is 5 characters)"], t.errors["title"] + end + end + + def test_validates_length_of_using_maximum_utf8 + with_kcode('UTF8') do + Topic.validates_length_of :title, :maximum => 5 + + t = Topic.create("title" => "一二三四五", "content" => "whatever") + assert t.valid? + + t.title = "一二34五六" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is too long (maximum is 5 characters)"], t.errors["title"] + end + end + + def test_validates_length_of_using_within_utf8 + with_kcode('UTF8') do + Topic.validates_length_of(:title, :content, :within => 3..5) + + t = Topic.new("title" => "一二", "content" => "12三四五六七") + assert !t.valid? + 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? + end + end + + def test_optionally_validates_length_of_using_within_utf8 + with_kcode('UTF8') do + Topic.validates_length_of :title, :within => 3..5, :allow_nil => true + + t = Topic.create(:title => "一二三四五") + assert t.valid?, t.errors.inspect + + t = Topic.create(:title => "一二三") + assert t.valid?, t.errors.inspect + + t.title = nil + assert t.valid?, t.errors.inspect + end + end + + def test_optionally_validates_length_of_using_within_on_create_utf8 + with_kcode('UTF8') do + Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}" + + t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever") + assert !t.save + assert t.errors[:title].any? + assert_equal "長すぎます: 10", t.errors[:title].first + + t.title = "一二三四五六七八九" + assert t.save + + t.title = "一二3" + assert t.save + + t.content = "一二三四五六七八九十" + assert t.save + + t.content = t.title = "一二三四五六" + assert t.save + end + end + + def test_optionally_validates_length_of_using_within_on_update_utf8 + with_kcode('UTF8') do + Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}" + + t = Topic.create("title" => "一二三4", "content" => "whatever") + assert !t.save + assert t.errors[:title].any? + + t.title = "1二三4" + assert !t.save + assert t.errors[:title].any? + assert_equal ["短すぎます: 5"], t.errors[:title] + + t.title = "一二三四五六七八九十A" + assert !t.save + assert t.errors[:title].any? + + t.title = "一二345" + assert t.save + end + end + + def test_validates_length_of_using_is_utf8 + with_kcode('UTF8') do + Topic.validates_length_of :title, :is => 5 + + t = Topic.create("title" => "一二345", "content" => "whatever") + assert t.valid? + + t.title = "一二345六" + assert !t.valid? + assert t.errors[:title].any? + assert_equal ["is the wrong length (should be 5 characters)"], t.errors["title"] + end + end + + def test_validates_length_of_with_block + Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.", + :tokenizer => lambda {|str| str.scan(/\w+/) } + t = Topic.create!(:content => "this content should be long enough") + assert t.valid? + + t.content = "not long enough" + assert !t.valid? + 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_custom_too_long_using_quotes + repair_validations(Developer) do + Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes" + d = Developer.new + d.name = "Jeffrey" + assert !d.valid? + assert_equal ["This string contains 'single' and \"double\" quotes"], d.errors[:name] + end + end + + def test_validates_length_of_with_custom_too_short_using_quotes + repair_validations(Developer) do + Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes" + d = Developer.new + d.name = "Joe" + assert !d.valid? + assert_equal ["This string contains 'single' and \"double\" quotes"], d.errors[:name] + end + end + + def test_validates_length_of_with_custom_message_using_quotes + repair_validations(Developer) do + Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes" + d = Developer.new + d.name = "Joe" + assert !d.valid? + assert_equal ["This string contains 'single' and \"double\" quotes"], d.errors[:name] + end + end + + def test_validates_length_of_for_ruby_class + repair_validations(Person) do + Person.validates_length_of :karma, :minimum => 5 + + p = Person.new + p.karma = "Pix" + assert p.invalid? + + assert_equal ["is too short (minimum is 5 characters)"], p.errors[:karma] + + p.karma = "The Smiths" + assert p.valid? + end + end +end diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb new file mode 100644 index 0000000000..0af6eb69ce --- /dev/null +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -0,0 +1,179 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/developer' +require 'models/person' + +class NumericalityValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + NIL = [nil] + BLANK = ["", " ", " \t \r \n"] + BIGDECIMAL_STRINGS = %w(12345678901234567890.1234567890) # 30 significent digits + FLOAT_STRINGS = %w(0.0 +0.0 -0.0 10.0 10.5 -10.5 -0.0001 -090.1 90.1e1 -90.1e5 -90.1e-5 90e-5) + 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) } + JUNK = ["not a number", "42 not a number", "0xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"] + INFINITY = [1.0/0.0] + + def test_default_validates_numericality_of + Topic.validates_numericality_of :approved + invalid!(NIL + BLANK + JUNK) + valid!(FLOATS + INTEGERS + BIGDECIMAL + INFINITY) + end + + def test_validates_numericality_of_with_nil_allowed + Topic.validates_numericality_of :approved, :allow_nil => 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 + + invalid!(NIL + BLANK + JUNK + FLOATS + BIGDECIMAL + INFINITY) + valid!(INTEGERS) + end + + def test_validates_numericality_of_with_integer_only_and_nil_allowed + Topic.validates_numericality_of :approved, :only_integer => true, :allow_nil => true + + invalid!(JUNK + FLOATS + BIGDECIMAL + INFINITY) + valid!(NIL + BLANK + INTEGERS) + end + + def test_validates_numericality_with_greater_than + Topic.validates_numericality_of :approved, :greater_than => 10 + + invalid!([-10, 10], 'must be greater than 10') + valid!([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') + valid!([10]) + 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') + 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') + valid!([-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') + valid!([-10, 10]) + end + + def test_validates_numericality_with_odd + Topic.validates_numericality_of :approved, :odd => true + + 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') + valid!([-2, 2]) + end + + def test_validates_numericality_with_greater_than_less_than_and_even + Topic.validates_numericality_of :approved, :greater_than => 1, :less_than => 4, :even => true + + invalid!([1, 3, 4]) + valid!([2]) + end + + def test_validates_numericality_with_numeric_message + Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}" + topic = Topic.new("title" => "numeric test", "approved" => 10) + + assert !topic.valid? + assert_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_equal ["greater than 4"], topic.errors[:approved] + end + + def test_numericality_with_getter_method + repair_validations(Developer) do + Developer.validates_numericality_of( :salary ) + developer = Developer.new("name" => "michael", "salary" => nil) + developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end") + assert developer.valid? + end + end + + def test_numericality_with_allow_nil_and_getter_method + repair_validations(Developer) do + Developer.validates_numericality_of( :salary, :allow_nil => true) + developer = Developer.new("name" => "michael", "salary" => nil) + developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end") + assert developer.valid? + end + end + + def test_validates_numericality_of_for_ruby_class + repair_validations(Person) do + Person.validates_numericality_of :karma, :allow_nil => false + + p = Person.new + p.karma = "Pix" + assert p.invalid? + + assert_equal ["is not a number"], p.errors[:karma] + + p.karma = "1234" + assert p.valid? + end + end + + private + + def invalid!(values, error = nil) + with_each_topic_approved_value(values) do |topic, value| + assert !topic.valid?, "#{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 + + def valid!(values) + with_each_topic_approved_value(values) do |topic, value| + assert topic.valid?, "#{value.inspect} not accepted as a number" + 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 + end + end +end diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb new file mode 100644 index 0000000000..f6bed4903a --- /dev/null +++ b/activemodel/test/cases/validations/presence_validation_test.rb @@ -0,0 +1,57 @@ +# encoding: utf-8 +require 'cases/helper' +require 'cases/tests_database' + +require 'models/topic' +require 'models/developer' +require 'models/person' + +class PresenceValidationTest < ActiveModel::TestCase + include ActiveModel::TestsDatabase + include ActiveModel::ValidationsRepairHelper + + repair_validations(Topic) + + def test_validate_presences + Topic.validates_presence_of(:title, :content) + + t = Topic.create + assert !t.save + assert_equal ["can't be blank"], t.errors[:title] + assert_equal ["can't be blank"], t.errors[:content] + + t.title = "something" + t.content = " " + + assert !t.save + assert_equal ["can't be blank"], t.errors[:content] + + t.content = "like stuff" + + assert t.save + end + + def test_validates_presence_of_with_custom_message_using_quotes + repair_validations(Developer) do + Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes" + d = Developer.new + d.name = "Joe" + assert !d.valid? + assert_equal ["This string contains 'single' and \"double\" quotes"], d.errors[:non_existent] + end + end + + def test_validates_presence_of_for_ruby_class + repair_validations(Person) do + Person.validates_presence_of :karma + + p = Person.new + assert p.invalid? + + assert_equal ["can't be blank"], p.errors[:karma] + + p.karma = "Cold" + assert p.valid? + end + end +end |