Skip to content

Commit

Permalink
add multiple call support to minimock per minitest#79
Browse files Browse the repository at this point in the history
[git-p4: depot-paths = "//src/minitest/dev/": change = 6962]
  • Loading branch information
Steven R. Baker committed Jan 29, 2012
1 parent 57b06f7 commit 88eec1b
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 26 deletions.
53 changes: 32 additions & 21 deletions lib/minitest/mock.rb
Expand Up @@ -19,8 +19,8 @@ class Mock
end

def initialize # :nodoc:
@expected_calls = {}
@actual_calls = Hash.new {|h,k| h[k] = [] }
@expected_calls = Hash.new { |calls, name| calls[name] = [] }
@actual_calls = Hash.new { |calls, name| calls[name] = [] }
end

##
Expand All @@ -46,7 +46,7 @@ def initialize # :nodoc:

def expect(name, retval, args=[])
raise ArgumentError, "args must be an array" unless Array === args
@expected_calls[name] = { :retval => retval, :args => args }
@expected_calls[name] << { :retval => retval, :args => args }
self
end

Expand All @@ -56,36 +56,47 @@ def expect(name, retval, args=[])
# expected.

def verify
@expected_calls.each_key do |name|
expected = @expected_calls[name]
msg1 = "expected #{name}, #{expected.inspect}"
msg2 = "#{msg1}, got #{@actual_calls[name].inspect}"

raise MockExpectationError, msg2 if
@actual_calls.has_key? name and
not @actual_calls[name].include?(expected)

raise MockExpectationError, msg1 unless
@actual_calls.has_key? name and @actual_calls[name].include?(expected)
@expected_calls.each do |name, calls|
calls.each do |expected|
msg1 = "expected #{name}, #{expected.inspect}"
msg2 = "#{msg1}, got #{@actual_calls[name].inspect}"

raise MockExpectationError, msg2 if
@actual_calls.has_key? name and
not @actual_calls[name].include?(expected)

raise MockExpectationError, msg1 unless
@actual_calls.has_key? name and @actual_calls[name].include?(expected)
end
end
true
end

def method_missing(sym, *args) # :nodoc:
expected = @expected_calls[sym]

unless expected then
unless @expected_calls.has_key?(sym) then
raise NoMethodError, "unmocked method %p, expected one of %p" %
[sym, @expected_calls.keys.sort_by(&:to_s)]
end

expected_args, retval = expected[:args], expected[:retval]
x_calls = @expected_calls[sym].select { |call| call[:args].size == args.size }

if x_calls.empty?
arg_sizes = @expected_calls[sym].map { |call| call[:args].size }.uniq.sort
raise ArgumentError, "mocked method %p expects %s arguments, got %d" %
[sym, arg_sizes.join('/'), args.size]
end

x_call = x_calls.find do |call|
call[:args].zip(args).all? { |mod, a| mod === a or mod == a }
end

unless expected_args.size == args.size
raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
[sym, expected[:args].size, args.size]
unless x_call
raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
[sym, args]
end

expected_args, retval = x_call[:args], x_call[:retval]

@actual_calls[sym] << {
:retval => retval,
:args => expected_args.zip(args).map { |mod, a| mod === a ? mod : a }
Expand Down
35 changes: 30 additions & 5 deletions test/test_minitest_mock.rb
Expand Up @@ -78,9 +78,9 @@ def test_blow_up_on_wrong_arguments
@mock.meaning_of_life
@mock.expect(:sum, 3, [1, 2])

@mock.sum(2, 4)

util_verify_bad
assert_raises MockExpectationError do
@mock.sum(2, 4)
end
end

def test_expect_with_non_array_args
Expand Down Expand Up @@ -142,15 +142,19 @@ def test_verify_allows_called_args_to_be_loosely_specified
def test_verify_raises_with_strict_args
mock = MiniTest::Mock.new
mock.expect :strict_expectation, true, [2]
mock.strict_expectation 1

util_verify_bad
assert_raises MockExpectationError do
mock.strict_expectation 1
end
end

def test_verify_shows_the_actual_arguments_in_the_message
mock = MiniTest::Mock.new
mock.expect :capitalized, true, ["a"]
mock.expect :capitalized, true, ["b"]

mock.capitalized "b"

e = assert_raises MockExpectationError do
mock.verify
end
Expand All @@ -162,6 +166,27 @@ def test_verify_shows_the_actual_arguments_in_the_message
assert_equal expected, e.message
end

def test_same_method_expects_are_verified_when_all_called
mock = MiniTest::Mock.new
mock.expect :foo, nil, [:bar]
mock.expect :foo, nil, [:baz]

mock.foo :bar
mock.foo :baz

assert mock.verify
end

def test_same_method_expects_blow_up_when_not_all_called
mock = MiniTest::Mock.new
mock.expect :foo, nil, [:bar]
mock.expect :foo, nil, [:baz]

mock.foo :baz

assert_raises(MockExpectationError) { mock.verify }
end

def util_verify_bad
assert_raises MockExpectationError do
@mock.verify
Expand Down

0 comments on commit 88eec1b

Please sign in to comment.