allow multiple values for AllowValueMatcher
With the deprecation of "should_allow_values_for" there is currently no clean way to specify multiple allowed (or forbidden) values for an attribute in a single assertion. This can make test cases unnecessarily verbose. This patch gives AllowValueMatcher the ability to take multiple values. The new matcher is fully downward compatible (i.e. given a single argument it behaves identically to the old matcher). This matcher will stop checking for bad values when the first bad value is encountered.
This commit is contained in:
parent
c86d8e2e0c
commit
cab62a1697
|
@ -2,7 +2,10 @@ module Shoulda # :nodoc:
|
||||||
module Matchers
|
module Matchers
|
||||||
module ActiveModel # :nodoc:
|
module ActiveModel # :nodoc:
|
||||||
|
|
||||||
# Ensures that the attribute can be set to the given value.
|
# Ensures that the attribute can be set to the given value or values. If
|
||||||
|
# multiple values are given the match succeeds only if all given values
|
||||||
|
# are allowed. Otherwise, the matcher fails at the first bad value in the
|
||||||
|
# argument list (the remaining arguments are not processed then).
|
||||||
#
|
#
|
||||||
# Options:
|
# Options:
|
||||||
# * <tt>with_message</tt> - value the test expects to find in
|
# * <tt>with_message</tt> - value the test expects to find in
|
||||||
|
@ -13,15 +16,16 @@ module Shoulda # :nodoc:
|
||||||
# it { should_not allow_value('bad').for(:isbn) }
|
# it { should_not allow_value('bad').for(:isbn) }
|
||||||
# it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
|
# it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
|
||||||
#
|
#
|
||||||
def allow_value(value)
|
def allow_value(*values)
|
||||||
AllowValueMatcher.new(value)
|
raise ArgumentError.new("need at least one argument") if values.empty?
|
||||||
|
AllowValueMatcher.new(*values)
|
||||||
end
|
end
|
||||||
|
|
||||||
class AllowValueMatcher # :nodoc:
|
class AllowValueMatcher # :nodoc:
|
||||||
include Helpers
|
include Helpers
|
||||||
|
|
||||||
def initialize(value)
|
def initialize(*values)
|
||||||
@value = value
|
@values_to_match = values
|
||||||
end
|
end
|
||||||
|
|
||||||
def for(attribute)
|
def for(attribute)
|
||||||
|
@ -39,8 +43,12 @@ module Shoulda # :nodoc:
|
||||||
if Symbol === @expected_message
|
if Symbol === @expected_message
|
||||||
@expected_message = default_error_message(@expected_message, :model_name => @instance.class.to_s.underscore, :attribute => @attribute)
|
@expected_message = default_error_message(@expected_message, :model_name => @instance.class.to_s.underscore, :attribute => @attribute)
|
||||||
end
|
end
|
||||||
@instance.send("#{@attribute}=", @value)
|
@values_to_match.each do |value|
|
||||||
!errors_match?
|
@value = value
|
||||||
|
@instance.send("#{@attribute}=", @value)
|
||||||
|
return false if errors_match?
|
||||||
|
end
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def failure_message
|
def failure_message
|
||||||
|
@ -52,7 +60,12 @@ module Shoulda # :nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
"allow #{@attribute} to be set to #{@value.inspect}"
|
"allow #{@attribute} to be set to " <<
|
||||||
|
if @values_to_match.length > 1
|
||||||
|
"any of [#{@values_to_match.map {|v| v.inspect }.join(', ')}]"
|
||||||
|
else
|
||||||
|
@values_to_match.first.inspect
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -17,6 +17,14 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher do
|
||||||
it "should not allow a bad value" do
|
it "should not allow a bad value" do
|
||||||
@model.should_not allow_value("xyz").for(:attr)
|
@model.should_not allow_value("xyz").for(:attr)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should allow several good values" do
|
||||||
|
@model.should allow_value("abcde", "deabc").for(:attr)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow several bad values" do
|
||||||
|
@model.should_not allow_value("xyz", "zyx", nil, []).for(:attr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "an attribute with a format validation and a custom message" do
|
context "an attribute with a format validation and a custom message" do
|
||||||
|
@ -51,12 +59,32 @@ describe Shoulda::Matchers::ActiveModel::AllowValueMatcher do
|
||||||
@model.should allow_value("12345").for(:attr)
|
@model.should allow_value("12345").for(:attr)
|
||||||
end
|
end
|
||||||
|
|
||||||
bad_values = [nil, "", "abc", "0", "50001", "123456"]
|
bad_values = [nil, "", "abc", "0", "50001", "123456", []]
|
||||||
|
|
||||||
bad_values.each do |value|
|
bad_values.each do |value|
|
||||||
it "should not allow a bad value (#{value.inspect})" do
|
it "should not allow a bad value (#{value.inspect})" do
|
||||||
@model.should_not allow_value(value).for(:attr)
|
@model.should_not allow_value(value).for(:attr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should not allow bad values (#{bad_values.map {|v| v.inspect}.join(', ')})" do
|
||||||
|
@model.should_not allow_value(*bad_values).for(:attr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "an AllowValueMatcher with multiple values" do
|
||||||
|
before { @matcher = allow_value("foo", "bar").for(:baz) }
|
||||||
|
|
||||||
|
it "should describe itself" do
|
||||||
|
@matcher.description.should eq('allow baz to be set to any of ["foo", "bar"]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "an AllowValueMatcher with a single value" do
|
||||||
|
before { @matcher = allow_value("foo").for(:baz) }
|
||||||
|
|
||||||
|
it "should describe itself" do
|
||||||
|
@matcher.description.should eq('allow baz to be set to "foo"')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue