/home/arjun/llvm-project/llvm/utils/unittest/googletest/src/gtest-printers.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2007, Google Inc. |
2 | | // All rights reserved. |
3 | | // |
4 | | // Redistribution and use in source and binary forms, with or without |
5 | | // modification, are permitted provided that the following conditions are |
6 | | // met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright |
9 | | // notice, this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above |
11 | | // copyright notice, this list of conditions and the following disclaimer |
12 | | // in the documentation and/or other materials provided with the |
13 | | // distribution. |
14 | | // * Neither the name of Google Inc. nor the names of its |
15 | | // contributors may be used to endorse or promote products derived from |
16 | | // this software without specific prior written permission. |
17 | | // |
18 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | | // |
30 | | // Author: wan@google.com (Zhanyong Wan) |
31 | | |
32 | | // Google Test - The Google C++ Testing Framework |
33 | | // |
34 | | // This file implements a universal value printer that can print a |
35 | | // value of any type T: |
36 | | // |
37 | | // void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr); |
38 | | // |
39 | | // It uses the << operator when possible, and prints the bytes in the |
40 | | // object otherwise. A user can override its behavior for a class |
41 | | // type Foo by defining either operator<<(::std::ostream&, const Foo&) |
42 | | // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that |
43 | | // defines Foo. |
44 | | |
45 | | #include "gtest/gtest-printers.h" |
46 | | #include <ctype.h> |
47 | | #include <stdio.h> |
48 | | #include <cwchar> |
49 | | #include <ostream> // NOLINT |
50 | | #include <string> |
51 | | #include "gtest/internal/gtest-port.h" |
52 | | |
53 | | namespace testing { |
54 | | |
55 | | namespace { |
56 | | |
57 | | using ::std::ostream; |
58 | | |
59 | | // Prints a segment of bytes in the given object. |
60 | | GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ |
61 | | GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ |
62 | | GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ |
63 | | void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, |
64 | 0 | size_t count, ostream* os) { |
65 | 0 | char text[5] = ""; |
66 | 0 | for (size_t i = 0; i != count; i++) { |
67 | 0 | const size_t j = start + i; |
68 | 0 | if (i != 0) { |
69 | 0 | // Organizes the bytes into groups of 2 for easy parsing by |
70 | 0 | // human. |
71 | 0 | if ((j % 2) == 0) |
72 | 0 | *os << ' '; |
73 | 0 | else |
74 | 0 | *os << '-'; |
75 | 0 | } |
76 | 0 | GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); |
77 | 0 | *os << text; |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | // Prints the bytes in the given value to the given ostream. |
82 | | void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, |
83 | 0 | ostream* os) { |
84 | 0 | // Tells the user how big the object is. |
85 | 0 | *os << count << "-byte object <"; |
86 | 0 |
|
87 | 0 | const size_t kThreshold = 132; |
88 | 0 | const size_t kChunkSize = 64; |
89 | 0 | // If the object size is bigger than kThreshold, we'll have to omit |
90 | 0 | // some details by printing only the first and the last kChunkSize |
91 | 0 | // bytes. |
92 | 0 | // TODO(wan): let the user control the threshold using a flag. |
93 | 0 | if (count < kThreshold) { |
94 | 0 | PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); |
95 | 0 | } else { |
96 | 0 | PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); |
97 | 0 | *os << " ... "; |
98 | 0 | // Rounds up to 2-byte boundary. |
99 | 0 | const size_t resume_pos = (count - kChunkSize + 1)/2*2; |
100 | 0 | PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); |
101 | 0 | } |
102 | 0 | *os << ">"; |
103 | 0 | } |
104 | | |
105 | | } // namespace |
106 | | |
107 | | namespace internal2 { |
108 | | |
109 | | // Delegates to PrintBytesInObjectToImpl() to print the bytes in the |
110 | | // given object. The delegation simplifies the implementation, which |
111 | | // uses the << operator and thus is easier done outside of the |
112 | | // ::testing::internal namespace, which contains a << operator that |
113 | | // sometimes conflicts with the one in STL. |
114 | | void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, |
115 | 0 | ostream* os) { |
116 | 0 | PrintBytesInObjectToImpl(obj_bytes, count, os); |
117 | 0 | } |
118 | | |
119 | | } // namespace internal2 |
120 | | |
121 | | namespace internal { |
122 | | |
123 | | // Depending on the value of a char (or wchar_t), we print it in one |
124 | | // of three formats: |
125 | | // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), |
126 | | // - as a hexidecimal escape sequence (e.g. '\x7F'), or |
127 | | // - as a special escape sequence (e.g. '\r', '\n'). |
128 | | enum CharFormat { |
129 | | kAsIs, |
130 | | kHexEscape, |
131 | | kSpecialEscape |
132 | | }; |
133 | | |
134 | | // Returns true if c is a printable ASCII character. We test the |
135 | | // value of c directly instead of calling isprint(), which is buggy on |
136 | | // Windows Mobile. |
137 | 0 | inline bool IsPrintableAscii(wchar_t c) { |
138 | 0 | return 0x20 <= c && c <= 0x7E; |
139 | 0 | } |
140 | | |
141 | | // Prints a wide or narrow char c as a character literal without the |
142 | | // quotes, escaping it when necessary; returns how c was formatted. |
143 | | // The template argument UnsignedChar is the unsigned version of Char, |
144 | | // which is the type of c. |
145 | | template <typename UnsignedChar, typename Char> |
146 | 0 | static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { |
147 | 0 | switch (static_cast<wchar_t>(c)) { |
148 | 0 | case L'\0': |
149 | 0 | *os << "\\0"; |
150 | 0 | break; |
151 | 0 | case L'\'': |
152 | 0 | *os << "\\'"; |
153 | 0 | break; |
154 | 0 | case L'\\': |
155 | 0 | *os << "\\\\"; |
156 | 0 | break; |
157 | 0 | case L'\a': |
158 | 0 | *os << "\\a"; |
159 | 0 | break; |
160 | 0 | case L'\b': |
161 | 0 | *os << "\\b"; |
162 | 0 | break; |
163 | 0 | case L'\f': |
164 | 0 | *os << "\\f"; |
165 | 0 | break; |
166 | 0 | case L'\n': |
167 | 0 | *os << "\\n"; |
168 | 0 | break; |
169 | 0 | case L'\r': |
170 | 0 | *os << "\\r"; |
171 | 0 | break; |
172 | 0 | case L'\t': |
173 | 0 | *os << "\\t"; |
174 | 0 | break; |
175 | 0 | case L'\v': |
176 | 0 | *os << "\\v"; |
177 | 0 | break; |
178 | 0 | default: |
179 | 0 | if (IsPrintableAscii(c)) { |
180 | 0 | *os << static_cast<char>(c); |
181 | 0 | return kAsIs; |
182 | 0 | } else { |
183 | 0 | *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c)); |
184 | 0 | return kHexEscape; |
185 | 0 | } |
186 | 0 | } |
187 | 0 | return kSpecialEscape; |
188 | 0 | } Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL20PrintAsCharLiteralToIhhEENS0_10CharFormatET0_PSo Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL20PrintAsCharLiteralToIhaEENS0_10CharFormatET0_PSo Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL20PrintAsCharLiteralToIwwEENS0_10CharFormatET0_PSo |
189 | | |
190 | | // Prints a wchar_t c as if it's part of a string literal, escaping it when |
191 | | // necessary; returns how c was formatted. |
192 | | static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { |
193 | | switch (c) { |
194 | | case L'\'': |
195 | | *os << "'"; |
196 | | return kAsIs; |
197 | | case L'"': |
198 | | *os << "\\\""; |
199 | | return kSpecialEscape; |
200 | | default: |
201 | | return PrintAsCharLiteralTo<wchar_t>(c, os); |
202 | | } |
203 | | } |
204 | | |
205 | | // Prints a char c as if it's part of a string literal, escaping it when |
206 | | // necessary; returns how c was formatted. |
207 | 0 | static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { |
208 | 0 | return PrintAsStringLiteralTo( |
209 | 0 | static_cast<wchar_t>(static_cast<unsigned char>(c)), os); |
210 | 0 | } |
211 | | |
212 | | // Prints a wide or narrow character c and its code. '\0' is printed |
213 | | // as "'\\0'", other unprintable characters are also properly escaped |
214 | | // using the standard C++ escape sequence. The template argument |
215 | | // UnsignedChar is the unsigned version of Char, which is the type of c. |
216 | | template <typename UnsignedChar, typename Char> |
217 | 0 | void PrintCharAndCodeTo(Char c, ostream* os) { |
218 | 0 | // First, print c as a literal in the most readable form we can find. |
219 | 0 | *os << ((sizeof(c) > 1) ? "L'" : "'"); |
220 | 0 | const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os); |
221 | 0 | *os << "'"; |
222 | 0 |
|
223 | 0 | // To aid user debugging, we also print c's code in decimal, unless |
224 | 0 | // it's 0 (in which case c was printed as '\\0', making the code |
225 | 0 | // obvious). |
226 | 0 | if (c == 0) |
227 | 0 | return; |
228 | 0 | *os << " (" << static_cast<int>(c); |
229 | 0 |
|
230 | 0 | // For more convenience, we print c's code again in hexidecimal, |
231 | 0 | // unless c was already printed in the form '\x##' or the code is in |
232 | 0 | // [1, 9]. |
233 | 0 | if (format == kHexEscape || (1 <= c && c <= 9)) { |
234 | 0 | // Do nothing. |
235 | 0 | } else { |
236 | 0 | *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c)); |
237 | 0 | } |
238 | 0 | *os << ")"; |
239 | 0 | } Unexecuted instantiation: _ZN7testing8internal18PrintCharAndCodeToIhhEEvT0_PSo Unexecuted instantiation: _ZN7testing8internal18PrintCharAndCodeToIhaEEvT0_PSo Unexecuted instantiation: _ZN7testing8internal18PrintCharAndCodeToIwwEEvT0_PSo |
240 | | |
241 | 0 | void PrintTo(unsigned char c, ::std::ostream* os) { |
242 | 0 | PrintCharAndCodeTo<unsigned char>(c, os); |
243 | 0 | } |
244 | 0 | void PrintTo(signed char c, ::std::ostream* os) { |
245 | 0 | PrintCharAndCodeTo<unsigned char>(c, os); |
246 | 0 | } |
247 | | |
248 | | // Prints a wchar_t as a symbol if it is printable or as its internal |
249 | | // code otherwise and also as its code. L'\0' is printed as "L'\\0'". |
250 | 0 | void PrintTo(wchar_t wc, ostream* os) { |
251 | 0 | PrintCharAndCodeTo<wchar_t>(wc, os); |
252 | 0 | } |
253 | | |
254 | | // Prints the given array of characters to the ostream. CharType must be either |
255 | | // char or wchar_t. |
256 | | // The array starts at begin, the length is len, it may include '\0' characters |
257 | | // and may not be NUL-terminated. |
258 | | template <typename CharType> |
259 | | GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ |
260 | | GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ |
261 | | GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ |
262 | | static void PrintCharsAsStringTo( |
263 | 0 | const CharType* begin, size_t len, ostream* os) { |
264 | 0 | const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; |
265 | 0 | *os << kQuoteBegin; |
266 | 0 | bool is_previous_hex = false; |
267 | 0 | for (size_t index = 0; index < len; ++index) { |
268 | 0 | const CharType cur = begin[index]; |
269 | 0 | if (is_previous_hex && IsXDigit(cur)) { |
270 | 0 | // Previous character is of '\x..' form and this character can be |
271 | 0 | // interpreted as another hexadecimal digit in its number. Break string to |
272 | 0 | // disambiguate. |
273 | 0 | *os << "\" " << kQuoteBegin; |
274 | 0 | } |
275 | 0 | is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; |
276 | 0 | } |
277 | 0 | *os << "\""; |
278 | 0 | } Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL20PrintCharsAsStringToIcEEvPKT_mPSo Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL20PrintCharsAsStringToIwEEvPKT_mPSo |
279 | | |
280 | | // Prints a (const) char/wchar_t array of 'len' elements, starting at address |
281 | | // 'begin'. CharType must be either char or wchar_t. |
282 | | template <typename CharType> |
283 | | GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ |
284 | | GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ |
285 | | GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ |
286 | | static void UniversalPrintCharArray( |
287 | 0 | const CharType* begin, size_t len, ostream* os) { |
288 | 0 | // The code |
289 | 0 | // const char kFoo[] = "foo"; |
290 | 0 | // generates an array of 4, not 3, elements, with the last one being '\0'. |
291 | 0 | // |
292 | 0 | // Therefore when printing a char array, we don't print the last element if |
293 | 0 | // it's '\0', such that the output matches the string literal as it's |
294 | 0 | // written in the source code. |
295 | 0 | if (len > 0 && begin[len - 1] == '\0') { |
296 | 0 | PrintCharsAsStringTo(begin, len - 1, os); |
297 | 0 | return; |
298 | 0 | } |
299 | 0 | |
300 | 0 | // If, however, the last element in the array is not '\0', e.g. |
301 | 0 | // const char kFoo[] = { 'f', 'o', 'o' }; |
302 | 0 | // we must print the entire array. We also print a message to indicate |
303 | 0 | // that the array is not NUL-terminated. |
304 | 0 | PrintCharsAsStringTo(begin, len, os); |
305 | 0 | *os << " (no terminating NUL)"; |
306 | 0 | } Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL23UniversalPrintCharArrayIcEEvPKT_mPSo Unexecuted instantiation: gtest-all.cc:_ZN7testing8internalL23UniversalPrintCharArrayIwEEvPKT_mPSo |
307 | | |
308 | | // Prints a (const) char array of 'len' elements, starting at address 'begin'. |
309 | 0 | void UniversalPrintArray(const char* begin, size_t len, ostream* os) { |
310 | 0 | UniversalPrintCharArray(begin, len, os); |
311 | 0 | } |
312 | | |
313 | | // Prints a (const) wchar_t array of 'len' elements, starting at address |
314 | | // 'begin'. |
315 | 0 | void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { |
316 | 0 | UniversalPrintCharArray(begin, len, os); |
317 | 0 | } |
318 | | |
319 | | // Prints the given C string to the ostream. |
320 | 0 | void PrintTo(const char* s, ostream* os) { |
321 | 0 | if (s == NULL) { |
322 | 0 | *os << "NULL"; |
323 | 0 | } else { |
324 | 0 | *os << ImplicitCast_<const void*>(s) << " pointing to "; |
325 | 0 | PrintCharsAsStringTo(s, strlen(s), os); |
326 | 0 | } |
327 | 0 | } |
328 | | |
329 | | // MSVC compiler can be configured to define whar_t as a typedef |
330 | | // of unsigned short. Defining an overload for const wchar_t* in that case |
331 | | // would cause pointers to unsigned shorts be printed as wide strings, |
332 | | // possibly accessing more memory than intended and causing invalid |
333 | | // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when |
334 | | // wchar_t is implemented as a native type. |
335 | | #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) |
336 | | // Prints the given wide C string to the ostream. |
337 | 0 | void PrintTo(const wchar_t* s, ostream* os) { |
338 | 0 | if (s == NULL) { |
339 | 0 | *os << "NULL"; |
340 | 0 | } else { |
341 | 0 | *os << ImplicitCast_<const void*>(s) << " pointing to "; |
342 | 0 | PrintCharsAsStringTo(s, std::wcslen(s), os); |
343 | 0 | } |
344 | 0 | } |
345 | | #endif // wchar_t is native |
346 | | |
347 | | // Prints a ::string object. |
348 | | #if GTEST_HAS_GLOBAL_STRING |
349 | | void PrintStringTo(const ::string& s, ostream* os) { |
350 | | PrintCharsAsStringTo(s.data(), s.size(), os); |
351 | | } |
352 | | #endif // GTEST_HAS_GLOBAL_STRING |
353 | | |
354 | 0 | void PrintStringTo(const ::std::string& s, ostream* os) { |
355 | 0 | PrintCharsAsStringTo(s.data(), s.size(), os); |
356 | 0 | } |
357 | | |
358 | | // Prints a ::wstring object. |
359 | | #if GTEST_HAS_GLOBAL_WSTRING |
360 | | void PrintWideStringTo(const ::wstring& s, ostream* os) { |
361 | | PrintCharsAsStringTo(s.data(), s.size(), os); |
362 | | } |
363 | | #endif // GTEST_HAS_GLOBAL_WSTRING |
364 | | |
365 | | #if GTEST_HAS_STD_WSTRING |
366 | 0 | void PrintWideStringTo(const ::std::wstring& s, ostream* os) { |
367 | 0 | PrintCharsAsStringTo(s.data(), s.size(), os); |
368 | 0 | } |
369 | | #endif // GTEST_HAS_STD_WSTRING |
370 | | |
371 | | } // namespace internal |
372 | | |
373 | | } // namespace testing |