Compare commits

...

6 Commits

Author SHA1 Message Date
Thorsten Klein
1cbd60d196
Merge 9d0754ba6b6de882d55bdfb9439a84c9aa85dd3e 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
Klein, Thorsten
9d0754ba6b Add common Clang warnings to cxx_base_flags and fix existing issues
This commit fixes several Clang warnings and updates cxx_base_flags to
always enable them, ensuring consistent warning coverage across builds.

Enabled additional warnings:
-Wswitch-default -Wswitch-enum -Wextra -Wcast-align -Wunused
-Wunreachable-code
2025-10-23 17:38:53 +02:00
15 changed files with 170 additions and 46 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

@ -5942,7 +5942,7 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
} \
template <typename arg_type> \
bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain( \
const arg_type& arg, \
[[maybe_unused]] const arg_type& arg, \
[[maybe_unused]] ::testing::MatchResultListener* result_listener) const
#define MATCHER_P(name, p0, description) \
@ -6027,7 +6027,7 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
template <typename arg_type> \
bool full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>:: \
gmock_Impl<arg_type>::MatchAndExplain( \
const arg_type& arg, \
[[maybe_unused]] const arg_type& arg, \
[[maybe_unused]] ::testing::MatchResultListener* result_listener) \
const

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

@ -301,6 +301,8 @@ void UnorderedElementsAreMatcherImplBase::DescribeToImpl(
case UnorderedMatcherRequire::Subset:
*os << "an injection from elements to requirements exists such that:\n";
break;
default:
break;
}
const char* sep = "";
@ -343,6 +345,8 @@ void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(
case UnorderedMatcherRequire::Subset:
*os << "no injection from elements to requirements exists such that:\n";
break;
default:
break;
}
const char* sep = "";
for (size_t i = 0; i != matcher_describers_.size(); ++i) {

View File

@ -301,6 +301,7 @@ void ReportUninterestingCall(CallReaction reaction, const std::string& msg) {
"knowing-when-to-expect-useoncall for details.\n",
stack_frames_to_skip);
break;
case kFail:
default: // FAIL
Expect(false, nullptr, -1, msg);
}

View File

@ -80,7 +80,7 @@ class TemplatedCopyable {
TemplatedCopyable() = default;
template <typename U>
TemplatedCopyable(const U& other) {} // NOLINT
TemplatedCopyable(const U&) {} // NOLINT
};
class FooInterface {
@ -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

@ -2829,6 +2829,8 @@ class PredicateFormatterFromMatcherTest : public ::testing::Test {
// an "interested" listener; so this will return |true|, thus
// simulating a flaky matcher.
return listener->IsInterested();
default:
break;
}
GTEST_LOG_(FATAL) << "This should never be reached";

View File

@ -91,7 +91,17 @@ macro(config_compiler_and_linker)
endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR
CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
set(cxx_base_flags "-Wall -Wshadow -Wconversion -Wundef")
set(cxx_base_flags "-Wall \
-Wshadow \
-Wconversion \
-Wundef \
-Wswitch-default \
-Wswitch-enum \
-Wextra \
-Wcast-align \
-Wunused \
-Wunreachable-code \
")
set(cxx_exception_flags "-fexceptions")
set(cxx_no_exception_flags "-fno-exceptions")
set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Winline -Wredundant-decls")

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()))) { \
@ -243,6 +244,8 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
break; \
} \
default: \
break; \
} \
} \
} else \

View File

@ -1497,6 +1497,8 @@ class Hunk {
++adds_;
hunk_adds_.push_back(std::make_pair('+', line));
break;
default:
break;
}
}
@ -3308,6 +3310,7 @@ static const char* GetAnsiColorCode(GTestColor color) {
return "2";
case GTestColor::kYellow:
return "3";
case GTestColor::kDefault:
default:
assert(false);
return "9";
@ -3564,6 +3567,9 @@ void PrettyUnitTestResultPrinter::OnTestPartResult(
// If the test part succeeded, we don't need to do anything.
case TestPartResult::kSuccess:
return;
case TestPartResult::kNonFatalFailure:
case TestPartResult::kFatalFailure:
case TestPartResult::kSkip:
default:
// Print failure message from the assertion
// (e.g. expected this and got that).
@ -3782,6 +3788,9 @@ void BriefUnitTestResultPrinter::OnTestPartResult(
// If the test part succeeded, we don't need to do anything.
case TestPartResult::kSuccess:
return;
case TestPartResult::kNonFatalFailure:
case TestPartResult::kFatalFailure:
case TestPartResult::kSkip:
default:
// Print failure message from the assertion
// (e.g. expected this and got that).

View File

@ -348,7 +348,7 @@ TEST_F(TestForDeathTest, SwitchStatement) {
ASSERT_DEATH(_Exit(1), "") << "exit in default switch handler";
switch (0)
case 0:
default:
EXPECT_DEATH(_Exit(1), "") << "exit in switch case";
GTEST_DISABLE_MSC_WARNINGS_POP_()
@ -1501,7 +1501,7 @@ TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) {
ASSERT_DEATH_IF_SUPPORTED(_Exit(1), "") << "exit in default switch handler";
switch (0)
case 0:
default:
EXPECT_DEATH_IF_SUPPORTED(_Exit(1), "") << "exit in switch case";
GTEST_DISABLE_MSC_WARNINGS_POP_()

View File

@ -239,7 +239,7 @@ TEST(GtestCheckSyntaxTest, WorksWithSwitch) {
}
switch (0)
case 0:
default:
GTEST_CHECK_(true) << "Check failed in switch case";
}

View File

@ -63,6 +63,7 @@ class MyEnvironment : public testing::Environment {
case FATAL_FAILURE:
FAIL() << "Expected fatal failure in global set-up.";
break;
case NO_FAILURE:
default:
break;
}

View File

@ -4248,7 +4248,7 @@ TEST(AssertionSyntaxTest, WorksWithSwitch) {
}
switch (0)
case 0:
default:
EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case";
// Binary assertions are implemented using a different code path
@ -4260,7 +4260,7 @@ TEST(AssertionSyntaxTest, WorksWithSwitch) {
}
switch (0)
case 0:
default:
EXPECT_NE(1, 2);
}