Permalink
Browse files

A few improvements to yield count matchers.

- Add `once` to fluent interface.
- Include the count description in failure message if it was specified as `once`.
- Use the "at most"/"at least" wording to correspond to the methods.
  • Loading branch information...
1 parent 585dddb commit 01fa642d8afb461256744cb1170770d221bac11e @myronmarston myronmarston committed Mar 11, 2013
Showing with 74 additions and 28 deletions.
  1. +26 −11 lib/rspec/matchers/built_in/yield.rb
  2. +48 −17 spec/rspec/matchers/yield_spec.rb
@@ -66,17 +66,27 @@ def self.assert_valid_expect_block!(block)
class YieldControl < BaseMatcher
def initialize
- @expectation_type = :==
- @expected_yields_count = 1
+ @expectation_type = nil
+ @expected_yields_count = nil
end
def matches?(block)
probe = YieldProbe.probe(block)
- probe.num_yields.send(@expectation_type, @expected_yields_count)
+
+ if @expectation_type
+ probe.num_yields.send(@expectation_type, @expected_yields_count)
+ else
+ probe.yielded_once?(:yield_control)
+ end
+ end
+
+ def once
+ exactly(1)
+ self
end
def twice
- exactly(2).times
+ exactly(2)
self
end
@@ -123,20 +133,25 @@ def set_expected_yields_count(relativity, n)
end
def relativity_failure_message
- if @expected_yields_count != 1
- " #@expected_yields_count #{human_readable_expecation_type}times"
- else
- ''
- end
+ return '' unless @expected_yields_count
+ " #{human_readable_expecation_type}#{human_readable_count}"
end
def human_readable_expecation_type
case @expectation_type
- when :<= then 'or less '
- when :>= then 'or more '
+ when :<= then 'at most '
+ when :>= then 'at least '
else ''
end
end
+
+ def human_readable_count
+ case @expected_yields_count
+ when 1 then "once"
+ when 2 then "twice"
+ else "#{@expected_yields_count} times"
+ end
+ end
end
class YieldWithNoArgs < BaseMatcher
@@ -67,51 +67,82 @@ def each_arg(*args, &block)
it 'fails if the block yields wrong number of times' do
expect {
expect { |b| [1, 2, 3].each(&b) }.to yield_control.twice
- }.to fail_with(/expected given block to yield control 2 times/)
- end
+ }.to fail_with(/expected given block to yield control twice/)
- it 'passes if the block yields twice' do
- expect { |b| [1, 2].each(&b) }.to yield_control.twice
+ expect {
+ expect { |b| [1, 2].each(&b) }.to yield_control.exactly(3).times
+ }.to fail_with(/expected given block to yield control 3 times/)
end
- it 'passes if the block yields exactly 3 times' do
+ it 'passes if the block yields the specified number of times' do
+ expect { |b| [1].each(&b) }.to yield_control.once
+ expect { |b| [1, 2].each(&b) }.to yield_control.twice
expect { |b| [1, 2, 3].each(&b) }.to yield_control.exactly(3).times
end
end
context "with at_least count" do
- it 'passes if the block yields twice' do
+ it 'passes if the block yields the given number of times' do
expect { |b| [1, 2].each(&b) }.to yield_control.at_least(2).times
+ expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(3).times
end
- it 'passes if the block yields :twice' do
- expect { |b| [1, 2].each(&b) }.to yield_control.at_least(:twice)
+ it 'passes if the block yields more times' do
+ expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(2).times
+ expect { |b| [1, 2, 3, 4].each(&b) }.to yield_control.at_least(3).times
end
- it 'passes if the block yields thrice' do
- expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(2).times
+ it 'allows :once and :twice to be passed as counts' do
+ expect { |b| [1].each(&b) }.to yield_control.at_least(:once)
+ expect { |b| [1, 2].each(&b) }.to yield_control.at_least(:once)
+
+ expect {
+ expect { |b| [].each(&b) }.to yield_control.at_least(:once)
+ }.to fail_with(/at least once/)
+
+ expect { |b| [1, 2].each(&b) }.to yield_control.at_least(:twice)
+ expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(:twice)
+
+ expect {
+ expect { |b| [1].each(&b) }.to yield_control.at_least(:twice)
+ }.to fail_with(/at least twice/)
end
- it 'fails if the block yields once' do
+ it 'fails if the block yields too few times' do
expect {
expect { |b| _yield_with_no_args(&b) }.to yield_control.at_least(2).times
- }.to fail_with(/expected given block to yield control 2 or more times/)
+ }.to fail_with(/expected given block to yield control at least twice/)
end
end
context "with at_most count" do
- it 'passes if the block yields twice' do
+ it 'passes if the block yields the given number of times' do
expect { |b| [1, 2].each(&b) }.to yield_control.at_most(2).times
+ expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(3).times
+ end
+
+ it 'passes if the block yields fewer times' do
+ expect { |b| [1, 2].each(&b) }.to yield_control.at_most(3).times
end
- it 'passes if the block yields thrice' do
- expect { |b| _yield_with_no_args(&b) }.to yield_control.at_most(2).times
+ it 'allows :once and :twice to be passed as counts' do
+ expect { |b| [1].each(&b) }.to yield_control.at_most(:once)
+
+ expect {
+ expect { |b| [1, 2].each(&b) }.to yield_control.at_most(:once)
+ }.to fail_with(/expected given block to yield control at most once/)
+
+ expect { |b| [1, 2].each(&b) }.to yield_control.at_most(:twice)
+
+ expect {
+ expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(:twice)
+ }.to fail_with(/expected given block to yield control at most twice/)
end
- it 'fails if the block yields once' do
+ it 'fails if the block yields too many times' do
expect {
expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(2).times
- }.to fail_with(/expected given block to yield control 2 or less times/)
+ }.to fail_with(/expected given block to yield control at most twice/)
end
end
end

0 comments on commit 01fa642

Please sign in to comment.