Permalink
Browse files

Instead of using Mock#method_missing, define the actual methods.

This was causing problems on MacRuby, which does not allow Ruby to
undefine native (Objective-C) method implementations.
  • Loading branch information...
alloy committed Nov 2, 2010
1 parent 89a334f commit 01327f27d1fa849e624d8001d3c3714582b17c46
Showing with 36 additions and 20 deletions.
  1. +4 −1 Rakefile
  2. +30 −17 lib/mocha/mock.rb
  3. +2 −2 test/unit/mock_test.rb
@@ -7,7 +7,10 @@ module Mocha
end

desc "Run all tests"
task 'default' => ['test:units', 'test:acceptance', 'test:performance']
task 'default' => 'test'

desc "Run all tests"
task 'test' => ['test:units', 'test:acceptance', 'test:performance']

namespace 'test' do

@@ -42,7 +42,7 @@ def expects(method_name_or_hash, backtrace = nil)
iterator = ArgumentIterator.new(method_name_or_hash)
iterator.each { |*args|
method_name = args.shift
ensure_method_not_already_defined(method_name)
__define_stub_method__(method_name)
expectation = Expectation.new(self, method_name, backtrace)
expectation.returns(args.shift) if args.length > 0
@expectations.add(expectation)
@@ -74,7 +74,7 @@ def stubs(method_name_or_hash, backtrace = nil)
iterator = ArgumentIterator.new(method_name_or_hash)
iterator.each { |*args|
method_name = args.shift
ensure_method_not_already_defined(method_name)
__define_stub_method__(method_name)
expectation = Expectation.new(self, method_name, backtrace)
expectation.at_least(0)
expectation.returns(args.shift) if args.length > 0
@@ -147,21 +147,11 @@ def initialize(name = nil, &block)

def stub_everything
@everything_stubbed = true
ANCESTOR_INSTANCE_METHODS.each { |m| __define_stub_method__(m) }
end

def method_missing(symbol, *arguments, &block)
if @responder and not @responder.respond_to?(symbol)
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
end
if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
matching_expectation_allowing_invocation.invoke(&block)
else
if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
message << Mockery.instance.mocha_inspect
raise ExpectationError.new(message, caller)
end
end
__match_invocation__(symbol, arguments, block)
end

def respond_to?(symbol, include_private = false)
@@ -187,11 +177,34 @@ def mocha_inspect
def inspect
mocha_inspect
end

def ensure_method_not_already_defined(method_name)
self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name)

def __define_stub_method__(symbol)
__metaclass__.class_eval(%{
def #{symbol}(*args, &block)
__match_invocation__('#{symbol}'.to_sym, args, block)
end
})
end

def __match_invocation__(symbol, arguments, block)
if @responder and not @responder.respond_to?(symbol)
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
end
if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
matching_expectation_allowing_invocation.invoke(&block)
else
if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
message << Mockery.instance.mocha_inspect
raise ExpectationError.new(message, caller)
end
end
end

methods = instance_methods - instance_methods(false)
methods.delete(:object_id) unless RUBY_VERSION < '1.9'
ANCESTOR_INSTANCE_METHODS = methods.reject { |m| m =~ /^__.*__$/ }

# :startdoc:

end
@@ -1,5 +1,5 @@
require File.expand_path('../../test_helper', __FILE__)
require 'mocha/mock'
require 'mocha/mockery' # requires 'mock'
require 'mocha/expectation_error'
require 'set'
require 'simple_counter'
@@ -299,4 +299,4 @@ def test_should_respond_to_any_method_if_stubbing_everything
assert mock.respond_to?(:xyz)
end

end
end

0 comments on commit 01327f2

Please sign in to comment.