module RSpec::Mocks::MessageExpectation::ImplementationDetails
@private Contains the parts of ‘MessageExpectation` that aren’t part of rspec-mocks’ public API. The class is very big and could really use some collaborators it delegates to for this stuff but for now this was the simplest way to split the public from private stuff to make it easier to publish the docs for the APIs we want published. rubocop:disable Metrics/ModuleLength
Attributes
argument_list_matcher[W]
error_generator[RW]
expected_from[W]
expected_received_count[W]
implementation[RW]
message[R]
orig_object[R]
type[R]
@private
Public Class Methods
new(error_generator, expectation_ordering, expected_from, method_double, type=:expectation, opts={}, &implementation_block)
click to toggle source
rubocop:disable Metrics/ParameterLists
# File lib/rspec/mocks/message_expectation.rb, line 418 def initialize(error_generator, expectation_ordering, expected_from, method_double, type=:expectation, opts={}, &implementation_block) @type = type @error_generator = error_generator @error_generator.opts = error_generator.opts.merge(opts) @expected_from = expected_from @method_double = method_double @orig_object = @method_double.object @message = @method_double.method_name @actual_received_count = 0 @actual_received_count_write_mutex = Support::Mutex.new @expected_received_count = type == :expectation ? 1 : :any @argument_list_matcher = ArgumentListMatcher::MATCH_ALL @order_group = expectation_ordering @order_group.register(self) unless type == :stub @expectation_type = type @ordered = false @at_least = @at_most = @exactly = nil # Initialized to nil so that we don't allocate an array for every # mock or stub. See also comment in `and_yield`. @args_to_yield = nil @eval_context = nil @yield_receiver_to_implementation_block = false @implementation = Implementation.new self.inner_implementation_action = implementation_block end
Public Instance Methods
actual_received_count_matters?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 582 def actual_received_count_matters? @at_least || @at_most || @exactly end
additional_expected_calls()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 569 def additional_expected_calls return 0 if @expectation_type == :stub || !@exactly @expected_received_count - 1 end
advise(*args)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 526 def advise(*args) similar_messages << args end
and_yield_receiver_to_implementation()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 452 def and_yield_receiver_to_implementation @yield_receiver_to_implementation_block = true self end
called_max_times?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 481 def called_max_times? @expected_received_count != :any && !@at_least && @expected_received_count > 0 && @actual_received_count >= @expected_received_count end
description_for(verb)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 558 def description_for(verb) @error_generator.describe_expectation( verb, @message, @expected_received_count, @actual_received_count, expected_args ) end
ensure_expected_ordering_received!()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 501 def ensure_expected_ordering_received! @order_group.verify_invocation_order(self) if @ordered true end
expectation_count_type()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 552 def expectation_count_type return :at_least if @at_least return :at_most if @at_most nil end
expected_args()
click to toggle source
rubocop:enable Metrics/ParameterLists
# File lib/rspec/mocks/message_expectation.rb, line 448 def expected_args @argument_list_matcher.expected_args end
expected_messages_received?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 497 def expected_messages_received? ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count? end
generate_error()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 534 def generate_error if similar_messages.empty? @error_generator.raise_expectation_error( @message, @expected_received_count, @argument_list_matcher, @actual_received_count, expectation_count_type, expected_args, @expected_from, exception_source_id ) else @error_generator.raise_similar_message_args_error( self, @similar_messages, @expected_from ) end end
ignoring_args?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 506 def ignoring_args? @expected_received_count == :any end
increase_actual_received_count!()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 586 def increase_actual_received_count! @actual_received_count_write_mutex.synchronize do @actual_received_count += 1 end end
invoke(parent_stub, *args, &block)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 469 def invoke(parent_stub, *args, &block) invoke_incrementing_actual_calls_by(1, true, parent_stub, *args, &block) end
invoke_without_incrementing_received_count(parent_stub, *args, &block)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 473 def invoke_without_incrementing_received_count(parent_stub, *args, &block) invoke_incrementing_actual_calls_by(0, true, parent_stub, *args, &block) end
matches?(message, *args)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 461 def matches?(message, *args) @message == message && @argument_list_matcher.args_match?(*args) end
matches_at_least_count?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 510 def matches_at_least_count? @at_least && @actual_received_count >= @expected_received_count end
matches_at_most_count?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 514 def matches_at_most_count? @at_most && @actual_received_count <= @expected_received_count end
matches_exact_count?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 518 def matches_exact_count? @expected_received_count == @actual_received_count end
matches_name_but_not_args(message, *args)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 488 def matches_name_but_not_args(message, *args) @message == message && !@argument_list_matcher.args_match?(*args) end
negative?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 477 def negative? @expected_received_count == 0 && !@at_least end
negative_expectation_for?(message)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 578 def negative_expectation_for?(message) @message == message && negative? end
ordered?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 574 def ordered? @ordered end
raise_out_of_order_error()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 565 def raise_out_of_order_error @error_generator.raise_out_of_order_error @message end
raise_unexpected_message_args_error(args_for_multiple_calls)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 548 def raise_unexpected_message_args_error(args_for_multiple_calls) @error_generator.raise_unexpected_message_args_error(self, args_for_multiple_calls, exception_source_id) end
safe_invoke(parent_stub, *args, &block)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 465 def safe_invoke(parent_stub, *args, &block) invoke_incrementing_actual_calls_by(1, false, parent_stub, *args, &block) end
similar_messages()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 522 def similar_messages @similar_messages ||= [] end
unadvise(args)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 530 def unadvise(args) similar_messages.delete_if { |message| args.include?(message) } end
verify_messages_received()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 492 def verify_messages_received return if expected_messages_received? generate_error end
yield_receiver_to_implementation_block?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 457 def yield_receiver_to_implementation_block? @yield_receiver_to_implementation_block end
Private Instance Methods
exception_source_id()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 594 def exception_source_id @exception_source_id ||= "#{self.class.name} #{__id__}" end
has_been_invoked?()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 625 def has_been_invoked? @actual_received_count > 0 end
initial_implementation_action=(action)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 648 def initial_implementation_action=(action) implementation.initial_action = action end
inner_implementation_action=(action)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 652 def inner_implementation_action=(action) return unless action warn_about_stub_override if implementation.inner_action implementation.inner_action = action end
invoke_incrementing_actual_calls_by(increment, allowed_to_fail, parent_stub, *args, &block)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 598 def invoke_incrementing_actual_calls_by(increment, allowed_to_fail, parent_stub, *args, &block) args.unshift(orig_object) if yield_receiver_to_implementation_block? if negative? || (allowed_to_fail && (@exactly || @at_most) && (@actual_received_count == @expected_received_count)) # args are the args we actually received, @argument_list_matcher is the # list of args we were expecting @error_generator.raise_expectation_error( @message, @expected_received_count, @argument_list_matcher, @actual_received_count + increment, expectation_count_type, args, nil, exception_source_id ) end @order_group.handle_order_constraint self if implementation.present? implementation.call(*args, &block) elsif parent_stub parent_stub.invoke(nil, *args, &block) end ensure @actual_received_count_write_mutex.synchronize do @actual_received_count += increment end end
raise_already_invoked_error_if_necessary(calling_customization)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 629 def raise_already_invoked_error_if_necessary(calling_customization) return unless has_been_invoked? error_generator.raise_already_invoked_error(message, calling_customization) end
set_expected_received_count(relativity, n)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 635 def set_expected_received_count(relativity, n) raise "`count` is not supported with negative message expectations" if negative? @at_least = (relativity == :at_least) @at_most = (relativity == :at_most) @exactly = (relativity == :exactly) @expected_received_count = case n when Numeric then n when :once then 1 when :twice then 2 when :thrice then 3 end end
terminal_implementation_action=(action)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 658 def terminal_implementation_action=(action) implementation.terminal_action = action end
warn_about_stub_override()
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 662 def warn_about_stub_override RSpec.warning( "You're overriding a previous stub implementation of `#{@message}`. " \ "Called from #{CallerFilter.first_non_rspec_line}." ) end
wrap_original(method_name, &block)
click to toggle source
# File lib/rspec/mocks/message_expectation.rb, line 669 def wrap_original(method_name, &block) if RSpec::Mocks::TestDouble === @method_double.object @error_generator.raise_only_valid_on_a_partial_double(method_name) else warn_about_stub_override if implementation.inner_action @implementation = AndWrapOriginalImplementation.new(@method_double.original_implementation_callable, block) @yield_receiver_to_implementation_block = false end nil end