aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/validations_test.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases/validations_test.rb')
-rw-r--r--activerecord/test/cases/validations_test.rb219
1 files changed, 219 insertions, 0 deletions
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
new file mode 100644
index 0000000000..9a70934b7e
--- /dev/null
+++ b/activerecord/test/cases/validations_test.rb
@@ -0,0 +1,219 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "models/topic"
+require "models/reply"
+require "models/developer"
+require "models/computer"
+require "models/parrot"
+require "models/company"
+require "models/price_estimate"
+
+class ValidationsTest < ActiveRecord::TestCase
+ fixtures :topics, :developers
+
+ # Most of the tests mess with the validations of Topic, so lets repair it all the time.
+ # Other classes we mess with will be dealt with in the specific tests
+ repair_validations(Topic)
+
+ def test_valid_uses_create_context_when_new
+ r = WrongReply.new
+ r.title = "Wrong Create"
+ assert_not_predicate r, :valid?
+ assert r.errors[:title].any?, "A reply with a bad title should mark that attribute as invalid"
+ assert_equal ["is Wrong Create"], r.errors[:title], "A reply with a bad content should contain an error"
+ end
+
+ def test_valid_uses_update_context_when_persisted
+ r = WrongReply.new
+ r.title = "Bad"
+ r.content = "Good"
+ assert r.save, "First validation should be successful"
+
+ r.title = "Wrong Update"
+ assert_not r.valid?, "Second validation should fail"
+
+ assert r.errors[:title].any?, "A reply with a bad title should mark that attribute as invalid"
+ assert_equal ["is Wrong Update"], r.errors[:title], "A reply with a bad content should contain an error"
+ end
+
+ def test_valid_using_special_context
+ r = WrongReply.new(title: "Valid title")
+ assert_not r.valid?(:special_case)
+ assert_equal "Invalid", r.errors[:author_name].join
+
+ r.author_name = "secret"
+ r.content = "Good"
+ assert r.valid?(:special_case)
+
+ r.author_name = nil
+ assert_not r.valid?(:special_case)
+ assert_equal "Invalid", r.errors[:author_name].join
+
+ r.author_name = "secret"
+ assert r.valid?(:special_case)
+ end
+
+ def test_invalid_using_multiple_contexts
+ r = WrongReply.new(title: "Wrong Create")
+ assert r.invalid?([:special_case, :create])
+ assert_equal "Invalid", r.errors[:author_name].join
+ assert_equal "is Wrong Create", r.errors[:title].join
+ end
+
+ def test_validate
+ r = WrongReply.new
+
+ r.validate
+ assert_empty r.errors[:author_name]
+
+ r.validate(:special_case)
+ assert_not_empty r.errors[:author_name]
+
+ r.author_name = "secret"
+
+ r.validate(:special_case)
+ assert_empty r.errors[:author_name]
+ end
+
+ def test_invalid_record_exception
+ assert_raise(ActiveRecord::RecordInvalid) { WrongReply.create! }
+ assert_raise(ActiveRecord::RecordInvalid) { WrongReply.new.save! }
+
+ r = WrongReply.new
+ invalid = assert_raise ActiveRecord::RecordInvalid do
+ r.save!
+ end
+ assert_equal r, invalid.record
+ end
+
+ def test_validate_with_bang
+ assert_raise(ActiveRecord::RecordInvalid) do
+ WrongReply.new.validate!
+ end
+ end
+
+ def test_validate_with_bang_and_context
+ assert_raise(ActiveRecord::RecordInvalid) do
+ WrongReply.new.validate!(:special_case)
+ end
+ r = WrongReply.new(title: "Valid title", author_name: "secret", content: "Good")
+ assert r.validate!(:special_case)
+ end
+
+ def test_exception_on_create_bang_many
+ assert_raise(ActiveRecord::RecordInvalid) do
+ WrongReply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }])
+ end
+ end
+
+ def test_exception_on_create_bang_with_block
+ assert_raise(ActiveRecord::RecordInvalid) do
+ WrongReply.create!("title" => "OK") do |r|
+ r.content = nil
+ end
+ end
+ end
+
+ def test_exception_on_create_bang_many_with_block
+ assert_raise(ActiveRecord::RecordInvalid) do
+ WrongReply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r|
+ r.content = nil
+ end
+ end
+ end
+
+ def test_save_without_validation
+ reply = WrongReply.new
+ assert_not reply.save
+ assert reply.save(validate: false)
+ end
+
+ def test_validates_acceptance_of_with_non_existent_table
+ Object.const_set :IncorporealModel, Class.new(ActiveRecord::Base)
+
+ assert_nothing_raised do
+ IncorporealModel.validates_acceptance_of(:incorporeal_column)
+ end
+ end
+
+ def test_throw_away_typing
+ d = Developer.new("name" => "David", "salary" => "100,000")
+ assert_not_predicate d, :valid?
+ assert_equal 100, d.salary
+ assert_equal "100,000", d.salary_before_type_cast
+ end
+
+ def test_validates_acceptance_of_with_undefined_attribute_methods
+ Topic.validates_acceptance_of(:approved)
+ topic = Topic.new(approved: true)
+ Topic.undefine_attribute_methods
+ assert topic.approved
+ end
+
+ def test_validates_acceptance_of_as_database_column
+ Topic.validates_acceptance_of(:approved)
+ topic = Topic.create("approved" => true)
+ assert topic["approved"]
+ end
+
+ def test_validators
+ assert_equal 1, Parrot.validators.size
+ assert_equal 1, Company.validators.size
+ assert_equal 1, Parrot.validators_on(:name).size
+ assert_equal 1, Company.validators_on(:name).size
+ end
+
+ def test_numericality_validation_with_mutation
+ klass = Class.new(Topic) do
+ attribute :wibble, :string
+ validates_numericality_of :wibble, only_integer: true
+ end
+
+ topic = klass.new(wibble: "123-4567")
+ topic.wibble.gsub!("-", "")
+
+ assert_predicate topic, :valid?
+ end
+
+ def test_numericality_validation_checks_against_raw_value
+ klass = Class.new(Topic) do
+ def self.model_name
+ ActiveModel::Name.new(self, nil, "Topic")
+ end
+ attribute :wibble, :decimal, scale: 2, precision: 9
+ validates_numericality_of :wibble, greater_than_or_equal_to: BigDecimal("97.18")
+ end
+
+ assert_not_predicate klass.new(wibble: "97.179"), :valid?
+ assert_not_predicate klass.new(wibble: 97.179), :valid?
+ assert_not_predicate klass.new(wibble: BigDecimal("97.179")), :valid?
+ end
+
+ def test_numericality_validator_wont_be_affected_by_custom_getter
+ price_estimate = PriceEstimate.new(price: 50)
+
+ assert_equal "$50.00", price_estimate.price
+ assert_equal 50, price_estimate.price_before_type_cast
+ assert_equal 50, price_estimate.read_attribute(:price)
+
+ assert_predicate price_estimate, :price_came_from_user?
+ assert_predicate price_estimate, :valid?
+
+ price_estimate.save!
+
+ assert_not_predicate price_estimate, :price_came_from_user?
+ assert_predicate price_estimate, :valid?
+ end
+
+ def test_acceptance_validator_doesnt_require_db_connection
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = "posts"
+ end
+ klass.reset_column_information
+
+ assert_no_queries do
+ klass.validates_acceptance_of(:foo)
+ end
+ end
+end