Skip to content

Commit

Permalink
Adding support to allow_nil option for delegate_method matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandrodevs authored and mcmire committed Jan 24, 2018
1 parent ba5b663 commit d49cfca
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 42 deletions.
101 changes: 80 additions & 21 deletions lib/shoulda/matchers/independent/delegate_method_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,11 @@ def initialize(delegating_method)
@delegate_method = @delegating_method
@delegate_object = Doublespeak::ObjectDouble.new

@delegated_arguments = []
@delegate_object_reader_method = nil
@context = nil
@subject = nil
@subject_double_collection = nil
@delegate_object_reader_method = nil
@delegated_arguments = []
@expects_to_allow_nil_delegate_object = false
end

def in_context(context)
Expand All @@ -180,11 +181,13 @@ def matches?(subject)

subject_has_delegating_method? &&
subject_has_delegate_object_reader_method? &&
subject_delegates_to_delegate_object_correctly?
subject_delegates_to_delegate_object_correctly? &&
subject_handles_nil_delegate_object?
end

def description
string = "delegate #{formatted_delegating_method_name} to " +
string =
"delegate #{formatted_delegating_method_name} to the " +
"#{formatted_delegate_object_reader_method_name} object"

if delegated_arguments.any?
Expand All @@ -195,6 +198,12 @@ def description
string << " as #{formatted_delegate_method}"
end

if expects_to_allow_nil_delegate_object?
string << ", allowing "
string << formatted_delegate_object_reader_method_name
string << " to return nil"
end

string
end

Expand All @@ -220,6 +229,11 @@ def with_prefix(prefix = nil)
self
end

def allow_nil
@expects_to_allow_nil_delegate_object = true
self
end

def build_delegating_method_prefix(prefix)
case prefix
when true, nil then delegate_object_reader_method
Expand All @@ -228,14 +242,29 @@ def build_delegating_method_prefix(prefix)
end

def failure_message
"Expected #{class_under_test} to #{description}\n" +
"Method calls sent to " +
"#{formatted_delegate_object_reader_method_name(include_module: true)}:" +
formatted_calls_on_delegate_object
message = "Expected #{class_under_test} to #{description}.\n\n"

if failed_to_allow_nil_delegate_object?
message << formatted_delegating_method_name(include_module: true)
message << ' did delegate to '
message << formatted_delegate_object_reader_method_name
message << ' when it was non-nil, but it failed to account '
message << 'for when '
message << formatted_delegate_object_reader_method_name
message << ' *was* nil.'
else
message << 'Method calls sent to '
message << formatted_delegate_object_reader_method_name(
include_module: true,
)
message << ": #{formatted_calls_on_delegate_object}"
end

Shoulda::Matchers.word_wrap(message)
end

def failure_message_when_negated
"Expected #{class_under_test} not to #{description}, but it did"
"Expected #{class_under_test} not to #{description}, but it did."
end

protected
Expand All @@ -246,7 +275,6 @@ def failure_message_when_negated
:delegating_method,
:method,
:delegate_method,
:subject_double_collection,
:delegate_object,
:delegate_object_reader_method

Expand All @@ -270,6 +298,10 @@ def class_under_test
end
end

def expects_to_allow_nil_delegate_object?
@expects_to_allow_nil_delegate_object
end

def formatted_delegate_method(options = {})
formatted_method_name_for(delegate_method, options)
end
Expand Down Expand Up @@ -329,11 +361,7 @@ def ensure_delegate_object_has_been_specified!
end

def subject_delegates_to_delegate_object_correctly?
register_subject_double_collection

Doublespeak.with_doubles_activated do
subject.public_send(delegating_method, *delegated_arguments)
end
call_delegating_method_with_delegate_method_returning(delegate_object)

if delegated_arguments.any?
delegate_object_received_call_with_delegated_arguments?
Expand All @@ -342,13 +370,44 @@ def subject_delegates_to_delegate_object_correctly?
end
end

def register_subject_double_collection
def subject_handles_nil_delegate_object?
@subject_handled_nil_delegate_object =
if expects_to_allow_nil_delegate_object?
begin
call_delegating_method_with_delegate_method_returning(nil)
true
rescue Module::DelegationError
false
rescue NoMethodError => error
if error.message =~ /undefined method `#{delegate_method}' for nil:NilClass/
false
else
raise error
end
end
else
true
end
end

def failed_to_allow_nil_delegate_object?
expects_to_allow_nil_delegate_object? &&
!@subject_handled_nil_delegate_object
end

def call_delegating_method_with_delegate_method_returning(value)
register_subject_double_collection_to(value)

Doublespeak.with_doubles_activated do
subject.public_send(delegating_method, *delegated_arguments)
end
end

def register_subject_double_collection_to(returned_value)
double_collection =
Doublespeak.double_collection_for(subject.singleton_class)
double_collection.register_stub(delegate_object_reader_method).
to_return(delegate_object)

@subject_double_collection = double_collection
to_return(returned_value)
end

def calls_to_delegate_method
Expand All @@ -363,7 +422,7 @@ def formatted_calls_on_delegate_object
string = ""

if calls_on_delegate_object.any?
string << "\n"
string << "\n\n"
calls_on_delegate_object.each_with_index do |call, i|
name = call.method_name
args = call.args.map { |arg| arg.inspect }.join(', ')
Expand Down
4 changes: 2 additions & 2 deletions spec/acceptance/independent_matchers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def post_office

expect(result).to indicate_number_of_tests_was_run(1)
expect(result).to have_output(
'Courier should delegate #deliver to #post_office object'
'Courier should delegate #deliver to the #post_office object'
)
end

Expand Down Expand Up @@ -119,7 +119,7 @@ def post_office

expect(result).to indicate_number_of_tests_was_run(1)
expect(result).to have_output(
/Courier\s+should delegate #deliver to #post_office object/
/Courier\s+should delegate #deliver to the #post_office object/
)
end
end
Loading

0 comments on commit d49cfca

Please sign in to comment.