1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/test/cases/validations_test.rb
Ryuta Kamizono 2fece9036d Fix numericality validator not to be affected by custom getter
Since fe9547b6, numericality validator would parse raw value only when a
value came from user to work type casting to a value from database.

But that was caused a regression that the validator would work against
getter value instead of parsed raw value, a getter is sometimes
customized by people. #33550

There we never guarantees that the value before type cast was going to
the used in this validation (actually here is only place that getter
value might not be used), but we should not change the behavior unless
there is some particular reason.

The purpose of fe9547b6 is to work type casting to a value from
database. We could achieve the purpose by using `read_attribute`,
without using getter value.

Fixes #33550.
2018-08-13 23:28:46 +09:00

212 lines
6.2 KiB
Ruby

# 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_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