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.
Attributes
@private
Public Class Methods
Source
# File lib/rspec/mocks/message_expectation.rb, line 426 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 self.invoking_internals = false # 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
rubocop:disable Metrics/ParameterLists
Public Instance Methods
Source
# File lib/rspec/mocks/message_expectation.rb, line 605 def actual_received_count_matters? @at_least || @at_most || @exactly end
Source
# File lib/rspec/mocks/message_expectation.rb, line 592 def additional_expected_calls return 0 if @expectation_type == :stub || !@exactly @expected_received_count - 1 end
Source
# File lib/rspec/mocks/message_expectation.rb, line 549 def advise(*args) similar_messages << args end
Source
# File lib/rspec/mocks/message_expectation.rb, line 462 def and_yield_receiver_to_implementation @yield_receiver_to_implementation_block = true self end
Source
# File lib/rspec/mocks/message_expectation.rb, line 504 def called_max_times? @expected_received_count != :any && !@at_least && @expected_received_count > 0 && @actual_received_count >= @expected_received_count end
Source
# File lib/rspec/mocks/message_expectation.rb, line 581 def description_for(verb) @error_generator.describe_expectation( verb, @message, @expected_received_count, @actual_received_count, expected_args ) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 524 def ensure_expected_ordering_received! @order_group.verify_invocation_order(self) if @ordered true end
Source
# File lib/rspec/mocks/message_expectation.rb, line 575 def expectation_count_type return :at_least if @at_least return :at_most if @at_most nil end
Source
# File lib/rspec/mocks/message_expectation.rb, line 458 def expected_args @argument_list_matcher.expected_args end
rubocop:enable Metrics/ParameterLists
Source
# File lib/rspec/mocks/message_expectation.rb, line 520 def expected_messages_received? ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count? end
Source
# File lib/rspec/mocks/message_expectation.rb, line 557 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
Source
# File lib/rspec/mocks/message_expectation.rb, line 529 def ignoring_args? @expected_received_count == :any end
Source
# File lib/rspec/mocks/message_expectation.rb, line 609 def increase_actual_received_count! @actual_received_count_write_mutex.synchronize do @actual_received_count += 1 end end
Source
# File lib/rspec/mocks/message_expectation.rb, line 481 def invoke(parent_stub, *args, &block) if invoking_internals safe_invoke_without_incrementing_received_count(parent_stub, *args, &block) else invoke_incrementing_actual_calls_by(1, true, parent_stub, *args, &block) end end
Source
# File lib/rspec/mocks/message_expectation.rb, line 495 def invoke_without_incrementing_received_count(parent_stub, *args, &block) invoke_incrementing_actual_calls_by(0, true, parent_stub, *args, &block) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 471 def matches?(message, *args) @message == message && @argument_list_matcher.args_match?(*args) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 533 def matches_at_least_count? @at_least && @actual_received_count >= @expected_received_count end
Source
# File lib/rspec/mocks/message_expectation.rb, line 537 def matches_at_most_count? @at_most && @actual_received_count <= @expected_received_count end
Source
# File lib/rspec/mocks/message_expectation.rb, line 541 def matches_exact_count? @expected_received_count == @actual_received_count end
Source
# File lib/rspec/mocks/message_expectation.rb, line 511 def matches_name_but_not_args(message, *args) @message == message && !@argument_list_matcher.args_match?(*args) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 500 def negative? @expected_received_count == 0 && !@at_least end
Source
# File lib/rspec/mocks/message_expectation.rb, line 601 def negative_expectation_for?(message) @message == message && negative? end
Source
# File lib/rspec/mocks/message_expectation.rb, line 597 def ordered? @ordered end
Source
# File lib/rspec/mocks/message_expectation.rb, line 588 def raise_out_of_order_error @error_generator.raise_out_of_order_error @message end
Source
# File lib/rspec/mocks/message_expectation.rb, line 571 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
Source
# File lib/rspec/mocks/message_expectation.rb, line 476 def safe_invoke(parent_stub, *args, &block) invoke_incrementing_actual_calls_by(1, false, parent_stub, *args, &block) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 490 def safe_invoke_without_incrementing_received_count(parent_stub, *args, &block) invoke_incrementing_actual_calls_by(0, false, parent_stub, *args, &block) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 545 def similar_messages @similar_messages ||= [] end
Source
# File lib/rspec/mocks/message_expectation.rb, line 553 def unadvise(args) similar_messages.delete_if { |message| args.include?(message) } end
Source
# File lib/rspec/mocks/message_expectation.rb, line 515 def verify_messages_received return if expected_messages_received? generate_error end
Source
# File lib/rspec/mocks/message_expectation.rb, line 467 def yield_receiver_to_implementation_block? @yield_receiver_to_implementation_block end
Private Instance Methods
Source
# File lib/rspec/mocks/message_expectation.rb, line 617 def exception_source_id @exception_source_id ||= "#{self.class.name} #{__id__}" end
Source
# File lib/rspec/mocks/message_expectation.rb, line 669 def has_been_invoked? @actual_received_count > 0 end
Source
# File lib/rspec/mocks/message_expectation.rb, line 692 def initial_implementation_action=(action) implementation.initial_action = action end
Source
# File lib/rspec/mocks/message_expectation.rb, line 696 def inner_implementation_action=(action) return unless action warn_about_stub_override if implementation.inner_action implementation.inner_action = action end
Source
# File lib/rspec/mocks/message_expectation.rb, line 636 def invoke_incrementing_actual_calls_by(increment, allowed_to_fail, parent_stub, *args, &block) self.invoking_internals = true 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 self.invoking_internals = false if implementation.present? implementation.call(*args, &block) elsif parent_stub parent_stub.invoke(nil, *args, &block) end ensure self.invoking_internals = false @actual_received_count_write_mutex.synchronize do @actual_received_count += increment end end
Source
# File lib/rspec/mocks/message_expectation.rb, line 621 def invoking_internals RSpec::Support.thread_local_data[:"__rspec_#{object_id}_invoking_internals"] end
Source
# File lib/rspec/mocks/message_expectation.rb, line 625 def invoking_internals=(value) # We clear the key for this rather than setting to false because otherwise the amount of # thread local data will keep growing over the lifetime of the thread (which is a long # time on a single threaded spec run e.g standard MRI) if value RSpec::Support.thread_local_data[:"__rspec_#{object_id}_invoking_internals"] = true else RSpec::Support.thread_local_data.delete(:"__rspec_#{object_id}_invoking_internals") end end
Source
# File lib/rspec/mocks/message_expectation.rb, line 673 def raise_already_invoked_error_if_necessary(calling_customization) return unless has_been_invoked? error_generator.raise_already_invoked_error(message, calling_customization) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 679 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
Source
# File lib/rspec/mocks/message_expectation.rb, line 702 def terminal_implementation_action=(action) implementation.terminal_action = action end
Source
# File lib/rspec/mocks/message_expectation.rb, line 706 def warn_about_stub_override RSpec.warning( "You're overriding a previous stub implementation of `#{@message}`. " \ "Called from #{CallerFilter.first_non_rspec_line}." ) end
Source
# File lib/rspec/mocks/message_expectation.rb, line 713 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