diff --git a/NEWS.md b/NEWS.md index 7c29e73e..2e1372e2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/lib/shoulda/matchers/active_model/allow_value_matcher.rb b/lib/shoulda/matchers/active_model/allow_value_matcher.rb index 57b8a9b0..88e1f3f7 100644 --- a/lib/shoulda/matchers/active_model/allow_value_matcher.rb +++ b/lib/shoulda/matchers/active_model/allow_value_matcher.rb @@ -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, diff --git a/lib/shoulda/matchers/active_model/disallow_value_matcher.rb b/lib/shoulda/matchers/active_model/disallow_value_matcher.rb index 0cdcf4c2..9cf648a8 100644 --- a/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +++ b/lib/shoulda/matchers/active_model/disallow_value_matcher.rb @@ -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 diff --git a/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb b/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb index 90d442f3..169aab9c 100644 --- a/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +++ b/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb @@ -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 diff --git a/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb b/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb index d744ce18..84db5c9b 100644 --- a/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +++ b/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb @@ -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 diff --git a/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb b/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb index c1538079..21ee7d88 100644 --- a/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +++ b/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb @@ -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 diff --git a/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb b/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb index 37004881..b699bdf1 100644 --- a/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +++ b/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb @@ -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 diff --git a/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb b/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb index c9cf2f37..cbd7dea0 100644 --- a/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +++ b/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb @@ -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? diff --git a/lib/shoulda/matchers/error.rb b/lib/shoulda/matchers/error.rb index 2ec38b14..e2b9f6b5 100644 --- a/lib/shoulda/matchers/error.rb +++ b/lib/shoulda/matchers/error.rb @@ -20,6 +20,10 @@ module Shoulda def message "" end + + def inspect + %(#<#{self.class}: #{message}>) + end end end end diff --git a/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb b/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb index c6a742cd..b646b009 100644 --- a/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb @@ -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 diff --git a/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb b/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb index 7c41ee33..467ec719 100644 --- a/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb @@ -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 diff --git a/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb b/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb index 2bd2df3f..02565b45 100644 --- a/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb @@ -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