Makes googlemock throw a runtime_error instead of abort when a mock

method with no default value is invoked (if exceptions are enabled).
This commit is contained in:
zhanyong.wan 2013-02-28 22:58:51 +00:00
parent cf40604cf0
commit edd4ab4945
4 changed files with 283 additions and 107 deletions

View File

@ -66,6 +66,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if GTEST_HAS_EXCEPTIONS
# include <stdexcept> // NOLINT
#endif
#include "gmock/gmock-actions.h" #include "gmock/gmock-actions.h"
#include "gmock/gmock-cardinalities.h" #include "gmock/gmock-cardinalities.h"
#include "gmock/gmock-matchers.h" #include "gmock/gmock-matchers.h"
@ -1425,10 +1429,12 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
return NULL; return NULL;
} }
// Performs the default action of this mock function on the given arguments // Performs the default action of this mock function on the given
// and returns the result. Asserts with a helpful call descrption if there is // arguments and returns the result. Asserts (or throws if
// no valid return value. This method doesn't depend on the mutable state of // exceptions are enabled) with a helpful call descrption if there
// this object, and thus can be called concurrently without locking. // is no valid return value. This method doesn't depend on the
// mutable state of this object, and thus can be called concurrently
// without locking.
// L = * // L = *
Result PerformDefaultAction(const ArgumentTuple& args, Result PerformDefaultAction(const ArgumentTuple& args,
const string& call_description) const { const string& call_description) const {
@ -1437,9 +1443,16 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
if (spec != NULL) { if (spec != NULL) {
return spec->GetAction().Perform(args); return spec->GetAction().Perform(args);
} }
Assert(DefaultValue<Result>::Exists(), "", -1, const string message = call_description +
call_description + "\n The mock function has no default action " "\n The mock function has no default action "
"set, and its return type has no default value set."); "set, and its return type has no default value set.";
#if GTEST_HAS_EXCEPTIONS
if (!DefaultValue<Result>::Exists()) {
throw std::runtime_error(message);
}
#else
Assert(DefaultValue<Result>::Exists(), "", -1, message);
#endif
return DefaultValue<Result>::Get(); return DefaultValue<Result>::Get();
} }

View File

@ -634,15 +634,19 @@ TEST(DoDefaultTest, ReturnsBuiltInDefaultValueByDefault) {
EXPECT_EQ(0, mock.IntFunc(true)); EXPECT_EQ(0, mock.IntFunc(true));
} }
// Tests that DoDefault() aborts the process when there is no built-in // Tests that DoDefault() throws (when exceptions are enabled) or aborts
// default value for the return type. // the process when there is no built-in default value for the return type.
TEST(DoDefaultDeathTest, DiesForUnknowType) { TEST(DoDefaultDeathTest, DiesForUnknowType) {
MockClass mock; MockClass mock;
EXPECT_CALL(mock, Foo()) EXPECT_CALL(mock, Foo())
.WillRepeatedly(DoDefault()); .WillRepeatedly(DoDefault());
#if GTEST_HAS_EXCEPTIONS
EXPECT_ANY_THROW(mock.Foo());
#else
EXPECT_DEATH_IF_SUPPORTED({ EXPECT_DEATH_IF_SUPPORTED({
mock.Foo(); mock.Foo();
}, ""); }, "");
#endif
} }
// Tests that using DoDefault() inside a composite action leads to a // Tests that using DoDefault() inside a composite action leads to a

View File

@ -1111,7 +1111,11 @@ TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) {
// TODO(wan@google.com): We should really verify the output message, // TODO(wan@google.com): We should really verify the output message,
// but we cannot yet due to that EXPECT_DEATH only captures stderr // but we cannot yet due to that EXPECT_DEATH only captures stderr
// while Google Mock logs to stdout. // while Google Mock logs to stdout.
#if GTEST_HAS_EXCEPTIONS
EXPECT_ANY_THROW(a.ReturnResult(1));
#else
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(1), ""); EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(1), "");
#endif
} }
// Tests that an excessive call (one whose arguments match the // Tests that an excessive call (one whose arguments match the
@ -1260,87 +1264,116 @@ TEST(SequenceTest, AnyOrderIsOkByDefault) {
// Tests that the calls must be in strict order when a complete order // Tests that the calls must be in strict order when a complete order
// is specified. // is specified.
TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo) { TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo1) {
MockA a; MockA a;
ON_CALL(a, ReturnResult(_))
.WillByDefault(Return(Result()));
Sequence s; Sequence s;
EXPECT_CALL(a, ReturnResult(1)) EXPECT_CALL(a, ReturnResult(1))
.InSequence(s) .InSequence(s);
.WillOnce(Return(Result()));
EXPECT_CALL(a, ReturnResult(2)) EXPECT_CALL(a, ReturnResult(2))
.InSequence(s) .InSequence(s);
.WillOnce(Return(Result()));
EXPECT_CALL(a, ReturnResult(3)) EXPECT_CALL(a, ReturnResult(3))
.InSequence(s) .InSequence(s);
.WillOnce(Return(Result()));
EXPECT_DEATH_IF_SUPPORTED({
a.ReturnResult(1);
a.ReturnResult(3);
a.ReturnResult(2);
}, "");
EXPECT_DEATH_IF_SUPPORTED({
a.ReturnResult(2);
a.ReturnResult(1);
a.ReturnResult(3);
}, "");
a.ReturnResult(1); a.ReturnResult(1);
// May only be called after a.ReturnResult(2).
EXPECT_NONFATAL_FAILURE(a.ReturnResult(3), "Unexpected mock function call");
a.ReturnResult(2); a.ReturnResult(2);
a.ReturnResult(3); a.ReturnResult(3);
} }
// Tests specifying a DAG using multiple sequences. // Tests that the calls must be in strict order when a complete order
TEST(SequenceTest, CallsMustConformToSpecifiedDag) { // is specified.
TEST(SequenceTest, CallsMustBeInStrictOrderWhenSaidSo2) {
MockA a; MockA a;
MockB b; ON_CALL(a, ReturnResult(_))
Sequence x, y; .WillByDefault(Return(Result()));
Sequence s;
EXPECT_CALL(a, ReturnResult(1)) EXPECT_CALL(a, ReturnResult(1))
.InSequence(x) .InSequence(s);
.WillOnce(Return(Result()));
EXPECT_CALL(b, DoB())
.Times(2)
.InSequence(y);
EXPECT_CALL(a, ReturnResult(2)) EXPECT_CALL(a, ReturnResult(2))
.InSequence(x, y) .InSequence(s);
.WillRepeatedly(Return(Result()));
EXPECT_CALL(a, ReturnResult(3)) // May only be called after a.ReturnResult(1).
.InSequence(x) EXPECT_NONFATAL_FAILURE(a.ReturnResult(2), "Unexpected mock function call");
.WillOnce(Return(Result()));
EXPECT_DEATH_IF_SUPPORTED({
a.ReturnResult(1);
b.DoB();
a.ReturnResult(2);
}, "");
EXPECT_DEATH_IF_SUPPORTED({
a.ReturnResult(2);
}, "");
EXPECT_DEATH_IF_SUPPORTED({
a.ReturnResult(3);
}, "");
EXPECT_DEATH_IF_SUPPORTED({
a.ReturnResult(1);
b.DoB();
b.DoB();
a.ReturnResult(3);
a.ReturnResult(2);
}, "");
b.DoB();
a.ReturnResult(1); a.ReturnResult(1);
b.DoB(); a.ReturnResult(2);
a.ReturnResult(3); }
// Tests specifying a DAG using multiple sequences.
class PartialOrderTest : public testing::Test {
protected:
PartialOrderTest() {
ON_CALL(a_, ReturnResult(_))
.WillByDefault(Return(Result()));
// Specifies this partial ordering:
//
// a.ReturnResult(1) ==>
// a.ReturnResult(2) * n ==> a.ReturnResult(3)
// b.DoB() * 2 ==>
Sequence x, y;
EXPECT_CALL(a_, ReturnResult(1))
.InSequence(x);
EXPECT_CALL(b_, DoB())
.Times(2)
.InSequence(y);
EXPECT_CALL(a_, ReturnResult(2))
.Times(AnyNumber())
.InSequence(x, y);
EXPECT_CALL(a_, ReturnResult(3))
.InSequence(x);
}
MockA a_;
MockB b_;
};
TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag1) {
a_.ReturnResult(1);
b_.DoB();
// May only be called after the second DoB().
EXPECT_NONFATAL_FAILURE(a_.ReturnResult(2), "Unexpected mock function call");
b_.DoB();
a_.ReturnResult(3);
}
TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag2) {
// May only be called after ReturnResult(1).
EXPECT_NONFATAL_FAILURE(a_.ReturnResult(2), "Unexpected mock function call");
a_.ReturnResult(1);
b_.DoB();
b_.DoB();
a_.ReturnResult(3);
}
TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag3) {
// May only be called last.
EXPECT_NONFATAL_FAILURE(a_.ReturnResult(3), "Unexpected mock function call");
a_.ReturnResult(1);
b_.DoB();
b_.DoB();
a_.ReturnResult(3);
}
TEST_F(PartialOrderTest, CallsMustConformToSpecifiedDag4) {
a_.ReturnResult(1);
b_.DoB();
b_.DoB();
a_.ReturnResult(3);
// May only be called before ReturnResult(3).
EXPECT_NONFATAL_FAILURE(a_.ReturnResult(2), "Unexpected mock function call");
} }
TEST(SequenceTest, Retirement) { TEST(SequenceTest, Retirement) {
@ -1530,71 +1563,112 @@ TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) {
a.DoA(2); a.DoA(2);
} }
// Calls must be in strict order when specified so. // Calls must be in strict order when specified so using .After().
TEST(AfterDeathTest, CallsMustBeInStrictOrderWhenSpecifiedSo) { TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo1) {
MockA a; MockA a;
MockB b; MockB b;
// Define ordering:
// a.DoA(1) ==> b.DoB() ==> a.DoA(2)
Expectation e1 = EXPECT_CALL(a, DoA(1));
Expectation e2 = EXPECT_CALL(b, DoB())
.After(e1);
EXPECT_CALL(a, DoA(2))
.After(e2);
a.DoA(1);
// May only be called after DoB().
EXPECT_NONFATAL_FAILURE(a.DoA(2), "Unexpected mock function call");
b.DoB();
a.DoA(2);
}
// Calls must be in strict order when specified so using .After().
TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo2) {
MockA a;
MockB b;
// Define ordering:
// a.DoA(1) ==> b.DoB() * 2 ==> a.DoA(2)
Expectation e1 = EXPECT_CALL(a, DoA(1)); Expectation e1 = EXPECT_CALL(a, DoA(1));
Expectation e2 = EXPECT_CALL(b, DoB()) Expectation e2 = EXPECT_CALL(b, DoB())
.Times(2) .Times(2)
.After(e1); .After(e1);
EXPECT_CALL(a, ReturnResult(2)) EXPECT_CALL(a, DoA(2))
.After(e2) .After(e2);
.WillOnce(Return(Result()));
a.DoA(1); a.DoA(1);
// If a call to ReturnResult() violates the specified order, no b.DoB();
// matching expectation will be found, and thus the default action
// will be done. Since the return type of ReturnResult() is not a // May only be called after the second DoB().
// built-in type, gmock won't know what to return and will thus EXPECT_NONFATAL_FAILURE(a.DoA(2), "Unexpected mock function call");
// abort the program. Therefore a death test can tell us whether
// gmock catches the order violation correctly.
//
// gtest and gmock print messages to stdout, which isn't captured by
// death tests. Therefore we have to match with an empty regular
// expression in all the EXPECT_DEATH()s.
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(2), "");
b.DoB(); b.DoB();
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(2), ""); a.DoA(2);
b.DoB();
a.ReturnResult(2);
} }
// Calls must satisfy the partial order when specified so. // Calls must satisfy the partial order when specified so.
TEST(AfterDeathTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) { TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) {
MockA a; MockA a;
ON_CALL(a, ReturnResult(_))
.WillByDefault(Return(Result()));
// Define ordering:
// a.DoA(1) ==>
// a.DoA(2) ==> a.ReturnResult(3)
Expectation e = EXPECT_CALL(a, DoA(1)); Expectation e = EXPECT_CALL(a, DoA(1));
const ExpectationSet es = EXPECT_CALL(a, DoA(2)); const ExpectationSet es = EXPECT_CALL(a, DoA(2));
EXPECT_CALL(a, ReturnResult(3)) EXPECT_CALL(a, ReturnResult(3))
.After(e, es) .After(e, es);
.WillOnce(Return(Result()));
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), ""); // May only be called last.
EXPECT_NONFATAL_FAILURE(a.ReturnResult(3), "Unexpected mock function call");
a.DoA(2); a.DoA(2);
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), "");
a.DoA(1); a.DoA(1);
a.ReturnResult(3); a.ReturnResult(3);
} }
// Calls must satisfy the partial order when specified so.
TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo2) {
MockA a;
// Define ordering:
// a.DoA(1) ==>
// a.DoA(2) ==> a.DoA(3)
Expectation e = EXPECT_CALL(a, DoA(1));
const ExpectationSet es = EXPECT_CALL(a, DoA(2));
EXPECT_CALL(a, DoA(3))
.After(e, es);
a.DoA(2);
// May only be called last.
EXPECT_NONFATAL_FAILURE(a.DoA(3), "Unexpected mock function call");
a.DoA(1);
a.DoA(3);
}
// .After() can be combined with .InSequence(). // .After() can be combined with .InSequence().
TEST(AfterDeathTest, CanBeUsedWithInSequence) { TEST(AfterTest, CanBeUsedWithInSequence) {
MockA a; MockA a;
Sequence s; Sequence s;
Expectation e = EXPECT_CALL(a, DoA(1)); Expectation e = EXPECT_CALL(a, DoA(1));
EXPECT_CALL(a, DoA(2)).InSequence(s); EXPECT_CALL(a, DoA(2)).InSequence(s);
EXPECT_CALL(a, ReturnResult(3)) EXPECT_CALL(a, DoA(3))
.InSequence(s).After(e) .InSequence(s)
.WillOnce(Return(Result())); .After(e);
a.DoA(1); a.DoA(1);
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), "");
// May only be after DoA(2).
EXPECT_NONFATAL_FAILURE(a.DoA(3), "Unexpected mock function call");
a.DoA(2); a.DoA(2);
a.ReturnResult(3); a.DoA(3);
} }
// .After() can be called multiple times. // .After() can be called multiple times.
@ -1636,17 +1710,24 @@ TEST(AfterTest, AcceptsUpToFiveArguments) {
// .After() allows input to contain duplicated Expectations. // .After() allows input to contain duplicated Expectations.
TEST(AfterTest, AcceptsDuplicatedInput) { TEST(AfterTest, AcceptsDuplicatedInput) {
MockA a; MockA a;
ON_CALL(a, ReturnResult(_))
.WillByDefault(Return(Result()));
// Define ordering:
// DoA(1) ==>
// DoA(2) ==> ReturnResult(3)
Expectation e1 = EXPECT_CALL(a, DoA(1)); Expectation e1 = EXPECT_CALL(a, DoA(1));
Expectation e2 = EXPECT_CALL(a, DoA(2)); Expectation e2 = EXPECT_CALL(a, DoA(2));
ExpectationSet es; ExpectationSet es;
es += e1; es += e1;
es += e2; es += e2;
EXPECT_CALL(a, ReturnResult(3)) EXPECT_CALL(a, ReturnResult(3))
.After(e1, e2, es, e1) .After(e1, e2, es, e1);
.WillOnce(Return(Result()));
a.DoA(1); a.DoA(1);
EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(3), "");
// May only be after DoA(2).
EXPECT_NONFATAL_FAILURE(a.ReturnResult(3), "Unexpected mock function call");
a.DoA(2); a.DoA(2);
a.ReturnResult(3); a.ReturnResult(3);

78
test/gmock_ex_test.cc Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2013, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: wan@google.com (Zhanyong Wan)
// Tests Google Mock's functionality that depends on exceptions.
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
using testing::HasSubstr;
using testing::internal::GoogleTestFailureException;
// A user-defined class.
class Something {};
class MockFoo {
public:
// A mock method that returns a user-defined type. Google Mock
// doesn't know what the default value for this type is.
MOCK_METHOD0(GetSomething, Something());
};
#if GTEST_HAS_EXCEPTIONS
TEST(DefaultValueTest, ThrowsRuntimeErrorWhenNoDefaultValue) {
MockFoo mock;
try {
// No expectation is set on this method, so Google Mock must
// return the default value. However, since Google Mock knows
// nothing about the return type, it doesn't know what to return,
// and has to throw (when exceptions are enabled) or abort
// (otherwise).
mock.GetSomething();
FAIL() << "GetSomething()'s return type has no default value, "
<< "so Google Mock should have thrown.";
} catch (const GoogleTestFailureException& /* unused */) {
FAIL() << "Google Test does not try to catch an exception of type "
<< "GoogleTestFailureException, which is used for reporting "
<< "a failure to other testing frameworks. Google Mock should "
<< "not throw a GoogleTestFailureException as it will kill the "
<< "entire test program instead of just the current TEST.";
} catch (const std::exception& ex) {
EXPECT_THAT(ex.what(), HasSubstr("has no default value"));
}
}
#endif
} // unnamed namespace