Merge 5062aa991f6257d8fdccb1dfeea676bca7f7c971 into d72f9c8aea6817cdf1ca0ac10887f328de7f3da2

This commit is contained in:
jcui 2026-04-28 23:23:44 -07:00 committed by GitHub
commit c653a846a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 60 additions and 0 deletions

View File

@ -272,6 +272,40 @@ TEST(StringViewMatcherTest, CanBeImplicitlyConstructedFromStringView) {
EXPECT_TRUE(m2.Matches("cats"));
EXPECT_FALSE(m2.Matches("dogs"));
}
// Tests that a StringView object can be implicitly converted to a
// Matcher<std::string> or Matcher<const std::string&>. This is the symmetric
// counterpart of CanBeImplicitlyConstructedFromString above; without these
// constructors, a StringView falls through to a polymorphic Eq matcher that
// stores the view by value and dangles past the constructing call.
TEST(StringMatcherTest, CanBeImplicitlyConstructedFromStringView) {
Matcher<std::string> m1 = internal::StringView("cats");
EXPECT_TRUE(m1.Matches("cats"));
EXPECT_FALSE(m1.Matches("dogs"));
Matcher<const std::string&> m2 = internal::StringView("cats");
EXPECT_TRUE(m2.Matches("cats"));
EXPECT_FALSE(m2.Matches("dogs"));
}
// Tests that the matcher copies the string data and is safe to use after the
// underlying buffer the StringView was constructed from is destroyed.
TEST(StringMatcherTest, StringViewCtorIsLifetimeSafe) {
Matcher<std::string> m1;
Matcher<const std::string&> m2;
{
std::string buffer = "cats";
m1 = internal::StringView(buffer);
m2 = internal::StringView(buffer);
// Mutate buffer and let it go out of scope to ensure the matcher does not
// alias |buffer|'s storage.
buffer = "dogs";
}
EXPECT_TRUE(m1.Matches("cats"));
EXPECT_FALSE(m1.Matches("dogs"));
EXPECT_TRUE(m2.Matches("cats"));
EXPECT_FALSE(m2.Matches("dogs"));
}
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
// Tests that a std::reference_wrapper<std::string> object can be implicitly

View File

@ -520,6 +520,13 @@ Matcher<const std::string&> : public internal::MatcherBase<const std::string&> {
// Allows the user to write "foo" instead of Eq("foo") sometimes.
Matcher(const char* s); // NOLINT
#if GTEST_INTERNAL_HAS_STRING_VIEW
// Allows the user to pass absl::string_views or std::string_views directly.
// Copies into a std::string so the matcher owns its data and does not alias
// a (possibly temporary) buffer in the caller.
Matcher(internal::StringView s); // NOLINT
#endif
};
template <>
@ -544,6 +551,13 @@ Matcher<std::string> : public internal::MatcherBase<std::string> {
// Allows the user to write "foo" instead of Eq("foo") sometimes.
Matcher(const char* s); // NOLINT
#if GTEST_INTERNAL_HAS_STRING_VIEW
// Allows the user to pass absl::string_views or std::string_views directly.
// Copies into a std::string so the matcher owns its data and does not alias
// a (possibly temporary) buffer in the caller.
Matcher(internal::StringView s); // NOLINT
#endif
};
#if GTEST_INTERNAL_HAS_STRING_VIEW

View File

@ -93,6 +93,18 @@ Matcher<internal::StringView>::Matcher(const char* s) {
Matcher<internal::StringView>::Matcher(internal::StringView s) {
*this = Eq(std::string(s));
}
// Constructs a matcher that matches a const std::string& whose value is
// equal to s. Copies into a std::string so the matcher owns its data.
Matcher<const std::string&>::Matcher(internal::StringView s) {
*this = Eq(std::string(s));
}
// Constructs a matcher that matches a std::string whose value is equal to s.
// Copies into a std::string so the matcher owns its data.
Matcher<std::string>::Matcher(internal::StringView s) {
*this = Eq(std::string(s));
}
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
} // namespace testing