Skip to content

Commit

Permalink
Extract ValidationMessageFinder from AllowValueMatcher
Browse files Browse the repository at this point in the history
  • Loading branch information
jferris committed Sep 13, 2012
1 parent 96d32c2 commit 3dbf5d4
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 34 deletions.
1 change: 1 addition & 0 deletions lib/shoulda/matchers/active_model.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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/allow_value_matcher'
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
Expand Down
51 changes: 17 additions & 34 deletions lib/shoulda/matchers/active_model/allow_value_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,34 +71,30 @@ def description
if strict?
"strictly #{base}"
else
base
message_finder.allow_description(allowed_values)
end
end

private

def errors_match?
has_messages? && errors_for_attribute_match?
end

def has_messages?
if strict?
exception_message_matches?
has_exception_message?
else
validation_messages_match?
message_finder.has_messages?
end
end

def exception_message_matches?
def has_exception_message?
@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
true
end

def errors_for_attribute_match?
Expand All @@ -113,23 +109,14 @@ def errors_for_attribute
if strict?
[strict_exception_message]
else
validation_messages_for_attribute
message_finder.messages
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
end
Expand All @@ -155,15 +142,15 @@ def error_source
if strict?
'exception'
else
'errors'
message_finder.source_description
end
end

def error_description
if strict?
exception_description
else
validation_error_description
message_finder.messages_description
end
end

Expand All @@ -175,14 +162,6 @@ def exception_description
end
end

def validation_error_description
if @instance.errors.empty?
"no errors"
else
"errors: #{pretty_error_messages(@instance)}"
end
end

def allowed_values
if @values_to_match.length > 1
"any of [#{@values_to_match.map(&:inspect).join(', ')}]"
Expand All @@ -205,7 +184,7 @@ def default_expected_message
if strict?
default_full_message
else
default_attribute_message
message_finder.expected_message_from(default_attribute_message)
end
end

Expand All @@ -228,6 +207,10 @@ def default_attribute_message
def model_name
@instance.class.to_s.underscore
end

def message_finder
@message_finder ||= ValidationMessageFinder.new(@instance, @attribute)
end
end
end
end
Expand Down
69 changes: 69 additions & 0 deletions lib/shoulda/matchers/active_model/validation_message_finder.rb
Original file line number Diff line number Diff line change
@@ -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

105 changes: 105 additions & 0 deletions spec/shoulda/active_model/validation_message_finder_spec.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3dbf5d4

Please sign in to comment.