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 authored September 11, 2012
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 notes on commit 025023d

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