module RSpec::Mocks::MessageExpectation::ImplementationDetails

def actual_received_count_matters?

def actual_received_count_matters?
  @at_least || @at_most || @exactly
end

def additional_expected_calls

def additional_expected_calls
  return 0 if @expectation_type == :stub || !@exactly
  @expected_received_count - 1
end

def advise(*args)

def advise(*args)
  similar_messages << args
end

def and_yield_receiver_to_implementation

def and_yield_receiver_to_implementation
  @yield_receiver_to_implementation_block = true
  self
end

def called_max_times?

def called_max_times?
  @expected_received_count != :any &&
    !@at_least &&
    @expected_received_count > 0 &&
    @actual_received_count >= @expected_received_count
end

def description_for(verb)

def description_for(verb)
  @error_generator.describe_expectation(
    verb, @message, @expected_received_count,
    @actual_received_count, expected_args
  )
end

def ensure_expected_ordering_received!

def ensure_expected_ordering_received!
  @order_group.verify_invocation_order(self) if @ordered
  true
end

def exception_source_id

def exception_source_id
  @exception_source_id ||= "#{self.class.name} #{__id__}"
end

def expectation_count_type

def expectation_count_type
  return :at_least if @at_least
  return :at_most if @at_most
  nil
end

def expected_args

def expected_args
  @argument_list_matcher.expected_args
end

def expected_messages_received?

def expected_messages_received?
  ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count?
end

def generate_error

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

def has_been_invoked?

def has_been_invoked?
  @actual_received_count > 0
end

def ignoring_args?

def ignoring_args?
  @expected_received_count == :any
end

def increase_actual_received_count!

def increase_actual_received_count!
  @actual_received_count_write_mutex.synchronize do
    @actual_received_count += 1
  end
end

def initial_implementation_action=(action)

def initial_implementation_action=(action)
  implementation.initial_action = action
end

def initialize(error_generator, expectation_ordering, expected_from, method_double,

rubocop:disable Metrics/ParameterLists
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

def inner_implementation_action=(action)

def inner_implementation_action=(action)
  return unless action
  warn_about_stub_override if implementation.inner_action
  implementation.inner_action = action
end

def invoke(parent_stub, *args, &block)

def invoke(parent_stub, *args, &block)
  invoke_incrementing_actual_calls_by(1, true, parent_stub, *args, &block)
end

def invoke_incrementing_actual_calls_by(increment, allowed_to_fail, parent_stub, *args, &block)

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

def invoke_without_incrementing_received_count(parent_stub, *args, &block)

def invoke_without_incrementing_received_count(parent_stub, *args, &block)
  invoke_incrementing_actual_calls_by(0, true, parent_stub, *args, &block)
end

def matches?(message, *args)

def matches?(message, *args)
  @message == message && @argument_list_matcher.args_match?(*args)
end

def matches_at_least_count?

def matches_at_least_count?
  @at_least && @actual_received_count >= @expected_received_count
end

def matches_at_most_count?

def matches_at_most_count?
  @at_most && @actual_received_count <= @expected_received_count
end

def matches_exact_count?

def matches_exact_count?
  @expected_received_count == @actual_received_count
end

def matches_name_but_not_args(message, *args)

def matches_name_but_not_args(message, *args)
  @message == message && !@argument_list_matcher.args_match?(*args)
end

def negative?

def negative?
  @expected_received_count == 0 && !@at_least
end

def negative_expectation_for?(message)

def negative_expectation_for?(message)
  @message == message && negative?
end

def ordered?

def ordered?
  @ordered
end

def raise_already_invoked_error_if_necessary(calling_customization)

def raise_already_invoked_error_if_necessary(calling_customization)
  return unless has_been_invoked?
  error_generator.raise_already_invoked_error(message, calling_customization)
end

def raise_out_of_order_error

def raise_out_of_order_error
  @error_generator.raise_out_of_order_error @message
end

def raise_unexpected_message_args_error(args_for_multiple_calls)

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

def safe_invoke(parent_stub, *args, &block)

def safe_invoke(parent_stub, *args, &block)
  invoke_incrementing_actual_calls_by(1, false, parent_stub, *args, &block)
end

def set_expected_received_count(relativity, n)

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

def similar_messages

def similar_messages
  @similar_messages ||= []
end

def terminal_implementation_action=(action)

def terminal_implementation_action=(action)
  implementation.terminal_action = action
end

def unadvise(args)

def unadvise(args)
  similar_messages.delete_if { |message| args.include?(message) }
end

def verify_messages_received

def verify_messages_received
  return if expected_messages_received?
  generate_error
end

def warn_about_stub_override

def warn_about_stub_override
  RSpec.warning(
    "You're overriding a previous stub implementation of `#{@message}`. " \
    "Called from #{CallerFilter.first_non_rspec_line}."
  )
end

def wrap_original(method_name, &block)

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

def yield_receiver_to_implementation_block?

def yield_receiver_to_implementation_block?
  @yield_receiver_to_implementation_block
end