2014-01-23 18:07:36 +00:00
|
|
|
module Shoulda
|
2013-12-05 16:38:30 +00:00
|
|
|
module Matchers
|
2014-01-23 18:07:36 +00:00
|
|
|
module ActiveModel
|
|
|
|
# The `validate_absence_of` matcher tests the usage of the
|
|
|
|
# `validates_absence_of` validation.
|
|
|
|
#
|
|
|
|
# class Artillery
|
|
|
|
# include ActiveModel::Model
|
|
|
|
# attr_accessor :arms
|
|
|
|
#
|
|
|
|
# validates_absence_of :arms
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# # RSpec
|
|
|
|
# describe Artillery do
|
|
|
|
# it { should validate_absence_of(:arms) }
|
|
|
|
# end
|
|
|
|
#
|
2015-09-30 19:15:23 +00:00
|
|
|
# # Minitest (Shoulda)
|
2014-01-23 18:07:36 +00:00
|
|
|
# class ArtilleryTest < ActiveSupport::TestCase
|
|
|
|
# should validate_absence_of(:arms)
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# #### Qualifiers
|
|
|
|
#
|
2015-03-28 14:24:45 +00:00
|
|
|
# ##### on
|
|
|
|
#
|
|
|
|
# Use `on` if your validation applies only under a certain context.
|
|
|
|
#
|
|
|
|
# class Artillery
|
|
|
|
# include ActiveModel::Model
|
|
|
|
# attr_accessor :arms
|
|
|
|
#
|
|
|
|
# validates_absence_of :arms, on: :create
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# # RSpec
|
|
|
|
# describe Artillery do
|
|
|
|
# it { should validate_absence_of(:arms).on(:create) }
|
|
|
|
# end
|
|
|
|
#
|
2015-09-30 19:15:23 +00:00
|
|
|
# # Minitest (Shoulda)
|
2015-03-28 14:24:45 +00:00
|
|
|
# class ArtilleryTest < ActiveSupport::TestCase
|
|
|
|
# should validate_absence_of(:arms).on(:create)
|
|
|
|
# end
|
|
|
|
#
|
2014-01-23 18:07:36 +00:00
|
|
|
# ##### with_message
|
2013-12-05 16:38:30 +00:00
|
|
|
#
|
2014-01-23 18:07:36 +00:00
|
|
|
# Use `with_message` if you are using a custom validation message.
|
|
|
|
#
|
|
|
|
# class Artillery
|
|
|
|
# include ActiveModel::Model
|
|
|
|
# attr_accessor :arms
|
|
|
|
#
|
|
|
|
# validates_absence_of :arms,
|
|
|
|
# message: "We're fresh outta arms here, soldier!"
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# # RSpec
|
|
|
|
# describe Artillery do
|
|
|
|
# it do
|
|
|
|
# should validate_absence_of(:arms).
|
|
|
|
# with_message("We're fresh outta arms here, soldier!")
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
2015-09-30 19:15:23 +00:00
|
|
|
# # Minitest (Shoulda)
|
2014-01-23 18:07:36 +00:00
|
|
|
# class ArtilleryTest < ActiveSupport::TestCase
|
|
|
|
# should validate_absence_of(:arms).
|
|
|
|
# with_message("We're fresh outta arms here, soldier!")
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# @return [ValidateAbsenceOfMatcher}
|
2013-12-05 16:38:30 +00:00
|
|
|
#
|
|
|
|
def validate_absence_of(attr)
|
|
|
|
ValidateAbsenceOfMatcher.new(attr)
|
|
|
|
end
|
|
|
|
|
2014-01-23 18:07:36 +00:00
|
|
|
# @private
|
|
|
|
class ValidateAbsenceOfMatcher < ValidationMatcher
|
2013-12-05 16:38:30 +00:00
|
|
|
def with_message(message)
|
|
|
|
@expected_message = message
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def matches?(subject)
|
|
|
|
super(subject)
|
|
|
|
@expected_message ||= :present
|
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
2015-09-26 05:10:00 +00:00
|
|
|
|
2013-12-05 16:38:30 +00:00
|
|
|
disallows_value_of(value, @expected_message)
|
|
|
|
end
|
|
|
|
|
|
|
|
def description
|
|
|
|
"require #{@attribute} to not be set"
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def value
|
|
|
|
if reflection
|
|
|
|
obj = reflection.klass.new
|
|
|
|
if collection?
|
|
|
|
[ obj ]
|
|
|
|
else
|
|
|
|
obj
|
|
|
|
end
|
|
|
|
else
|
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
2015-09-26 05:10:00 +00:00
|
|
|
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
|
2013-12-05 16:38:30 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
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
2015-09-26 05:10:00 +00:00
|
|
|
def column_type
|
2013-12-05 16:38:30 +00:00
|
|
|
@subject.class.respond_to?(:columns_hash) &&
|
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
2015-09-26 05:10:00 +00:00
|
|
|
@subject.class.columns_hash[@attribute.to_s].respond_to?(:type) &&
|
|
|
|
@subject.class.columns_hash[@attribute.to_s].type
|
2013-12-05 16:38:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def collection?
|
|
|
|
if reflection
|
|
|
|
[:has_many, :has_and_belongs_to_many].include?(reflection.macro)
|
|
|
|
else
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def reflection
|
|
|
|
@subject.class.respond_to?(:reflect_on_association) &&
|
|
|
|
@subject.class.reflect_on_association(@attribute)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|