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