-
-
Notifications
You must be signed in to change notification settings - Fork 398
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make count expectation of yield_control generic
- Loading branch information
Showing
2 changed files
with
134 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
module RSpec | ||
module Matchers | ||
module BuiltIn | ||
# @api private | ||
# Provides the implementation for `yield_control`. | ||
# Not intended to be instantiated directly. | ||
module CountExpectation | ||
def initialize(*args) | ||
@count_expectation_type = @count_expected_count = nil | ||
super(*args) | ||
end | ||
|
||
# @api public | ||
# Specifies that the method is expected to yield once. | ||
def once | ||
exactly(1) | ||
self | ||
end | ||
|
||
# @api public | ||
# Specifies that the method is expected to yield twice. | ||
def twice | ||
exactly(2) | ||
self | ||
end | ||
|
||
# @api public | ||
# Specifies that the method is expected to yield thrice. | ||
def thrice | ||
exactly(3) | ||
self | ||
end | ||
|
||
# @api public | ||
# Specifies that the method is expected to yield the given number of times. | ||
def exactly(number) | ||
set_expected_count(:==, number) | ||
self | ||
end | ||
|
||
# @api public | ||
# Specifies the maximum number of times the method is expected to yield | ||
def at_most(number) | ||
set_expected_count(:<=, number) | ||
self | ||
end | ||
|
||
# @api public | ||
# Specifies the minimum number of times the method is expected to yield | ||
def at_least(number) | ||
set_expected_count(:>=, number) | ||
self | ||
end | ||
|
||
# @api public | ||
# No-op. Provides syntactic sugar. | ||
def times | ||
self | ||
end | ||
|
||
# @private | ||
def matches?(actual_count) | ||
expected_count_matches?(actual_count) | ||
end | ||
|
||
# @private | ||
def does_not_match?(actual_count) | ||
!expected_count_matches?(actual_count) | ||
end | ||
|
||
private | ||
|
||
def expected_count_matches?(actual_count) | ||
@actual_count = actual_count | ||
@actual_count.__send__(@count_expectation_type || :>=, @count_expected_count || 1) | ||
end | ||
|
||
def has_expected_count? | ||
!!@count_expectation_type | ||
end | ||
|
||
def set_expected_count(relativity, n) | ||
raise "Multiple count constraints are not supported" if @count_expectation_type | ||
|
||
@count_expectation_type = relativity | ||
@count_expected_count = count_constraint_to_number(n) | ||
end | ||
|
||
def count_constraint_to_number(n) | ||
case n | ||
when Numeric then n | ||
when :once then 1 | ||
when :twice then 2 | ||
when :thrice then 3 | ||
else raise ArgumentError, | ||
"Expected a number, :once, :twice or :thrice," \ | ||
" but got #{n}" | ||
end | ||
end | ||
|
||
def count_expectation_description | ||
"#{human_readable_expectation_type}#{human_readable_count(@count_expected_count)}" | ||
end | ||
|
||
def count_failure_reason(action) | ||
"#{count_expectation_description}" \ | ||
" but #{action}#{human_readable_count(@actual_count)}" | ||
end | ||
|
||
def human_readable_expectation_type | ||
case @count_expectation_type | ||
when :<= then ' at most' | ||
when :>= then ' at least' | ||
else '' | ||
end | ||
end | ||
|
||
def human_readable_count(count) | ||
case count | ||
when nil then '' | ||
when 1 then ' once' | ||
when 2 then ' twice' | ||
else " #{count} times" | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters