class RuboCop::Cop::RSpec::ReceiveMessages


end
allow(Service).to receive(:foo).and_return(qux)
allow(Service).to receive(:foo).and_return(bar)
before do
# good - ignore same message
end
allow(Service).to receive_messages(foo: bar, baz: qux)
before do
# good
end
allow(Service).to receive(:baz).and_return(qux)
allow(Service).to receive(:foo).and_return(bar)
before do
# bad
@example
before they are defined.
order of stubs. This in turn may cause e.g. variables to be called
The autocorrection is marked as unsafe, because it may change the
@safety
Checks for multiple messages stubbed on the same object.

def add_repeated_lines_and_arguments(items)

def add_repeated_lines_and_arguments(items)
  uniq_items = uniq_items(items)
  repeated_lines = uniq_items.map(&:first_line)
  uniq_items.map do |item|
    [item, repeated_lines - [item.first_line], arguments(uniq_items)]
  end
end

def arguments(items)

def arguments(items)
  items.map do |item|
    receive_and_return_argument(item) do |receive_arg, return_arg|
      "#{normalize_receive_arg(receive_arg)}: " \
        "#{normalize_return_arg(return_arg)}"
    end
  end
end

def heredoc_or_splat?(node)

def heredoc_or_splat?(node)
  (node.type?(:str, :dstr) && node.heredoc?) || node.splat_type?
end

def item_range_by_whole_lines(item)

def item_range_by_whole_lines(item)
  range_by_whole_lines(item.source_range, include_final_newline: true)
end

def message(repeated_lines)

def message(repeated_lines)
  format(MSG, loc: repeated_lines)
end

def normalize_receive_arg(receive_arg)

def normalize_receive_arg(receive_arg)
  if requires_quotes?(receive_arg)
    "'#{receive_arg}'"
  else
    receive_arg
  end
end

def normalize_return_arg(return_arg)

def normalize_return_arg(return_arg)
  if return_arg.hash_type? && !return_arg.braces?
    "{ #{return_arg.source} }"
  else
    return_arg.source
  end
end

def on_begin(node)

def on_begin(node)
  repeated_receive_message(node).each do |item, repeated_lines, args|
    next if repeated_lines.empty?
    register_offense(item, repeated_lines, args)
  end
end

def register_offense(item, repeated_lines, args)

def register_offense(item, repeated_lines, args)
  add_offense(item, message: message(repeated_lines)) do |corrector|
    if item.loc.line > repeated_lines.max
      replace_to_receive_messages(corrector, item, args)
    else
      corrector.remove(item_range_by_whole_lines(item))
    end
  end
end

def repeated_receive_message(node)

def repeated_receive_message(node)
  node
    .children
    .select { |child| allow_receive_message?(child) }
    .group_by { |child| allow_argument(child) }
    .values
    .reject(&:one?)
    .flat_map { |items| add_repeated_lines_and_arguments(items) }
end

def replace_to_receive_messages(corrector, item, args)

def replace_to_receive_messages(corrector, item, args)
  receive_node(item) do |node|
    corrector.replace(node,
                      "receive_messages(#{args.join(', ')})")
  end
end

def requires_quotes?(value)

def requires_quotes?(value)
  value.match?(/^:".*?"|=$|^\W+$/)
end

def uniq_items(items)

def uniq_items(items)
  items.select do |item|
    items.none? do |i|
      receive_arg(item).first == receive_arg(i).first &&
        !same_line?(item, i)
    end
  end
end