1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Unit tests for all str_cat.h functions
16
17 #include "absl/strings/str_cat.h"
18
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstdlib>
22 #include <limits>
23 #include <string>
24 #include <vector>
25
26 #include "gtest/gtest.h"
27 #include "absl/strings/str_format.h"
28 #include "absl/strings/string_view.h"
29
30 #ifdef __ANDROID__
31 // Android assert messages only go to system log, so death tests cannot inspect
32 // the message for matching.
33 #define ABSL_EXPECT_DEBUG_DEATH(statement, regex) \
34 EXPECT_DEBUG_DEATH(statement, ".*")
35 #else
36 #define ABSL_EXPECT_DEBUG_DEATH(statement, regex) \
37 EXPECT_DEBUG_DEATH(statement, regex)
38 #endif
39
40 namespace {
41
42 // Test absl::StrCat of ints and longs of various sizes and signdedness.
TEST(StrCat,Ints)43 TEST(StrCat, Ints) {
44 const short s = -1; // NOLINT(runtime/int)
45 const uint16_t us = 2;
46 const int i = -3;
47 const unsigned int ui = 4;
48 const long l = -5; // NOLINT(runtime/int)
49 const unsigned long ul = 6; // NOLINT(runtime/int)
50 const long long ll = -7; // NOLINT(runtime/int)
51 const unsigned long long ull = 8; // NOLINT(runtime/int)
52 const ptrdiff_t ptrdiff = -9;
53 const size_t size = 10;
54 const intptr_t intptr = -12;
55 const uintptr_t uintptr = 13;
56 std::string answer;
57 answer = absl::StrCat(s, us);
58 EXPECT_EQ(answer, "-12");
59 answer = absl::StrCat(i, ui);
60 EXPECT_EQ(answer, "-34");
61 answer = absl::StrCat(l, ul);
62 EXPECT_EQ(answer, "-56");
63 answer = absl::StrCat(ll, ull);
64 EXPECT_EQ(answer, "-78");
65 answer = absl::StrCat(ptrdiff, size);
66 EXPECT_EQ(answer, "-910");
67 answer = absl::StrCat(ptrdiff, intptr);
68 EXPECT_EQ(answer, "-9-12");
69 answer = absl::StrCat(uintptr, 0);
70 EXPECT_EQ(answer, "130");
71 }
72
TEST(StrCat,Enums)73 TEST(StrCat, Enums) {
74 enum SmallNumbers { One = 1, Ten = 10 } e = Ten;
75 EXPECT_EQ("10", absl::StrCat(e));
76 EXPECT_EQ("-5", absl::StrCat(SmallNumbers(-5)));
77
78 enum class Option { Boxers = 1, Briefs = -1 };
79
80 EXPECT_EQ("-1", absl::StrCat(Option::Briefs));
81
82 enum class Airplane : uint64_t {
83 Airbus = 1,
84 Boeing = 1000,
85 Canary = 10000000000 // too big for "int"
86 };
87
88 EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary));
89
90 enum class TwoGig : int32_t {
91 TwoToTheZero = 1,
92 TwoToTheSixteenth = 1 << 16,
93 TwoToTheThirtyFirst = INT32_MIN
94 };
95 EXPECT_EQ("65536", absl::StrCat(TwoGig::TwoToTheSixteenth));
96 EXPECT_EQ("-2147483648", absl::StrCat(TwoGig::TwoToTheThirtyFirst));
97 EXPECT_EQ("-1", absl::StrCat(static_cast<TwoGig>(-1)));
98
99 enum class FourGig : uint32_t {
100 TwoToTheZero = 1,
101 TwoToTheSixteenth = 1 << 16,
102 TwoToTheThirtyFirst = 1U << 31 // too big for "int"
103 };
104 EXPECT_EQ("65536", absl::StrCat(FourGig::TwoToTheSixteenth));
105 EXPECT_EQ("2147483648", absl::StrCat(FourGig::TwoToTheThirtyFirst));
106 EXPECT_EQ("4294967295", absl::StrCat(static_cast<FourGig>(-1)));
107
108 EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary));
109 }
110
TEST(StrCat,Basics)111 TEST(StrCat, Basics) {
112 std::string result;
113
114 std::string strs[] = {"Hello", "Cruel", "World"};
115
116 std::string stdstrs[] = {
117 "std::Hello",
118 "std::Cruel",
119 "std::World"
120 };
121
122 absl::string_view pieces[] = {"Hello", "Cruel", "World"};
123
124 const char* c_strs[] = {
125 "Hello",
126 "Cruel",
127 "World"
128 };
129
130 int32_t i32s[] = {'H', 'C', 'W'};
131 uint64_t ui64s[] = {12345678910LL, 10987654321LL};
132
133 EXPECT_EQ(absl::StrCat(), "");
134
135 result = absl::StrCat(false, true, 2, 3);
136 EXPECT_EQ(result, "0123");
137
138 result = absl::StrCat(-1);
139 EXPECT_EQ(result, "-1");
140
141 result = absl::StrCat(absl::SixDigits(0.5));
142 EXPECT_EQ(result, "0.5");
143
144 result = absl::StrCat(strs[1], pieces[2]);
145 EXPECT_EQ(result, "CruelWorld");
146
147 result = absl::StrCat(stdstrs[1], " ", stdstrs[2]);
148 EXPECT_EQ(result, "std::Cruel std::World");
149
150 result = absl::StrCat(strs[0], ", ", pieces[2]);
151 EXPECT_EQ(result, "Hello, World");
152
153 result = absl::StrCat(strs[0], ", ", strs[1], " ", strs[2], "!");
154 EXPECT_EQ(result, "Hello, Cruel World!");
155
156 result = absl::StrCat(pieces[0], ", ", pieces[1], " ", pieces[2]);
157 EXPECT_EQ(result, "Hello, Cruel World");
158
159 result = absl::StrCat(c_strs[0], ", ", c_strs[1], " ", c_strs[2]);
160 EXPECT_EQ(result, "Hello, Cruel World");
161
162 result = absl::StrCat("ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!");
163 EXPECT_EQ(result, "ASCII 72, 67 87!");
164
165 result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!");
166 EXPECT_EQ(result, "12345678910, 10987654321!");
167
168 std::string one =
169 "1"; // Actually, it's the size of this string that we want; a
170 // 64-bit build distinguishes between size_t and uint64_t,
171 // even though they're both unsigned 64-bit values.
172 result = absl::StrCat("And a ", one.size(), " and a ",
173 &result[2] - &result[0], " and a ", one, " 2 3 4", "!");
174 EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!");
175
176 // result = absl::StrCat("Single chars won't compile", '!');
177 // result = absl::StrCat("Neither will nullptrs", nullptr);
178 result =
179 absl::StrCat("To output a char by ASCII/numeric value, use +: ", '!' + 0);
180 EXPECT_EQ(result, "To output a char by ASCII/numeric value, use +: 33");
181
182 float f = 100000.5;
183 result = absl::StrCat("A hundred K and a half is ", absl::SixDigits(f));
184 EXPECT_EQ(result, "A hundred K and a half is 100000");
185
186 f = 100001.5;
187 result =
188 absl::StrCat("A hundred K and one and a half is ", absl::SixDigits(f));
189 EXPECT_EQ(result, "A hundred K and one and a half is 100002");
190
191 double d = 100000.5;
192 d *= d;
193 result =
194 absl::StrCat("A hundred K and a half squared is ", absl::SixDigits(d));
195 EXPECT_EQ(result, "A hundred K and a half squared is 1.00001e+10");
196
197 result = absl::StrCat(1, 2, 333, 4444, 55555, 666666, 7777777, 88888888,
198 999999999);
199 EXPECT_EQ(result, "12333444455555666666777777788888888999999999");
200 }
201
TEST(StrCat,CornerCases)202 TEST(StrCat, CornerCases) {
203 std::string result;
204
205 result = absl::StrCat(""); // NOLINT
206 EXPECT_EQ(result, "");
207 result = absl::StrCat("", "");
208 EXPECT_EQ(result, "");
209 result = absl::StrCat("", "", "");
210 EXPECT_EQ(result, "");
211 result = absl::StrCat("", "", "", "");
212 EXPECT_EQ(result, "");
213 result = absl::StrCat("", "", "", "", "");
214 EXPECT_EQ(result, "");
215 }
216
TEST(StrCat,NullConstCharPtr)217 TEST(StrCat, NullConstCharPtr) {
218 const char* null = nullptr;
219 EXPECT_EQ(absl::StrCat("mon", null, "key"), "monkey");
220 }
221
222 // A minimal allocator that uses malloc().
223 template <typename T>
224 struct Mallocator {
225 typedef T value_type;
226 typedef size_t size_type;
227 typedef ptrdiff_t difference_type;
228 typedef T* pointer;
229 typedef const T* const_pointer;
230 typedef T& reference;
231 typedef const T& const_reference;
232
max_size__anona7fc5ba30111::Mallocator233 size_type max_size() const {
234 return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type);
235 }
236 template <typename U>
237 struct rebind {
238 typedef Mallocator<U> other;
239 };
240 Mallocator() = default;
241 template <class U>
Mallocator__anona7fc5ba30111::Mallocator242 Mallocator(const Mallocator<U>&) {} // NOLINT(runtime/explicit)
243
allocate__anona7fc5ba30111::Mallocator244 T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
deallocate__anona7fc5ba30111::Mallocator245 void deallocate(T* p, size_t) { std::free(p); }
246 };
247 template <typename T, typename U>
operator ==(const Mallocator<T> &,const Mallocator<U> &)248 bool operator==(const Mallocator<T>&, const Mallocator<U>&) {
249 return true;
250 }
251 template <typename T, typename U>
operator !=(const Mallocator<T> &,const Mallocator<U> &)252 bool operator!=(const Mallocator<T>&, const Mallocator<U>&) {
253 return false;
254 }
255
TEST(StrCat,CustomAllocator)256 TEST(StrCat, CustomAllocator) {
257 using mstring =
258 std::basic_string<char, std::char_traits<char>, Mallocator<char>>;
259 const mstring str1("PARACHUTE OFF A BLIMP INTO MOSCONE!!");
260
261 const mstring str2("Read this book about coffee tables");
262
263 std::string result = absl::StrCat(str1, str2);
264 EXPECT_EQ(result,
265 "PARACHUTE OFF A BLIMP INTO MOSCONE!!"
266 "Read this book about coffee tables");
267 }
268
TEST(StrCat,MaxArgs)269 TEST(StrCat, MaxArgs) {
270 std::string result;
271 // Test 10 up to 26 arguments, the old maximum
272 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a");
273 EXPECT_EQ(result, "123456789a");
274 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b");
275 EXPECT_EQ(result, "123456789ab");
276 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c");
277 EXPECT_EQ(result, "123456789abc");
278 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d");
279 EXPECT_EQ(result, "123456789abcd");
280 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e");
281 EXPECT_EQ(result, "123456789abcde");
282 result =
283 absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f");
284 EXPECT_EQ(result, "123456789abcdef");
285 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
286 "g");
287 EXPECT_EQ(result, "123456789abcdefg");
288 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
289 "g", "h");
290 EXPECT_EQ(result, "123456789abcdefgh");
291 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
292 "g", "h", "i");
293 EXPECT_EQ(result, "123456789abcdefghi");
294 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
295 "g", "h", "i", "j");
296 EXPECT_EQ(result, "123456789abcdefghij");
297 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
298 "g", "h", "i", "j", "k");
299 EXPECT_EQ(result, "123456789abcdefghijk");
300 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
301 "g", "h", "i", "j", "k", "l");
302 EXPECT_EQ(result, "123456789abcdefghijkl");
303 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
304 "g", "h", "i", "j", "k", "l", "m");
305 EXPECT_EQ(result, "123456789abcdefghijklm");
306 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
307 "g", "h", "i", "j", "k", "l", "m", "n");
308 EXPECT_EQ(result, "123456789abcdefghijklmn");
309 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
310 "g", "h", "i", "j", "k", "l", "m", "n", "o");
311 EXPECT_EQ(result, "123456789abcdefghijklmno");
312 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
313 "g", "h", "i", "j", "k", "l", "m", "n", "o", "p");
314 EXPECT_EQ(result, "123456789abcdefghijklmnop");
315 result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
316 "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q");
317 EXPECT_EQ(result, "123456789abcdefghijklmnopq");
318 // No limit thanks to C++11's variadic templates
319 result = absl::StrCat(
320 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "a", "b", "c", "d", "e", "f", "g", "h",
321 "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w",
322 "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
323 "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
324 EXPECT_EQ(result,
325 "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
326 }
327
TEST(StrAppend,Basics)328 TEST(StrAppend, Basics) {
329 std::string result = "existing text";
330
331 std::string strs[] = {"Hello", "Cruel", "World"};
332
333 std::string stdstrs[] = {
334 "std::Hello",
335 "std::Cruel",
336 "std::World"
337 };
338
339 absl::string_view pieces[] = {"Hello", "Cruel", "World"};
340
341 const char* c_strs[] = {
342 "Hello",
343 "Cruel",
344 "World"
345 };
346
347 int32_t i32s[] = {'H', 'C', 'W'};
348 uint64_t ui64s[] = {12345678910LL, 10987654321LL};
349
350 std::string::size_type old_size = result.size();
351 absl::StrAppend(&result);
352 EXPECT_EQ(result.size(), old_size);
353
354 old_size = result.size();
355 absl::StrAppend(&result, strs[0]);
356 EXPECT_EQ(result.substr(old_size), "Hello");
357
358 old_size = result.size();
359 absl::StrAppend(&result, strs[1], pieces[2]);
360 EXPECT_EQ(result.substr(old_size), "CruelWorld");
361
362 old_size = result.size();
363 absl::StrAppend(&result, stdstrs[0], ", ", pieces[2]);
364 EXPECT_EQ(result.substr(old_size), "std::Hello, World");
365
366 old_size = result.size();
367 absl::StrAppend(&result, strs[0], ", ", stdstrs[1], " ", strs[2], "!");
368 EXPECT_EQ(result.substr(old_size), "Hello, std::Cruel World!");
369
370 old_size = result.size();
371 absl::StrAppend(&result, pieces[0], ", ", pieces[1], " ", pieces[2]);
372 EXPECT_EQ(result.substr(old_size), "Hello, Cruel World");
373
374 old_size = result.size();
375 absl::StrAppend(&result, c_strs[0], ", ", c_strs[1], " ", c_strs[2]);
376 EXPECT_EQ(result.substr(old_size), "Hello, Cruel World");
377
378 old_size = result.size();
379 absl::StrAppend(&result, "ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!");
380 EXPECT_EQ(result.substr(old_size), "ASCII 72, 67 87!");
381
382 old_size = result.size();
383 absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!");
384 EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!");
385
386 std::string one =
387 "1"; // Actually, it's the size of this string that we want; a
388 // 64-bit build distinguishes between size_t and uint64_t,
389 // even though they're both unsigned 64-bit values.
390 old_size = result.size();
391 absl::StrAppend(&result, "And a ", one.size(), " and a ",
392 &result[2] - &result[0], " and a ", one, " 2 3 4", "!");
393 EXPECT_EQ(result.substr(old_size), "And a 1 and a 2 and a 1 2 3 4!");
394
395 // result = absl::StrCat("Single chars won't compile", '!');
396 // result = absl::StrCat("Neither will nullptrs", nullptr);
397 old_size = result.size();
398 absl::StrAppend(&result,
399 "To output a char by ASCII/numeric value, use +: ", '!' + 0);
400 EXPECT_EQ(result.substr(old_size),
401 "To output a char by ASCII/numeric value, use +: 33");
402
403 // Test 9 arguments, the old maximum
404 old_size = result.size();
405 absl::StrAppend(&result, 1, 22, 333, 4444, 55555, 666666, 7777777, 88888888,
406 9);
407 EXPECT_EQ(result.substr(old_size), "1223334444555556666667777777888888889");
408
409 // No limit thanks to C++11's variadic templates
410 old_size = result.size();
411 absl::StrAppend(
412 &result, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, //
413 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", //
414 "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", //
415 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", //
416 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", //
417 "No limit thanks to C++11's variadic templates");
418 EXPECT_EQ(result.substr(old_size),
419 "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
420 "No limit thanks to C++11's variadic templates");
421 }
422
TEST(StrCat,VectorBoolReferenceTypes)423 TEST(StrCat, VectorBoolReferenceTypes) {
424 std::vector<bool> v;
425 v.push_back(true);
426 v.push_back(false);
427 std::vector<bool> const& cv = v;
428 // Test that vector<bool>::reference and vector<bool>::const_reference
429 // are handled as if the were really bool types and not the proxy types
430 // they really are.
431 std::string result = absl::StrCat(v[0], v[1], cv[0], cv[1]); // NOLINT
432 EXPECT_EQ(result, "1010");
433 }
434
435 // Passing nullptr to memcpy is undefined behavior and this test
436 // provides coverage of codepaths that handle empty strings with nullptrs.
TEST(StrCat,AvoidsMemcpyWithNullptr)437 TEST(StrCat, AvoidsMemcpyWithNullptr) {
438 EXPECT_EQ(absl::StrCat(42, absl::string_view{}), "42");
439
440 // Cover CatPieces code.
441 EXPECT_EQ(absl::StrCat(1, 2, 3, 4, 5, absl::string_view{}), "12345");
442
443 // Cover AppendPieces.
444 std::string result;
445 absl::StrAppend(&result, 1, 2, 3, 4, 5, absl::string_view{});
446 EXPECT_EQ(result, "12345");
447 }
448
449 #if GTEST_HAS_DEATH_TEST
TEST(StrAppend,Death)450 TEST(StrAppend, Death) {
451 std::string s = "self";
452 // on linux it's "assertion", on mac it's "Assertion",
453 // on chromiumos it's "Assertion ... failed".
454 ABSL_EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s.c_str() + 1),
455 "ssertion.*failed");
456 ABSL_EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s), "ssertion.*failed");
457 }
458 #endif // GTEST_HAS_DEATH_TEST
459
TEST(StrAppend,CornerCases)460 TEST(StrAppend, CornerCases) {
461 std::string result;
462 absl::StrAppend(&result, "");
463 EXPECT_EQ(result, "");
464 absl::StrAppend(&result, "", "");
465 EXPECT_EQ(result, "");
466 absl::StrAppend(&result, "", "", "");
467 EXPECT_EQ(result, "");
468 absl::StrAppend(&result, "", "", "", "");
469 EXPECT_EQ(result, "");
470 absl::StrAppend(&result, "", "", "", "", "");
471 EXPECT_EQ(result, "");
472 }
473
TEST(StrAppend,CornerCasesNonEmptyAppend)474 TEST(StrAppend, CornerCasesNonEmptyAppend) {
475 for (std::string result : {"hello", "a string too long to fit in the SSO"}) {
476 const std::string expected = result;
477 absl::StrAppend(&result, "");
478 EXPECT_EQ(result, expected);
479 absl::StrAppend(&result, "", "");
480 EXPECT_EQ(result, expected);
481 absl::StrAppend(&result, "", "", "");
482 EXPECT_EQ(result, expected);
483 absl::StrAppend(&result, "", "", "", "");
484 EXPECT_EQ(result, expected);
485 absl::StrAppend(&result, "", "", "", "", "");
486 EXPECT_EQ(result, expected);
487 }
488 }
489
490 template <typename IntType>
CheckHex(IntType v,const char * nopad_format,const char * zeropad_format,const char * spacepad_format)491 void CheckHex(IntType v, const char* nopad_format, const char* zeropad_format,
492 const char* spacepad_format) {
493 char expected[256];
494
495 std::string actual = absl::StrCat(absl::Hex(v, absl::kNoPad));
496 snprintf(expected, sizeof(expected), nopad_format, v);
497 EXPECT_EQ(expected, actual) << " decimal value " << v;
498
499 for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad20; ++spec) {
500 std::string actual =
501 absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
502 snprintf(expected, sizeof(expected), zeropad_format,
503 spec - absl::kZeroPad2 + 2, v);
504 EXPECT_EQ(expected, actual) << " decimal value " << v;
505 }
506
507 for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad20; ++spec) {
508 std::string actual =
509 absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
510 snprintf(expected, sizeof(expected), spacepad_format,
511 spec - absl::kSpacePad2 + 2, v);
512 EXPECT_EQ(expected, actual) << " decimal value " << v;
513 }
514 }
515
516 template <typename IntType>
CheckDec(IntType v,const char * nopad_format,const char * zeropad_format,const char * spacepad_format)517 void CheckDec(IntType v, const char* nopad_format, const char* zeropad_format,
518 const char* spacepad_format) {
519 char expected[256];
520
521 std::string actual = absl::StrCat(absl::Dec(v, absl::kNoPad));
522 snprintf(expected, sizeof(expected), nopad_format, v);
523 EXPECT_EQ(expected, actual) << " decimal value " << v;
524
525 for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad20; ++spec) {
526 std::string actual =
527 absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec)));
528 snprintf(expected, sizeof(expected), zeropad_format,
529 spec - absl::kZeroPad2 + 2, v);
530 EXPECT_EQ(expected, actual)
531 << " decimal value " << v << " format '" << zeropad_format
532 << "' digits " << (spec - absl::kZeroPad2 + 2);
533 }
534
535 for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad20; ++spec) {
536 std::string actual =
537 absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec)));
538 snprintf(expected, sizeof(expected), spacepad_format,
539 spec - absl::kSpacePad2 + 2, v);
540 EXPECT_EQ(expected, actual)
541 << " decimal value " << v << " format '" << spacepad_format
542 << "' digits " << (spec - absl::kSpacePad2 + 2);
543 }
544 }
545
CheckHexDec64(uint64_t v)546 void CheckHexDec64(uint64_t v) {
547 unsigned long long ullv = v; // NOLINT(runtime/int)
548
549 CheckHex(ullv, "%llx", "%0*llx", "%*llx");
550 CheckDec(ullv, "%llu", "%0*llu", "%*llu");
551
552 long long llv = static_cast<long long>(ullv); // NOLINT(runtime/int)
553 CheckDec(llv, "%lld", "%0*lld", "%*lld");
554
555 if (sizeof(v) == sizeof(&v)) {
556 auto uintptr = static_cast<uintptr_t>(v);
557 void* ptr = reinterpret_cast<void*>(uintptr);
558 CheckHex(ptr, "%llx", "%0*llx", "%*llx");
559 }
560 }
561
CheckHexDec32(uint32_t uv)562 void CheckHexDec32(uint32_t uv) {
563 CheckHex(uv, "%x", "%0*x", "%*x");
564 CheckDec(uv, "%u", "%0*u", "%*u");
565 int32_t v = static_cast<int32_t>(uv);
566 CheckDec(v, "%d", "%0*d", "%*d");
567
568 if (sizeof(v) == sizeof(&v)) {
569 auto uintptr = static_cast<uintptr_t>(v);
570 void* ptr = reinterpret_cast<void*>(uintptr);
571 CheckHex(ptr, "%x", "%0*x", "%*x");
572 }
573 }
574
CheckAll(uint64_t v)575 void CheckAll(uint64_t v) {
576 CheckHexDec64(v);
577 CheckHexDec32(static_cast<uint32_t>(v));
578 }
579
TestFastPrints()580 void TestFastPrints() {
581 // Test all small ints; there aren't many and they're common.
582 for (int i = 0; i < 10000; i++) {
583 CheckAll(i);
584 }
585
586 CheckAll(std::numeric_limits<uint64_t>::max());
587 CheckAll(std::numeric_limits<uint64_t>::max() - 1);
588 CheckAll(std::numeric_limits<int64_t>::min());
589 CheckAll(std::numeric_limits<int64_t>::min() + 1);
590 CheckAll(std::numeric_limits<uint32_t>::max());
591 CheckAll(std::numeric_limits<uint32_t>::max() - 1);
592 CheckAll(std::numeric_limits<int32_t>::min());
593 CheckAll(std::numeric_limits<int32_t>::min() + 1);
594 CheckAll(999999999); // fits in 32 bits
595 CheckAll(1000000000); // fits in 32 bits
596 CheckAll(9999999999); // doesn't fit in 32 bits
597 CheckAll(10000000000); // doesn't fit in 32 bits
598 CheckAll(999999999999999999); // fits in signed 64-bit
599 CheckAll(9999999999999999999u); // fits in unsigned 64-bit, but not signed.
600 CheckAll(1000000000000000000); // fits in signed 64-bit
601 CheckAll(10000000000000000000u); // fits in unsigned 64-bit, but not signed.
602
603 CheckAll(999999999876543210); // check all decimal digits, signed
604 CheckAll(9999999999876543210u); // check all decimal digits, unsigned.
605 CheckAll(0x123456789abcdef0); // check all hex digits
606 CheckAll(0x12345678);
607
608 int8_t minus_one_8bit = -1;
609 EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit)));
610
611 int16_t minus_one_16bit = -1;
612 EXPECT_EQ("ffff", absl::StrCat(absl::Hex(minus_one_16bit)));
613 }
614
TEST(Numbers,TestFunctionsMovedOverFromNumbersMain)615 TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) {
616 TestFastPrints();
617 }
618
619 struct PointStringify {
620 template <typename FormatSink>
AbslStringify(FormatSink & sink,const PointStringify & p)621 friend void AbslStringify(FormatSink& sink, const PointStringify& p) {
622 sink.Append("(");
623 sink.Append(absl::StrCat(p.x));
624 sink.Append(", ");
625 sink.Append(absl::StrCat(p.y));
626 sink.Append(")");
627 }
628
629 double x = 10.0;
630 double y = 20.0;
631 };
632
TEST(StrCat,AbslStringifyExample)633 TEST(StrCat, AbslStringifyExample) {
634 PointStringify p;
635 EXPECT_EQ(absl::StrCat(p), "(10, 20)");
636 EXPECT_EQ(absl::StrCat("a ", p, " z"), "a (10, 20) z");
637 }
638
639 struct PointStringifyUsingFormat {
640 template <typename FormatSink>
AbslStringify(FormatSink & sink,const PointStringifyUsingFormat & p)641 friend void AbslStringify(FormatSink& sink,
642 const PointStringifyUsingFormat& p) {
643 absl::Format(&sink, "(%g, %g)", p.x, p.y);
644 }
645
646 double x = 10.0;
647 double y = 20.0;
648 };
649
TEST(StrCat,AbslStringifyExampleUsingFormat)650 TEST(StrCat, AbslStringifyExampleUsingFormat) {
651 PointStringifyUsingFormat p;
652 EXPECT_EQ(absl::StrCat(p), "(10, 20)");
653 EXPECT_EQ(absl::StrCat("a ", p, " z"), "a (10, 20) z");
654 }
655
656 enum class EnumWithStringify { Many = 0, Choices = 1 };
657
658 template <typename Sink>
AbslStringify(Sink & sink,EnumWithStringify e)659 void AbslStringify(Sink& sink, EnumWithStringify e) {
660 absl::Format(&sink, "%s", e == EnumWithStringify::Many ? "Many" : "Choices");
661 }
662
TEST(StrCat,AbslStringifyWithEnum)663 TEST(StrCat, AbslStringifyWithEnum) {
664 const auto e = EnumWithStringify::Choices;
665 EXPECT_EQ(absl::StrCat(e), "Choices");
666 }
667
668 template <typename Integer>
CheckSingleArgumentIntegerLimits()669 void CheckSingleArgumentIntegerLimits() {
670 Integer max = std::numeric_limits<Integer>::max();
671 Integer min = std::numeric_limits<Integer>::min();
672
673 EXPECT_EQ(absl::StrCat(max), std::to_string(max));
674 EXPECT_EQ(absl::StrCat(min), std::to_string(min));
675 }
676
TEST(StrCat,SingleArgumentLimits)677 TEST(StrCat, SingleArgumentLimits) {
678 CheckSingleArgumentIntegerLimits<int32_t>();
679 CheckSingleArgumentIntegerLimits<uint32_t>();
680 CheckSingleArgumentIntegerLimits<int64_t>();
681 CheckSingleArgumentIntegerLimits<uint64_t>();
682 }
683
684 } // namespace
685