lib/rspec/matchers/built_in/yield.rb in rspec-expectations-3.6.0.beta2 vs lib/rspec/matchers/built_in/yield.rb in rspec-expectations-3.6.0

- old
+ new

@@ -6,39 +6,46 @@ # @private # Object that is yielded to `expect` when one of the # yield matchers is used. Provides information about # the yield behavior of the object-under-test. class YieldProbe - def self.probe(block) - probe = new(block) + def self.probe(block, &callback) + probe = new(block, &callback) return probe unless probe.has_block? - probe.assert_valid_expect_block! - block.call(probe) - probe.assert_used! - probe + probe.probe end attr_accessor :num_yields, :yielded_args - def initialize(block) + def initialize(block, &callback) @block = block + @callback = callback || Proc.new {} @used = false self.num_yields = 0 self.yielded_args = [] end def has_block? Proc === @block end + def probe + assert_valid_expect_block! + @block.call(self) + assert_used! + self + end + def to_proc @used = true probe = self + callback = @callback Proc.new do |*args| probe.num_yields += 1 probe.yielded_args << args + callback.call(*args) nil # to indicate the block does not return a meaningful value end end def single_yield_args @@ -54,16 +61,10 @@ 'method that yields multiple times. Use the yield_successive_args ' \ 'matcher for that case.' end end - def successive_yield_args - yielded_args.map do |arg_array| - arg_array.size == 1 ? arg_array.first : arg_array - end - end - def assert_used! return if @used raise 'You must pass the argument yielded to your expect block on ' \ 'to the method-under-test as a block. It acts as a probe that ' \ 'allows the matcher to detect whether or not the method-under-test ' \ @@ -267,14 +268,19 @@ @expected = args end # @private def matches?(block) - @probe = YieldProbe.probe(block) + @args_matched_when_yielded = true + @probe = YieldProbe.new(block) do + @actual = @probe.single_yield_args + @actual_formatted = actual_formatted + @args_matched_when_yielded &&= args_currently_match? + end return false unless @probe.has_block? - @actual = @probe.single_yield_args - @probe.yielded_once?(:yield_with_args) && args_match? + @probe.probe + @probe.yielded_once?(:yield_with_args) && @args_matched_when_yielded end # @private def does_not_match?(block) !matches?(block) && @probe.has_block? @@ -315,29 +321,29 @@ end def negative_failure_reason if !@probe.has_block? 'was not a block' - elsif all_args_match? + elsif @args_matched_when_yielded && !@expected.empty? 'yielded with expected arguments' \ "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \ - "\n got: #{actual_formatted}" + "\n got: #{@actual_formatted}" else 'did' end end - def args_match? + def args_currently_match? if @expected.empty? # expect {...}.to yield_with_args @positive_args_failure = 'yielded with no arguments' if @actual.empty? return !@actual.empty? end unless (match = all_args_match?) @positive_args_failure = 'yielded with unexpected arguments' \ "\nexpected: #{surface_descriptions_in(@expected).inspect}" \ - "\n got: #{actual_formatted}" + "\n got: #{@actual_formatted}" end match end @@ -354,14 +360,25 @@ @expected = args end # @private def matches?(block) - @probe = YieldProbe.probe(block) + @actual_formatted = [] + @actual = [] + args_matched_when_yielded = true + yield_count = 0 + + @probe = YieldProbe.probe(block) do |*arg_array| + arg_or_args = arg_array.size == 1 ? arg_array.first : arg_array + @actual_formatted << RSpec::Support::ObjectFormatter.format(arg_or_args) + @actual << arg_or_args + args_matched_when_yielded &&= values_match?(@expected[yield_count], arg_or_args) + yield_count += 1 + end + return false unless @probe.has_block? - @actual = @probe.successive_yield_args - args_match? + args_matched_when_yielded && yield_count == @expected.length end def does_not_match?(block) !matches?(block) && @probe.has_block? end @@ -388,31 +405,27 @@ true end private - def args_match? - values_match?(@expected, @actual) - end - def expected_arg_description @expected.map { |e| description_of e }.join(', ') end def positive_failure_reason return 'was not a block' unless @probe.has_block? 'yielded with unexpected arguments' \ "\nexpected: #{surface_descriptions_in(@expected).inspect}" \ - "\n got: #{actual_formatted}" + "\n got: [#{@actual_formatted.join(", ")}]" end def negative_failure_reason return 'was not a block' unless @probe.has_block? 'yielded with expected arguments' \ "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \ - "\n got: #{actual_formatted}" + "\n got: [#{@actual_formatted.join(", ")}]" end end end end end