Make string matchers work with std::wstring_view
This reapplies the change that was rolled back, with the change that it removes the convertibility requirement to string_view, because that excluded some desirable explicit conversions (like absl::Cord). Note that this is now the same criterion previously used by testing::internal::StringLike. Fixes: #4912 PiperOrigin-RevId: 959205696 Change-Id: I002cb1224f5a2701bdf8e68ea4d91776b9c38593
This commit is contained in:
committed by
Copybara-Service
parent
5f9ad7d401
commit
488c47cc68
@@ -4982,116 +4982,68 @@ internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf(
|
||||
|
||||
// Matches a string equal to str.
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<std::string>> StrEq(
|
||||
const internal::StringLike<T>& str) {
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<internal::StringType<T>>> StrEq(
|
||||
const T& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::string>(std::string(str), true, true));
|
||||
internal::StrEqualityMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(str), true, true));
|
||||
}
|
||||
|
||||
// Matches a string not equal to str.
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<std::string>> StrNe(
|
||||
const internal::StringLike<T>& str) {
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<internal::StringType<T>>> StrNe(
|
||||
const T& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::string>(std::string(str), false, true));
|
||||
internal::StrEqualityMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(str), false, true));
|
||||
}
|
||||
|
||||
// Matches a string equal to str, ignoring case.
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<std::string>> StrCaseEq(
|
||||
const internal::StringLike<T>& str) {
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<internal::StringType<T>>>
|
||||
StrCaseEq(const T& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::string>(std::string(str), true, false));
|
||||
internal::StrEqualityMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(str), true, false));
|
||||
}
|
||||
|
||||
// Matches a string not equal to str, ignoring case.
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<std::string>> StrCaseNe(
|
||||
const internal::StringLike<T>& str) {
|
||||
return MakePolymorphicMatcher(internal::StrEqualityMatcher<std::string>(
|
||||
std::string(str), false, false));
|
||||
PolymorphicMatcher<internal::StrEqualityMatcher<internal::StringType<T>>>
|
||||
StrCaseNe(const T& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(str), false, false));
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any string, std::string, or C string
|
||||
// that contains the given substring.
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::HasSubstrMatcher<std::string>> HasSubstr(
|
||||
const internal::StringLike<T>& substring) {
|
||||
PolymorphicMatcher<internal::HasSubstrMatcher<internal::StringType<T>>>
|
||||
HasSubstr(const T& substring) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::HasSubstrMatcher<std::string>(std::string(substring)));
|
||||
internal::HasSubstrMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(substring)));
|
||||
}
|
||||
|
||||
// Matches a string that starts with 'prefix' (case-sensitive).
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::StartsWithMatcher<std::string>> StartsWith(
|
||||
const internal::StringLike<T>& prefix) {
|
||||
PolymorphicMatcher<internal::StartsWithMatcher<internal::StringType<T>>>
|
||||
StartsWith(const T& prefix) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StartsWithMatcher<std::string>(std::string(prefix)));
|
||||
internal::StartsWithMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(prefix)));
|
||||
}
|
||||
|
||||
// Matches a string that ends with 'suffix' (case-sensitive).
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::EndsWithMatcher<std::string>> EndsWith(
|
||||
const internal::StringLike<T>& suffix) {
|
||||
PolymorphicMatcher<internal::EndsWithMatcher<internal::StringType<T>>> EndsWith(
|
||||
const T& suffix) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::EndsWithMatcher<std::string>(std::string(suffix)));
|
||||
internal::EndsWithMatcher<internal::StringType<T>>(
|
||||
internal::StringType<T>(suffix)));
|
||||
}
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// Wide string matchers.
|
||||
|
||||
// Matches a string equal to str.
|
||||
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrEq(
|
||||
const std::wstring& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::wstring>(str, true, true));
|
||||
}
|
||||
|
||||
// Matches a string not equal to str.
|
||||
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrNe(
|
||||
const std::wstring& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::wstring>(str, false, true));
|
||||
}
|
||||
|
||||
// Matches a string equal to str, ignoring case.
|
||||
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrCaseEq(
|
||||
const std::wstring& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::wstring>(str, true, false));
|
||||
}
|
||||
|
||||
// Matches a string not equal to str, ignoring case.
|
||||
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrCaseNe(
|
||||
const std::wstring& str) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StrEqualityMatcher<std::wstring>(str, false, false));
|
||||
}
|
||||
|
||||
// Creates a matcher that matches any ::wstring, std::wstring, or C wide string
|
||||
// that contains the given substring.
|
||||
inline PolymorphicMatcher<internal::HasSubstrMatcher<std::wstring>> HasSubstr(
|
||||
const std::wstring& substring) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::HasSubstrMatcher<std::wstring>(substring));
|
||||
}
|
||||
|
||||
// Matches a string that starts with 'prefix' (case-sensitive).
|
||||
inline PolymorphicMatcher<internal::StartsWithMatcher<std::wstring>> StartsWith(
|
||||
const std::wstring& prefix) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::StartsWithMatcher<std::wstring>(prefix));
|
||||
}
|
||||
|
||||
// Matches a string that ends with 'suffix' (case-sensitive).
|
||||
inline PolymorphicMatcher<internal::EndsWithMatcher<std::wstring>> EndsWith(
|
||||
const std::wstring& suffix) {
|
||||
return MakePolymorphicMatcher(
|
||||
internal::EndsWithMatcher<std::wstring>(suffix));
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
// Creates a polymorphic matcher that matches a 2-tuple where the
|
||||
// first field == the second field.
|
||||
inline internal::Eq2Matcher Eq() { return internal::Eq2Matcher(); }
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
#include "test/gmock-matchers_test.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#if GTEST_INTERNAL_HAS_STRING_VIEW
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
// Silence warning C4244: 'initializing': conversion from 'int' to 'short',
|
||||
// possible loss of data and C4100, unreferenced local parameter
|
||||
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244 4100)
|
||||
@@ -1254,22 +1258,29 @@ TEST(RefTest, ExplainsResult) {
|
||||
// Tests string comparison matchers.
|
||||
|
||||
template <typename T = std::string>
|
||||
std::string FromStringLike(internal::StringLike<T> str) {
|
||||
return std::string(str);
|
||||
internal::StringType<T> ToString(T str) {
|
||||
return internal::StringType<T>(str);
|
||||
}
|
||||
|
||||
TEST(StringLike, TestConversions) {
|
||||
EXPECT_EQ("foo", FromStringLike("foo"));
|
||||
EXPECT_EQ("foo", FromStringLike(std::string("foo")));
|
||||
TEST(StringType, TestConversions) {
|
||||
EXPECT_EQ("foo", ToString("foo"));
|
||||
EXPECT_EQ("foo", ToString(std::string("foo")));
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
EXPECT_EQ(L"foo", ToString(L"foo"));
|
||||
EXPECT_EQ(L"foo", ToString(std::wstring(L"foo")));
|
||||
#endif
|
||||
|
||||
#if GTEST_INTERNAL_HAS_STRING_VIEW
|
||||
EXPECT_EQ("foo", FromStringLike(internal::StringView("foo")));
|
||||
EXPECT_EQ("foo", ToString(internal::StringView("foo")));
|
||||
EXPECT_EQ(L"foo", ToString(std::wstring_view(L"foo")));
|
||||
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
||||
|
||||
// Non deducible types.
|
||||
EXPECT_EQ("", FromStringLike({}));
|
||||
EXPECT_EQ("foo", FromStringLike({'f', 'o', 'o'}));
|
||||
EXPECT_EQ("", ToString({}));
|
||||
EXPECT_EQ("foo", ToString({'f', 'o', 'o'}));
|
||||
const char buf[] = "foo";
|
||||
EXPECT_EQ("foo", FromStringLike({buf, buf + 3}));
|
||||
EXPECT_EQ("foo", ToString({buf, buf + 3}));
|
||||
}
|
||||
|
||||
TEST(StrEqTest, MatchesEqualString) {
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "gtest/gtest-printers.h"
|
||||
@@ -812,9 +813,26 @@ class [[nodiscard]] ImplicitCastEqMatcher {
|
||||
StoredRhs stored_rhs_;
|
||||
};
|
||||
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<std::is_constructible_v<std::string, T>>>
|
||||
using StringLike = T;
|
||||
// Dummy function (never defined) whose return type evaluates to std::string if
|
||||
// the given type is a string-like type that can be converted to std::string,
|
||||
// either directly or through an intermediate std::string_view.
|
||||
template <class T>
|
||||
extern std::enable_if_t<std::is_constructible_v<std::string, T>, std::string>
|
||||
ResolveAsString(const void* /* preferred */);
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// Same as above, but for std::wstring. In cases where both conversions are
|
||||
// possible, this overload takes lower priority.
|
||||
template <class T>
|
||||
extern std::enable_if_t<std::is_constructible_v<std::wstring, T>, std::wstring>
|
||||
ResolveAsString(... /* fallback */);
|
||||
#endif
|
||||
|
||||
// Evaluates to the std::basic_string type that the given string-like type can
|
||||
// be converted to. Prefers std::string over std::wstring if both are possible.
|
||||
// Fails in a SFINAE-friendly way if no conversion was viable.
|
||||
template <typename T>
|
||||
using StringType = decltype(ResolveAsString<T>(nullptr));
|
||||
|
||||
// Implements polymorphic matchers MatchesRegex(regex) and
|
||||
// ContainsRegex(regex), which can be used as a Matcher<T> as long as
|
||||
@@ -877,9 +895,10 @@ inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
|
||||
}
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||
const internal::StringLike<T>& regex) {
|
||||
return MatchesRegex(new internal::RE(std::string(regex)));
|
||||
std::enable_if_t<std::is_constructible_v<internal::RE, internal::StringType<T>>,
|
||||
PolymorphicMatcher<internal::MatchesRegexMatcher>>
|
||||
MatchesRegex(const T& regex) {
|
||||
return MatchesRegex(new internal::RE(internal::StringType<T>(regex)));
|
||||
}
|
||||
|
||||
// Matches a string that contains regular expression 'regex'.
|
||||
@@ -889,9 +908,10 @@ inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
|
||||
}
|
||||
template <typename T = std::string>
|
||||
PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||
const internal::StringLike<T>& regex) {
|
||||
return ContainsRegex(new internal::RE(std::string(regex)));
|
||||
std::enable_if_t<std::is_constructible_v<internal::RE, internal::StringType<T>>,
|
||||
PolymorphicMatcher<internal::MatchesRegexMatcher>>
|
||||
ContainsRegex(const T& regex) {
|
||||
return ContainsRegex(new internal::RE(internal::StringType<T>(regex)));
|
||||
}
|
||||
|
||||
// Creates a polymorphic matcher that matches anything equal to x.
|
||||
|
||||
Reference in New Issue
Block a user