Uniqueness: Fix default behavior for case-insensitive models

If you have a model that has a uniqueness validation using
`case_sensitive: false`, and you are testing against but do not qualify
the matcher with `case_insensitive`, then the matcher will pass
unexpectedly. Take this model for instance:

    class Product < ActiveRecord::Base
      validates_uniqueness_of :name, case_sensitive: false
    end

Currently, the following test passes. With this commit, it will now
(correctly) fail:

    describe Product do
      it { is_expected.to validate_uniqueness_of(:name) }
    end
This commit is contained in:
Anthony Navarre + Elliot Winkler 2015-02-16 14:39:15 -07:00 committed by Elliot Winkler
parent c3482d1bf1
commit 57a19228b6
2 changed files with 43 additions and 6 deletions

View File

@ -244,6 +244,7 @@ module Shoulda
set_scoped_attributes &&
validate_everything_except_duplicate_nils_or_blanks? &&
validate_case_sensitivity? &&
validate_after_scope_change? &&
allows_nil? &&
allows_blank?
@ -353,6 +354,22 @@ module Shoulda
disallows_value_of(existing_value, @expected_message)
end
def validate_case_sensitivity?
value = existing_value
if value.respond_to?(:swapcase)
swapcased_value = value.swapcase
if @options[:case_insensitive]
disallows_value_of(swapcased_value, @expected_message)
else
allows_value_of(swapcased_value, @expected_message)
end
else
true
end
end
def create_record_with_value
@existing_record = create_record_in_database
end
@ -462,11 +479,7 @@ module Shoulda
end
def existing_value
value = existing_record.__send__(@attribute)
if @options[:case_insensitive] && value.respond_to?(:swapcase!)
value.swapcase!
end
value
existing_record.__send__(@attribute)
end
def class_name

View File

@ -392,7 +392,7 @@ describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher, type: :mo
end
end
context 'when the model has a case-sensitive validation on a string attribute' do
context 'when the model has a case-sensitive validation' do
context 'when case_insensitive is not specified' do
it 'accepts' do
record = build_record_validating_uniqueness(
@ -416,6 +416,30 @@ describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher, type: :mo
end
end
context 'when the model has a case-insensitive validation' do
context 'when case_insensitive is not specified' do
it 'rejects' do
record = build_record_validating_uniqueness(
attribute_type: :string,
validation_options: { case_sensitive: false }
)
expect(record).not_to validate_uniqueness
end
end
context 'when case_insensitive is specified' do
it 'accepts' do
record = build_record_validating_uniqueness(
attribute_type: :string,
validation_options: { case_sensitive: false }
)
expect(record).to validate_uniqueness.case_insensitive
end
end
end
context 'when the validation is declared with allow_nil' do
context 'given a new record whose attribute is nil' do
it 'accepts' do