Compare commits

...

6 Commits

Author SHA1 Message Date
Jeremy Nimmer
dc423ae29a
Merge f1e068d5c577a019f1f6c199f2e3f21859c45d13 into 7140cd416cecd7462a8aae488024abeee55598e4 2026-06-11 19:28:11 +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
Jeremy Nimmer
f1e068d5c5 Fix ParamIteratorInterface copy constructor defaulting 2025-11-06 10:36:07 -08:00
6 changed files with 140 additions and 39 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

@ -1957,6 +1957,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,27 +962,71 @@ TYPED_TEST_SUITE(MockMethodMockFunctionSignatureTest,
TYPED_TEST(MockMethodMockFunctionSignatureTest,
IsMockFunctionTemplateArgumentDeducedForRawSignature) {
// 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) {
// 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) {
// 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>
struct AlternateCallable {};

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()))) { \

View File

@ -99,6 +99,7 @@ class [[nodiscard]] ParamGenerator;
template <typename T>
class [[nodiscard]] ParamIteratorInterface {
public:
ParamIteratorInterface() = default;
virtual ~ParamIteratorInterface() = default;
// A pointer to the base generator instance.
// Used only for the purposes of iterator comparison
@ -121,6 +122,9 @@ class [[nodiscard]] ParamIteratorInterface {
// element in the sequence generated by the generator.
// Used for implementing ParamGenerator<T>::operator==().
virtual bool Equals(const ParamIteratorInterface& other) const = 0;
protected:
// Make available for subclasses to use to implement Clone().
ParamIteratorInterface(const ParamIteratorInterface&) = default;
};
// Class iterating over elements provided by an implementation of
@ -844,7 +848,7 @@ class [[nodiscard]] CartesianProductGenerator
template <class I>
class IteratorImpl;
template <size_t... I>
class IteratorImpl<std::index_sequence<I...>>
class IteratorImpl<std::index_sequence<I...>> final
: public ParamIteratorInterface<ParamType> {
public:
IteratorImpl(const ParamGeneratorInterface<ParamType>* base,
@ -856,7 +860,7 @@ class [[nodiscard]] CartesianProductGenerator
current_(is_end ? end_ : begin_) {
ComputeCurrentValue();
}
~IteratorImpl() override = default;
~IteratorImpl() final = default;
const ParamGeneratorInterface<ParamType>* BaseGenerator() const override {
return base_;
@ -900,6 +904,8 @@ class [[nodiscard]] CartesianProductGenerator
}
private:
IteratorImpl(const IteratorImpl&) = default;
template <size_t ThisI>
void AdvanceIfEnd() {
if (std::get<ThisI>(current_) != std::get<ThisI>(end_)) return;