Tighten CouldNotSetAttributeError restriction

Why:

* Previously, `allow_value` would raise a CouldNotSetAttributeError
  if the value being set didn't match the value the attribute had after
  being set, but only if the attribute was being changed from nil to
  non-nil or non-nil to nil.
* It turns out it doesn't matter which value you're trying to set the
  attribute to -- if the attribute rejects that change it's confusing
  either way. (In fact, I was recently bit by a case in which I was
  trying to validate numericality of an attribute, where the writer
  method for that attribute was overridden to ensure that the attribute
  always stored a number and never contained non-number characters.
  This ended up making the numericality validation useless, of
  course -- but it caused confusion because the test acted in a way
  I didn't expect.)

To satisfy the above:

* `allow_value` now raises a CouldNotSetAttributeError if the attribute
  rejects the value being set in *any* way.
* However, add a `ignoring_interference_by_writer` qualifier so that
  it is possible to manually override this behavior.
* Fix tests that are failing now because of this new change:
  * Fix tests for allow_value matcher
  * Fix tests for numericality matcher
  * Remove tests for numericality matcher + integer column
    * An integer column will typecast any non-integer value to an
      integer.
    * Because of the typecasting, our tests for the numericality matcher
      against an integer column don't quite work, because we can't
      really test what happens when the attribute is set to a
      non-integer value. Now that `allow_value` is more strict, we're
      getting a CouldNotSetAttributeError when attempting to do so.
    * The tests mentioned were originally added to ensure that we are
      handling RangeErrors that ActiveRecord used to emit. This doesn't
      happen anymore, so the tests aren't necessary anymore either.
  * Fix tests for acceptance matcher
  * Fix tests for absence matcher
This commit is contained in:
Elliot Winkler 2015-09-25 23:10:00 -06:00
parent e6e81b9de0
commit 9d9dc4e6b9
12 changed files with 351 additions and 253 deletions

98
NEWS.md
View File

@ -53,24 +53,102 @@
* There are two changes to `allow_value`:
* The negative form of the matcher has been changed so that instead of
* 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)
``` ruby
expect(record).not_to allow_value('good value', *bad_values)
```
([19ce8a6])
* The matcher may raise an error if the attribute in question contains
custom logic to ignore certain values, resulting in a discrepancy between
the value you provide and the value that the attribute is actually set to.
Specifically, if the attribute cannot be changed from a non-nil value to a
nil value, or vice versa, then you'll get a CouldNotSetAttributeError. The
current behavior (which is to permit this) is misleading, as the test that
you're writing under the hood by using `allow_value` could be different from
the test that actually ends up getting run. ([eaaa2d8])
* `allow_value` now raises a CouldNotSetAttributeError if in setting the
attribute, the value of the attribute from reading the attribute back is
different from the one used to set it.
This would happen if the writer method for that attribute has custom logic
to ignore certain incoming values or change them in any way. Here are three
examples we've seen:
* You're attempting to assert that an attribute should not allow nil, yet
the attribute's writer method contains a conditional to do nothing if
the attribute is set to nil:
``` ruby
class Foo
include ActiveModel::Model
attr_reader :bar
def bar=(value)
return if value.nil?
@bar = value
end
end
describe Foo do
it do
foo = Foo.new
foo.bar = "baz"
# This will raise a CouldNotSetAttributeError since `foo.bar` is now "123"
expect(foo).not_to allow_value(nil).for(:bar)
end
end
```
* You're attempting to assert that an numeric attribute should not allow a
string that contains non-numeric characters, yet the writer method for
that attribute strips out non-numeric characters:
``` ruby
class Foo
include ActiveModel::Model
attr_reader :bar
def bar=(value)
@bar = value.gsub(/\D+/, '')
end
end
describe Foo do
it do
foo = Foo.new
# This will raise a CouldNotSetAttributeError since `foo.bar` is now "123"
expect(foo).not_to allow_value("abc123").for(:bar)
end
end
```
* You're passing a value to `allow_value` that the model typecasts into
another value:
``` ruby
describe Foo do
# Assume that `attr` is a string
# This will raise a CouldNotSetAttributeError since `attr` typecasts `[]` to `"[]"`
it { should_not allow_value([]).for(:attr) }
end
```
With all of these failing examples, why are we making this change? We want
to guard you (as the developer) from writing a test that you think acts one
way but actually acts a different way, as this could lead to a confusing
false positive or negative.
If you understand the problem and wish to override this behavior so that
you do not get a CouldNotSetAttributeError, you can add the
`ignoring_interference_by_writer` qualifier like so. Note that this will not
always cause the test to pass.
``` ruby
it { should_not allow_value([]).for(:attr).ignoring_interference_by_writer }
```
([eaaa2d8])
* `validate_uniqueness_of` is now properly case-insensitive by default, to match
the default behavior of the validation itself. This is a backward-incompatible

View File

@ -226,6 +226,7 @@ module Shoulda
self.options = {}
self.after_setting_value_callback = -> {}
self.validator = Validator.new
@ignoring_interference_by_writer = false
end
def for(attribute)
@ -255,6 +256,11 @@ module Shoulda
self
end
def ignoring_interference_by_writer
@ignoring_interference_by_writer = true
self
end
def _after_setting_value(&callback)
self.after_setting_value_callback = callback
end
@ -297,6 +303,10 @@ module Shoulda
validator.attribute = attribute
end
def ignoring_interference_by_writer?
@ignoring_interference_by_writer
end
def value_matches?(value)
self.value = value
set_attribute(value)
@ -305,14 +315,14 @@ module Shoulda
def set_attribute(value)
instance.__send__("#{attribute_to_set}=", value)
ensure_that_attribute_has_been_changed_to_or_from_nil!(value)
ensure_that_attribute_was_set!(value)
after_setting_value_callback.call
end
def ensure_that_attribute_has_been_changed_to_or_from_nil!(expected_value)
def ensure_that_attribute_was_set!(expected_value)
actual_value = instance.__send__(attribute_to_set)
if expected_value.nil? != actual_value.nil?
if expected_value != actual_value && !ignoring_interference_by_writer?
raise CouldNotSetAttributeError.create(
instance.class,
attribute_to_set,

View File

@ -31,6 +31,11 @@ module Shoulda
self
end
def ignoring_interference_by_writer
@allow_matcher.ignoring_interference_by_writer
self
end
def failure_message
@allow_matcher.failure_message_when_negated
end

View File

@ -80,7 +80,11 @@ module Shoulda
def submatchers
@_submatchers ||=
comparison_combos.map do |diff, submatcher_method_name|
matcher = __send__(submatcher_method_name, @value + diff, nil)
matcher = __send__(
submatcher_method_name,
(@value + diff).to_s,
nil
)
matcher.with_message(@message, values: { count: @value })
matcher
end

View File

@ -8,9 +8,10 @@ module Shoulda
def initialize(attribute, options = {})
@attribute = attribute
@disallow_value_matcher = DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE).
for(@attribute).
with_message(:even)
@disallow_value_matcher =
DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE.to_s).
for(@attribute).
with_message(:even)
end
def allowed_type

View File

@ -8,9 +8,10 @@ module Shoulda
def initialize(attribute, options = {})
@attribute = attribute
@disallow_value_matcher = DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE).
for(@attribute).
with_message(:odd)
@disallow_value_matcher =
DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE.to_s).
for(@attribute).
with_message(:odd)
end
def allowed_type

View File

@ -7,7 +7,8 @@ module Shoulda
NON_INTEGER_VALUE = 0.1
def initialize(attribute)
@attribute = attribute
@disallow_value_matcher = DisallowValueMatcher.new(NON_INTEGER_VALUE).
@disallow_value_matcher =
DisallowValueMatcher.new(NON_INTEGER_VALUE.to_s).
for(attribute).
with_message(:not_an_integer)
end

View File

@ -86,6 +86,7 @@ module Shoulda
def matches?(subject)
super(subject)
@expected_message ||= :present
disallows_value_of(value, @expected_message)
end
@ -103,21 +104,22 @@ module Shoulda
else
obj
end
elsif [Fixnum, Float].include?(attribute_class)
1
elsif attribute_class == BigDecimal
BigDecimal.new(1, 0)
elsif !attribute_class || attribute_class == String
'an arbitrary value'
else
attribute_class.new
case column_type
when :integer, :float then 1
when :decimal then BigDecimal.new(1, 0)
when :datetime, :time, :timestamp then Time.now
when :date then Date.new
when :binary then "0"
else 'an arbitrary value'
end
end
end
def attribute_class
def column_type
@subject.class.respond_to?(:columns_hash) &&
@subject.class.columns_hash[@attribute.to_s].respond_to?(:klass) &&
@subject.class.columns_hash[@attribute.to_s].klass
@subject.class.columns_hash[@attribute.to_s].respond_to?(:type) &&
@subject.class.columns_hash[@attribute.to_s].type
end
def collection?

View File

@ -20,6 +20,10 @@ module Shoulda
def message
""
end
def inspect
%(#<#{self.class}: #{message}>)
end
end
end
end

View File

@ -62,7 +62,9 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
it 'rejects several bad values' do
expect(validating_format(with: /abc/)).
not_to allow_value('xyz', 'zyx', nil, []).for(:attr)
not_to allow_value('xyz', 'zyx', nil, []).
for(:attr).
ignoring_interference_by_writer
end
end
@ -182,12 +184,18 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model 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)
expect(model).
not_to allow_value(bad_value).
for(:attr).
ignoring_interference_by_writer
end
end
it 'does not match given multiple bad values' do
expect(model).not_to allow_value(*bad_values).for(:attr)
expect(model).
not_to allow_value(*bad_values).
for(:attr).
ignoring_interference_by_writer
end
it "does not match given good values along with bad values" do
@ -241,48 +249,139 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do
end
end
context 'when the attribute writer method ignores a non-nil value' do
context 'when the attribute has a reader method' do
it 'raises a CouldNotSetAttributeError' do
model = define_active_model_class 'Example' do
attr_reader :name
context 'when the attribute interferes with attempts to be set' do
context 'when the matcher has not been qualified with #ignoring_interference_by_writer' do
context 'when the attribute cannot be changed from nil to non-nil' do
it 'raises a CouldNotSetAttributeError' do
model = define_active_model_class 'Example' do
attr_reader :name
def name=(_value)
nil
def name=(_value)
nil
end
end
assertion = -> {
expect(model.new).to allow_value('anything').for(:name)
}
expect(&assertion).to raise_error(
described_class::CouldNotSetAttributeError
)
end
end
assertion = -> {
expect(model.new).to allow_value('anything').for(:name)
}
context 'when the attribute cannot be changed from non-nil to nil' do
it 'raises a CouldNotSetAttribute error' do
model = define_active_model_class 'Example' do
attr_reader :name
expect(&assertion).to raise_error(
Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError
)
def name=(value)
@name = value unless value.nil?
end
end
record = model.new(name: 'some name')
assertion = -> {
expect(record).to allow_value(nil).for(:name)
}
expect(&assertion).to raise_error(
described_class::CouldNotSetAttributeError
)
end
end
context 'when the attribute cannot be changed from a non-nil value to another non-nil value' do
it 'raises a CouldNotSetAttribute error' do
model = define_active_model_class 'Example' do
attr_reader :name
def name=(_value)
@name = 'constant name'
end
end
record = model.new(name: 'some name')
assertion = -> {
expect(record).to allow_value('another name').for(:name)
}
expect(&assertion).to raise_error(
described_class::CouldNotSetAttributeError
)
end
end
end
end
context 'when the attribute writer method ignores a nil value' do
context 'when the attribute has a reader method' do
it 'raises a CouldNotSetAttribute error' do
model = define_active_model_class 'Example' do
attr_reader :name
context 'when the matcher has been qualified with #ignoring_interference_by_writer' do
context 'when the attribute cannot be changed from nil to non-nil' do
it 'does not raise an error at all' do
model = define_active_model_class 'Example' do
attr_reader :name
def name=(value)
@name = value unless value.nil?
def name=(_value)
nil
end
end
assertion = lambda do
expect(model.new).
to allow_value('anything').
for(:name).
ignoring_interference_by_writer
end
expect(&assertion).not_to raise_error
end
end
record = model.new(name: 'some name')
context 'when the attribute cannot be changed from non-nil to nil' do
it 'does not raise an error at all' do
model = define_active_model_class 'Example' do
attr_reader :name
assertion = -> {
expect(record).to allow_value(nil).for(:name)
}
def name=(value)
@name = value unless value.nil?
end
end
expect(&assertion).to raise_error(
Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError
)
record = model.new(name: 'some name')
assertion = lambda do
expect(record).
to allow_value(nil).
for(:name).
ignoring_interference_by_writer
end
expect(&assertion).not_to raise_error
end
end
context 'when the attribute cannot be changed from a non-nil value to another non-nil value' do
it 'does not raise an error at all' do
model = define_active_model_class 'Example' do
attr_reader :name
def name=(_value)
@name = 'constant name'
end
end
record = model.new(name: 'some name')
assertion = lambda do
expect(record).
to allow_value('another name').
for(:name).
ignoring_interference_by_writer
end
expect(&assertion).not_to raise_error
end
end
end
end

View File

@ -3,28 +3,28 @@ require 'unit_spec_helper'
describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :model do
context 'a model with an acceptance validation' do
it 'accepts when the attributes match' do
expect(validating_acceptance).to matcher
expect(record_validating_acceptance).to matcher
end
it 'does not overwrite the default message with nil' do
expect(validating_acceptance).to matcher.with_message(nil)
expect(record_validating_acceptance).to matcher.with_message(nil)
end
end
context 'a model without an acceptance validation' do
it 'rejects' do
expect(define_model(:example, attr: :string).new).not_to matcher
expect(record_validating_nothing).not_to matcher
end
end
context 'an attribute which must be accepted with a custom message' do
it 'accepts when the message matches' do
expect(validating_acceptance(message: 'custom')).
expect(record_validating_acceptance(message: 'custom')).
to matcher.with_message(/custom/)
end
it 'rejects when the message does not match' do
expect(validating_acceptance(message: 'custom')).
expect(record_validating_acceptance(message: 'custom')).
not_to matcher.with_message(/wrong/)
end
end
@ -33,9 +33,21 @@ describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :mod
validate_acceptance_of(:attr)
end
def validating_acceptance(options = {})
define_model(:example, attr: :string) do
def model_validating_nothing(&block)
define_active_model_class(:example, accessors: [:attr], &block)
end
def record_validating_nothing
model_validating_nothing.new
end
def model_validating_acceptance(options = {})
model_validating_nothing do
validates_acceptance_of :attr, options
end.new
end
end
def record_validating_acceptance(options = {})
model_validating_acceptance(options).new
end
end

View File

@ -229,20 +229,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
)
expect(record).to validate_numericality.is_less_than_or_equal_to(18)
end
context 'if the given value is right at the allowed max value for the column' do
it 'does not raise an error' do
record = build_record_with_integer_column_of_limit(2,
less_than_or_equal_to: 32767
)
assertion = lambda do
expect(record).
to validate_numericality.
is_less_than_or_equal_to(32767)
end
expect(&assertion).not_to raise_error
end
end
end
context 'and not validating with less_than_or_equal_to' do
@ -268,16 +254,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
to validate_numericality.
is_less_than(18)
end
context 'if the given value is right at the allowed max value for the column' do
it 'does not raise an error' do
record = build_record_with_integer_column_of_limit(2, less_than: 32767)
assertion = lambda do
expect(record).to validate_numericality.is_less_than(32767)
end
expect(&assertion).not_to raise_error
end
end
end
context 'and not validating with less_than' do
@ -301,26 +277,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
record = build_record_validating_numericality(equal_to: 18)
expect(record).to validate_numericality.is_equal_to(18)
end
context 'if the given value is right at the allowed min value for the column' do
it 'does not raise an error' do
record = build_record_with_integer_column_of_limit(2, equal_to: -32768)
assertion = lambda do
expect(record).to validate_numericality.is_equal_to(-32768)
end
expect(&assertion).not_to raise_error
end
end
context 'if the given value is right at the allowed max value for the column' do
it 'does not raise an error' do
record = build_record_with_integer_column_of_limit(2, equal_to: 32767)
assertion = lambda do
expect(record).to validate_numericality.is_equal_to(32767)
end
expect(&assertion).not_to raise_error
end
end
end
context 'and not validating with equal_to' do
@ -346,20 +302,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
to validate_numericality.
is_greater_than_or_equal_to(18)
end
context 'if the given value is right at the allowed min value for the column' do
it 'does not raise an error' do
record = build_record_with_integer_column_of_limit(2,
greater_than_or_equal_to: -32768
)
assertion = lambda do
expect(record).
to validate_numericality_of(:attr).
is_greater_than_or_equal_to(-32768)
end
expect(&assertion).not_to raise_error
end
end
end
context 'not validating with greater_than_or_equal_to' do
@ -385,20 +327,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
to validate_numericality.
is_greater_than(18)
end
context 'if the given value is right at the allowed min value for the column' do
it 'does not raise an error' do
record = build_record_with_integer_column_of_limit(2,
greater_than: -32768
)
assertion = lambda do
expect(record).
to validate_numericality_of(:attr).
is_greater_than(-32768)
end
expect(&assertion).not_to raise_error
end
end
end
context 'and not validating with greater_than' do
@ -511,13 +439,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
only_integer.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be an integer" when attr is set to 0.1,
got errors:
* "must be greater than 18" (attribute: attr, value: "0.1")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be an integer" when attr is set to "0.1",
got errors:
* "must be greater than 18" (attribute: attr, value: "0.1")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -529,13 +455,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
only_integer.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be an integer" when attr is set to 0.1,
got errors:
* "must be greater than 18" (attribute: attr, value: "0.1")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be an integer" when attr is set to "0.1",
got errors:
* "must be greater than 18" (attribute: attr, value: "0.1")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -550,12 +474,10 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
even.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got no errors
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got no errors
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -570,13 +492,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
even.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be even" when attr is set to 1,
got errors:
* "must be greater than 18" (attribute: attr, value: "1")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be even" when attr is set to "1",
got errors:
* "must be greater than 18" (attribute: attr, value: "1")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -591,12 +511,10 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
odd.
is_less_than_or_equal_to(99)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be less than or equal to 99" when attr is set to 101,
got no errors
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be less than or equal to 99" when attr is set to "101",
got no errors
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -613,12 +531,10 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
is_greater_than(18).
is_less_than(99)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got no errors
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got no errors
MESSAGE
expect(&assertion).to fail_with_message(message)
end
end
@ -635,13 +551,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
only_integer.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got errors:
* "must be greater than 19" (attribute: attr, value: "19")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got errors:
* "must be greater than 19" (attribute: attr, value: "19")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -656,12 +570,10 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
only_integer.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got no errors
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got no errors
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -676,13 +588,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
even.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got errors:
* "must be greater than 20" (attribute: attr, value: "20")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got errors:
* "must be greater than 20" (attribute: attr, value: "20")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -697,12 +607,10 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
even.
is_greater_than(18)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got no errors
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got no errors
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -717,12 +625,10 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
odd.
is_less_than_or_equal_to(99)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be less than or equal to 99" when attr is set to 101,
got no errors
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be less than or equal to 99" when attr is set to "101",
got no errors
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -737,13 +643,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
odd.
is_less_than_or_equal_to(99)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be less than or equal to 99" when attr is set to 101,
got errors:
* "must be less than or equal to 97" (attribute: attr, value: "101")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be less than or equal to 99" when attr is set to "101",
got errors:
* "must be less than or equal to 97" (attribute: attr, value: "101")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -760,13 +664,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
is_greater_than(18).
is_less_than(99)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to 18,
got errors:
* "must be greater than 19" (attribute: attr, value: "19")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be greater than 18" when attr is set to "18",
got errors:
* "must be greater than 19" (attribute: attr, value: "19")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
@ -783,13 +685,11 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
is_greater_than(18).
is_less_than(99)
end
message = format_message_according_to_rails_version(
<<-MESSAGE.strip_heredoc
Expected errors to include "must be less than 99" when attr is set to 100,
got errors:
* "must be less than 100" (attribute: attr, value: "100")
MESSAGE
)
message = <<-MESSAGE.strip_heredoc
Expected errors to include "must be less than 99" when attr is set to "100",
got errors:
* "must be less than 100" (attribute: attr, value: "100")
MESSAGE
expect(&assertion).to fail_with_message(message)
end
end
@ -970,23 +870,4 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :m
def attribute_name
:attr
end
def define_model_with_integer_column_of_limit(limit, validation_options = {})
column_options = { type: :integer, options: { limit: limit } }
define_model :example, attribute_name => column_options do |model|
model.validates_numericality_of(attribute_name, validation_options)
end
end
def build_record_with_integer_column_of_limit(limit, validation_options = {})
define_model_with_integer_column_of_limit(limit, validation_options).new
end
def format_message_according_to_rails_version(message)
if rails_gte_4_2?
message
else
message.gsub(/"((?:\d+)(?:\.\d+)?)"/, '\1')
end
end
end