Skip to content

Commit

Permalink
Added strict option to Numericality matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam89 authored and mcmire committed Mar 29, 2015
1 parent 0318238 commit 4e4c546
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 13 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
`params` hash. Although we don't require you to use this qualifier, we do
recommend it, as it's a more precise check. ([#675])

* Add `strict` qualifier to `validate_numericality_of`. ([#620])

[#402]: https://github.com/thoughtbot/shoulda-matchers/pull/402
[#587]: https://github.com/thoughtbot/shoulda-matchers/pull/587
[#662]: https://github.com/thoughtbot/shoulda-matchers/pull/662
Expand All @@ -75,6 +77,7 @@
[#648]: https://github.com/thoughtbot/shoulda-matchers/pull/648
[#675]: https://github.com/thoughtbot/shoulda-matchers/pull/675
[#677]: https://github.com/thoughtbot/shoulda-matchers/pull/677
[#620]: https://github.com/thoughtbot/shoulda-matchers/pull/620

# 2.8.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def with_message(message)
self
end

def strict
@disallow_value_matcher.strict
self
end

def allowed_type
raise NotImplementedError
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,16 @@ def initialize(attribute)
@attribute = attribute
@submatchers = []
@diff_to_compare = DEFAULT_DIFF_TO_COMPARE
@strict = false
add_disallow_value_matcher
end

def strict
@submatchers.each(&:strict)
@strict = true
self
end

def only_integer
prepare_submatcher(
NumericalityMatchers::OnlyIntegerMatcher.new(@attribute)
Expand Down Expand Up @@ -383,7 +390,18 @@ def matches?(subject)
end

def description
"only allow #{allowed_types} for #{@attribute}#{comparison_descriptions}"
description_parts = ["only allow #{allowed_types} for #{@attribute}"]

if comparison_descriptions.present?
description_parts << comparison_descriptions
end

if @strict
description_parts.insert(1, 'strictly')
description_parts.join(', ')
else
description_parts.join(' ')
end
end

def failure_message
Expand Down Expand Up @@ -455,7 +473,7 @@ def submatcher_allowed_types

def comparison_descriptions
description_array = submatcher_comparison_descriptions
description_array.empty? ? '' : ' which are ' + submatcher_comparison_descriptions.join(' and ')
description_array.empty? ? '' : 'which are ' + submatcher_comparison_descriptions.join(' and ')
end

def submatcher_comparison_descriptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,40 @@

it_behaves_like 'a numerical submatcher'

shared_examples_for 'strict qualifier' do
def validation_qualifier
matcher_qualifier.to_s.gsub(/^is_/, '').to_sym
end

context 'asserting strict validation when validating strictly' do
it 'accepts' do
record = instance_with_validations(
validation_qualifier => 1,
strict: true
)
expect(record).to matcher.__send__(matcher_qualifier, 1).strict
end
end

context 'asserting non-strict validation when validating strictly' do
it 'rejects' do
pending 'This needs to be fixed'
record = instance_with_validations(
validation_qualifier => 1,
strict: true
)
expect(record).not_to matcher.__send__(matcher_qualifier, 1)
end
end

context 'asserting strict validation when not validating strictly' do
it 'rejects' do
record = instance_with_validations(validation_qualifier => 1)
expect(record).not_to matcher.__send__(matcher_qualifier, 1).strict
end
end
end

context 'when initialized without correct numerical matcher' do
it 'raises an argument error' do
fake_matcher = matcher
Expand All @@ -18,6 +52,12 @@ class << fake_matcher
end

context 'is_greater_than' do
include_examples 'strict qualifier' do
def matcher_qualifier
:is_greater_than
end
end

it do
expect(instance_with_validations(greater_than: 2))
.to matcher.is_greater_than(2)
Expand All @@ -38,7 +78,13 @@ class << fake_matcher
end
end

context 'greater_than_or_equal_to' do
context 'is_greater_than_or_equal_to' do
include_examples 'strict qualifier' do
def matcher_qualifier
:is_greater_than_or_equal_to
end
end

it do
expect(instance_with_validations(greater_than_or_equal_to: 2))
.to matcher.is_greater_than_or_equal_to(2)
Expand All @@ -60,7 +106,13 @@ class << fake_matcher
end
end

context 'less_than' do
context 'is_less_than' do
include_examples 'strict qualifier' do
def matcher_qualifier
:is_less_than
end
end

it do
expect(instance_with_validations(less_than: 2))
.to matcher.is_less_than(2)
Expand All @@ -82,7 +134,13 @@ class << fake_matcher
end
end

context 'less_than_or_equal_to' do
context 'is_less_than_or_equal_to' do
include_examples 'strict qualifier' do
def matcher_qualifier
:is_less_than_or_equal_to
end
end

it do
expect(instance_with_validations(less_than_or_equal_to: 2))
.to matcher.is_less_than_or_equal_to(2)
Expand All @@ -105,6 +163,12 @@ class << fake_matcher
end

context 'is_equal_to' do
include_examples 'strict qualifier' do
def matcher_qualifier
:is_equal_to
end
end

it do
expect(instance_with_validations(equal_to: 0))
.to matcher.is_equal_to(0)
Expand Down Expand Up @@ -150,19 +214,27 @@ class << fake_matcher
end
end

def model_with_validations(options = {})
define_model :example, attribute_name => :string do |model|
model.validates_numericality_of(attribute_name, options)
model.attr_accessible(attribute_name)
end
end

def instance_with_validations(options = {})
define_model :example, attr: :string do
validates_numericality_of :attr, options
attr_accessible :attr
end.new
model_with_validations(options).new(attribute_name => '1')
end

def instance_without_validations
define_model :example, attr: :string do
attr_accessible :attr
define_model :example, attribute_name => :string do |model|
model.attr_accessible(attribute_name)
end.new
end

def attribute_name
:attr
end

def matcher
validate_numericality_of(:attr)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@
end
end

context 'asserting strict validation when validating strictly' do
it 'accepts' do
expect(validating_even_number(strict: true)).to subject.strict
end
end

context 'asserting non-strict validation when validating strictly' do
it 'rejects' do
pending 'This needs to be fixed'
expect(validating_even_number(strict: true)).not_to subject
end
end

context 'asserting strict validation when not validating strictly' do
it 'rejects' do
expect(validating_even_number).not_to subject.strict
end
end

def validating_even_number(options = {})
define_model :example, attr: :string do
Expand All @@ -56,4 +74,4 @@ def not_validating_even_number
define_model(:example, attr: :string).new
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@
end
end

context 'asserting strict validation when validating strictly' do
it 'accepts' do
expect(validating_odd_number(strict: true)).to subject.strict
end
end

context 'asserting non-strict validation when validating strictly' do
it 'rejects' do
pending 'This needs to be fixed'
expect(validating_odd_number(strict: true)).not_to subject
end
end

context 'asserting strict validation when not validating strictly' do
it 'rejects' do
expect(validating_odd_number).not_to subject.strict
end
end

def validating_odd_number(options = {})
define_model :example, attr: :string do
Expand All @@ -56,4 +74,4 @@ def not_validating_odd_number
define_model(:example, attr: :string).new
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@
end
end

context 'asserting strict validation when validating strictly' do
it 'accepts' do
expect(validating_only_integer(strict: true)).to subject.strict
end
end

context 'asserting non-strict validation when validating strictly' do
it 'rejects' do
pending 'This needs to be fixed'
expect(validating_only_integer(strict: true)).not_to subject
end
end

context 'asserting strict validation when not validating strictly' do
it 'rejects' do
expect(validating_only_integer).not_to subject.strict
end
end

def validating_only_integer(options = {})
define_model :example, attr: :string do
validates_numericality_of :attr, { only_integer: true }.merge(options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,27 @@ def default_validation_values
end
end

context 'qualified with strict' do
context 'and validating strictly' do
it 'accepts' do
record = build_record_validating_numericality(strict: true)
expect(record).to validate_numericality.strict
end
end

context 'and not validating strictly' do
it 'rejects since ActiveModel::StrictValidationFailed is never raised' do
record = build_record_validating_numericality(attribute_name: :attr)
assertion = lambda do
expect(record).to validate_numericality_of(:attr).strict
end
expect(&assertion).to fail_with_message_including(
'Expected exception to include "Attr is not a number"'
)
end
end
end

context 'with combinations of qualifiers together' do
all_qualifier_combinations.each do |combination|
if combination.size > 1
Expand Down Expand Up @@ -717,6 +738,24 @@ def set_attr!; self.attr = 5 end
)
end
end

context 'qualified with strict' do
it 'describes that it relies upon a strict validation' do
matcher = validate_numericality_of(:attr).strict
expect(matcher.description).to eq(
'only allow numbers for attr, strictly'
)
end

context 'and qualified with a comparison qualifier' do
it 'places the comparison description after "strictly"' do
matcher = validate_numericality_of(:attr).is_less_than(18).strict
expect(matcher.description).to eq(
'only allow numbers for attr, strictly, which are less than 18'
)
end
end
end
end

def build_validation_options(args)
Expand All @@ -739,6 +778,7 @@ def apply_qualifiers!(args)
end

def define_model_validating_numericality(options = {})
attribute_name = options.fetch(:attribute_name) { self.attribute_name }
define_model 'Example', attribute_name => :string do |model|
model.validates_numericality_of(attribute_name, options)
end
Expand Down

0 comments on commit 4e4c546

Please sign in to comment.