Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: thoughtbot/shoulda-matchers
...
head fork: thoughtbot/shoulda-matchers
  • 2 commits
  • 7 files changed
  • 0 commit comments
  • 1 contributor
2  lib/shoulda/matchers/active_model.rb
View
@@ -1,5 +1,7 @@
require 'shoulda/matchers/active_model/helpers'
require 'shoulda/matchers/active_model/validation_matcher'
+require 'shoulda/matchers/active_model/validation_message_finder'
+require 'shoulda/matchers/active_model/exception_message_finder'
require 'shoulda/matchers/active_model/allow_value_matcher'
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
103 lib/shoulda/matchers/active_model/allow_value_matcher.rb
View
@@ -29,7 +29,7 @@ class AllowValueMatcher # :nodoc:
def initialize(*values)
@values_to_match = values
- @strict = false
+ @message_finder_factory = ValidationMessageFinder
@options = {}
end
@@ -44,7 +44,7 @@ def with_message(message)
end
def strict
- @strict = true
+ @message_finder_factory = ExceptionMessageFinder
self
end
@@ -66,39 +66,17 @@ def negative_failure_message
end
def description
- base = "allow #{@attribute} to be set to #{allowed_values}"
-
- if strict?
- "strictly #{base}"
- else
- base
- end
+ message_finder.allow_description(allowed_values)
end
private
def errors_match?
- if strict?
- exception_message_matches?
- else
- validation_messages_match?
- end
+ has_messages? && errors_for_attribute_match?
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
- errors_for_attribute_match?
- end
+ def has_messages?
+ message_finder.has_messages?
end
def errors_for_attribute_match?
@@ -110,28 +88,7 @@ def errors_for_attribute_match?
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
- errors = @instance.errors.on(@attribute)
- end
- Array.wrap(errors)
- end
-
- def strict?
- @strict
+ message_finder.messages
end
def errors_match_regexp?
@@ -152,35 +109,11 @@ def expectation
end
def error_source
- if strict?
- 'exception'
- else
- 'errors'
- end
+ message_finder.source_description
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
- "errors: #{pretty_error_messages(@instance)}"
- end
+ message_finder.messages_description
end
def allowed_values
@@ -202,19 +135,7 @@ def expected_message
end
def default_expected_message
- if strict?
- default_full_message
- else
- default_attribute_message
- end
- end
-
- def default_full_message
- "#{human_attribute_name} #{default_attribute_message}"
- end
-
- def human_attribute_name
- @instance.class.human_attribute_name(@attribute)
+ message_finder.expected_message_from(default_attribute_message)
end
def default_attribute_message
@@ -228,6 +149,10 @@ def default_attribute_message
def model_name
@instance.class.to_s.underscore
end
+
+ def message_finder
+ @message_finder ||= @message_finder_factory.new(@instance, @attribute)
+ end
end
end
end
58 lib/shoulda/matchers/active_model/exception_message_finder.rb
View
@@ -0,0 +1,58 @@
+module Shoulda
+ module Matchers
+ module ActiveModel
+
+ # Finds message information from exceptions thrown by #valid?
+ class ExceptionMessageFinder
+ def initialize(instance, attribute)
+ @instance = instance
+ @attribute = attribute
+ end
+
+ def allow_description(allowed_values)
+ "doesn't raise when #{@attribute} is set to #{allowed_values}"
+ end
+
+ def messages_description
+ if has_messages?
+ messages.join
+ else
+ 'no exception'
+ end
+ end
+
+ def has_messages?
+ messages.any?
+ end
+
+ def messages
+ @messages ||= validate_and_rescue
+ end
+
+ def source_description
+ 'exception'
+ end
+
+ def expected_message_from(attribute_message)
+ "#{human_attribute_name} #{attribute_message}"
+ end
+
+ private
+
+ def validate_and_rescue
+ @instance.valid?
+ []
+ rescue ::ActiveModel::StrictValidationFailed => exception
+ [exception.message]
+ end
+
+ def human_attribute_name
+ @instance.class.human_attribute_name(@attribute)
+ end
+ end
+
+ end
+ end
+end
+
+
69 lib/shoulda/matchers/active_model/validation_message_finder.rb
View
@@ -0,0 +1,69 @@
+module Shoulda
+ module Matchers
+ module ActiveModel
+
+ # Finds message information from a model's #errors method.
+ class ValidationMessageFinder
+ include Helpers
+
+ def initialize(instance, attribute)
+ @instance = instance
+ @attribute = attribute
+ end
+
+ def allow_description(allowed_values)
+ "allow #{@attribute} to be set to #{allowed_values}"
+ end
+
+ def expected_message_from(attribute_message)
+ attribute_message
+ end
+
+ def has_messages?
+ errors.present?
+ end
+
+ def source_description
+ 'errors'
+ end
+
+ def messages_description
+ if errors.empty?
+ "no errors"
+ else
+ "errors: #{pretty_error_messages(validated_instance)}"
+ end
+ end
+
+ def messages
+ Array.wrap(messages_for_attribute)
+ end
+
+ private
+
+ def messages_for_attribute
+ if errors.respond_to?(:[])
+ errors[@attribute]
+ else
+ errors.on(@attribute)
+ end
+ end
+
+ def errors
+ validated_instance.errors
+ end
+
+ def validated_instance
+ @validated_instance ||= validate_instance
+ end
+
+ def validate_instance
+ @instance.valid?
+ @instance
+ end
+ end
+
+ end
+ end
+end
+
2  spec/shoulda/active_model/allow_value_matcher_spec.rb
View
@@ -107,7 +107,7 @@
it "describes itself" do
allow_value("xyz").for(:attr).strict.description.
- should == 'strictly allow attr to be set to "xyz"'
+ should == %{doesn't raise when attr is set to "xyz"}
end
it "provides a useful negative failure message" do
112 spec/shoulda/active_model/exception_message_finder_spec.rb
View
@@ -0,0 +1,112 @@
+require 'spec_helper'
+
+describe Shoulda::Matchers::ActiveModel::ExceptionMessageFinder do
+ if Rails::VERSION::STRING.to_f >= 3.2
+ context '#allow_description' do
+ it 'describes its attribute' do
+ finder = build_finder(:attribute => :attr)
+
+ description = finder.allow_description('allowed values')
+
+ description.should == "doesn't raise when attr is set to allowed values"
+ end
+ end
+
+ context '#expected_message_from' do
+ it 'returns the message with the attribute name prefixed' do
+ finder = build_finder(:attribute => :attr)
+
+ message = finder.expected_message_from('some message')
+
+ message.should == 'Attr some message'
+ end
+ end
+
+ context '#has_messages?' do
+ it 'has messages when some validations fail' do
+ finder = build_finder(:format => /abc/, :value => 'xyz')
+
+ result = finder.has_messages?
+
+ result.should be_true
+ end
+
+ it 'has no messages when all validations pass' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ result = finder.has_messages?
+
+ result.should be_false
+ end
+ end
+
+ context '#messages' do
+ it 'returns errors for the given attribute' do
+ finder = build_finder(
+ :attribute => :attr,
+ :format => /abc/,
+ :value => 'xyz'
+ )
+
+ messages = finder.messages
+
+ messages.should == ['Attr is invalid']
+ end
+ end
+
+ context '#messages_description' do
+ it 'describes errors for the given attribute' do
+ finder = build_finder(
+ :attribute => :attr,
+ :format => /abc/,
+ :value => 'xyz'
+ )
+
+ description = finder.messages_description
+
+ description.should == 'Attr is invalid'
+ end
+
+ it 'describes errors when there are none' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ description = finder.messages_description
+
+ description.should == 'no exception'
+ end
+ end
+
+ context '#source_description' do
+ it 'describes the source of its messages' do
+ finder = build_finder
+
+ description = finder.source_description
+
+ description.should == 'exception'
+ end
+ end
+ end
+
+ def build_finder(arguments = {})
+ arguments[:attribute] ||= :attr
+ instance = build_instance_validating(
+ arguments[:attribute],
+ arguments[:format] || /abc/,
+ arguments[:value] || 'abc'
+ )
+ Shoulda::Matchers::ActiveModel::ExceptionMessageFinder.new(
+ instance,
+ arguments[:attribute]
+ )
+ end
+
+ def build_instance_validating(attribute, format, value)
+ model_class = define_model(:example, attribute => :string) do
+ attr_accessible attribute
+ validates_format_of attribute, :with => format, :strict => true
+ end
+
+ model_class.new(attribute => value)
+ end
+end
+
105 spec/shoulda/active_model/validation_message_finder_spec.rb
View
@@ -0,0 +1,105 @@
+require 'spec_helper'
+
+describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
+ context '#allow_description' do
+ it 'describes its attribute' do
+ finder = build_finder(:attribute => :attr)
+
+ description = finder.allow_description('allowed values')
+
+ description.should == 'allow attr to be set to allowed values'
+ end
+ end
+
+ context '#expected_message_from' do
+ it 'returns the message as-is' do
+ finder = build_finder
+
+ message = finder.expected_message_from('some message')
+
+ message.should == 'some message'
+ end
+ end
+
+ context '#has_messages?' do
+ it 'has messages when some validations fail' do
+ finder = build_finder(:format => /abc/, :value => 'xyz')
+
+ result = finder.has_messages?
+
+ result.should be_true
+ end
+
+ it 'has no messages when all validations pass' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ result = finder.has_messages?
+
+ result.should be_false
+ end
+ end
+
+ context '#messages' do
+ it 'returns errors for the given attribute' do
+ finder = build_finder(:format => /abc/, :value => 'xyz')
+
+ messages = finder.messages
+
+ messages.should == ['is invalid']
+ end
+ end
+
+ context '#messages_description' do
+ it 'describes errors for the given attribute' do
+ finder = build_finder(
+ :attribute => :attr,
+ :format => /abc/,
+ :value => 'xyz'
+ )
+
+ description = finder.messages_description
+
+ description.should == 'errors: ["attr is invalid (\"xyz\")"]'
+ end
+
+ it 'describes errors when there are none' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ description = finder.messages_description
+
+ description.should == 'no errors'
+ end
+ end
+
+ context '#source_description' do
+ it 'describes the source of its messages' do
+ finder = build_finder
+
+ description = finder.source_description
+
+ description.should == 'errors'
+ end
+ end
+
+ def build_finder(arguments = {})
+ arguments[:attribute] ||= :attr
+ instance = build_instance_validating(
+ arguments[:attribute],
+ arguments[:format] || /abc/,
+ arguments[:value] || 'abc'
+ )
+ Shoulda::Matchers::ActiveModel::ValidationMessageFinder.new(
+ instance,
+ arguments[:attribute]
+ )
+ end
+
+ def build_instance_validating(attribute, format, value)
+ model_class = define_model(:example, attribute => :string) do
+ attr_accessible attribute
+ validates_format_of attribute, :with => format
+ end
+
+ model_class.new(attribute => value)
+ end
+end

No commit comments for this range

Something went wrong with that request. Please try again.