Skip to content

Commit

Permalink
Raise error on multiple cout constraints.
Browse files Browse the repository at this point in the history
In particular, it would be reasonable to expect yield_control.at_least(1).at_most(4).times to work

This also simplifies the failure message in case no count constraint was called.
  • Loading branch information
marcandre committed Mar 17, 2020
1 parent 94b4293 commit 90aac3f
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 10 deletions.
21 changes: 12 additions & 9 deletions lib/rspec/matchers/built_in/yield.rb
Expand Up @@ -98,7 +98,7 @@ def assert_valid_expect_block!
# Not intended to be instantiated directly.
class YieldControl < BaseMatcher
def initialize
at_least(:once)
@expectation_type = @expected_yields_count = nil
end

# @api public
Expand Down Expand Up @@ -153,7 +153,7 @@ def times
def matches?(block)
@probe = YieldProbe.probe(block)
return false unless @probe.has_block?

return @probe.num_yields > 0 unless @expectation_type
@probe.num_yields.__send__(@expectation_type, @expected_yields_count)
end

Expand Down Expand Up @@ -182,6 +182,8 @@ def supports_block_expectations?
private

def set_expected_yields_count(relativity, n)
raise "Multiple count constraints are not supported" if @expectation_type

@expectation_type = relativity
@expected_yields_count = count_constraint_to_number(n)
end
Expand All @@ -200,23 +202,24 @@ def count_constraint_to_number(n)

def failure_reason
return ' but was not a block' unless @probe.has_block?
" #{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
" but yielded #{human_readable_count(@probe.num_yields)}"
"#{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
" but yielded#{human_readable_count(@probe.num_yields)}"
end

def human_readable_expectation_type
case @expectation_type
when :<= then 'at most '
when :>= then 'at least '
when :<= then ' at most'
when :>= then ' at least'
else ''
end
end

def human_readable_count(count)
case count
when 1 then 'once'
when 2 then 'twice'
else "#{count} times"
when nil then ''
when 1 then ' once'
when 2 then ' twice'
else " #{count} times"
end
end
end
Expand Down
7 changes: 6 additions & 1 deletion spec/rspec/matchers/built_in/yield_spec.rb
Expand Up @@ -58,7 +58,7 @@ def each_arg(*args, &block)
it 'fails if the block does not yield' do
expect {
expect { |b| _dont_yield(&b) }.to yield_control
}.to fail_with(/expected given block to yield control/)
}.to fail_with(/expected given block to yield control but/)
end

it 'does not return a meaningful value from the block' do
Expand All @@ -73,6 +73,11 @@ def each_arg(*args, &block)
expect { yield_control.at_most(nil) }.to raise_error(ArgumentError)
end

# TODO: This needs implementing.
it 'is yet to support multiple calls to count constraints' do
expect { yield_control.at_least(1).at_most(4).times }.to raise_error(/multiple/i)
end

context "with exact count" do
it 'fails if the block yields wrong number of times' do
expect {
Expand Down

0 comments on commit 90aac3f

Please sign in to comment.