Skip to content

Commit

Permalink
Change behavior of should_not allow_value
Browse files Browse the repository at this point in the history
Instead of asserting that any of the given value is an invalid value
(allowing good values to pass through), assert that *all* values are
invalid values (allowing good values not to pass through).

This means that this test which formerly passed now fails (assuming that
'good value' is a value that does not produce an invalid record):

    expect(record).not_to allow_value('good value', *bad_values)
  • Loading branch information
mcmire committed Feb 9, 2015
1 parent a4045a1 commit 19c38a6
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 15 deletions.
12 changes: 12 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 3.0.0

### Backward-incompatible changes

* The negative form of `allow_value` has been changed so that instead of
asserting that any of the given values is an invalid value (allowing good
values to pass through), assert that *all* values are invalid values (allowing
good values not to pass through). This means that this test which formerly
passed will now fail:

expect(record).not_to allow_value('good value', *bad_values)

# 2.8.0

### Deprecations
Expand Down
27 changes: 18 additions & 9 deletions lib/shoulda/matchers/active_model/allow_value_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,12 @@ def _after_setting_value(&callback)

def matches?(instance)
self.instance = instance
validator.record = instance
values_to_match.all? { |value| value_matches?(value) }
end

values_to_match.none? do |value|
validator.reset
self.value = value
set_attribute(value)
errors_match? || any_range_error_occurred?
end
def does_not_match?(instance)
self.instance = instance
values_to_match.all? { |value| !value_matches?(value) }
end

def failure_message
Expand All @@ -241,15 +239,26 @@ def description

protected

attr_reader :attribute_to_check_message_against
attr_accessor :values_to_match, :instance, :attribute_to_set, :value,
attr_reader :instance, :attribute_to_check_message_against
attr_accessor :values_to_match, :attribute_to_set, :value,
:matched_error, :after_setting_value_callback, :validator

def instance=(instance)
@instance = instance
validator.record = instance
end

def attribute_to_check_message_against=(attribute)
@attribute_to_check_message_against = attribute
validator.attribute = attribute
end

def value_matches?(value)
self.value = value
set_attribute(value)
!(errors_match? || any_range_error_occurred?)
end

def set_attribute(value)
set_attribute_ignoring_range_errors(value)
after_setting_value_callback.call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,24 +165,29 @@
less_than_or_equal_to: 50000
end.new
end

bad_values = [nil, '', 'abc', '0', '50001', '123456', []]

it 'allows a good value' do
it 'matches given a good value' do
expect(model).to allow_value('12345').for(:attr)
end

bad_values.each do |bad_value|
it "rejects a bad value (#{bad_value.inspect})" do
it 'does not match given a bad value' do
bad_values.each do |bad_value|
expect(model).not_to allow_value(bad_value).for(:attr)
end
end

it "rejects several bad values (#{bad_values.map(&:inspect).join(', ')})" do
it 'does not match given multiple bad values' do
expect(model).not_to allow_value(*bad_values).for(:attr)
end

it "rejects a mix of both good and bad values" do
expect(model).not_to allow_value('12345', *bad_values).for(:attr)
it "does not match given good values along with bad values" do
message = %{Expected errors when attr is set to "12345",\ngot no errors}

expect {
expect(model).not_to allow_value('12345', *bad_values).for(:attr)
}.to fail_with_message(message)
end
end

Expand Down

0 comments on commit 19c38a6

Please sign in to comment.