Refactor inclusion & exclusion matchers
This is part of a collection of commits that aim to improve failure messages across the board, in order to make matchers easier to debug when something goes wrong. * Make the description of the matcher more readable. * Add boolean methods to check whether `allow_nil` or `allow_blank` have been specified, to conform to the interface that ValidationMatcher introduces. * Fix or fill in tests involving failure messages and descriptions to match these changes and recent changes to ValidationMatcher and allow_value.
This commit is contained in:
parent
cecccc6836
commit
2e35b3730e
|
@ -122,9 +122,9 @@ module Shoulda
|
|||
class ValidateExclusionOfMatcher < ValidationMatcher
|
||||
def initialize(attribute)
|
||||
super(attribute)
|
||||
@expected_message = :exclusion
|
||||
@array = nil
|
||||
@range = nil
|
||||
@expected_message = nil
|
||||
end
|
||||
|
||||
def in_array(array)
|
||||
|
@ -139,13 +139,23 @@ module Shoulda
|
|||
self
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
@expected_message = message if message
|
||||
self
|
||||
end
|
||||
def simple_description
|
||||
if @range
|
||||
"validate that :#{@attribute} lies outside the range #{@range.inspect}"
|
||||
else
|
||||
description = "validate that :#{@attribute}"
|
||||
|
||||
def description
|
||||
"ensure exclusion of #{@attribute} in #{inspect_message}"
|
||||
if @array.many?
|
||||
description << " is neither " + @array.map(&:inspect).to_sentence(
|
||||
two_words_connector: " nor ",
|
||||
last_word_connector: ", nor "
|
||||
)
|
||||
else
|
||||
description << " is not #{@array.first.inspect}"
|
||||
end
|
||||
|
||||
description
|
||||
end
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
|
@ -165,28 +175,24 @@ module Shoulda
|
|||
|
||||
def disallows_all_values_in_array?
|
||||
@array.all? do |value|
|
||||
disallows_value_of(value, expected_message)
|
||||
disallows_value_of(value, @expected_message)
|
||||
end
|
||||
end
|
||||
|
||||
def allows_lower_value
|
||||
@minimum == 0 || allows_value_of(@minimum - 1, expected_message)
|
||||
@minimum == 0 || allows_value_of(@minimum - 1, @expected_message)
|
||||
end
|
||||
|
||||
def allows_higher_value
|
||||
allows_value_of(@maximum + 1, expected_message)
|
||||
allows_value_of(@maximum + 1, @expected_message)
|
||||
end
|
||||
|
||||
def disallows_minimum_value
|
||||
disallows_value_of(@minimum, expected_message)
|
||||
disallows_value_of(@minimum, @expected_message)
|
||||
end
|
||||
|
||||
def disallows_maximum_value
|
||||
disallows_value_of(@maximum, expected_message)
|
||||
end
|
||||
|
||||
def expected_message
|
||||
@expected_message || :exclusion
|
||||
disallows_value_of(@maximum, @expected_message)
|
||||
end
|
||||
|
||||
def inspect_message
|
||||
|
|
|
@ -310,31 +310,63 @@ EOT
|
|||
self
|
||||
end
|
||||
|
||||
def expects_to_allow_blank?
|
||||
@options[:allow_blank]
|
||||
end
|
||||
|
||||
def allow_nil(allow_nil = true)
|
||||
@options[:allow_nil] = allow_nil
|
||||
self
|
||||
end
|
||||
|
||||
def expects_to_allow_nil?
|
||||
@options[:allow_nil]
|
||||
end
|
||||
|
||||
def with_message(message)
|
||||
if message
|
||||
@expects_custom_validation_message = true
|
||||
@low_message = message
|
||||
@high_message = message
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def with_low_message(message)
|
||||
@low_message = message if message
|
||||
if message
|
||||
@expects_custom_validation_message = true
|
||||
@low_message = message
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def with_high_message(message)
|
||||
@high_message = message if message
|
||||
if message
|
||||
@high_message = message
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
"ensure inclusion of #{@attribute} in #{inspect_message}"
|
||||
def simple_description
|
||||
if @range
|
||||
"validate that :#{@attribute} lies inside the range #{@range.inspect}"
|
||||
else
|
||||
description = "validate that :#{@attribute}"
|
||||
|
||||
if @array.many?
|
||||
description << " is either " + @array.map(&:inspect).to_sentence(
|
||||
two_words_connector: " or ",
|
||||
last_word_connector: ", or "
|
||||
)
|
||||
else
|
||||
description << " is #{@array.first.inspect}"
|
||||
end
|
||||
|
||||
description
|
||||
end
|
||||
end
|
||||
|
||||
def matches?(subject)
|
||||
|
@ -398,7 +430,9 @@ EOT
|
|||
end
|
||||
|
||||
def disallows_lower_value
|
||||
@minimum == 0 || disallows_value_of(@minimum - 1, @low_message)
|
||||
@minimum.nil? ||
|
||||
@minimum == 0 ||
|
||||
disallows_value_of(@minimum - 1, @low_message)
|
||||
end
|
||||
|
||||
def disallows_higher_value
|
||||
|
|
|
@ -57,6 +57,14 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
|
|||
expect(model).to validate_exclusion_of(:attr).in_range(2...5).
|
||||
with_message(/should be out of this range/)
|
||||
end
|
||||
|
||||
it 'has correct description' do
|
||||
matcher = validate_exclusion_of(:attr).in_range(1..10)
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr lies outside the range 1..10'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'an attribute which must be excluded from an array' do
|
||||
|
@ -75,9 +83,31 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
|
|||
not_to validate_exclusion_of(:attr).in_array(%w(cat dog))
|
||||
end
|
||||
|
||||
it 'has correct description' do
|
||||
expect(validate_exclusion_of(:attr).in_array([true, 'dog']).description).
|
||||
to eq 'ensure exclusion of attr in [true, "dog"]'
|
||||
context 'when there is one value' do
|
||||
it 'has correct description' do
|
||||
expect(validate_exclusion_of(:attr).in_array([true]).description).
|
||||
to eq 'validate that :attr is not true'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are two values' do
|
||||
it 'has correct description' do
|
||||
matcher = validate_exclusion_of(:attr).in_array([true, 'dog'])
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr is neither true nor "dog"'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are three or more values' do
|
||||
it 'has correct description' do
|
||||
matcher = validate_exclusion_of(:attr).in_array([true, 'dog', 'cat'])
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr is neither true, "dog", nor "cat"'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def validating_exclusion(options)
|
||||
|
|
|
@ -679,6 +679,50 @@ describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :mode
|
|||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
context 'given an array of values' do
|
||||
context 'when there is one value' do
|
||||
it 'returns the correct string' do
|
||||
matcher = validate_inclusion_of(:attr).in_array([true])
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr is true'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are two values' do
|
||||
it 'returns the correct string' do
|
||||
matcher = validate_inclusion_of(:attr).in_array([true, 'dog'])
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr is either true or "dog"'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are three or more values' do
|
||||
it 'returns the correct string' do
|
||||
matcher = validate_inclusion_of(:attr).in_array([true, 'dog', 'cat'])
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr is either true, "dog", or "cat"'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'given a range of values' do
|
||||
it 'returns the correct string' do
|
||||
matcher = validate_inclusion_of(:attr).in_range(1..10)
|
||||
|
||||
expect(matcher.description).to eq(
|
||||
'validate that :attr lies inside the range 1..10'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def object_builder_class
|
||||
@_object_builder_class ||= Struct.new(:attribute, :object, :validation_options)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue