Compare commits

...

6 Commits

Author SHA1 Message Date
Gabriel Staples
f13e9d53be
Merge 717e4be8edcc6810cf2a0b95ace0a4aea5d7b351 into 7140cd416cecd7462a8aae488024abeee55598e4 2026-06-11 19:28:22 +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
Gabriel Staples
717e4be8ed docs/community_created_documentation.md: update links...
...to my content, as well as add a description of it.
2024-12-05 08:13:16 -07:00
6 changed files with 135 additions and 39 deletions

View File

@ -3,5 +3,6 @@
The following is a list, in no particular order, of links to documentation The following is a list, in no particular order, of links to documentation
created by the Googletest community. created by the Googletest community.
* [Googlemock Insights](https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/googletest/insights.md), * [Googlemock Insights](https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/googletest/insights.md), by [Gabriel Staples](https://www.linkedin.com/in/gabriel-staples/) ([ElectricRCAircraftGuy](https://github.com/ElectricRCAircraftGuy))
by [ElectricRCAircraftGuy](https://github.com/ElectricRCAircraftGuy)
This covers some of the more nuanced features such as using multiple `EXPECT_CALL()`s, and using `.WillRepeatedly(InvokeWithoutArgs([&callCounter](){ callCounter++; }));` to count the number of times a mock function is called between each call when doing successive calls of the function under test.

View File

@ -3386,30 +3386,6 @@ With this definition, the above assertion will give a better message:
Actual: 27 (the remainder is 6) 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` #### `MatchAndExplain`
You should let `MatchAndExplain()` print *any additional information* that can 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 `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be
`unsigned long`; and so on. `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 ### Writing New Parameterized Matchers Quickly
Sometimes you'll want to define a matcher that has parameters. For that you can Sometimes you'll want to define a matcher that has parameters. For that you can

View File

@ -1957,6 +1957,11 @@ struct SignatureOf<R(Args...)> {
using type = 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> template <template <typename> class C, typename F>
struct SignatureOf<C<F>, struct SignatureOf<C<F>,
typename std::enable_if<std::is_function<F>::value>::type> typename std::enable_if<std::is_function<F>::value>::type>

View File

@ -942,6 +942,15 @@ static constexpr bool IsMockFunctionTemplateArgumentDeducedTo(
} // namespace } // 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> template <typename F>
class MockMethodMockFunctionSignatureTest : public Test {}; class MockMethodMockFunctionSignatureTest : public Test {};
@ -953,25 +962,69 @@ TYPED_TEST_SUITE(MockMethodMockFunctionSignatureTest,
TYPED_TEST(MockMethodMockFunctionSignatureTest, TYPED_TEST(MockMethodMockFunctionSignatureTest,
IsMockFunctionTemplateArgumentDeducedForRawSignature) { IsMockFunctionTemplateArgumentDeducedForRawSignature) {
using Argument = TypeParam; // Non-const
MockFunction<Argument> foo; {
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo)); 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, TYPED_TEST(MockMethodMockFunctionSignatureTest,
IsMockFunctionTemplateArgumentDeducedForStdFunction) { IsMockFunctionTemplateArgumentDeducedForStdFunction) {
using Argument = std::function<TypeParam>; // Non-const
MockFunction<Argument> foo; {
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo)); 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( TYPED_TEST(
MockMethodMockFunctionSignatureTest, MockMethodMockFunctionSignatureTest,
IsMockFunctionCallMethodSignatureTheSameForRawSignatureAndStdFunction) { IsMockFunctionCallMethodSignatureTheSameForRawSignatureAndStdFunction) {
using ForRawSignature = decltype(&MockFunction<TypeParam>::Call); // Non-const
using ForStdFunction = {
decltype(&MockFunction<std::function<TypeParam>>::Call); using ForRawSignature = decltype(&MockFunction<TypeParam>::Call);
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value)); 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> template <typename F>

View File

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

View File

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