Compare commits

...

6 Commits

Author SHA1 Message Date
Ingo Prötel
3cb89a9eac
Merge 6489e631ea9c26345f7fdc84ea2289271d83f795 into 7140cd416cecd7462a8aae488024abeee55598e4 2026-06-11 19:28:10 +02:00
Mike Kruskal
7140cd416c Flip the recommendation about using EXPECT statements inside custom matchers.
PiperOrigin-RevId: 925686474
Change-Id: I7b5d7e82dc8618d6914844446fa260468b947ece
2026-06-02 18:03:04 -07:00
Abseil Team
a721f1b20c Automated Code Change
PiperOrigin-RevId: 924116072
Change-Id: I3e04ebbff65c897e50c37e1a47a2018f31382104
2026-05-30 20:49:30 -07:00
Aaron Jacobs
8736d2cd5c gmock-spec-builders: support mocking const-qualified function types.
In particular this automatically gives us support for examples like the
following:

    using SomeFn = absl::AnyInvocable<R(Args...) const>;
    MockFunction<SomeFn> some_fn;

PiperOrigin-RevId: 921303527
Change-Id: I19bf59671781e85db65cc20c0d6ea10b056c528a
2026-05-26 01:30:54 -07:00
Abseil Team
09f45f51fb Mark gtest_dt_ptr as const.
PiperOrigin-RevId: 920667027
Change-Id: I3dd71c96e206eb19bf3e62bb08ce7043d83fb526
2026-05-24 16:31:25 -07:00
Ingo Prötel
6489e631ea Allow declaring calls as uninteresting:
ON_CALL(mock, foo(_)).WillByDefault(...).Uninteresting();

This will supress 'Uninteresting call' warnings in raw and naggy mocks for the declared calls but will still give warnings for other calls.
2025-04-24 21:09:32 +02:00
6 changed files with 199 additions and 45 deletions

View File

@ -3386,30 +3386,6 @@ With this definition, the above assertion will give a better message:
Actual: 27 (the remainder is 6)
```
#### Using EXPECT_ Statements in Matchers
You can also use `EXPECT_...` statements inside custom matcher definitions. In
many cases, this allows you to write your matcher more concisely while still
providing an informative error message. For example:
```cpp
MATCHER(IsDivisibleBy7, "") {
const auto remainder = arg % 7;
EXPECT_EQ(remainder, 0);
return true;
}
```
If you write a test that includes the line `EXPECT_THAT(27, IsDivisibleBy7());`,
you will get an error something like the following:
```shell
Expected equality of these values:
remainder
Which is: 6
0
```
#### `MatchAndExplain`
You should let `MatchAndExplain()` print *any additional information* that can
@ -3429,6 +3405,66 @@ the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the
`arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be
`unsigned long`; and so on.
#### Anti-pattern: Using EXPECT_ Statements in Matchers
Using `EXPECT_...` statements inside custom matcher definitions is an
**anti-pattern** and should be avoided.
While it might appear to write matchers more concisely and generate informative
messages, this pattern has critical issues:
1. **Negation Breakage (`Not`):** If wrapped in `Not(IsDivisibleBy7())`,
evaluating it still triggers the internal `EXPECT_EQ`, registering a test
failure on the runner even when the overall assertion is expected to
succeed.
2. **Composition / Container Breakage (`AnyOf`, `AllOf`, `Contains`):** When
composed or used inside container matchers, elements that are expected
mismatches will trigger the internal `EXPECT_` and register spurious
failures.
3. **ASSERT_* compilation errors:** `ASSERT_*` macros use `return;` to abort
from a void function. Since matchers return `bool`, using `ASSERT_` inside
them triggers a compilation error.
4. **Purity Violations:** Matchers must be functionally pure (side-effect
free), whereas registering global failures is a major side effect.
5. **Line Number Confusion:** Failure reports point to the matcher's definition
line rather than the calling `EXPECT_THAT`
line.
##### The Anti-Pattern
```cpp
// Anti-pattern: Do not do this!
MATCHER(IsDivisibleBy7, "") {
const auto remainder = arg % 7;
EXPECT_EQ(remainder, 0); // Spurious failures if negated/composed!
return true;
}
```
##### The Correct Solution
To write concise matchers that delegate to other matchers and safely propagate
the mismatch explanation, use **`::testing::ExplainMatchResult`** instead,
passing it the sub-matcher, the value to check, and the `result_listener`:
```cpp
MATCHER(IsDivisibleBy7, "") {
const auto remainder = arg % 7;
return ::testing::ExplainMatchResult(::testing::Eq(0), remainder,
result_listener);
}
```
If you write a test that includes the line:
```cpp
EXPECT_THAT(28, Not(IsDivisibleBy7()));
```
it will correctly report the mismatch, properly point to the `EXPECT_THAT` line
number, and support negation (`Not`) and composition (`AllOf`, `AnyOf`, etc.)
without registering spurious failures.
### Writing New Parameterized Matchers Quickly
Sometimes you'll want to define a matcher that has parameters. For that you can

View File

@ -276,6 +276,13 @@ class UntypedOnCallSpecBase {
Clause last_clause_;
}; // class UntypedOnCallSpecBase
// Possible reactions on uninteresting calls.
enum CallReaction {
kAllow,
kWarn,
kFail,
};
// This template class implements an ON_CALL spec.
template <typename F>
class OnCallSpec : public UntypedOnCallSpecBase {
@ -332,6 +339,16 @@ class OnCallSpec : public UntypedOnCallSpecBase {
return action_;
}
OnCallSpec& Uninteresting() {
AssertSpecProperty(not call_reaction_,
"Uninteresting() may only be called "
"once in an ON_CALL().");
call_reaction_ = CallReaction::kAllow;
return *this;
}
std::optional<CallReaction> GetCallReaction() const { return call_reaction_; }
private:
// The information in statement
//
@ -346,18 +363,13 @@ class OnCallSpec : public UntypedOnCallSpecBase {
// matchers => matchers_
// multi-argument-matcher => extra_matcher_
// action => action_
// optional call reaction => call_reaction_
ArgumentMatcherTuple matchers_;
Matcher<const ArgumentTuple&> extra_matcher_;
Action<F> action_;
std::optional<CallReaction> call_reaction_;
}; // class OnCallSpec
// Possible reactions on uninteresting calls.
enum CallReaction {
kAllow,
kWarn,
kFail,
};
} // namespace internal
// Utilities for manipulating mock objects.
@ -1798,9 +1810,16 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args)
// made on this mock object BEFORE performing the action,
// because the action may DELETE the mock object and make the
// following expression meaningless.
const CallReaction reaction =
CallReaction reaction =
Mock::GetReactionOnUninterestingCalls(MockObject());
// Check if there is an OnCallSpec that marks this call as a
// 'known' uninteresting call that should be allowed regardless.
const OnCallSpec<F>* const spec = this->FindOnCallSpec(args);
if (spec && spec->GetCallReaction()) {
reaction = *spec->GetCallReaction();
}
// True if and only if we need to print this call's arguments and return
// value. This definition must be kept in sync with
// the behavior of ReportUninterestingCall().
@ -1957,6 +1976,11 @@ struct SignatureOf<R(Args...)> {
using type = R(Args...);
};
template <typename R, typename... Args>
struct SignatureOf<R(Args...) const> {
using type = R(Args...);
};
template <template <typename> class C, typename F>
struct SignatureOf<C<F>,
typename std::enable_if<std::is_function<F>::value>::type>

View File

@ -942,6 +942,15 @@ static constexpr bool IsMockFunctionTemplateArgumentDeducedTo(
} // namespace
// Like std::add_const, but for function types.
template <typename F>
struct AddConstToFunction;
template <typename R, typename... Args>
struct AddConstToFunction<R(Args...)> {
using type = R(Args...) const;
};
template <typename F>
class MockMethodMockFunctionSignatureTest : public Test {};
@ -953,25 +962,69 @@ TYPED_TEST_SUITE(MockMethodMockFunctionSignatureTest,
TYPED_TEST(MockMethodMockFunctionSignatureTest,
IsMockFunctionTemplateArgumentDeducedForRawSignature) {
using Argument = TypeParam;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
// Non-const
{
using Argument = TypeParam;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
}
// Const
{
using Argument = typename AddConstToFunction<TypeParam>::type;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
}
}
TYPED_TEST(MockMethodMockFunctionSignatureTest,
IsMockFunctionTemplateArgumentDeducedForStdFunction) {
using Argument = std::function<TypeParam>;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
// Non-const
{
using Argument = std::function<TypeParam>;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
}
// As of 2026-05 MSVC doesn't know how to deal with this, providing pages of
// inscrutable errors about std::_Get_function_impl. But this is fine, since
// std::function<R(Args...) const> doesn't apply the const qualifier correctly
// anyway.
#if !defined(_MSC_VER)
// Const
{
using Argument =
std::function<typename AddConstToFunction<TypeParam>::type>;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
}
#endif
}
TYPED_TEST(
MockMethodMockFunctionSignatureTest,
IsMockFunctionCallMethodSignatureTheSameForRawSignatureAndStdFunction) {
using ForRawSignature = decltype(&MockFunction<TypeParam>::Call);
using ForStdFunction =
decltype(&MockFunction<std::function<TypeParam>>::Call);
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
// Non-const
{
using ForRawSignature = decltype(&MockFunction<TypeParam>::Call);
using ForStdFunction =
decltype(&MockFunction<std::function<TypeParam>>::Call);
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
}
// Const
{
using ConstTypeParam = typename AddConstToFunction<TypeParam>::type;
using ForRawSignature = decltype(&MockFunction<ConstTypeParam>::Call);
using ForStdFunction =
decltype(&MockFunction<std::function<ConstTypeParam>>::Call);
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
}
}
template <typename F>

View File

@ -157,6 +157,26 @@ TEST(RawMockTest, WarningForUninterestingCall) {
GMOCK_FLAG_SET(verbose, saved_flag);
}
// Tests that a raw mock generates no warnings for declared uninteresting calls.
TEST(RawMockTest, NoWarningForDeclaredUninterestingCall) {
const std::string saved_flag = GMOCK_FLAG_GET(verbose);
GMOCK_FLAG_SET(verbose, "warning");
MockFoo raw_foo;
ON_CALL(raw_foo, DoThis()).WillByDefault(InvokeWithoutArgs([](){})).Uninteresting();
ON_CALL(raw_foo, DoThat(_)).WillByDefault(Return(1)).Uninteresting();
CaptureStdout();
raw_foo.DoThis();
raw_foo.DoThat(true);
EXPECT_THAT(GetCapturedStdout(),
Not(HasSubstr("Uninteresting mock function call")));
GMOCK_FLAG_SET(verbose, saved_flag);
}
// Tests that a raw mock generates warnings for uninteresting calls
// that delete the mock object.
TEST(RawMockTest, WarningForUninterestingCallAfterDeath) {
@ -342,6 +362,26 @@ TEST(NaggyMockTest, WarningForUninterestingCall) {
GMOCK_FLAG_SET(verbose, saved_flag);
}
// Tests that a raw mock generates no warnings for declared uninteresting calls.
TEST(NaggyMockTest, NoWarningForDeclaredUninterestingCall) {
const std::string saved_flag = GMOCK_FLAG_GET(verbose);
GMOCK_FLAG_SET(verbose, "warning");
NaggyMock<MockFoo> naggy_foo;
ON_CALL(naggy_foo, DoThis()).WillByDefault(InvokeWithoutArgs([](){})).Uninteresting();
ON_CALL(naggy_foo, DoThat(_)).WillByDefault(Return(1)).Uninteresting();
CaptureStdout();
naggy_foo.DoThis();
naggy_foo.DoThat(true);
EXPECT_THAT(GetCapturedStdout(),
Not(HasSubstr("Uninteresting mock function call")));
GMOCK_FLAG_SET(verbose, saved_flag);
}
// Tests that a naggy mock generates a warning for an uninteresting call
// that deletes the mock object.
TEST(NaggyMockTest, WarningForUninterestingCallAfterDeath) {

View File

@ -129,7 +129,7 @@ class GTEST_API_ Message {
int>::type = 0
#endif // GTEST_HAS_ABSL
>
inline Message& operator<<(const T& val) {
Message& operator<<(const T& val) {
// Some libraries overload << for STL containers. These
// overloads are defined in the global namespace instead of ::std.
//
@ -155,7 +155,7 @@ class GTEST_API_ Message {
template <typename T,
typename std::enable_if<absl::HasAbslStringify<T>::value, // NOLINT
int>::type = 0>
inline Message& operator<<(const T& val) {
Message& operator<<(const T& val) {
// ::operator<< is needed here for a similar reason as with the non-Abseil
// version above
using ::operator<<;

View File

@ -229,7 +229,8 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
} \
if (gtest_dt != nullptr) { \
std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \
const std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr( \
gtest_dt); \
switch (gtest_dt->AssumeRole()) { \
case ::testing::internal::DeathTest::OVERSEE_TEST: \
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \