Compare commits

...

6 Commits

Author SHA1 Message Date
jdfa
c99edc7be5
Merge db0e9a6836644ec19fa7ace682f13b3c81eec9e4 into a0f06a70e3da7afa88da9527c43951bca1f7cef2 2026-07-29 21:22:14 +00:00
Abseil Team
a0f06a70e3 Make GoogleTest handle std::monostate and valueless_by_exception() for std::variant similarly to how it handles std::nullopt
Fixes: #2066
PiperOrigin-RevId: 955981465
Change-Id: I6b34dc2e634d4b727a50fb3e21e5d8e25c39a13b
2026-07-29 11:08:13 -07:00
Copybara-Service
3ff51c3e80 Merge pull request #5041 from alvinjaison:fix/get-test-suite-shuffle-index
PiperOrigin-RevId: 955317170
Change-Id: I40e01cdafe58768ccdb743dcf38717e48edcde41
2026-07-28 09:58:12 -07:00
Alvin Jaison
1269db9643 Fix GetTestSuite(i) ignoring shuffle order UnitTestImpl::GetTestSuite(int i) computes the shuffled index from test_suite_indices_ but then accesses test_suites_ using the raw parameter 'i' instead of the computed 'index'. This causes the public API UnitTest::GetTestSuite(i) to return test suites in original registration order rather than the active shuffle order. The mutable variant GetMutableSuiteCase(i) correctly uses 'index', and the equivalent function TestSuite::GetTestInfo(i) also uses 'index'. This was a copy-paste typo introduced in commit bd851333 (Sep 2009) when the shuffle feature was first added. The bug is observable from within TestEventListener callbacks during test execution when --gtest_shuffle is active. 2026-07-24 16:11:55 +01:00
Andrii Kucherenko
db0e9a6836 Fixed comments 2023-02-03 17:53:13 +02:00
Andrii Kucherenko
31156e74f3 #3683 Added SetMockName function to distinguish between mock objects 2023-01-31 21:03:59 +02:00
7 changed files with 110 additions and 26 deletions

View File

@ -189,6 +189,14 @@ expectations must be matched in a given order, you can use the
[`InSequence` clause](reference/mocking.md#EXPECT_CALL.InSequence) of
`EXPECT_CALL`, or use an [`InSequence` object](reference/mocking.md#InSequence).
## Distinguishing between Unintresting Calls from Different Mocks
By default unintresting mock function calls will be logged as function name and its address.
In case when multiple instances of same mocked class is used it can be useful to set mock name:
```cpp
Mock::SetMockName(&mock_obj, "NamedObject");
```
## Verifying and Resetting a Mock
gMock will verify the expectations on a mock object when it is destructed, or

View File

@ -382,6 +382,15 @@ class GTEST_API_ Mock {
static bool VerifyAndClear(void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
// Set name for mock. Will be used in output.
// Useful when multiple instances of same mock is required.
static void SetMockName(void* mock_obj, const std::string& mock_name)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
// Returns mock name which was set using SetMockName
static std::string GetMockName(const void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
// Returns whether the mock was created as a naggy mock (default)
static bool IsNaggy(void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
@ -1622,6 +1631,8 @@ class FunctionMocker<R(Args...)> final : public UntypedFunctionMockerBase {
DescribeDefaultActionTo(args, os);
*os << " Function call: " << Name();
UniversalPrint(args, os);
const auto mock_name = Mock::GetMockName(MockObject());
if (!mock_name.empty()) *os << " on " << mock_name;
}
// Returns the expectation that matches the given function arguments

View File

@ -471,6 +471,7 @@ struct MockObjectState {
int first_used_line;
::std::string first_used_test_suite;
::std::string first_used_test;
::std::string name;
bool leakable; // true if and only if it's OK to leak the object.
FunctionMockers function_mockers; // All registered methods of the object.
};
@ -634,6 +635,22 @@ bool Mock::VerifyAndClear(void* mock_obj)
return VerifyAndClearExpectationsLocked(mock_obj);
}
// Set name for mock. Will be used in output.
// Useful when multiple instances of same mock is required.
void Mock::SetMockName(void* mock_obj, const std::string& mock_name)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
g_mock_object_registry.states()[mock_obj].name = mock_name;
}
// Returns mock name which was set using SetMockName
std::string Mock::GetMockName(const void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
if (g_mock_object_registry.states().count(mock_obj) == 0) return "";
return g_mock_object_registry.states()[mock_obj].name;
}
// Verifies and clears all expectations on the given mock object. If
// the expectations aren't satisfied, generates one or more Google
// Test non-fatal failures and returns false.
@ -712,14 +729,13 @@ void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker)
internal::g_gmock_mutex.AssertHeld();
for (MockObjectRegistry::StateMap::iterator it =
g_mock_object_registry.states().begin();
it != g_mock_object_registry.states().end(); ++it) {
it != g_mock_object_registry.states().end();) {
FunctionMockers& mockers = it->second.function_mockers;
if (mockers.erase(mocker) > 0) {
// mocker was in mockers and has been just removed.
if (mockers.empty()) {
g_mock_object_registry.states().erase(it);
}
return;
mockers.erase(mocker);
if (mockers.empty()) {
it = g_mock_object_registry.states().erase(it);
} else {
++it;
}
}
}

View File

@ -190,6 +190,24 @@ TEST(RawMockTest, InfoForUninterestingCall) {
GMOCK_FLAG_SET(verbose, saved_flag);
}
// Tests that a raw mock using mock name in warnings for uninteresting calls.
TEST(RawMockTest, NamedMockInUninteresingCall) {
MockFoo raw_foo;
const std::string saved_flag = GMOCK_FLAG_GET(verbose);
GMOCK_FLAG_SET(verbose, "info");
const std::string test_name = "NamedMock";
Mock::SetMockName(&raw_foo, test_name);
CaptureStdout();
raw_foo.DoThis();
ASSERT_THAT(GetCapturedStdout(),
HasSubstr("Uninteresting mock function call"));
EXPECT_THAT(GetCapturedStdout(), HasSubstr(test_name));
GMOCK_FLAG_SET(verbose, saved_flag);
}
TEST(RawMockTest, IsNaggy_IsNice_IsStrict) {
MockFoo raw_foo;
EXPECT_TRUE(Mock::IsNaggy(&raw_foo));

View File

@ -945,13 +945,13 @@ template <typename T>
class [[nodiscard]] UniversalPrinter<std::optional<T>> {
public:
static void Print(const std::optional<T>& value, ::std::ostream* os) {
*os << '(';
if (!value) {
*os << "nullopt";
UniversalPrint(std::nullopt, os);
} else {
*os << '(';
UniversalPrint(*value, os);
*os << ')';
}
*os << ')';
}
};
@ -961,27 +961,38 @@ class [[nodiscard]] UniversalPrinter<std::nullopt_t> {
static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; }
};
struct UniversalPrinterVisitor {
template <typename T>
void operator()(const T& arg) const {
*os << "'" << GetTypeName<T>() << "(index = " << index << ")' with value ";
UniversalPrint(arg, os);
}
::std::ostream* os;
std::size_t index;
};
// Printer for std::variant
template <typename... T>
class [[nodiscard]] UniversalPrinter<std::variant<T...>> {
public:
static void Print(const std::variant<T...>& value, ::std::ostream* os) {
*os << '(';
std::visit(Visitor{os, value.index()}, value);
*os << ')';
}
private:
struct Visitor {
template <typename U>
void operator()(const U& u) const {
*os << "'" << GetTypeName<U>() << "(index = " << index
<< ")' with value ";
UniversalPrint(u, os);
if (value.valueless_by_exception()) {
*os << "(valueless)";
} else {
*os << '(';
std::visit(UniversalPrinterVisitor{os, value.index()}, value);
*os << ')';
}
::std::ostream* os;
std::size_t index;
};
}
};
// Printer for std::monostate
template <>
class [[nodiscard]] UniversalPrinter<std::monostate> {
public:
static void Print(std::monostate, ::std::ostream* os) {
*os << "(monostate)";
}
};
// UniversalPrintArray(begin, len, os) prints an array of 'len'

View File

@ -587,7 +587,7 @@ class GTEST_API_ UnitTestImpl {
// total_test_suite_count() - 1. If i is not in that range, returns NULL.
const TestSuite* GetTestSuite(int i) const {
const int index = GetElementOr(test_suite_indices_, i, -1);
return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)];
return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)];
}
// Legacy API is deprecated but still available

View File

@ -2030,6 +2030,26 @@ TEST(PrintOneofTest, Basic) {
PrintToString(Type(NonPrintable{})));
}
TEST(PrintVariantTest, Monostate) {
EXPECT_EQ("(monostate)", PrintToString(std::monostate()));
#if GTEST_HAS_EXCEPTIONS
struct ThrowOnMove {
ThrowOnMove() = default;
ThrowOnMove(ThrowOnMove&& other) { *this = std::move(other); }
ThrowOnMove& operator=(ThrowOnMove&&) {
(void)std::vector<bool>().at(0);
return *this;
}
};
std::variant<std::monostate, ThrowOnMove> v = std::monostate();
EXPECT_EQ("('std::monostate(index = 0)' with value (monostate))",
PrintToString(v));
EXPECT_THROW(v = ThrowOnMove(), std::out_of_range);
EXPECT_EQ("(valueless)", PrintToString(v));
#endif
}
#if GTEST_INTERNAL_HAS_COMPARE_LIB
TEST(PrintOrderingTest, Basic) {
EXPECT_EQ("(less)", PrintToString(std::strong_ordering::less));