openstreetmap-website/vendor/gems/rspec-1.1.2/lib/spec/mocks/message_expectation.rb
2008-01-22 16:39:09 +00:00

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