From f086b7e40f9fb9240671641e6e568c87c028ef22 Mon Sep 17 00:00:00 2001 From: James Mead Date: Tue, 25 Oct 2022 08:14:38 +0100 Subject: [PATCH] Support multiple methods in responds_with matcher This provides a terser syntax for matching an object which responds in a certain way, e.g. object = mock() object.expects(:method_1).with(responds_with(:upcase => "FOO", :reverse => "oof")) object.method_1("foo") # no error raised, because "foo".upcase == "FOO" and "foo".reverse == "oof" Addresses #578. --- lib/mocha/parameter_matchers/responds_with.rb | 37 ++++++++++++++++--- .../parameter_matchers/responds_with_test.rb | 10 +++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/mocha/parameter_matchers/responds_with.rb b/lib/mocha/parameter_matchers/responds_with.rb index 7c434295a..4808e64df 100644 --- a/lib/mocha/parameter_matchers/responds_with.rb +++ b/lib/mocha/parameter_matchers/responds_with.rb @@ -1,12 +1,18 @@ require 'mocha/parameter_matchers/base' +require 'mocha/parameter_matchers/all_of' require 'yaml' module Mocha module ParameterMatchers - # Matches any object that responds to +message+ with +result+. To put it another way, it tests the quack, not the duck. + # @overload def responds_with(message, result) + # Matches any object that responds to +message+ with +result+. To put it another way, it tests the quack, not the duck. + # @param [Symbol] message method to invoke. + # @param [Object] result expected result of sending +message+. + # @overload def responds_with(messages_vs_results) + # Matches any object that responds to all the messages with the corresponding results as specified by +messages_vs_results+. + # @param [Hash] messages_vs_results +Hash+ of messages vs results. + # @raise [ArgumentError] if +messages_vs_results+ does not contain at least one entry. # - # @param [Symbol] message method to invoke. - # @param [Object] result expected result of sending +message+. # @return [RespondsWith] parameter matcher. # # @see Expectation#with @@ -22,8 +28,29 @@ module ParameterMatchers # object.expects(:method_1).with(responds_with(:upcase, "BAR")) # object.method_1("foo") # # error raised, because "foo".upcase != "BAR" - def responds_with(message, result) - RespondsWith.new(message, result) + # + # @example Actual parameter responds with "FOO" when :upcase is invoked and "oof" when :reverse is invoked. + # object = mock() + # object.expects(:method_1).with(responds_with(:upcase => "FOO", :reverse => "oof")) + # object.method_1("foo") + # # no error raised, because "foo".upcase == "FOO" and "foo".reverse == "oof" + def responds_with(*options) + case options.length + when 0 + raise ArgumentError, 'No arguments. Expecting at least one.' + when 1 + option = options.first + raise ArgumentError, 'Argument is not a Hash.' unless option.is_a?(Hash) + raise ArgumentError, 'Argument has no entries.' if option.empty? + + matchers = option.map { |message, result| RespondsWith.new(message, result) } + AllOf.new(*matchers) + when 2 + message, result = options + RespondsWith.new(message, result) + else + raise ArgumentError, 'Too many arguments; use either a single argument (must be a Hash) or two arguments (a message and a result).' + end end # Parameter matcher which matches if actual parameter returns expected result when specified method is invoked. diff --git a/test/unit/parameter_matchers/responds_with_test.rb b/test/unit/parameter_matchers/responds_with_test.rb index 493f37f19..8a1fb660c 100644 --- a/test/unit/parameter_matchers/responds_with_test.rb +++ b/test/unit/parameter_matchers/responds_with_test.rb @@ -35,4 +35,14 @@ def test_should_describe_matcher matcher = responds_with(:foo, :bar) assert_equal 'responds_with(:foo, :bar)', matcher.mocha_inspect end + + def test_should_match_parameter_responding_with_expected_values_for_given_messages + matcher = responds_with(upcase: 'FOO', reverse: 'oof') + assert matcher.matches?(['foo']) + end + + def test_should_describe_matcher_with_multiple_messages_vs_results + matcher = responds_with(foo: :bar, baz: 123) + assert_equal 'all_of(responds_with(:foo, :bar), responds_with(:baz, 123))', matcher.mocha_inspect + end end