Skip to content
This repository
Browse code

Add AllowValueMatcher#strict to test strict validations

* Checks for exceptions raised from #validates! and :strict => true
  • Loading branch information...
commit 025023d432302159ea03a36442aa070499392d72 1 parent 481631c
Joe Ferris jferris authored
86 lib/shoulda/matchers/active_model/allow_value_matcher.rb
@@ -29,6 +29,7 @@ class AllowValueMatcher # :nodoc:
29 29
30 30 def initialize(*values)
31 31 @values_to_match = values
  32 + @strict = false
32 33 @options = {}
33 34 end
34 35
@@ -42,6 +43,11 @@ def with_message(message)
42 43 self
43 44 end
44 45
  46 + def strict
  47 + @strict = true
  48 + self
  49 + end
  50 +
45 51 def matches?(instance)
46 52 @instance = instance
47 53 @values_to_match.none? do |value|
@@ -60,24 +66,62 @@ def negative_failure_message
60 66 end
61 67
62 68 def description
63   - "allow #{@attribute} to be set to #{allowed_values}"
  69 + base = "allow #{@attribute} to be set to #{allowed_values}"
  70 +
  71 + if strict?
  72 + "strictly #{base}"
  73 + else
  74 + base
  75 + end
64 76 end
65 77
66 78 private
67 79
68 80 def errors_match?
  81 + if strict?
  82 + exception_message_matches?
  83 + else
  84 + validation_messages_match?
  85 + end
  86 + end
  87 +
  88 + def exception_message_matches?
  89 + @instance.valid?
  90 + false
  91 + rescue ::ActiveModel::StrictValidationFailed => exception
  92 + @strict_exception = exception
  93 + errors_for_attribute_match?
  94 + end
  95 +
  96 + def validation_messages_match?
69 97 if @instance.valid?
70 98 false
71 99 else
72   - if expected_message
73   - @matched_error = errors_match_regexp? || errors_match_string?
74   - else
75   - errors_for_attribute.compact.any?
76   - end
  100 + errors_for_attribute_match?
  101 + end
  102 + end
  103 +
  104 + def errors_for_attribute_match?
  105 + if expected_message
  106 + @matched_error = errors_match_regexp? || errors_match_string?
  107 + else
  108 + errors_for_attribute.compact.any?
77 109 end
78 110 end
79 111
80 112 def errors_for_attribute
  113 + if strict?
  114 + [strict_exception_message]
  115 + else
  116 + validation_messages_for_attribute
  117 + end
  118 + end
  119 +
  120 + def strict_exception_message
  121 + @strict_exception.message
  122 + end
  123 +
  124 + def validation_messages_for_attribute
81 125 if @instance.errors.respond_to?(:[])
82 126 errors = @instance.errors[@attribute]
83 127 else
@@ -86,6 +130,10 @@ def errors_for_attribute
86 130 Array.wrap(errors)
87 131 end
88 132
  133 + def strict?
  134 + @strict
  135 + end
  136 +
89 137 def errors_match_regexp?
90 138 if Regexp === expected_message
91 139 errors_for_attribute.detect { |e| e =~ expected_message }
@@ -100,10 +148,34 @@ def errors_match_string?
100 148
101 149 def expectation
102 150 includes_expected_message = expected_message ? "to include #{expected_message.inspect}" : ''
103   - ["errors", includes_expected_message, "when #{@attribute} is set to #{@value.inspect}"].join(' ')
  151 + [error_source, includes_expected_message, "when #{@attribute} is set to #{@value.inspect}"].join(' ')
  152 + end
  153 +
  154 + def error_source
  155 + if strict?
  156 + 'exception'
  157 + else
  158 + 'errors'
  159 + end
104 160 end
105 161
106 162 def error_description
  163 + if strict?
  164 + exception_description
  165 + else
  166 + validation_error_description
  167 + end
  168 + end
  169 +
  170 + def exception_description
  171 + if @strict_exception
  172 + strict_exception_message
  173 + else
  174 + 'no exception'
  175 + end
  176 + end
  177 +
  178 + def validation_error_description
107 179 if @instance.errors.empty?
108 180 "no errors"
109 181 else
32 spec/shoulda/active_model/allow_value_matcher_spec.rb
@@ -88,4 +88,36 @@
88 88 end.should raise_error(ArgumentError, /at least one argument/)
89 89 end
90 90 end
  91 +
  92 + if Rails::VERSION::STRING.to_f >= 3.2
  93 + context "an attribute with a strict format validation" do
  94 + let(:model) do
  95 + define_model :example, :attr => :string do
  96 + validates_format_of :attr, :with => /abc/, :strict => true
  97 + end.new
  98 + end
  99 +
  100 + it "strictly rejects a bad value" do
  101 + model.should_not allow_value("xyz").for(:attr).strict
  102 + end
  103 +
  104 + it "strictly allows a bad value with a different message" do
  105 + model.should allow_value("xyz").for(:attr).with_message(/abc/).strict
  106 + end
  107 +
  108 + it "describes itself" do
  109 + allow_value("xyz").for(:attr).strict.description.
  110 + should == 'strictly allow attr to be set to "xyz"'
  111 + end
  112 +
  113 + it "provides a useful negative failure message" do
  114 + matcher = allow_value("xyz").for(:attr).strict.with_message(/abc/)
  115 + matcher.matches?(model)
  116 + matcher.negative_failure_message.
  117 + should == 'Expected exception to include /abc/ ' +
  118 + 'when attr is set to "xyz", got Attr is invalid'
  119 + end
  120 + end
  121 + end
  122 +
91 123 end

0 comments on commit 025023d

Please sign in to comment.
Something went wrong with that request. Please try again.