lib/assert/stub.rb in assert-2.15.1 vs lib/assert/stub.rb in assert-2.15.2
- old
+ new
@@ -2,24 +2,34 @@
def self.stubs
@stubs ||= {}
end
- def self.stub(*args, &block)
- (self.stubs[Assert::Stub.key(*args)] ||= Assert::Stub.new(*args)).tap do |s|
- s.do = block
- end
+ def self.stub(obj, meth, &block)
+ (self.stubs[Assert::Stub.key(obj, meth)] ||= begin
+ orig_caller = caller
+ Assert::Stub.new(obj, meth, orig_caller)
+ end).tap{ |s| s.do = block }
end
- def self.unstub(*args)
- (self.stubs.delete(Assert::Stub.key(*args)) || Assert::Stub::NullStub.new).teardown
+ def self.unstub(obj, meth)
+ (self.stubs.delete(Assert::Stub.key(obj, meth)) || Assert::Stub::NullStub.new).teardown
end
def self.unstub!
self.stubs.keys.each{ |key| self.stubs.delete(key).teardown }
end
+ def self.stub_send(obj, meth, *args, &block)
+ orig_caller = caller
+ stub = self.stubs.fetch(Assert::Stub.key(obj, meth)) do
+ msg = "`#{meth}` not stubbed"
+ raise NotStubbedError.new(msg).tap{ |e| e.set_backtrace(orig_caller) }
+ end
+ stub.call_method(args, &block)
+ end
+
StubError = Class.new(ArgumentError)
NotStubbedError = Class.new(StubError)
StubArityError = Class.new(StubError)
class Stub
@@ -32,56 +42,57 @@
"--#{object.object_id}--#{method_name}--"
end
attr_reader :method_name, :name, :ivar_name, :do
- def initialize(object, method_name, &block)
+ def initialize(object, method_name, orig_caller = nil, &block)
+ orig_caller ||= caller
@metaclass = class << object; self; end
@method_name = method_name.to_s
@name = "__assert_stub__#{object.object_id}_#{@method_name}"
@ivar_name = "@__assert_stub_#{object.object_id}_" \
"#{@method_name.to_sym.object_id}"
- setup(object)
+ setup(object, orig_caller)
- @do = block || Proc.new do |*args, &block|
- err_msg = "#{inspect_call(args)} not stubbed."
- inspect_lookup_stubs.tap do |stubs|
- err_msg += "\nStubs:\n#{stubs}" if !stubs.empty?
- end
- raise NotStubbedError, err_msg
- end
- @lookup = Hash.new{ |hash, key| self.do }
+ @do = block
+ @lookup = {}
end
- def call(*args, &block)
+ def do=(block)
+ @do = block || @do
+ end
+
+ def call_method(args, &block)
+ @method.call(*args, &block)
+ end
+
+ def call(args, orig_caller = nil, &block)
+ orig_caller ||= caller
unless arity_matches?(args)
- message = "arity mismatch on `#{@method_name}`: " \
- "expected #{number_of_args(@method.arity)}, " \
- "called with #{args.size}"
- raise StubArityError, message
+ msg = "arity mismatch on `#{@method_name}`: " \
+ "expected #{number_of_args(@method.arity)}, " \
+ "called with #{args.size}"
+ raise StubArityError.new(msg).tap{ |e| e.set_backtrace(orig_caller) }
end
- @lookup[args].call(*args, &block)
+ lookup(args, orig_caller).call(*args, &block)
rescue NotStubbedError => exception
@lookup.rehash
- @lookup[args].call(*args, &block)
+ lookup(args, orig_caller).call(*args, &block)
end
def with(*args, &block)
+ orig_caller = caller
unless arity_matches?(args)
- message = "arity mismatch on `#{@method_name}`: " \
- "expected #{number_of_args(@method.arity)}, " \
- "stubbed with #{args.size}"
- raise StubArityError, message
+ msg = "arity mismatch on `#{@method_name}`: " \
+ "expected #{number_of_args(@method.arity)}, " \
+ "stubbed with #{args.size}"
+ raise StubArityError.new(msg).tap{ |e| e.set_backtrace(orig_caller) }
end
@lookup[args] = block
end
- def do=(block)
- @do = block || @do
- end
-
def teardown
@metaclass.send(:undef_method, @method_name)
Assert.send(:remove_instance_variable, @ivar_name)
@metaclass.send(:alias_method, @method_name, @name)
@metaclass.send(:undef_method, @name)
@@ -93,13 +104,14 @@
">"
end
protected
- def setup(object)
+ def setup(object, orig_caller)
unless object.respond_to?(@method_name)
- raise StubError, "#{object.inspect} does not respond to `#{@method_name}`"
+ msg = "#{object.inspect} does not respond to `#{@method_name}`"
+ raise StubError.new(msg).tap{ |e| e.set_backtrace(orig_caller) }
end
is_constant = object.kind_of?(Module)
local_object_methods = object.methods(false).map(&:to_s)
all_object_methods = object.methods.map(&:to_s)
if (is_constant && !local_object_methods.include?(@method_name)) ||
@@ -116,15 +128,27 @@
@method = object.method(@name)
Assert.instance_variable_set(@ivar_name, self)
@metaclass.class_eval <<-stub_method
def #{@method_name}(*args, &block)
- Assert.instance_variable_get("#{@ivar_name}").call(*args, &block)
+ Assert.instance_variable_get("#{@ivar_name}").call(args, caller, &block)
end
stub_method
end
private
+
+ def lookup(args, orig_caller)
+ @lookup.fetch(args) do
+ self.do || begin
+ msg = "#{inspect_call(args)} not stubbed."
+ inspect_lookup_stubs.tap do |stubs|
+ msg += "\nStubs:\n#{stubs}" if !stubs.empty?
+ end
+ raise NotStubbedError.new(msg).tap{ |e| e.set_backtrace(orig_caller) }
+ end
+ end
+ end
def arity_matches?(args)
return true if @method.arity == args.size # mandatory args
return true if @method.arity < 0 && args.size >= (@method.arity+1).abs # variable args
return false