Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to numericality: :other_than #1282

Merged
merged 1 commit into from Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -9,7 +9,8 @@ class ComparisonMatcher < ValidationMatcher
:>= => :greater_than_or_equal_to,
:< => :less_than,
:<= => :less_than_or_equal_to,
:== => :equal_to
:== => :equal_to,
:!= => :other_than,
}

def initialize(numericality_matcher, value, operator)
Expand Down Expand Up @@ -125,6 +126,8 @@ def assertions
[true, false, false]
when :<=
[true, true, false]
when :!=
[true, false, true]
end
end

Expand All @@ -146,6 +149,7 @@ def comparison_expectation
when :== then "equal to"
when :< then "less than"
when :<= then "less than or equal to"
when :!= then 'other than'
end
end
end
Expand Down
Expand Up @@ -204,6 +204,33 @@ module ActiveModel
# is_greater_than(21)
# end
#
# ##### is_other_than
#
# Use `is_other_than` to test usage of the `:other_than` option.
# This asserts that the attribute can take a number which is not equal to
# the given value.
#
# class Person
# include ActiveModel::Model
# attr_accessor :legal_age
#
# validates_numericality_of :legal_age, other_than: 21
# end
#
# # RSpec
# RSpec.describe Person, type: :model do
# it do
# should validate_numericality_of(:legal_age).
# is_other_than(21)
# end
# end
#
# # Minitest (Shoulda)
# class PersonTest < ActiveSupport::TestCase
# should validate_numericality_of(:legal_age).
# is_other_than(21)
# end
#
# ##### even
#
# Use `even` to test usage of the `:even` option. This asserts that the
Expand Down Expand Up @@ -395,6 +422,11 @@ def is_less_than_or_equal_to(value)
self
end

def is_other_than(value)
prepare_submatcher(comparison_matcher_for(value, :!=).for(@attribute))
self
end

def with_message(message)
@expects_custom_validation_message = true
@expected_message = message
Expand Down
Expand Up @@ -39,6 +39,13 @@ def all_qualifiers
validation_name: :equal_to,
validation_value: 1,
},
{
category: :comparison,
name: :is_other_than,
argument: 1,
validation_name: :other_than,
validation_value: 1,
},
{
category: :cardinality,
name: :odd,
Expand Down Expand Up @@ -991,6 +998,125 @@ def configure_validation_matcher(matcher)
end
end

context 'qualified with is_other_than' do
context 'and validating with other_than' do
it 'accepts' do
record = build_record_validating_numericality(other_than: 18)
expect(record).to validate_numericality.is_other_than(18)
end

it 'rejects when used in the negative' do
record = build_record_validating_numericality(other_than: 18)

assertion = lambda do
expect(record).not_to validate_numericality.is_other_than(18)
end

expect(&assertion).to fail_with_message(<<~MESSAGE)
Expected Example not to validate that :attr looks like a number other
than 18, but this could not be proved.
After setting :attr to ‹"abcd"›, the matcher expected the Example to
be valid, but it was invalid instead, producing these validation
errors:

* attr: ["is not a number"]
MESSAGE
end

it_supports(
'ignoring_interference_by_writer',
tests: {
reject_if_qualified_but_changing_value_interferes: {
model_name: 'Example',
attribute_name: :attr,
changing_values_with: :next_value,
expected_message: <<-MESSAGE.strip
Expected Example to validate that :attr looks like a number other than
18, but this could not be proved.
After setting :attr to ‹"18"› -- which was read back as ‹"19"› -- the
matcher expected the Example to be invalid, but it was valid instead.

As indicated in the message above, :attr seems to be changing certain
values as they are set, and this could have something to do with why
this test is failing. If you've overridden the writer method for this
attribute, then you may need to change it to make this test pass, or
do something else entirely.
MESSAGE
}
}
) do
def validation_matcher_scenario_args
super.deep_merge(validation_options: { other_than: 18 })
end

def configure_validation_matcher(matcher)
matcher.is_other_than(18)
end
end

context 'when the attribute is a virtual attribute in an ActiveRecord model' do
it 'accepts' do
record = build_record_validating_numericality_of_virtual_attribute(
other_than: 18,
)
expect(record).to validate_numericality.is_other_than(18)
end
end

context 'when the column is an integer column' do
it 'accepts (and does not raise an error)' do
record = build_record_validating_numericality(
column_type: :integer,
other_than: 18
)

expect(record).to validate_numericality.is_other_than(18)
end
end

context 'when the column is a float column' do
it 'accepts (and does not raise an error)' do
record = build_record_validating_numericality(
column_type: :float,
other_than: 18
)

expect(record).to validate_numericality.is_other_than(18)
end
end

context 'when the column is a decimal column' do
it 'accepts (and does not raise an error)' do
record = build_record_validating_numericality(
column_type: :decimal,
other_than: 18,
)

expect(record).to validate_numericality.is_other_than(18)
end
end
end

context 'and not validating with other_than' do
it 'rejects since it does not disallow numbers that are not the value' do
record = build_record_validating_numericality

assertion = lambda do
expect(record).to validate_numericality.is_other_than(18)
end

message = <<-MESSAGE
Expected Example to validate that :attr looks like a number other than
18, but this could not be proved.
After setting :attr to ‹"18"›, the matcher expected the Example to be
invalid, but it was valid instead.
MESSAGE

expect(&assertion).to fail_with_message(message)
end
end
end

context 'qualified with is_greater_than_or_equal to' do
context 'validating with greater_than_or_equal_to' do
it 'accepts' do
Expand Down