Improve error message handling in ValidateNumericalityOfMatcher and OnlyIntegerMatcher.

This commit is contained in:
Reade Harris 2012-10-23 12:30:18 -04:00 committed by Jason Draper
parent 6ba8c9f1a1
commit 8a563c18a5
6 changed files with 71 additions and 20 deletions

View File

@ -3,7 +3,7 @@ module Shoulda # :nodoc:
module ActiveModel # :nodoc: module ActiveModel # :nodoc:
class DisallowValueMatcher # :nodoc: class DisallowValueMatcher # :nodoc:
def initialize(value) def initialize(value)
@allow_matcher = Shoulda::Matchers::ActiveModel::AllowValueMatcher.new(value) @allow_matcher = AllowValueMatcher.new(value)
end end
def matches?(subject) def matches?(subject)

View File

@ -2,22 +2,31 @@ module Shoulda # :nodoc:
module Matchers module Matchers
module ActiveModel # :nodoc: module ActiveModel # :nodoc:
class OnlyIntegerMatcher # :nodoc: class OnlyIntegerMatcher # :nodoc:
NON_INTEGER_VALUE = 0.1
def initialize(attribute) def initialize(attribute)
@attribute = attribute @attribute = attribute
@disallow_value_matcher = DisallowValueMatcher.new(NON_INTEGER_VALUE).
for(attribute).
with_message(:not_an_integer)
end end
def matches?(subject) def matches?(subject)
matcher = AllowValueMatcher.new(0.1).for(@attribute) @disallow_value_matcher.matches?(subject)
!matcher.matches?(subject)
end end
def with_message(message) def with_message(message)
@disallow_value_matcher.with_message(message)
self self
end end
def allowed_types def allowed_types
"integer" "integer"
end end
def failure_message
@disallow_value_matcher.failure_message
end
end end
end end
end end

View File

@ -18,6 +18,8 @@ module Shoulda # :nodoc:
end end
class ValidateNumericalityOfMatcher class ValidateNumericalityOfMatcher
NON_NUMERIC_VALUE = 'abcd'
def initialize(attribute) def initialize(attribute)
@attribute = attribute @attribute = attribute
@options = {} @options = {}
@ -29,18 +31,16 @@ module Shoulda # :nodoc:
def only_integer def only_integer
only_integer_matcher = OnlyIntegerMatcher.new(@attribute) only_integer_matcher = OnlyIntegerMatcher.new(@attribute)
add_submatcher(only_integer_matcher) add_submatcher(only_integer_matcher)
self self
end end
def with_message(message) def with_message(message)
@expected_message = message @submatchers.each { |matcher| matcher.with_message(message) }
self self
end end
def matches?(subject) def matches?(subject)
@subject = subject @subject = subject
set_expected_message_on_submatchers
submatchers_match? submatchers_match?
end end
@ -49,27 +49,33 @@ module Shoulda # :nodoc:
end end
def failure_message def failure_message
@disallow_value_matcher.failure_message submatcher_failure_messages.last
end end
private private
def add_disallow_value_matcher def add_disallow_value_matcher
@disallow_value_matcher = DisallowValueMatcher.new('abcd').for(@attribute) disallow_value_matcher = DisallowValueMatcher.new(NON_NUMERIC_VALUE).
add_submatcher(@disallow_value_matcher) for(@attribute).
with_message(:not_a_number)
add_submatcher(disallow_value_matcher)
end end
def add_submatcher(submatcher) def add_submatcher(submatcher)
@submatchers << submatcher @submatchers << submatcher
end end
def set_expected_message_on_submatchers def submatchers_match?
message = @expected_message || :not_a_number failing_submatchers.empty?
@submatchers.each { |matcher| matcher.with_message(message) }
end end
def submatchers_match? def submatcher_failure_messages
@submatchers.all? { |matcher| matcher.matches?(@subject) } failing_submatchers.map(&:failure_message)
end
def failing_submatchers
@failing_submatchers ||= @submatchers.select { |matcher| !matcher.matches?(@subject) }
end end
def allowed_types def allowed_types
@ -78,7 +84,7 @@ module Shoulda # :nodoc:
end end
def submatcher_allowed_types def submatcher_allowed_types
@submatchers.map(&:allowed_types).reject { |type| type.empty? } @submatchers.map(&:allowed_types).reject(&:empty?)
end end
end end
end end

View File

@ -42,7 +42,7 @@ describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher do
end end
it "delegates its failure message to its allow matcher's negative failure message" do it "delegates its failure message to its allow matcher's negative failure message" do
allow_matcher = stub_everything(negative_failure_message: "allow matcher failure") allow_matcher = stub_everything(:negative_failure_message => "allow matcher failure")
Shoulda::Matchers::ActiveModel::AllowValueMatcher.stubs(:new).returns(allow_matcher) Shoulda::Matchers::ActiveModel::AllowValueMatcher.stubs(:new).returns(allow_matcher)
matcher = new_matcher("abcde") matcher = new_matcher("abcde")

View File

@ -25,6 +25,27 @@ describe Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher do
end end
end end
context "given an attribute that only allows integer values with a custom validation message" do
before do
define_model :example, :attr => :string do
validates_numericality_of :attr, { :only_integer => true, :message => 'custom' }
end
@model = Example.new
end
it "should only allow integer values for that attribute with that message" do
matcher = new_matcher(:attr)
matcher.with_message(/custom/)
matcher.matches?(@model).should be_true
end
it "should not allow integer values for that attribute with another message" do
matcher = new_matcher(:attr)
matcher.with_message(/wrong/)
matcher.matches?(@model).should be_false
end
end
context "given an attribute that allows values other than integers" do context "given an attribute that allows values other than integers" do
before do before do
@model = define_model(:example, :attr => :string).new @model = define_model(:example, :attr => :string).new
@ -34,6 +55,12 @@ describe Shoulda::Matchers::ActiveModel::OnlyIntegerMatcher do
matcher = new_matcher(:attr) matcher = new_matcher(:attr)
matcher.matches?(@model).should be_false matcher.matches?(@model).should be_false
end end
it "should fail with the ActiveRecord :not_an_integer message" do
matcher = new_matcher(:attr)
matcher.matches?(@model)
matcher.failure_message.should include 'Expected errors to include "must be an integer"'
end
end end
def new_matcher(attribute) def new_matcher(attribute)

View File

@ -25,11 +25,20 @@ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
matcher.matches?(@model).should be_true matcher.matches?(@model).should be_true
end end
it "should not enforce integer values for that attribute" do context "when asked to enforce integer values for that attribute" do
it "should not match" do
matcher = new_matcher(:attr) matcher = new_matcher(:attr)
matcher.only_integer matcher.only_integer
matcher.matches?(@model).should be_false matcher.matches?(@model).should be_false
end end
it "should fail with the ActiveRecord :not_an_integer message" do
matcher = new_matcher(:attr)
matcher.only_integer
matcher.matches?(@model)
matcher.failure_message.should include 'Expected errors to include "must be an integer"'
end
end
end end
context "given a numeric attribute which must be integer" do context "given a numeric attribute which must be integer" do