Skip to content
This repository
  • 2 commits
  • 7 files changed
  • 0 comments
  • 1 contributor
2  lib/shoulda/matchers/active_model.rb
... ...
@@ -1,5 +1,7 @@
1 1
 require 'shoulda/matchers/active_model/helpers'
2 2
 require 'shoulda/matchers/active_model/validation_matcher'
  3
+require 'shoulda/matchers/active_model/validation_message_finder'
  4
+require 'shoulda/matchers/active_model/exception_message_finder'
3 5
 require 'shoulda/matchers/active_model/allow_value_matcher'
4 6
 require 'shoulda/matchers/active_model/ensure_length_of_matcher'
5 7
 require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
103  lib/shoulda/matchers/active_model/allow_value_matcher.rb
@@ -29,7 +29,7 @@ class AllowValueMatcher # :nodoc:
29 29
 
30 30
         def initialize(*values)
31 31
           @values_to_match = values
32  
-          @strict = false
  32
+          @message_finder_factory = ValidationMessageFinder
33 33
           @options = {}
34 34
         end
35 35
 
@@ -44,7 +44,7 @@ def with_message(message)
44 44
         end
45 45
 
46 46
         def strict
47  
-          @strict = true
  47
+          @message_finder_factory = ExceptionMessageFinder
48 48
           self
49 49
         end
50 50
 
@@ -66,39 +66,17 @@ def negative_failure_message
66 66
         end
67 67
 
68 68
         def description
69  
-          base = "allow #{@attribute} to be set to #{allowed_values}"
70  
-
71  
-          if strict?
72  
-            "strictly #{base}"
73  
-          else
74  
-            base
75  
-          end
  69
+          message_finder.allow_description(allowed_values)
76 70
         end
77 71
 
78 72
         private
79 73
 
80 74
         def errors_match?
81  
-          if strict?
82  
-            exception_message_matches?
83  
-          else
84  
-            validation_messages_match?
85  
-          end
  75
+          has_messages? && errors_for_attribute_match?
86 76
         end
87 77
 
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?
97  
-          if @instance.valid?
98  
-            false
99  
-          else
100  
-            errors_for_attribute_match?
101  
-          end
  78
+        def has_messages?
  79
+          message_finder.has_messages?
102 80
         end
103 81
 
104 82
         def errors_for_attribute_match?
@@ -110,28 +88,7 @@ def errors_for_attribute_match?
110 88
         end
111 89
 
112 90
         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
125  
-          if @instance.errors.respond_to?(:[])
126  
-            errors = @instance.errors[@attribute]
127  
-          else
128  
-            errors = @instance.errors.on(@attribute)
129  
-          end
130  
-          Array.wrap(errors)
131  
-        end
132  
-
133  
-        def strict?
134  
-          @strict
  91
+          message_finder.messages
135 92
         end
136 93
 
137 94
         def errors_match_regexp?
@@ -152,35 +109,11 @@ def expectation
152 109
         end
153 110
 
154 111
         def error_source
155  
-          if strict?
156  
-            'exception'
157  
-          else
158  
-            'errors'
159  
-          end
  112
+          message_finder.source_description
160 113
         end
161 114
 
162 115
         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
179  
-          if @instance.errors.empty?
180  
-            "no errors"
181  
-          else
182  
-            "errors: #{pretty_error_messages(@instance)}"
183  
-          end
  116
+          message_finder.messages_description
184 117
         end
185 118
 
186 119
         def allowed_values
@@ -202,19 +135,7 @@ def expected_message
202 135
         end
203 136
 
204 137
         def default_expected_message
205  
-          if strict?
206  
-            default_full_message
207  
-          else
208  
-            default_attribute_message
209  
-          end
210  
-        end
211  
-
212  
-        def default_full_message
213  
-          "#{human_attribute_name} #{default_attribute_message}"
214  
-        end
215  
-
216  
-        def human_attribute_name
217  
-          @instance.class.human_attribute_name(@attribute)
  138
+          message_finder.expected_message_from(default_attribute_message)
218 139
         end
219 140
 
220 141
         def default_attribute_message
@@ -228,6 +149,10 @@ def default_attribute_message
228 149
         def model_name
229 150
           @instance.class.to_s.underscore
230 151
         end
  152
+
  153
+        def message_finder
  154
+          @message_finder ||= @message_finder_factory.new(@instance, @attribute)
  155
+        end
231 156
       end
232 157
     end
233 158
   end
58  lib/shoulda/matchers/active_model/exception_message_finder.rb
... ...
@@ -0,0 +1,58 @@
  1
+module Shoulda
  2
+  module Matchers
  3
+    module ActiveModel
  4
+
  5
+      # Finds message information from exceptions thrown by #valid?
  6
+      class ExceptionMessageFinder
  7
+        def initialize(instance, attribute)
  8
+          @instance = instance
  9
+          @attribute = attribute
  10
+        end
  11
+
  12
+        def allow_description(allowed_values)
  13
+          "doesn't raise when #{@attribute} is set to #{allowed_values}"
  14
+        end
  15
+
  16
+        def messages_description
  17
+          if has_messages?
  18
+            messages.join
  19
+          else
  20
+            'no exception'
  21
+          end
  22
+        end
  23
+
  24
+        def has_messages?
  25
+          messages.any?
  26
+        end
  27
+
  28
+        def messages
  29
+          @messages ||= validate_and_rescue
  30
+        end
  31
+
  32
+        def source_description
  33
+          'exception'
  34
+        end
  35
+
  36
+        def expected_message_from(attribute_message)
  37
+          "#{human_attribute_name} #{attribute_message}"
  38
+        end
  39
+
  40
+        private
  41
+
  42
+        def validate_and_rescue
  43
+          @instance.valid?
  44
+          []
  45
+        rescue ::ActiveModel::StrictValidationFailed => exception
  46
+          [exception.message]
  47
+        end
  48
+
  49
+        def human_attribute_name
  50
+          @instance.class.human_attribute_name(@attribute)
  51
+        end
  52
+      end
  53
+
  54
+    end
  55
+  end
  56
+end
  57
+
  58
+
69  lib/shoulda/matchers/active_model/validation_message_finder.rb
... ...
@@ -0,0 +1,69 @@
  1
+module Shoulda
  2
+  module Matchers
  3
+    module ActiveModel
  4
+
  5
+      # Finds message information from a model's #errors method.
  6
+      class ValidationMessageFinder
  7
+        include Helpers
  8
+
  9
+        def initialize(instance, attribute)
  10
+          @instance = instance
  11
+          @attribute = attribute
  12
+        end
  13
+
  14
+        def allow_description(allowed_values)
  15
+          "allow #{@attribute} to be set to #{allowed_values}"
  16
+        end
  17
+
  18
+        def expected_message_from(attribute_message)
  19
+          attribute_message
  20
+        end
  21
+
  22
+        def has_messages?
  23
+          errors.present?
  24
+        end
  25
+
  26
+        def source_description
  27
+          'errors'
  28
+        end
  29
+
  30
+        def messages_description
  31
+          if errors.empty?
  32
+            "no errors"
  33
+          else
  34
+            "errors: #{pretty_error_messages(validated_instance)}"
  35
+          end
  36
+        end
  37
+
  38
+        def messages
  39
+          Array.wrap(messages_for_attribute)
  40
+        end
  41
+
  42
+        private
  43
+
  44
+        def messages_for_attribute
  45
+          if errors.respond_to?(:[])
  46
+            errors[@attribute]
  47
+          else
  48
+            errors.on(@attribute)
  49
+          end
  50
+        end
  51
+
  52
+        def errors
  53
+          validated_instance.errors
  54
+        end
  55
+
  56
+        def validated_instance
  57
+          @validated_instance ||= validate_instance
  58
+        end
  59
+
  60
+        def validate_instance
  61
+          @instance.valid?
  62
+          @instance
  63
+        end
  64
+      end
  65
+
  66
+    end
  67
+  end
  68
+end
  69
+
2  spec/shoulda/active_model/allow_value_matcher_spec.rb
@@ -107,7 +107,7 @@
107 107
 
108 108
       it "describes itself" do
109 109
         allow_value("xyz").for(:attr).strict.description.
110  
-          should == 'strictly allow attr to be set to "xyz"'
  110
+          should == %{doesn't raise when attr is set to "xyz"}
111 111
       end
112 112
 
113 113
       it "provides a useful negative failure message" do
112  spec/shoulda/active_model/exception_message_finder_spec.rb
... ...
@@ -0,0 +1,112 @@
  1
+require 'spec_helper'
  2
+
  3
+describe Shoulda::Matchers::ActiveModel::ExceptionMessageFinder do
  4
+  if Rails::VERSION::STRING.to_f >= 3.2
  5
+    context '#allow_description' do
  6
+      it 'describes its attribute' do
  7
+        finder = build_finder(:attribute => :attr)
  8
+
  9
+        description = finder.allow_description('allowed values')
  10
+
  11
+        description.should == "doesn't raise when attr is set to allowed values"
  12
+      end
  13
+    end
  14
+
  15
+    context '#expected_message_from' do
  16
+      it 'returns the message with the attribute name prefixed' do
  17
+        finder = build_finder(:attribute => :attr)
  18
+
  19
+        message = finder.expected_message_from('some message')
  20
+
  21
+        message.should == 'Attr some message'
  22
+      end
  23
+    end
  24
+
  25
+    context '#has_messages?' do
  26
+      it 'has messages when some validations fail' do
  27
+        finder = build_finder(:format => /abc/, :value => 'xyz')
  28
+
  29
+        result = finder.has_messages?
  30
+
  31
+        result.should be_true
  32
+      end
  33
+
  34
+      it 'has no messages when all validations pass' do
  35
+        finder = build_finder(:format => /abc/, :value => 'abc')
  36
+
  37
+        result = finder.has_messages?
  38
+
  39
+        result.should be_false
  40
+      end
  41
+    end
  42
+
  43
+    context '#messages' do
  44
+      it 'returns errors for the given attribute' do
  45
+        finder = build_finder(
  46
+          :attribute => :attr,
  47
+          :format => /abc/,
  48
+          :value => 'xyz'
  49
+        )
  50
+
  51
+        messages = finder.messages
  52
+
  53
+        messages.should == ['Attr is invalid']
  54
+      end
  55
+    end
  56
+
  57
+    context '#messages_description' do
  58
+      it 'describes errors for the given attribute' do
  59
+        finder = build_finder(
  60
+          :attribute => :attr,
  61
+          :format => /abc/,
  62
+          :value => 'xyz'
  63
+        )
  64
+
  65
+        description = finder.messages_description
  66
+
  67
+        description.should == 'Attr is invalid'
  68
+      end
  69
+
  70
+      it 'describes errors when there are none' do
  71
+        finder = build_finder(:format => /abc/, :value => 'abc')
  72
+
  73
+        description = finder.messages_description
  74
+
  75
+        description.should == 'no exception'
  76
+      end
  77
+    end
  78
+
  79
+    context '#source_description' do
  80
+      it 'describes the source of its messages' do
  81
+        finder = build_finder
  82
+
  83
+        description = finder.source_description
  84
+
  85
+        description.should == 'exception'
  86
+      end
  87
+    end
  88
+  end
  89
+
  90
+  def build_finder(arguments = {})
  91
+    arguments[:attribute] ||= :attr
  92
+    instance = build_instance_validating(
  93
+      arguments[:attribute],
  94
+      arguments[:format] || /abc/,
  95
+      arguments[:value] || 'abc'
  96
+    )
  97
+    Shoulda::Matchers::ActiveModel::ExceptionMessageFinder.new(
  98
+      instance,
  99
+      arguments[:attribute]
  100
+    )
  101
+  end
  102
+
  103
+  def build_instance_validating(attribute, format, value)
  104
+    model_class = define_model(:example, attribute => :string) do
  105
+      attr_accessible attribute
  106
+      validates_format_of attribute, :with => format, :strict => true
  107
+    end
  108
+
  109
+    model_class.new(attribute => value)
  110
+  end
  111
+end
  112
+
105  spec/shoulda/active_model/validation_message_finder_spec.rb
... ...
@@ -0,0 +1,105 @@
  1
+require 'spec_helper'
  2
+
  3
+describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
  4
+  context '#allow_description' do
  5
+    it 'describes its attribute' do
  6
+      finder = build_finder(:attribute => :attr)
  7
+
  8
+      description = finder.allow_description('allowed values')
  9
+
  10
+      description.should == 'allow attr to be set to allowed values'
  11
+    end
  12
+  end
  13
+
  14
+  context '#expected_message_from' do
  15
+    it 'returns the message as-is' do
  16
+      finder = build_finder
  17
+
  18
+      message = finder.expected_message_from('some message')
  19
+
  20
+      message.should == 'some message'
  21
+    end
  22
+  end
  23
+
  24
+  context '#has_messages?' do
  25
+    it 'has messages when some validations fail' do
  26
+      finder = build_finder(:format => /abc/, :value => 'xyz')
  27
+
  28
+      result = finder.has_messages?
  29
+
  30
+      result.should be_true
  31
+    end
  32
+
  33
+    it 'has no messages when all validations pass' do
  34
+      finder = build_finder(:format => /abc/, :value => 'abc')
  35
+
  36
+      result = finder.has_messages?
  37
+
  38
+      result.should be_false
  39
+    end
  40
+  end
  41
+
  42
+  context '#messages' do
  43
+    it 'returns errors for the given attribute' do
  44
+      finder = build_finder(:format => /abc/, :value => 'xyz')
  45
+
  46
+      messages = finder.messages
  47
+
  48
+      messages.should == ['is invalid']
  49
+    end
  50
+  end
  51
+
  52
+  context '#messages_description' do
  53
+    it 'describes errors for the given attribute' do
  54
+      finder = build_finder(
  55
+        :attribute => :attr,
  56
+        :format => /abc/,
  57
+        :value => 'xyz'
  58
+      )
  59
+
  60
+      description = finder.messages_description
  61
+
  62
+      description.should == 'errors: ["attr is invalid (\"xyz\")"]'
  63
+    end
  64
+
  65
+    it 'describes errors when there are none' do
  66
+      finder = build_finder(:format => /abc/, :value => 'abc')
  67
+
  68
+      description = finder.messages_description
  69
+
  70
+      description.should == 'no errors'
  71
+    end
  72
+  end
  73
+
  74
+  context '#source_description' do
  75
+    it 'describes the source of its messages' do
  76
+      finder = build_finder
  77
+
  78
+      description = finder.source_description
  79
+
  80
+      description.should == 'errors'
  81
+    end
  82
+  end
  83
+
  84
+  def build_finder(arguments = {})
  85
+    arguments[:attribute] ||= :attr
  86
+    instance = build_instance_validating(
  87
+      arguments[:attribute],
  88
+      arguments[:format] || /abc/,
  89
+      arguments[:value] || 'abc'
  90
+    )
  91
+    Shoulda::Matchers::ActiveModel::ValidationMessageFinder.new(
  92
+      instance,
  93
+      arguments[:attribute]
  94
+    )
  95
+  end
  96
+
  97
+  def build_instance_validating(attribute, format, value)
  98
+    model_class = define_model(:example, attribute => :string) do
  99
+      attr_accessible attribute
  100
+      validates_format_of attribute, :with => format
  101
+    end
  102
+
  103
+    model_class.new(attribute => value)
  104
+  end
  105
+end

No commit comments for this range

Something went wrong with that request. Please try again.