def method_missing sym, *args, **kwargs, &block # :nodoc:
:nodoc:
def method_missing sym, *args, **kwargs, &block # :nodoc:
unless @expected_calls.key?(sym) then
if @delegator && @delegator.respond_to?(sym)
if kwargs.empty? then # FIX: drop this after 2.7 dead
return @delegator.public_send(sym, *args, &block)
else
return @delegator.public_send(sym, *args, **kwargs, &block)
end
else
raise NoMethodError, "unmocked method %p, expected one of %p" %
[sym, @expected_calls.keys.sort_by(&:to_s)]
end
end
index = @actual_calls[sym].length
expected_call = @expected_calls[sym][index]
unless expected_call then
raise MockExpectationError, "No more expects available for %p: %p %p" %
[sym, args, kwargs]
end
expected_args, expected_kwargs, retval, val_block =
expected_call.values_at(:args, :kwargs, :retval, :block)
expected_kwargs = kwargs.map { |ak, av| [ak, Object] }.to_h if
Hash == expected_kwargs
if val_block then
# keep "verify" happy
@actual_calls[sym] << expected_call
raise MockExpectationError, "mocked method %p failed block w/ %p %p" %
[sym, args, kwargs] unless val_block.call(*args, **kwargs, &block)
return retval
end
if expected_args.size != args.size then
raise ArgumentError, "mocked method %p expects %d arguments, got %p" %
[sym, expected_args.size, args]
end
if expected_kwargs.size != kwargs.size then
raise ArgumentError, "mocked method %p expects %d keyword arguments, got %p" %
[sym, expected_kwargs.size, kwargs]
end
zipped_args = expected_args.zip(args)
fully_matched = zipped_args.all? { |mod, a|
mod === a or mod == a
}
unless fully_matched then
fmt = "mocked method %p called with unexpected arguments %p"
raise MockExpectationError, fmt % [sym, args]
end
unless expected_kwargs.keys.sort == kwargs.keys.sort then
fmt = "mocked method %p called with unexpected keywords %p vs %p"
raise MockExpectationError, fmt % [sym, expected_kwargs.keys, kwargs.keys]
end
zipped_kwargs = expected_kwargs.map { |ek, ev|
av = kwargs[ek]
[ek, [ev, av]]
}.to_h
fully_matched = zipped_kwargs.all? { |ek, (ev, av)|
ev === av or ev == av
}
unless fully_matched then
fmt = "mocked method %p called with unexpected keyword arguments %p vs %p"
raise MockExpectationError, fmt % [sym, expected_kwargs, kwargs]
end
@actual_calls[sym] << {
:retval => retval,
:args => zipped_args.map { |e, a| e === a ? e : a },
:kwargs => zipped_kwargs.map { |k, (e, a)| [k, e === a ? e : a] }.to_h,
}
retval
end