Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add AllowValueMatcher#strict to test strict validations

* Checks for exceptions raised from #validates! and :strict => true
  • Loading branch information...
commit 025023d432302159ea03a36442aa070499392d72 1 parent 481631c
@jferris jferris authored
View
86 lib/shoulda/matchers/active_model/allow_value_matcher.rb
@@ -29,6 +29,7 @@ class AllowValueMatcher # :nodoc:
def initialize(*values)
@values_to_match = values
+ @strict = false
@options = {}
end
@@ -42,6 +43,11 @@ def with_message(message)
self
end
+ def strict
+ @strict = true
+ self
+ end
+
def matches?(instance)
@instance = instance
@values_to_match.none? do |value|
@@ -60,24 +66,62 @@ def negative_failure_message
end
def description
- "allow #{@attribute} to be set to #{allowed_values}"
+ base = "allow #{@attribute} to be set to #{allowed_values}"
+
+ if strict?
+ "strictly #{base}"
+ else
+ base
+ end
end
private
def errors_match?
+ if strict?
+ exception_message_matches?
+ else
+ validation_messages_match?
+ end
+ end
+
+ def exception_message_matches?
+ @instance.valid?
+ false
+ rescue ::ActiveModel::StrictValidationFailed => exception
+ @strict_exception = exception
+ errors_for_attribute_match?
+ end
+
+ def validation_messages_match?
if @instance.valid?
false
else
- if expected_message
- @matched_error = errors_match_regexp? || errors_match_string?
- else
- errors_for_attribute.compact.any?
- end
+ errors_for_attribute_match?
+ end
+ end
+
+ def errors_for_attribute_match?
+ if expected_message
+ @matched_error = errors_match_regexp? || errors_match_string?
+ else
+ errors_for_attribute.compact.any?
end
end
def errors_for_attribute
+ if strict?
+ [strict_exception_message]
+ else
+ validation_messages_for_attribute
+ end
+ end
+
+ def strict_exception_message
+ @strict_exception.message
+ end
+
+ def validation_messages_for_attribute
if @instance.errors.respond_to?(:[])
errors = @instance.errors[@attribute]
else
@@ -86,6 +130,10 @@ def errors_for_attribute
Array.wrap(errors)
end
+ def strict?
+ @strict
+ end
+
def errors_match_regexp?
if Regexp === expected_message
errors_for_attribute.detect { |e| e =~ expected_message }
@@ -100,10 +148,34 @@ def errors_match_string?
def expectation
includes_expected_message = expected_message ? "to include #{expected_message.inspect}" : ''
- ["errors", includes_expected_message, "when #{@attribute} is set to #{@value.inspect}"].join(' ')
+ [error_source, includes_expected_message, "when #{@attribute} is set to #{@value.inspect}"].join(' ')
+ end
+
+ def error_source
+ if strict?
+ 'exception'
+ else
+ 'errors'
+ end
end
def error_description
+ if strict?
+ exception_description
+ else
+ validation_error_description
+ end
+ end
+
+ def exception_description
+ if @strict_exception
+ strict_exception_message
+ else
+ 'no exception'
+ end
+ end
+
+ def validation_error_description
if @instance.errors.empty?
"no errors"
else
View
32 spec/shoulda/active_model/allow_value_matcher_spec.rb
@@ -88,4 +88,36 @@
end.should raise_error(ArgumentError, /at least one argument/)
end
end
+
+ if Rails::VERSION::STRING.to_f >= 3.2
+ context "an attribute with a strict format validation" do
+ let(:model) do
+ define_model :example, :attr => :string do
+ validates_format_of :attr, :with => /abc/, :strict => true
+ end.new
+ end
+
+ it "strictly rejects a bad value" do
+ model.should_not allow_value("xyz").for(:attr).strict
+ end
+
+ it "strictly allows a bad value with a different message" do
+ model.should allow_value("xyz").for(:attr).with_message(/abc/).strict
+ end
+
+ it "describes itself" do
+ allow_value("xyz").for(:attr).strict.description.
+ should == 'strictly allow attr to be set to "xyz"'
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = allow_value("xyz").for(:attr).strict.with_message(/abc/)
+ matcher.matches?(model)
+ matcher.negative_failure_message.
+ should == 'Expected exception to include /abc/ ' +
+ 'when attr is set to "xyz", got Attr is invalid'
+ end
+ end
+ end
+
end
Please sign in to comment.
Something went wrong with that request. Please try again.