Skip to content

Commit 6b625a7

Browse files
author
zhanyong.wan
committed
Improves gtest's failure messages. In particulars, char pointers and
char arrays are not escapped properly. git-svn-id: http://googletest.googlecode.com/svn/trunk@616 861a406c-534a-0410-8894-cb66d6ee9925
1 parent aa3c420 commit 6b625a7

12 files changed

+550
-197
lines changed

include/gtest/gtest-printers.h

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -630,9 +630,12 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
630630
}
631631
}
632632
// This overload prints a (const) char array compactly.
633-
GTEST_API_ void UniversalPrintArray(const char* begin,
634-
size_t len,
635-
::std::ostream* os);
633+
GTEST_API_ void UniversalPrintArray(
634+
const char* begin, size_t len, ::std::ostream* os);
635+
636+
// This overload prints a (const) wchar_t array compactly.
637+
GTEST_API_ void UniversalPrintArray(
638+
const wchar_t* begin, size_t len, ::std::ostream* os);
636639

637640
// Implements printing an array type T[N].
638641
template <typename T, size_t N>
@@ -673,19 +676,72 @@ class UniversalPrinter<T&> {
673676
// Prints a value tersely: for a reference type, the referenced value
674677
// (but not the address) is printed; for a (const) char pointer, the
675678
// NUL-terminated string (but not the pointer) is printed.
679+
676680
template <typename T>
677-
void UniversalTersePrint(const T& value, ::std::ostream* os) {
678-
UniversalPrint(value, os);
679-
}
680-
inline void UniversalTersePrint(const char* str, ::std::ostream* os) {
681-
if (str == NULL) {
682-
*os << "NULL";
683-
} else {
684-
UniversalPrint(string(str), os);
681+
class UniversalTersePrinter {
682+
public:
683+
static void Print(const T& value, ::std::ostream* os) {
684+
UniversalPrint(value, os);
685685
}
686-
}
687-
inline void UniversalTersePrint(char* str, ::std::ostream* os) {
688-
UniversalTersePrint(static_cast<const char*>(str), os);
686+
};
687+
template <typename T>
688+
class UniversalTersePrinter<T&> {
689+
public:
690+
static void Print(const T& value, ::std::ostream* os) {
691+
UniversalPrint(value, os);
692+
}
693+
};
694+
template <typename T, size_t N>
695+
class UniversalTersePrinter<T[N]> {
696+
public:
697+
static void Print(const T (&value)[N], ::std::ostream* os) {
698+
UniversalPrinter<T[N]>::Print(value, os);
699+
}
700+
};
701+
template <>
702+
class UniversalTersePrinter<const char*> {
703+
public:
704+
static void Print(const char* str, ::std::ostream* os) {
705+
if (str == NULL) {
706+
*os << "NULL";
707+
} else {
708+
UniversalPrint(string(str), os);
709+
}
710+
}
711+
};
712+
template <>
713+
class UniversalTersePrinter<char*> {
714+
public:
715+
static void Print(char* str, ::std::ostream* os) {
716+
UniversalTersePrinter<const char*>::Print(str, os);
717+
}
718+
};
719+
720+
#if GTEST_HAS_STD_WSTRING
721+
template <>
722+
class UniversalTersePrinter<const wchar_t*> {
723+
public:
724+
static void Print(const wchar_t* str, ::std::ostream* os) {
725+
if (str == NULL) {
726+
*os << "NULL";
727+
} else {
728+
UniversalPrint(::std::wstring(str), os);
729+
}
730+
}
731+
};
732+
#endif
733+
734+
template <>
735+
class UniversalTersePrinter<wchar_t*> {
736+
public:
737+
static void Print(wchar_t* str, ::std::ostream* os) {
738+
UniversalTersePrinter<const wchar_t*>::Print(str, os);
739+
}
740+
};
741+
742+
template <typename T>
743+
void UniversalTersePrint(const T& value, ::std::ostream* os) {
744+
UniversalTersePrinter<T>::Print(value, os);
689745
}
690746

691747
// Prints a value using the type inferred by the compiler. The
@@ -790,7 +846,7 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
790846
template <typename T>
791847
::std::string PrintToString(const T& value) {
792848
::std::stringstream ss;
793-
internal::UniversalTersePrint(value, &ss);
849+
internal::UniversalTersePrinter<T>::Print(value, &ss);
794850
return ss.str();
795851
}
796852

include/gtest/gtest.h

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,24 +1291,101 @@ GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
12911291

12921292
namespace internal {
12931293

1294+
// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
1295+
// value of type ToPrint that is an operand of a comparison assertion
1296+
// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
1297+
// the comparison, and is used to help determine the best way to
1298+
// format the value. In particular, when the value is a C string
1299+
// (char pointer) and the other operand is an STL string object, we
1300+
// want to format the C string as a string, since we know it is
1301+
// compared by value with the string object. If the value is a char
1302+
// pointer but the other operand is not an STL string object, we don't
1303+
// know whether the pointer is supposed to point to a NUL-terminated
1304+
// string, and thus want to print it as a pointer to be safe.
1305+
//
1306+
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
1307+
1308+
// The default case.
1309+
template <typename ToPrint, typename OtherOperand>
1310+
class FormatForComparison {
1311+
public:
1312+
static ::std::string Format(const ToPrint& value) {
1313+
return ::testing::PrintToString(value);
1314+
}
1315+
};
1316+
1317+
// Array.
1318+
template <typename ToPrint, size_t N, typename OtherOperand>
1319+
class FormatForComparison<ToPrint[N], OtherOperand> {
1320+
public:
1321+
static ::std::string Format(const ToPrint* value) {
1322+
return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
1323+
}
1324+
};
1325+
1326+
// By default, print C string as pointers to be safe, as we don't know
1327+
// whether they actually point to a NUL-terminated string.
1328+
1329+
#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
1330+
template <typename OtherOperand> \
1331+
class FormatForComparison<CharType*, OtherOperand> { \
1332+
public: \
1333+
static ::std::string Format(CharType* value) { \
1334+
return ::testing::PrintToString(static_cast<const void*>(value)); \
1335+
} \
1336+
}
1337+
1338+
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
1339+
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
1340+
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
1341+
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
1342+
1343+
#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
1344+
1345+
// If a C string is compared with an STL string object, we know it's meant
1346+
// to point to a NUL-terminated string, and thus can print it as a string.
1347+
1348+
#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
1349+
template <> \
1350+
class FormatForComparison<CharType*, OtherStringType> { \
1351+
public: \
1352+
static ::std::string Format(CharType* value) { \
1353+
return ::testing::PrintToString(value); \
1354+
} \
1355+
}
1356+
1357+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
1358+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
1359+
1360+
#if GTEST_HAS_GLOBAL_STRING
1361+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
1362+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
1363+
#endif
1364+
1365+
#if GTEST_HAS_GLOBAL_WSTRING
1366+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
1367+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
1368+
#endif
1369+
1370+
#if GTEST_HAS_STD_WSTRING
1371+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
1372+
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
1373+
#endif
1374+
1375+
#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
1376+
12941377
// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
12951378
// operand to be used in a failure message. The type (but not value)
12961379
// of the other operand may affect the format. This allows us to
12971380
// print a char* as a raw pointer when it is compared against another
1298-
// char*, and print it as a C string when it is compared against an
1299-
// std::string object, for example.
1300-
//
1301-
// The default implementation ignores the type of the other operand.
1302-
// Some specialized versions are used to handle formatting wide or
1303-
// narrow C strings.
1381+
// char* or void*, and print it as a C string when it is compared
1382+
// against an std::string object, for example.
13041383
//
13051384
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
13061385
template <typename T1, typename T2>
13071386
String FormatForComparisonFailureMessage(const T1& value,
13081387
const T2& /* other_operand */) {
1309-
// C++Builder compiles this incorrectly if the namespace isn't explicitly
1310-
// given.
1311-
return ::testing::PrintToString(value);
1388+
return FormatForComparison<T1, T2>::Format(value);
13121389
}
13131390

13141391
// The helper function for {ASSERT|EXPECT}_EQ.
@@ -1320,7 +1397,7 @@ AssertionResult CmpHelperEQ(const char* expected_expression,
13201397
#ifdef _MSC_VER
13211398
# pragma warning(push) // Saves the current warning state.
13221399
# pragma warning(disable:4389) // Temporarily disables warning on
1323-
// signed/unsigned mismatch.
1400+
// signed/unsigned mismatch.
13241401
#endif
13251402

13261403
if (expected == actual) {

include/gtest/internal/gtest-internal.h

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -195,67 +195,6 @@ class GTEST_API_ ScopedTrace {
195195
template <typename T>
196196
String StreamableToString(const T& streamable);
197197

198-
// The Symbian compiler has a bug that prevents it from selecting the
199-
// correct overload of FormatForComparisonFailureMessage (see below)
200-
// unless we pass the first argument by reference. If we do that,
201-
// however, Visual Age C++ 10.1 generates a compiler error. Therefore
202-
// we only apply the work-around for Symbian.
203-
#if defined(__SYMBIAN32__)
204-
# define GTEST_CREF_WORKAROUND_ const&
205-
#else
206-
# define GTEST_CREF_WORKAROUND_
207-
#endif
208-
209-
// When this operand is a const char* or char*, if the other operand
210-
// is a ::std::string or ::string, we print this operand as a C string
211-
// rather than a pointer (we do the same for wide strings); otherwise
212-
// we print it as a pointer to be safe.
213-
214-
// This internal macro is used to avoid duplicated code.
215-
#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
216-
inline String FormatForComparisonFailureMessage(\
217-
operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
218-
const operand2_type& /*operand2*/) {\
219-
return operand1_printer(str);\
220-
}\
221-
inline String FormatForComparisonFailureMessage(\
222-
const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
223-
const operand2_type& /*operand2*/) {\
224-
return operand1_printer(str);\
225-
}
226-
227-
GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
228-
#if GTEST_HAS_STD_WSTRING
229-
GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
230-
#endif // GTEST_HAS_STD_WSTRING
231-
232-
#if GTEST_HAS_GLOBAL_STRING
233-
GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
234-
#endif // GTEST_HAS_GLOBAL_STRING
235-
#if GTEST_HAS_GLOBAL_WSTRING
236-
GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
237-
#endif // GTEST_HAS_GLOBAL_WSTRING
238-
239-
#undef GTEST_FORMAT_IMPL_
240-
241-
// The next four overloads handle the case where the operand being
242-
// printed is a char/wchar_t pointer and the other operand is not a
243-
// string/wstring object. In such cases, we just print the operand as
244-
// a pointer to be safe.
245-
#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \
246-
template <typename T> \
247-
String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \
248-
const T&) { \
249-
return PrintToString(static_cast<const void*>(p)); \
250-
}
251-
252-
GTEST_FORMAT_CHAR_PTR_IMPL_(char)
253-
GTEST_FORMAT_CHAR_PTR_IMPL_(const char)
254-
GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t)
255-
GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t)
256-
257-
#undef GTEST_FORMAT_CHAR_PTR_IMPL_
258-
259198
// Constructs and returns the message for an equality assertion
260199
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
261200
//

include/gtest/internal/gtest-port.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,10 @@ inline bool IsUpper(char ch) {
15851585
inline bool IsXDigit(char ch) {
15861586
return isxdigit(static_cast<unsigned char>(ch)) != 0;
15871587
}
1588+
inline bool IsXDigit(wchar_t ch) {
1589+
const unsigned char low_byte = static_cast<unsigned char>(ch);
1590+
return ch == low_byte && isxdigit(low_byte) != 0;
1591+
}
15881592

15891593
inline char ToLower(char ch) {
15901594
return static_cast<char>(tolower(static_cast<unsigned char>(ch)));

include/gtest/internal/gtest-string.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,6 @@ class GTEST_API_ String {
8282
public:
8383
// Static utility methods
8484

85-
// Returns the input enclosed in double quotes if it's not NULL;
86-
// otherwise returns "(null)". For example, "\"Hello\"" is returned
87-
// for input "Hello".
88-
//
89-
// This is useful for printing a C string in the syntax of a literal.
90-
//
91-
// Known issue: escape sequences are not handled yet.
92-
static String ShowCStringQuoted(const char* c_str);
93-
9485
// Clones a 0-terminated C string, allocating memory using new. The
9586
// caller is responsible for deleting the return value using
9687
// delete[]. Returns the cloned string, or NULL if the input is
@@ -139,10 +130,6 @@ class GTEST_API_ String {
139130
// returned.
140131
static String ShowWideCString(const wchar_t* wide_c_str);
141132

142-
// Similar to ShowWideCString(), except that this function encloses
143-
// the converted string in double quotes.
144-
static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
145-
146133
// Compares two wide C strings. Returns true iff they have the same
147134
// content.
148135
//

0 commit comments

Comments
 (0)