Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 |
||
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 |
||
47 | #include |
||
48 | #include |
||
49 | #include |
||
50 | #include "gtest/internal/gtest-port.h" |
||
51 | |||
52 | namespace testing { |
||
53 | |||
54 | namespace { |
||
55 | |||
56 | using ::std::ostream; |
||
57 | |||
58 | // Prints a segment of bytes in the given object. |
||
59 | void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, |
||
60 | size_t count, ostream* os) { |
||
61 | char text[5] = ""; |
||
62 | for (size_t i = 0; i != count; i++) { |
||
63 | const size_t j = start + i; |
||
64 | if (i != 0) { |
||
65 | // Organizes the bytes into groups of 2 for easy parsing by |
||
66 | // human. |
||
67 | if ((j % 2) == 0) |
||
68 | *os << ' '; |
||
69 | else |
||
70 | *os << '-'; |
||
71 | } |
||
72 | GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); |
||
73 | *os << text; |
||
74 | } |
||
75 | } |
||
76 | |||
77 | // Prints the bytes in the given value to the given ostream. |
||
78 | void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, |
||
79 | ostream* os) { |
||
80 | // Tells the user how big the object is. |
||
81 | *os << count << "-byte object <"; |
||
82 | |||
83 | const size_t kThreshold = 132; |
||
84 | const size_t kChunkSize = 64; |
||
85 | // If the object size is bigger than kThreshold, we'll have to omit |
||
86 | // some details by printing only the first and the last kChunkSize |
||
87 | // bytes. |
||
88 | // TODO(wan): let the user control the threshold using a flag. |
||
89 | if (count < kThreshold) { |
||
90 | PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); |
||
91 | } else { |
||
92 | PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); |
||
93 | *os << " ... "; |
||
94 | // Rounds up to 2-byte boundary. |
||
95 | const size_t resume_pos = (count - kChunkSize + 1)/2*2; |
||
96 | PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); |
||
97 | } |
||
98 | *os << ">"; |
||
99 | } |
||
100 | |||
101 | } // namespace |
||
102 | |||
103 | namespace internal2 { |
||
104 | |||
105 | // Delegates to PrintBytesInObjectToImpl() to print the bytes in the |
||
106 | // given object. The delegation simplifies the implementation, which |
||
107 | // uses the << operator and thus is easier done outside of the |
||
108 | // ::testing::internal namespace, which contains a << operator that |
||
109 | // sometimes conflicts with the one in STL. |
||
110 | void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, |
||
111 | ostream* os) { |
||
112 | PrintBytesInObjectToImpl(obj_bytes, count, os); |
||
113 | } |
||
114 | |||
115 | } // namespace internal2 |
||
116 | |||
117 | namespace internal { |
||
118 | |||
119 | // Depending on the value of a char (or wchar_t), we print it in one |
||
120 | // of three formats: |
||
121 | // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), |
||
122 | // - as a hexidecimal escape sequence (e.g. '\x7F'), or |
||
123 | // - as a special escape sequence (e.g. '\r', '\n'). |
||
124 | enum CharFormat { |
||
125 | kAsIs, |
||
126 | kHexEscape, |
||
127 | kSpecialEscape |
||
128 | }; |
||
129 | |||
130 | // Returns true if c is a printable ASCII character. We test the |
||
131 | // value of c directly instead of calling isprint(), which is buggy on |
||
132 | // Windows Mobile. |
||
133 | inline bool IsPrintableAscii(wchar_t c) { |
||
134 | return 0x20 <= c && c <= 0x7E; |
||
135 | } |
||
136 | |||
137 | // Prints a wide or narrow char c as a character literal without the |
||
138 | // quotes, escaping it when necessary; returns how c was formatted. |
||
139 | // The template argument UnsignedChar is the unsigned version of Char, |
||
140 | // which is the type of c. |
||
141 | template |
||
142 | static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { |
||
143 | switch (static_cast |
||
144 | case L'\0': |
||
145 | *os << "\\0"; |
||
146 | break; |
||
147 | case L'\'': |
||
148 | *os << "\\'"; |
||
149 | break; |
||
150 | case L'\\': |
||
151 | *os << "\\\\"; |
||
152 | break; |
||
153 | case L'\a': |
||
154 | *os << "\\a"; |
||
155 | break; |
||
156 | case L'\b': |
||
157 | *os << "\\b"; |
||
158 | break; |
||
159 | case L'\f': |
||
160 | *os << "\\f"; |
||
161 | break; |
||
162 | case L'\n': |
||
163 | *os << "\\n"; |
||
164 | break; |
||
165 | case L'\r': |
||
166 | *os << "\\r"; |
||
167 | break; |
||
168 | case L'\t': |
||
169 | *os << "\\t"; |
||
170 | break; |
||
171 | case L'\v': |
||
172 | *os << "\\v"; |
||
173 | break; |
||
174 | default: |
||
175 | if (IsPrintableAscii(c)) { |
||
176 | *os << static_cast |
||
177 | return kAsIs; |
||
178 | } else { |
||
179 | *os << "\\x" + String::FormatHexInt(static_cast |
||
180 | return kHexEscape; |
||
181 | } |
||
182 | } |
||
183 | return kSpecialEscape; |
||
184 | } |
||
185 | |||
186 | // Prints a wchar_t c as if it's part of a string literal, escaping it when |
||
187 | // necessary; returns how c was formatted. |
||
188 | static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { |
||
189 | switch (c) { |
||
190 | case L'\'': |
||
191 | *os << "'"; |
||
192 | return kAsIs; |
||
193 | case L'"': |
||
194 | *os << "\\\""; |
||
195 | return kSpecialEscape; |
||
196 | default: |
||
197 | return PrintAsCharLiteralTo |
||
198 | } |
||
199 | } |
||
200 | |||
201 | // Prints a char c as if it's part of a string literal, escaping it when |
||
202 | // necessary; returns how c was formatted. |
||
203 | static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { |
||
204 | return PrintAsStringLiteralTo( |
||
205 | static_cast |
||
206 | } |
||
207 | |||
208 | // Prints a wide or narrow character c and its code. '\0' is printed |
||
209 | // as "'\\0'", other unprintable characters are also properly escaped |
||
210 | // using the standard C++ escape sequence. The template argument |
||
211 | // UnsignedChar is the unsigned version of Char, which is the type of c. |
||
212 | template |
||
213 | void PrintCharAndCodeTo(Char c, ostream* os) { |
||
214 | // First, print c as a literal in the most readable form we can find. |
||
215 | *os << ((sizeof(c) > 1) ? "L'" : "'"); |
||
216 | const CharFormat format = PrintAsCharLiteralTo |
||
217 | *os << "'"; |
||
218 | |||
219 | // To aid user debugging, we also print c's code in decimal, unless |
||
220 | // it's 0 (in which case c was printed as '\\0', making the code |
||
221 | // obvious). |
||
222 | if (c == 0) |
||
223 | return; |
||
224 | *os << " (" << static_cast |
||
225 | |||
226 | // For more convenience, we print c's code again in hexidecimal, |
||
227 | // unless c was already printed in the form '\x##' or the code is in |
||
228 | // [1, 9]. |
||
229 | if (format == kHexEscape || (1 <= c && c <= 9)) { |
||
230 | // Do nothing. |
||
231 | } else { |
||
232 | *os << ", 0x" << String::FormatHexInt(static_cast |
||
233 | } |
||
234 | *os << ")"; |
||
235 | } |
||
236 | |||
237 | void PrintTo(unsigned char c, ::std::ostream* os) { |
||
238 | PrintCharAndCodeTo |
||
239 | } |
||
240 | void PrintTo(signed char c, ::std::ostream* os) { |
||
241 | PrintCharAndCodeTo |
||
242 | } |
||
243 | |||
244 | // Prints a wchar_t as a symbol if it is printable or as its internal |
||
245 | // code otherwise and also as its code. L'\0' is printed as "L'\\0'". |
||
246 | void PrintTo(wchar_t wc, ostream* os) { |
||
247 | PrintCharAndCodeTo |
||
248 | } |
||
249 | |||
250 | // Prints the given array of characters to the ostream. CharType must be either |
||
251 | // char or wchar_t. |
||
252 | // The array starts at begin, the length is len, it may include '\0' characters |
||
253 | // and may not be NUL-terminated. |
||
254 | template |
||
255 | static void PrintCharsAsStringTo( |
||
256 | const CharType* begin, size_t len, ostream* os) { |
||
257 | const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; |
||
258 | *os << kQuoteBegin; |
||
259 | bool is_previous_hex = false; |
||
260 | for (size_t index = 0; index < len; ++index) { |
||
261 | const CharType cur = begin[index]; |
||
262 | if (is_previous_hex && IsXDigit(cur)) { |
||
263 | // Previous character is of '\x..' form and this character can be |
||
264 | // interpreted as another hexadecimal digit in its number. Break string to |
||
265 | // disambiguate. |
||
266 | *os << "\" " << kQuoteBegin; |
||
267 | } |
||
268 | is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; |
||
269 | } |
||
270 | *os << "\""; |
||
271 | } |
||
272 | |||
273 | // Prints a (const) char/wchar_t array of 'len' elements, starting at address |
||
274 | // 'begin'. CharType must be either char or wchar_t. |
||
275 | template |
||
276 | static void UniversalPrintCharArray( |
||
277 | const CharType* begin, size_t len, ostream* os) { |
||
278 | // The code |
||
279 | // const char kFoo[] = "foo"; |
||
280 | // generates an array of 4, not 3, elements, with the last one being '\0'. |
||
281 | // |
||
282 | // Therefore when printing a char array, we don't print the last element if |
||
283 | // it's '\0', such that the output matches the string literal as it's |
||
284 | // written in the source code. |
||
285 | if (len > 0 && begin[len - 1] == '\0') { |
||
286 | PrintCharsAsStringTo(begin, len - 1, os); |
||
287 | return; |
||
288 | } |
||
289 | |||
290 | // If, however, the last element in the array is not '\0', e.g. |
||
291 | // const char kFoo[] = { 'f', 'o', 'o' }; |
||
292 | // we must print the entire array. We also print a message to indicate |
||
293 | // that the array is not NUL-terminated. |
||
294 | PrintCharsAsStringTo(begin, len, os); |
||
295 | *os << " (no terminating NUL)"; |
||
296 | } |
||
297 | |||
298 | // Prints a (const) char array of 'len' elements, starting at address 'begin'. |
||
299 | void UniversalPrintArray(const char* begin, size_t len, ostream* os) { |
||
300 | UniversalPrintCharArray(begin, len, os); |
||
301 | } |
||
302 | |||
303 | // Prints a (const) wchar_t array of 'len' elements, starting at address |
||
304 | // 'begin'. |
||
305 | void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { |
||
306 | UniversalPrintCharArray(begin, len, os); |
||
307 | } |
||
308 | |||
309 | // Prints the given C string to the ostream. |
||
310 | void PrintTo(const char* s, ostream* os) { |
||
311 | if (s == NULL) { |
||
312 | *os << "NULL"; |
||
313 | } else { |
||
314 | *os << ImplicitCast_ |
||
315 | PrintCharsAsStringTo(s, strlen(s), os); |
||
316 | } |
||
317 | } |
||
318 | |||
319 | // MSVC compiler can be configured to define whar_t as a typedef |
||
320 | // of unsigned short. Defining an overload for const wchar_t* in that case |
||
321 | // would cause pointers to unsigned shorts be printed as wide strings, |
||
322 | // possibly accessing more memory than intended and causing invalid |
||
323 | // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when |
||
324 | // wchar_t is implemented as a native type. |
||
325 | #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) |
||
326 | // Prints the given wide C string to the ostream. |
||
327 | void PrintTo(const wchar_t* s, ostream* os) { |
||
328 | if (s == NULL) { |
||
329 | *os << "NULL"; |
||
330 | } else { |
||
331 | *os << ImplicitCast_ |
||
332 | PrintCharsAsStringTo(s, wcslen(s), os); |
||
333 | } |
||
334 | } |
||
335 | #endif // wchar_t is native |
||
336 | |||
337 | // Prints a ::string object. |
||
338 | #if GTEST_HAS_GLOBAL_STRING |
||
339 | void PrintStringTo(const ::string& s, ostream* os) { |
||
340 | PrintCharsAsStringTo(s.data(), s.size(), os); |
||
341 | } |
||
342 | #endif // GTEST_HAS_GLOBAL_STRING |
||
343 | |||
344 | void PrintStringTo(const ::std::string& s, ostream* os) { |
||
345 | PrintCharsAsStringTo(s.data(), s.size(), os); |
||
346 | } |
||
347 | |||
348 | // Prints a ::wstring object. |
||
349 | #if GTEST_HAS_GLOBAL_WSTRING |
||
350 | void PrintWideStringTo(const ::wstring& s, ostream* os) { |
||
351 | PrintCharsAsStringTo(s.data(), s.size(), os); |
||
352 | } |
||
353 | #endif // GTEST_HAS_GLOBAL_WSTRING |
||
354 | |||
355 | #if GTEST_HAS_STD_WSTRING |
||
356 | void PrintWideStringTo(const ::std::wstring& s, ostream* os) { |
||
357 | PrintCharsAsStringTo(s.data(), s.size(), os); |
||
358 | } |
||
359 | #endif // GTEST_HAS_STD_WSTRING |
||
360 | |||
361 | } // namespace internal |
||
362 | |||
363 | } // namespace testing><>><>><>><>><>><>><>><>><>><>>><>><>><>><>=>=>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>=>=>><>><>><>><>>"; |