267 lines
7.4 KiB
Ruby
267 lines
7.4 KiB
Ruby
module Spec
|
|
module Mocks
|
|
|
|
class BaseExpectation
|
|
attr_reader :sym
|
|
|
|
def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={})
|
|
@error_generator = error_generator
|
|
@error_generator.opts = opts
|
|
@expected_from = expected_from
|
|
@sym = sym
|
|
@method_block = method_block
|
|
@return_block = nil
|
|
@actual_received_count = 0
|
|
@expected_received_count = expected_received_count
|
|
@args_expectation = ArgumentExpectation.new([AnyArgsConstraint.new])
|
|
@consecutive = false
|
|
@exception_to_raise = nil
|
|
@symbol_to_throw = nil
|
|
@order_group = expectation_ordering
|
|
@at_least = nil
|
|
@at_most = nil
|
|
@args_to_yield = []
|
|
end
|
|
|
|
def expected_args
|
|
@args_expectation.args
|
|
end
|
|
|
|
def and_return(*values, &return_block)
|
|
Kernel::raise AmbiguousReturnError unless @method_block.nil?
|
|
case values.size
|
|
when 0 then value = nil
|
|
when 1 then value = values[0]
|
|
else
|
|
value = values
|
|
@consecutive = true
|
|
@expected_received_count = values.size if !ignoring_args? &&
|
|
@expected_received_count < values.size
|
|
end
|
|
@return_block = block_given? ? return_block : lambda { value }
|
|
# Ruby 1.9 - see where this is used below
|
|
@ignore_args = !block_given?
|
|
end
|
|
|
|
# :call-seq:
|
|
# and_raise()
|
|
# and_raise(Exception) #any exception class
|
|
# and_raise(exception) #any exception object
|
|
#
|
|
# == Warning
|
|
#
|
|
# When you pass an exception class, the MessageExpectation will
|
|
# raise an instance of it, creating it with +new+. If the exception
|
|
# class initializer requires any parameters, you must pass in an
|
|
# instance and not the class.
|
|
def and_raise(exception=Exception)
|
|
@exception_to_raise = exception
|
|
end
|
|
|
|
def and_throw(symbol)
|
|
@symbol_to_throw = symbol
|
|
end
|
|
|
|
def and_yield(*args)
|
|
@args_to_yield << args
|
|
self
|
|
end
|
|
|
|
def matches(sym, args)
|
|
@sym == sym and @args_expectation.check_args(args)
|
|
end
|
|
|
|
def invoke(args, block)
|
|
@order_group.handle_order_constraint self
|
|
|
|
begin
|
|
Kernel::raise @exception_to_raise unless @exception_to_raise.nil?
|
|
Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?
|
|
|
|
if !@method_block.nil?
|
|
default_return_val = invoke_method_block(args)
|
|
elsif @args_to_yield.size > 0
|
|
default_return_val = invoke_with_yield(block)
|
|
else
|
|
default_return_val = nil
|
|
end
|
|
|
|
if @consecutive
|
|
return invoke_consecutive_return_block(args, block)
|
|
elsif @return_block
|
|
return invoke_return_block(args, block)
|
|
else
|
|
return default_return_val
|
|
end
|
|
ensure
|
|
@actual_received_count += 1
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
def invoke_method_block(args)
|
|
begin
|
|
@method_block.call(*args)
|
|
rescue => detail
|
|
@error_generator.raise_block_failed_error @sym, detail.message
|
|
end
|
|
end
|
|
|
|
def invoke_with_yield(block)
|
|
if block.nil?
|
|
@error_generator.raise_missing_block_error @args_to_yield
|
|
end
|
|
@args_to_yield.each do |args_to_yield_this_time|
|
|
if block.arity > -1 && args_to_yield_this_time.length != block.arity
|
|
@error_generator.raise_wrong_arity_error args_to_yield_this_time, block.arity
|
|
end
|
|
block.call(*args_to_yield_this_time)
|
|
end
|
|
end
|
|
|
|
def invoke_consecutive_return_block(args, block)
|
|
args << block unless block.nil?
|
|
value = @return_block.call(*args)
|
|
|
|
index = [@actual_received_count, value.size-1].min
|
|
value[index]
|
|
end
|
|
|
|
def invoke_return_block(args, block)
|
|
args << block unless block.nil?
|
|
# Ruby 1.9 - when we set @return_block to return values
|
|
# regardless of arguments, any arguments will result in
|
|
# a "wrong number of arguments" error
|
|
if @ignore_args
|
|
@return_block.call()
|
|
else
|
|
@return_block.call(*args)
|
|
end
|
|
end
|
|
end
|
|
|
|
class MessageExpectation < BaseExpectation
|
|
|
|
def matches_name_but_not_args(sym, args)
|
|
@sym == sym and not @args_expectation.check_args(args)
|
|
end
|
|
|
|
def verify_messages_received
|
|
return if ignoring_args? || matches_exact_count? ||
|
|
matches_at_least_count? || matches_at_most_count?
|
|
|
|
generate_error
|
|
rescue Spec::Mocks::MockExpectationError => error
|
|
error.backtrace.insert(0, @expected_from)
|
|
Kernel::raise error
|
|
end
|
|
|
|
def ignoring_args?
|
|
@expected_received_count == :any
|
|
end
|
|
|
|
def matches_at_least_count?
|
|
@at_least && @actual_received_count >= @expected_received_count
|
|
end
|
|
|
|
def matches_at_most_count?
|
|
@at_most && @actual_received_count <= @expected_received_count
|
|
end
|
|
|
|
def matches_exact_count?
|
|
@expected_received_count == @actual_received_count
|
|
end
|
|
|
|
def generate_error
|
|
@error_generator.raise_expectation_error(@sym, @expected_received_count, @actual_received_count, *@args_expectation.args)
|
|
end
|
|
|
|
def with(*args, &block)
|
|
@method_block = block if block
|
|
@args_expectation = ArgumentExpectation.new(args)
|
|
self
|
|
end
|
|
|
|
def exactly(n)
|
|
set_expected_received_count :exactly, n
|
|
self
|
|
end
|
|
|
|
def at_least(n)
|
|
set_expected_received_count :at_least, n
|
|
self
|
|
end
|
|
|
|
def at_most(n)
|
|
set_expected_received_count :at_most, n
|
|
self
|
|
end
|
|
|
|
def times(&block)
|
|
@method_block = block if block
|
|
self
|
|
end
|
|
|
|
def any_number_of_times(&block)
|
|
@method_block = block if block
|
|
@expected_received_count = :any
|
|
self
|
|
end
|
|
|
|
def never
|
|
@expected_received_count = 0
|
|
self
|
|
end
|
|
|
|
def once(&block)
|
|
@method_block = block if block
|
|
@expected_received_count = 1
|
|
self
|
|
end
|
|
|
|
def twice(&block)
|
|
@method_block = block if block
|
|
@expected_received_count = 2
|
|
self
|
|
end
|
|
|
|
def ordered(&block)
|
|
@method_block = block if block
|
|
@order_group.register(self)
|
|
@ordered = true
|
|
self
|
|
end
|
|
|
|
def negative_expectation_for?(sym)
|
|
return false
|
|
end
|
|
|
|
protected
|
|
def set_expected_received_count(relativity, n)
|
|
@at_least = (relativity == :at_least)
|
|
@at_most = (relativity == :at_most)
|
|
@expected_received_count = case n
|
|
when Numeric
|
|
n
|
|
when :once
|
|
1
|
|
when :twice
|
|
2
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
class NegativeMessageExpectation < MessageExpectation
|
|
def initialize(message, expectation_ordering, expected_from, sym, method_block)
|
|
super(message, expectation_ordering, expected_from, sym, method_block, 0)
|
|
end
|
|
|
|
def negative_expectation_for?(sym)
|
|
return @sym == sym
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|