1 // Copyright 2020 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 #include "absl/strings/str_format.h"
16
17 #include <cstdarg>
18 #include <cstdint>
19 #include <cstdio>
20 #include <string>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/strings/cord.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27
28 namespace absl {
29 ABSL_NAMESPACE_BEGIN
30 namespace {
31 using str_format_internal::FormatArgImpl;
32
33 using FormatEntryPointTest = ::testing::Test;
34
TEST_F(FormatEntryPointTest,Format)35 TEST_F(FormatEntryPointTest, Format) {
36 std::string sink;
37 EXPECT_TRUE(Format(&sink, "A format %d", 123));
38 EXPECT_EQ("A format 123", sink);
39 sink.clear();
40
41 ParsedFormat<'d'> pc("A format %d");
42 EXPECT_TRUE(Format(&sink, pc, 123));
43 EXPECT_EQ("A format 123", sink);
44 }
45
TEST_F(FormatEntryPointTest,FormatWithV)46 TEST_F(FormatEntryPointTest, FormatWithV) {
47 std::string sink;
48 EXPECT_TRUE(Format(&sink, "A format %v", 123));
49 EXPECT_EQ("A format 123", sink);
50 sink.clear();
51
52 ParsedFormat<'v'> pc("A format %v");
53 EXPECT_TRUE(Format(&sink, pc, 123));
54 EXPECT_EQ("A format 123", sink);
55 }
56
TEST_F(FormatEntryPointTest,UntypedFormat)57 TEST_F(FormatEntryPointTest, UntypedFormat) {
58 constexpr const char* formats[] = {
59 "",
60 "a",
61 "%80d",
62 #if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
63 // MSVC, NaCL and Android don't support positional syntax.
64 "complicated multipart %% %1$d format %1$0999d",
65 #endif // _MSC_VER
66 };
67 for (const char* fmt : formats) {
68 std::string actual;
69 int i = 123;
70 FormatArgImpl arg_123(i);
71 absl::Span<const FormatArgImpl> args(&arg_123, 1);
72 UntypedFormatSpec format(fmt);
73
74 EXPECT_TRUE(FormatUntyped(&actual, format, args));
75 char buf[4096]{};
76 snprintf(buf, sizeof(buf), fmt, 123);
77 EXPECT_EQ(
78 str_format_internal::FormatPack(
79 str_format_internal::UntypedFormatSpecImpl::Extract(format), args),
80 buf);
81 EXPECT_EQ(actual, buf);
82 }
83 // The internal version works with a preparsed format.
84 ParsedFormat<'d'> pc("A format %d");
85 int i = 345;
86 FormatArg arg(i);
87 std::string out;
88 EXPECT_TRUE(str_format_internal::FormatUntyped(
89 &out, str_format_internal::UntypedFormatSpecImpl(&pc), {&arg, 1}));
90 EXPECT_EQ("A format 345", out);
91 }
92
TEST_F(FormatEntryPointTest,StringFormat)93 TEST_F(FormatEntryPointTest, StringFormat) {
94 EXPECT_EQ("123", StrFormat("%d", 123));
95 constexpr absl::string_view view("=%d=", 4);
96 EXPECT_EQ("=123=", StrFormat(view, 123));
97 }
98
TEST_F(FormatEntryPointTest,StringFormatV)99 TEST_F(FormatEntryPointTest, StringFormatV) {
100 std::string hello = "hello";
101 EXPECT_EQ("hello", StrFormat("%v", hello));
102 EXPECT_EQ("123", StrFormat("%v", 123));
103 constexpr absl::string_view view("=%v=", 4);
104 EXPECT_EQ("=123=", StrFormat(view, 123));
105 }
106
TEST_F(FormatEntryPointTest,AppendFormat)107 TEST_F(FormatEntryPointTest, AppendFormat) {
108 std::string s;
109 std::string& r = StrAppendFormat(&s, "%d", 123);
110 EXPECT_EQ(&s, &r); // should be same object
111 EXPECT_EQ("123", r);
112 }
113
TEST_F(FormatEntryPointTest,AppendFormatWithV)114 TEST_F(FormatEntryPointTest, AppendFormatWithV) {
115 std::string s;
116 std::string& r = StrAppendFormat(&s, "%v", 123);
117 EXPECT_EQ(&s, &r); // should be same object
118 EXPECT_EQ("123", r);
119 }
120
TEST_F(FormatEntryPointTest,AppendFormatFail)121 TEST_F(FormatEntryPointTest, AppendFormatFail) {
122 std::string s = "orig";
123
124 UntypedFormatSpec format(" more %d");
125 FormatArgImpl arg("not an int");
126
127 EXPECT_EQ("orig",
128 str_format_internal::AppendPack(
129 &s, str_format_internal::UntypedFormatSpecImpl::Extract(format),
130 {&arg, 1}));
131 }
132
TEST_F(FormatEntryPointTest,AppendFormatFailWithV)133 TEST_F(FormatEntryPointTest, AppendFormatFailWithV) {
134 std::string s = "orig";
135
136 UntypedFormatSpec format(" more %v");
137 FormatArgImpl arg("not an int");
138
139 EXPECT_EQ("orig",
140 str_format_internal::AppendPack(
141 &s, str_format_internal::UntypedFormatSpecImpl::Extract(format),
142 {&arg, 1}));
143 }
144
TEST_F(FormatEntryPointTest,ManyArgs)145 TEST_F(FormatEntryPointTest, ManyArgs) {
146 EXPECT_EQ(
147 "60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 "
148 "36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 "
149 "12 11 10 9 8 7 6 5 4 3 2 1",
150 StrFormat("%60$d %59$d %58$d %57$d %56$d %55$d %54$d %53$d %52$d %51$d "
151 "%50$d %49$d %48$d %47$d %46$d %45$d %44$d %43$d %42$d %41$d "
152 "%40$d %39$d %38$d %37$d %36$d %35$d %34$d %33$d %32$d %31$d "
153 "%30$d %29$d %28$d %27$d %26$d %25$d %24$d %23$d %22$d %21$d "
154 "%20$d %19$d %18$d %17$d %16$d %15$d %14$d %13$d %12$d %11$d "
155 "%10$d %9$d %8$d %7$d %6$d %5$d %4$d %3$d %2$d %1$d",
156 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
157 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
158 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
159 51, 52, 53, 54, 55, 56, 57, 58, 59, 60));
160 }
161
TEST_F(FormatEntryPointTest,Preparsed)162 TEST_F(FormatEntryPointTest, Preparsed) {
163 ParsedFormat<'d'> pc("%d");
164 EXPECT_EQ("123", StrFormat(pc, 123));
165 // rvalue ok?
166 EXPECT_EQ("123", StrFormat(ParsedFormat<'d'>("%d"), 123));
167 constexpr absl::string_view view("=%d=", 4);
168 EXPECT_EQ("=123=", StrFormat(ParsedFormat<'d'>(view), 123));
169 }
170
TEST_F(FormatEntryPointTest,PreparsedWithV)171 TEST_F(FormatEntryPointTest, PreparsedWithV) {
172 ParsedFormat<'v'> pc("%v");
173 EXPECT_EQ("123", StrFormat(pc, 123));
174 // rvalue ok?
175 EXPECT_EQ("123", StrFormat(ParsedFormat<'v'>("%v"), 123));
176 constexpr absl::string_view view("=%v=", 4);
177 EXPECT_EQ("=123=", StrFormat(ParsedFormat<'v'>(view), 123));
178 }
179
TEST_F(FormatEntryPointTest,FormatCountCapture)180 TEST_F(FormatEntryPointTest, FormatCountCapture) {
181 int n = 0;
182 EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
183 EXPECT_EQ(0, n);
184 EXPECT_EQ("123", StrFormat("%d%n", 123, FormatCountCapture(&n)));
185 EXPECT_EQ(3, n);
186 }
187
TEST_F(FormatEntryPointTest,FormatCountCaptureWithV)188 TEST_F(FormatEntryPointTest, FormatCountCaptureWithV) {
189 int n = 0;
190 EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
191 EXPECT_EQ(0, n);
192 EXPECT_EQ("123", StrFormat("%v%n", 123, FormatCountCapture(&n)));
193 EXPECT_EQ(3, n);
194 }
195
TEST_F(FormatEntryPointTest,FormatCountCaptureWrongType)196 TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) {
197 // Should reject int*.
198 int n = 0;
199 UntypedFormatSpec format("%d%n");
200 int i = 123, *ip = &n;
201 FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)};
202
203 EXPECT_EQ("", str_format_internal::FormatPack(
204 str_format_internal::UntypedFormatSpecImpl::Extract(format),
205 absl::MakeSpan(args)));
206 }
207
TEST_F(FormatEntryPointTest,FormatCountCaptureWrongTypeWithV)208 TEST_F(FormatEntryPointTest, FormatCountCaptureWrongTypeWithV) {
209 // Should reject int*.
210 int n = 0;
211 UntypedFormatSpec format("%v%n");
212 int i = 123, *ip = &n;
213 FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)};
214
215 EXPECT_EQ("", str_format_internal::FormatPack(
216 str_format_internal::UntypedFormatSpecImpl::Extract(format),
217 absl::MakeSpan(args)));
218 }
219
TEST_F(FormatEntryPointTest,FormatCountCaptureMultiple)220 TEST_F(FormatEntryPointTest, FormatCountCaptureMultiple) {
221 int n1 = 0;
222 int n2 = 0;
223 EXPECT_EQ(" 1 2",
224 StrFormat("%5d%n%10d%n", 1, FormatCountCapture(&n1), 2,
225 FormatCountCapture(&n2)));
226 EXPECT_EQ(5, n1);
227 EXPECT_EQ(15, n2);
228 }
229
TEST_F(FormatEntryPointTest,FormatCountCaptureExample)230 TEST_F(FormatEntryPointTest, FormatCountCaptureExample) {
231 int n;
232 std::string s;
233 StrAppendFormat(&s, "%s: %n%s\n", "(1,1)", FormatCountCapture(&n), "(1,2)");
234 StrAppendFormat(&s, "%*s%s\n", n, "", "(2,2)");
235 EXPECT_EQ(7, n);
236 EXPECT_EQ(
237 "(1,1): (1,2)\n"
238 " (2,2)\n",
239 s);
240 }
241
TEST_F(FormatEntryPointTest,FormatCountCaptureExampleWithV)242 TEST_F(FormatEntryPointTest, FormatCountCaptureExampleWithV) {
243 int n;
244 std::string s;
245 std::string a1 = "(1,1)";
246 std::string a2 = "(1,2)";
247 std::string a3 = "(2,2)";
248 StrAppendFormat(&s, "%v: %n%v\n", a1, FormatCountCapture(&n), a2);
249 StrAppendFormat(&s, "%*s%v\n", n, "", a3);
250 EXPECT_EQ(7, n);
251 EXPECT_EQ(
252 "(1,1): (1,2)\n"
253 " (2,2)\n",
254 s);
255 }
256
TEST_F(FormatEntryPointTest,Stream)257 TEST_F(FormatEntryPointTest, Stream) {
258 const std::string formats[] = {
259 "",
260 "a",
261 "%80d",
262 "%d %u %c %s %f %g",
263 #if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
264 // MSVC, NaCL and Android don't support positional syntax.
265 "complicated multipart %% %1$d format %1$080d",
266 #endif // _MSC_VER
267 };
268 std::string buf(4096, '\0');
269 for (const auto& fmt : formats) {
270 const auto parsed =
271 ParsedFormat<'d', 'u', 'c', 's', 'f', 'g'>::NewAllowIgnored(fmt);
272 std::ostringstream oss;
273 oss << StreamFormat(*parsed, 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
274 int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), //
275 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
276 ASSERT_TRUE(oss) << fmt;
277 ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
278 << fmt_result;
279 EXPECT_EQ(buf.c_str(), oss.str());
280 }
281 }
282
TEST_F(FormatEntryPointTest,StreamWithV)283 TEST_F(FormatEntryPointTest, StreamWithV) {
284 const std::string formats[] = {
285 "",
286 "a",
287 "%v %u %c %v %f %v",
288 };
289
290 const std::string formats_for_buf[] = {
291 "",
292 "a",
293 "%d %u %c %s %f %g",
294 };
295
296 std::string buf(4096, '\0');
297 for (auto i = 0; i < ABSL_ARRAYSIZE(formats); ++i) {
298 const auto parsed =
299 ParsedFormat<'v', 'u', 'c', 'v', 'f', 'v'>::NewAllowIgnored(formats[i]);
300 std::ostringstream oss;
301 oss << StreamFormat(*parsed, 123, 3, 49,
302 absl::string_view("multistreaming!!!"), 1.01, 1.01);
303 int fmt_result =
304 snprintf(&*buf.begin(), buf.size(), formats_for_buf[i].c_str(), //
305 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
306 ASSERT_TRUE(oss) << formats[i];
307 ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
308 << fmt_result;
309 EXPECT_EQ(buf.c_str(), oss.str());
310 }
311 }
312
TEST_F(FormatEntryPointTest,StreamOk)313 TEST_F(FormatEntryPointTest, StreamOk) {
314 std::ostringstream oss;
315 oss << StreamFormat("hello %d", 123);
316 EXPECT_EQ("hello 123", oss.str());
317 EXPECT_TRUE(oss.good());
318 }
319
TEST_F(FormatEntryPointTest,StreamOkWithV)320 TEST_F(FormatEntryPointTest, StreamOkWithV) {
321 std::ostringstream oss;
322 oss << StreamFormat("hello %v", 123);
323 EXPECT_EQ("hello 123", oss.str());
324 EXPECT_TRUE(oss.good());
325 }
326
TEST_F(FormatEntryPointTest,StreamFail)327 TEST_F(FormatEntryPointTest, StreamFail) {
328 std::ostringstream oss;
329 UntypedFormatSpec format("hello %d");
330 FormatArgImpl arg("non-numeric");
331 oss << str_format_internal::Streamable(
332 str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1});
333 EXPECT_EQ("hello ", oss.str()); // partial write
334 EXPECT_TRUE(oss.fail());
335 }
336
TEST_F(FormatEntryPointTest,StreamFailWithV)337 TEST_F(FormatEntryPointTest, StreamFailWithV) {
338 std::ostringstream oss;
339 UntypedFormatSpec format("hello %v");
340 FormatArgImpl arg("non-numeric");
341 oss << str_format_internal::Streamable(
342 str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1});
343 EXPECT_EQ("hello ", oss.str()); // partial write
344 EXPECT_TRUE(oss.fail());
345 }
346
WithSnprintf(const char * fmt,...)347 std::string WithSnprintf(const char* fmt, ...) {
348 std::string buf;
349 buf.resize(128);
350 va_list va;
351 va_start(va, fmt);
352 int r = vsnprintf(&*buf.begin(), buf.size(), fmt, va);
353 va_end(va);
354 EXPECT_GE(r, 0);
355 EXPECT_LT(r, buf.size());
356 buf.resize(r);
357 return buf;
358 }
359
TEST_F(FormatEntryPointTest,FloatPrecisionArg)360 TEST_F(FormatEntryPointTest, FloatPrecisionArg) {
361 // Test that positional parameters for width and precision
362 // are indexed to precede the value.
363 // Also sanity check the same formats against snprintf.
364 EXPECT_EQ("0.1", StrFormat("%.1f", 0.1));
365 EXPECT_EQ("0.1", WithSnprintf("%.1f", 0.1));
366 EXPECT_EQ(" 0.1", StrFormat("%*.1f", 5, 0.1));
367 EXPECT_EQ(" 0.1", WithSnprintf("%*.1f", 5, 0.1));
368 EXPECT_EQ("0.1", StrFormat("%.*f", 1, 0.1));
369 EXPECT_EQ("0.1", WithSnprintf("%.*f", 1, 0.1));
370 EXPECT_EQ(" 0.1", StrFormat("%*.*f", 5, 1, 0.1));
371 EXPECT_EQ(" 0.1", WithSnprintf("%*.*f", 5, 1, 0.1));
372 }
373 namespace streamed_test {
374 struct X {};
operator <<(std::ostream & os,const X &)375 std::ostream& operator<<(std::ostream& os, const X&) {
376 return os << "X";
377 }
378 } // streamed_test
379
TEST_F(FormatEntryPointTest,FormatStreamed)380 TEST_F(FormatEntryPointTest, FormatStreamed) {
381 EXPECT_EQ("123", StrFormat("%s", FormatStreamed(123)));
382 EXPECT_EQ(" 123", StrFormat("%5s", FormatStreamed(123)));
383 EXPECT_EQ("123 ", StrFormat("%-5s", FormatStreamed(123)));
384 EXPECT_EQ("X", StrFormat("%s", FormatStreamed(streamed_test::X())));
385 EXPECT_EQ("123", StrFormat("%s", FormatStreamed(StreamFormat("%d", 123))));
386 }
387
TEST_F(FormatEntryPointTest,FormatStreamedWithV)388 TEST_F(FormatEntryPointTest, FormatStreamedWithV) {
389 EXPECT_EQ("123", StrFormat("%v", FormatStreamed(123)));
390 EXPECT_EQ("X", StrFormat("%v", FormatStreamed(streamed_test::X())));
391 EXPECT_EQ("123", StrFormat("%v", FormatStreamed(StreamFormat("%d", 123))));
392 }
393
394 // Helper class that creates a temporary file and exposes a FILE* to it.
395 // It will close the file on destruction.
396 class TempFile {
397 public:
TempFile()398 TempFile() : file_(std::tmpfile()) {}
~TempFile()399 ~TempFile() { std::fclose(file_); }
400
file() const401 std::FILE* file() const { return file_; }
402
403 // Read the file into a string.
ReadFile()404 std::string ReadFile() {
405 std::fseek(file_, 0, SEEK_END);
406 int size = std::ftell(file_);
407 EXPECT_GT(size, 0);
408 std::rewind(file_);
409 std::string str(2 * size, ' ');
410 int read_bytes = std::fread(&str[0], 1, str.size(), file_);
411 EXPECT_EQ(read_bytes, size);
412 str.resize(read_bytes);
413 EXPECT_TRUE(std::feof(file_));
414 return str;
415 }
416
417 private:
418 std::FILE* file_;
419 };
420
TEST_F(FormatEntryPointTest,FPrintF)421 TEST_F(FormatEntryPointTest, FPrintF) {
422 TempFile tmp;
423 int result =
424 FPrintF(tmp.file(), "STRING: %s NUMBER: %010d", std::string("ABC"), -19);
425 EXPECT_EQ(result, 30);
426 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
427 }
428
TEST_F(FormatEntryPointTest,FPrintFWithV)429 TEST_F(FormatEntryPointTest, FPrintFWithV) {
430 TempFile tmp;
431 int result =
432 FPrintF(tmp.file(), "STRING: %v NUMBER: %010d", std::string("ABC"), -19);
433 EXPECT_EQ(result, 30);
434 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
435 }
436
TEST_F(FormatEntryPointTest,FPrintFError)437 TEST_F(FormatEntryPointTest, FPrintFError) {
438 errno = 0;
439 int result = FPrintF(stdin, "ABC");
440 EXPECT_LT(result, 0);
441 EXPECT_EQ(errno, EBADF);
442 }
443
444 #ifdef __GLIBC__
TEST_F(FormatEntryPointTest,FprintfTooLarge)445 TEST_F(FormatEntryPointTest, FprintfTooLarge) {
446 std::FILE* f = std::fopen("/dev/null", "w");
447 int width = 2000000000;
448 errno = 0;
449 int result = FPrintF(f, "%*d %*d", width, 0, width, 0);
450 EXPECT_LT(result, 0);
451 EXPECT_EQ(errno, EFBIG);
452 std::fclose(f);
453 }
454
TEST_F(FormatEntryPointTest,PrintF)455 TEST_F(FormatEntryPointTest, PrintF) {
456 int stdout_tmp = dup(STDOUT_FILENO);
457
458 TempFile tmp;
459 std::fflush(stdout);
460 dup2(fileno(tmp.file()), STDOUT_FILENO);
461
462 int result = PrintF("STRING: %s NUMBER: %010d", std::string("ABC"), -19);
463
464 std::fflush(stdout);
465 dup2(stdout_tmp, STDOUT_FILENO);
466 close(stdout_tmp);
467
468 EXPECT_EQ(result, 30);
469 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
470 }
471
TEST_F(FormatEntryPointTest,PrintFWithV)472 TEST_F(FormatEntryPointTest, PrintFWithV) {
473 int stdout_tmp = dup(STDOUT_FILENO);
474
475 TempFile tmp;
476 std::fflush(stdout);
477 dup2(fileno(tmp.file()), STDOUT_FILENO);
478
479 int result = PrintF("STRING: %v NUMBER: %010d", std::string("ABC"), -19);
480
481 std::fflush(stdout);
482 dup2(stdout_tmp, STDOUT_FILENO);
483 close(stdout_tmp);
484
485 EXPECT_EQ(result, 30);
486 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
487 }
488 #endif // __GLIBC__
489
TEST_F(FormatEntryPointTest,SNPrintF)490 TEST_F(FormatEntryPointTest, SNPrintF) {
491 char buffer[16];
492 int result =
493 SNPrintF(buffer, sizeof(buffer), "STRING: %s", std::string("ABC"));
494 EXPECT_EQ(result, 11);
495 EXPECT_EQ(std::string(buffer), "STRING: ABC");
496
497 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456);
498 EXPECT_EQ(result, 14);
499 EXPECT_EQ(std::string(buffer), "NUMBER: 123456");
500
501 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 1234567);
502 EXPECT_EQ(result, 15);
503 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
504
505 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 12345678);
506 EXPECT_EQ(result, 16);
507 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
508
509 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456789);
510 EXPECT_EQ(result, 17);
511 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
512
513 result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size");
514 EXPECT_EQ(result, 37);
515 }
516
TEST_F(FormatEntryPointTest,SNPrintFWithV)517 TEST_F(FormatEntryPointTest, SNPrintFWithV) {
518 char buffer[16];
519 int result =
520 SNPrintF(buffer, sizeof(buffer), "STRING: %v", std::string("ABC"));
521 EXPECT_EQ(result, 11);
522 EXPECT_EQ(std::string(buffer), "STRING: ABC");
523
524 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 123456);
525 EXPECT_EQ(result, 14);
526 EXPECT_EQ(std::string(buffer), "NUMBER: 123456");
527
528 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 1234567);
529 EXPECT_EQ(result, 15);
530 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
531
532 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 12345678);
533 EXPECT_EQ(result, 16);
534 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
535
536 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 123456789);
537 EXPECT_EQ(result, 17);
538 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
539
540 std::string size = "size";
541
542 result = SNPrintF(nullptr, 0, "Just checking the %v of the output.", size);
543 EXPECT_EQ(result, 37);
544 }
545
TEST(StrFormat,BehavesAsDocumented)546 TEST(StrFormat, BehavesAsDocumented) {
547 std::string s = absl::StrFormat("%s, %d!", "Hello", 123);
548 EXPECT_EQ("Hello, 123!", s);
549 std::string hello = "Hello";
550 std::string s2 = absl::StrFormat("%v, %v!", hello, 123);
551 EXPECT_EQ("Hello, 123!", s2);
552 // The format of a replacement is
553 // '%'[position][flags][width['.'precision]][length_modifier][format]
554 EXPECT_EQ(absl::StrFormat("%1$+3.2Lf", 1.1), "+1.10");
555 // Text conversion:
556 // "c" - Character. Eg: 'a' -> "A", 20 -> " "
557 EXPECT_EQ(StrFormat("%c", 'a'), "a");
558 EXPECT_EQ(StrFormat("%c", 0x20), " ");
559 // Formats char and integral types: int, long, uint64_t, etc.
560 EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
561 EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT
562 EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
563 // "s" - string Eg: "C" -> "C", std::string("C++") -> "C++"
564 // Formats std::string, char*, string_view, and Cord.
565 EXPECT_EQ(StrFormat("%s", "C"), "C");
566 EXPECT_EQ(StrFormat("%v", std::string("C")), "C");
567 EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
568 EXPECT_EQ(StrFormat("%v", std::string("C++")), "C++");
569 EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
570 EXPECT_EQ(StrFormat("%v", string_view("view")), "view");
571 EXPECT_EQ(StrFormat("%s", absl::Cord("cord")), "cord");
572 EXPECT_EQ(StrFormat("%v", absl::Cord("cord")), "cord");
573 // Integral Conversion
574 // These format integral types: char, int, long, uint64_t, etc.
575 EXPECT_EQ(StrFormat("%d", char{10}), "10");
576 EXPECT_EQ(StrFormat("%d", int{10}), "10");
577 EXPECT_EQ(StrFormat("%d", long{10}), "10"); // NOLINT
578 EXPECT_EQ(StrFormat("%d", uint64_t{10}), "10");
579 EXPECT_EQ(StrFormat("%v", int{10}), "10");
580 EXPECT_EQ(StrFormat("%v", long{10}), "10"); // NOLINT
581 EXPECT_EQ(StrFormat("%v", uint64_t{10}), "10");
582 // d,i - signed decimal Eg: -10 -> "-10"
583 EXPECT_EQ(StrFormat("%d", -10), "-10");
584 EXPECT_EQ(StrFormat("%i", -10), "-10");
585 EXPECT_EQ(StrFormat("%v", -10), "-10");
586 // o - octal Eg: 10 -> "12"
587 EXPECT_EQ(StrFormat("%o", 10), "12");
588 // u - unsigned decimal Eg: 10 -> "10"
589 EXPECT_EQ(StrFormat("%u", 10), "10");
590 EXPECT_EQ(StrFormat("%v", 10), "10");
591 // x/X - lower,upper case hex Eg: 10 -> "a"/"A"
592 EXPECT_EQ(StrFormat("%x", 10), "a");
593 EXPECT_EQ(StrFormat("%X", 10), "A");
594 // Floating-point, with upper/lower-case output.
595 // These format floating points types: float, double, long double, etc.
596 EXPECT_EQ(StrFormat("%.1f", float{1}), "1.0");
597 EXPECT_EQ(StrFormat("%.1f", double{1}), "1.0");
598 const long double long_double = 1.0;
599 EXPECT_EQ(StrFormat("%.1f", long_double), "1.0");
600 // These also format integral types: char, int, long, uint64_t, etc.:
601 EXPECT_EQ(StrFormat("%.1f", char{1}), "1.0");
602 EXPECT_EQ(StrFormat("%.1f", int{1}), "1.0");
603 EXPECT_EQ(StrFormat("%.1f", long{1}), "1.0"); // NOLINT
604 EXPECT_EQ(StrFormat("%.1f", uint64_t{1}), "1.0");
605 // f/F - decimal. Eg: 123456789 -> "123456789.000000"
606 EXPECT_EQ(StrFormat("%f", 123456789), "123456789.000000");
607 EXPECT_EQ(StrFormat("%F", 123456789), "123456789.000000");
608 // e/E - exponentiated Eg: .01 -> "1.00000e-2"/"1.00000E-2"
609 EXPECT_EQ(StrFormat("%e", .01), "1.000000e-02");
610 EXPECT_EQ(StrFormat("%E", .01), "1.000000E-02");
611 // g/G - exponentiate to fit Eg: .01 -> "0.01", 1e10 ->"1e+10"/"1E+10"
612 EXPECT_EQ(StrFormat("%g", .01), "0.01");
613 EXPECT_EQ(StrFormat("%g", 1e10), "1e+10");
614 EXPECT_EQ(StrFormat("%G", 1e10), "1E+10");
615 EXPECT_EQ(StrFormat("%v", .01), "0.01");
616 EXPECT_EQ(StrFormat("%v", 1e10), "1e+10");
617 // a/A - lower,upper case hex Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1"
618
619 // On Android platform <=21, there is a regression in hexfloat formatting.
620 #if !defined(__ANDROID_API__) || __ANDROID_API__ > 21
621 EXPECT_EQ(StrFormat("%.1a", -3.0), "-0x1.8p+1"); // .1 to fix MSVC output
622 EXPECT_EQ(StrFormat("%.1A", -3.0), "-0X1.8P+1"); // .1 to fix MSVC output
623 #endif
624
625 // Other conversion
626 int64_t value = 0x7ffdeb4;
627 auto ptr_value = static_cast<uintptr_t>(value);
628 const int& something = *reinterpret_cast<const int*>(ptr_value);
629 EXPECT_EQ(StrFormat("%p", &something), StrFormat("0x%x", ptr_value));
630
631 // Output widths are supported, with optional flags.
632 EXPECT_EQ(StrFormat("%3d", 1), " 1");
633 EXPECT_EQ(StrFormat("%3d", 123456), "123456");
634 EXPECT_EQ(StrFormat("%06.2f", 1.234), "001.23");
635 EXPECT_EQ(StrFormat("%+d", 1), "+1");
636 EXPECT_EQ(StrFormat("% d", 1), " 1");
637 EXPECT_EQ(StrFormat("%-4d", -1), "-1 ");
638 EXPECT_EQ(StrFormat("%#o", 10), "012");
639 EXPECT_EQ(StrFormat("%#x", 15), "0xf");
640 EXPECT_EQ(StrFormat("%04d", 8), "0008");
641 EXPECT_EQ(StrFormat("%#04x", 0), "0000");
642 EXPECT_EQ(StrFormat("%#04x", 1), "0x01");
643 // Posix positional substitution.
644 EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"),
645 "veni, vidi, vici!");
646 // Length modifiers are ignored.
647 EXPECT_EQ(StrFormat("%hhd", int{1}), "1");
648 EXPECT_EQ(StrFormat("%hd", int{1}), "1");
649 EXPECT_EQ(StrFormat("%ld", int{1}), "1");
650 EXPECT_EQ(StrFormat("%lld", int{1}), "1");
651 EXPECT_EQ(StrFormat("%Ld", int{1}), "1");
652 EXPECT_EQ(StrFormat("%jd", int{1}), "1");
653 EXPECT_EQ(StrFormat("%zd", int{1}), "1");
654 EXPECT_EQ(StrFormat("%td", int{1}), "1");
655 EXPECT_EQ(StrFormat("%qd", int{1}), "1");
656
657 // Bool is handled correctly depending on whether %v is used
658 EXPECT_EQ(StrFormat("%v", true), "true");
659 EXPECT_EQ(StrFormat("%v", false), "false");
660 EXPECT_EQ(StrFormat("%d", true), "1");
661 }
662
663 using str_format_internal::ExtendedParsedFormat;
664 using str_format_internal::ParsedFormatBase;
665
666 struct SummarizeConsumer {
667 std::string* out;
SummarizeConsumerabsl::__anon2f0891220111::SummarizeConsumer668 explicit SummarizeConsumer(std::string* out) : out(out) {}
669
Appendabsl::__anon2f0891220111::SummarizeConsumer670 bool Append(string_view s) {
671 *out += "[" + std::string(s) + "]";
672 return true;
673 }
674
ConvertOneabsl::__anon2f0891220111::SummarizeConsumer675 bool ConvertOne(const str_format_internal::UnboundConversion& conv,
676 string_view s) {
677 *out += "{";
678 *out += std::string(s);
679 *out += ":";
680 *out += std::to_string(conv.arg_position) + "$";
681 if (conv.width.is_from_arg()) {
682 *out += std::to_string(conv.width.get_from_arg()) + "$*";
683 }
684 if (conv.precision.is_from_arg()) {
685 *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
686 }
687 *out += str_format_internal::FormatConversionCharToChar(conv.conv);
688 *out += "}";
689 return true;
690 }
691 };
692
SummarizeParsedFormat(const ParsedFormatBase & pc)693 std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
694 std::string out;
695 if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
696 return out;
697 }
698
699 using ParsedFormatTest = ::testing::Test;
700
TEST_F(ParsedFormatTest,SimpleChecked)701 TEST_F(ParsedFormatTest, SimpleChecked) {
702 EXPECT_EQ("[ABC]{d:1$d}[DEF]",
703 SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF")));
704 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}",
705 SummarizeParsedFormat(ParsedFormat<'s', 'd', 'f'>("%sFFF%dZZZ%f")));
706 EXPECT_EQ("{s:1$s}[ ]{.*d:3$.2$*d}",
707 SummarizeParsedFormat(ParsedFormat<'s', '*', 'd'>("%s %.*d")));
708 }
709
TEST_F(ParsedFormatTest,SimpleCheckedWithV)710 TEST_F(ParsedFormatTest, SimpleCheckedWithV) {
711 EXPECT_EQ("[ABC]{v:1$v}[DEF]",
712 SummarizeParsedFormat(ParsedFormat<'v'>("ABC%vDEF")));
713 EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}",
714 SummarizeParsedFormat(ParsedFormat<'v', 'v', 'f'>("%vFFF%vZZZ%f")));
715 EXPECT_EQ("{v:1$v}[ ]{.*d:3$.2$*d}",
716 SummarizeParsedFormat(ParsedFormat<'v', '*', 'd'>("%v %.*d")));
717 }
718
TEST_F(ParsedFormatTest,SimpleUncheckedCorrect)719 TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) {
720 auto f = ParsedFormat<'d'>::New("ABC%dDEF");
721 ASSERT_TRUE(f);
722 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
723
724 std::string format = "%sFFF%dZZZ%f";
725 auto f2 = ParsedFormat<'s', 'd', 'f'>::New(format);
726
727 ASSERT_TRUE(f2);
728 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
729
730 f2 = ParsedFormat<'s', 'd', 'f'>::New("%s %d %f");
731
732 ASSERT_TRUE(f2);
733 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
734
735 auto star = ParsedFormat<'*', 'd'>::New("%*d");
736 ASSERT_TRUE(star);
737 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
738
739 auto dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d");
740 ASSERT_TRUE(dollar);
741 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
742 // with reuse
743 dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d %1$d");
744 ASSERT_TRUE(dollar);
745 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
746 SummarizeParsedFormat(*dollar));
747 }
748
TEST_F(ParsedFormatTest,SimpleUncheckedCorrectWithV)749 TEST_F(ParsedFormatTest, SimpleUncheckedCorrectWithV) {
750 auto f = ParsedFormat<'v'>::New("ABC%vDEF");
751 ASSERT_TRUE(f);
752 EXPECT_EQ("[ABC]{v:1$v}[DEF]", SummarizeParsedFormat(*f));
753
754 std::string format = "%vFFF%vZZZ%f";
755 auto f2 = ParsedFormat<'v', 'v', 'f'>::New(format);
756
757 ASSERT_TRUE(f2);
758 EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
759
760 f2 = ParsedFormat<'v', 'v', 'f'>::New("%v %v %f");
761
762 ASSERT_TRUE(f2);
763 EXPECT_EQ("{v:1$v}[ ]{v:2$v}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
764 }
765
TEST_F(ParsedFormatTest,SimpleUncheckedIgnoredArgs)766 TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
767 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC")));
768 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("%dABC")));
769 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC%2$s")));
770 auto f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC");
771 ASSERT_TRUE(f);
772 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
773 f = ParsedFormat<'d', 's'>::NewAllowIgnored("%dABC");
774 ASSERT_TRUE(f);
775 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
776 f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC%2$s");
777 ASSERT_TRUE(f);
778 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
779 }
780
TEST_F(ParsedFormatTest,SimpleUncheckedIgnoredArgsWithV)781 TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgsWithV) {
782 EXPECT_FALSE((ParsedFormat<'v', 'v'>::New("ABC")));
783 EXPECT_FALSE((ParsedFormat<'v', 'v'>::New("%vABC")));
784 EXPECT_FALSE((ParsedFormat<'v', 's'>::New("ABC%2$s")));
785 auto f = ParsedFormat<'v', 'v'>::NewAllowIgnored("ABC");
786 ASSERT_TRUE(f);
787 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
788 f = ParsedFormat<'v', 'v'>::NewAllowIgnored("%vABC");
789 ASSERT_TRUE(f);
790 EXPECT_EQ("{v:1$v}[ABC]", SummarizeParsedFormat(*f));
791 }
792
TEST_F(ParsedFormatTest,SimpleUncheckedUnsupported)793 TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) {
794 EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x"));
795 EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x"));
796 }
797
TEST_F(ParsedFormatTest,SimpleUncheckedIncorrect)798 TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
799 EXPECT_FALSE(ParsedFormat<'d'>::New(""));
800
801 EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d"));
802
803 std::string format = "%sFFF%dZZZ%f";
804 EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
805 }
806
TEST_F(ParsedFormatTest,SimpleUncheckedIncorrectWithV)807 TEST_F(ParsedFormatTest, SimpleUncheckedIncorrectWithV) {
808 EXPECT_FALSE(ParsedFormat<'v'>::New(""));
809
810 EXPECT_FALSE(ParsedFormat<'v'>::New("ABC%vDEF%v"));
811
812 std::string format = "%vFFF%vZZZ%f";
813 EXPECT_FALSE((ParsedFormat<'v', 'v', 'g'>::New(format)));
814 }
815
816 #if defined(__cpp_nontype_template_parameter_auto)
817
818 template <auto T>
819 std::true_type IsValidParsedFormatArgTest(ParsedFormat<T>*);
820
821 template <auto T>
822 std::false_type IsValidParsedFormatArgTest(...);
823
824 template <auto T>
825 using IsValidParsedFormatArg = decltype(IsValidParsedFormatArgTest<T>(nullptr));
826
TEST_F(ParsedFormatTest,OnlyValidTypesAllowed)827 TEST_F(ParsedFormatTest, OnlyValidTypesAllowed) {
828 ASSERT_TRUE(IsValidParsedFormatArg<'c'>::value);
829
830 ASSERT_TRUE(IsValidParsedFormatArg<FormatConversionCharSet::d>::value);
831
832 ASSERT_TRUE(IsValidParsedFormatArg<absl::FormatConversionCharSet::d |
833 absl::FormatConversionCharSet::x>::value);
834 ASSERT_TRUE(
835 IsValidParsedFormatArg<absl::FormatConversionCharSet::kIntegral>::value);
836
837 // This is an easy mistake to make, however, this will reduce to an integer
838 // which has no meaning, so we need to ensure it doesn't compile.
839 ASSERT_FALSE(IsValidParsedFormatArg<'x' | 'd'>::value);
840
841 // For now, we disallow construction based on ConversionChar (rather than
842 // CharSet)
843 ASSERT_FALSE(IsValidParsedFormatArg<absl::FormatConversionChar::d>::value);
844 }
845
TEST_F(ParsedFormatTest,ExtendedTyping)846 TEST_F(ParsedFormatTest, ExtendedTyping) {
847 EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::d>::New(""));
848 ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::d>::New("%d"));
849 auto v1 = ParsedFormat<'d', absl::FormatConversionCharSet::s>::New("%d%s");
850 ASSERT_TRUE(v1);
851 auto v2 = ParsedFormat<absl::FormatConversionCharSet::d, 's'>::New("%d%s");
852 ASSERT_TRUE(v2);
853 auto v3 = ParsedFormat<absl::FormatConversionCharSet::d |
854 absl::FormatConversionCharSet::s,
855 's'>::New("%d%s");
856 ASSERT_TRUE(v3);
857 auto v4 = ParsedFormat<absl::FormatConversionCharSet::d |
858 absl::FormatConversionCharSet::s,
859 's'>::New("%s%s");
860 ASSERT_TRUE(v4);
861 }
862
TEST_F(ParsedFormatTest,ExtendedTypingWithV)863 TEST_F(ParsedFormatTest, ExtendedTypingWithV) {
864 EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::v>::New(""));
865 ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::v>::New("%v"));
866 auto v1 = ParsedFormat<'v', absl::FormatConversionCharSet::v>::New("%v%v");
867 ASSERT_TRUE(v1);
868 auto v2 = ParsedFormat<absl::FormatConversionCharSet::v, 'v'>::New("%v%v");
869 ASSERT_TRUE(v2);
870 auto v3 = ParsedFormat<absl::FormatConversionCharSet::v |
871 absl::FormatConversionCharSet::v,
872 'v'>::New("%v%v");
873 ASSERT_TRUE(v3);
874 auto v4 = ParsedFormat<absl::FormatConversionCharSet::v |
875 absl::FormatConversionCharSet::v,
876 'v'>::New("%v%v");
877 ASSERT_TRUE(v4);
878 }
879 #endif
880
TEST_F(ParsedFormatTest,UncheckedCorrect)881 TEST_F(ParsedFormatTest, UncheckedCorrect) {
882 auto f =
883 ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New("ABC%dDEF");
884 ASSERT_TRUE(f);
885 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
886
887 std::string format = "%sFFF%dZZZ%f";
888 auto f2 = ExtendedParsedFormat<
889 absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
890 absl::FormatConversionCharSet::kFloating>::New(format);
891
892 ASSERT_TRUE(f2);
893 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
894
895 f2 = ExtendedParsedFormat<
896 absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
897 absl::FormatConversionCharSet::kFloating>::New("%s %d %f");
898
899 ASSERT_TRUE(f2);
900 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
901
902 auto star =
903 ExtendedParsedFormat<absl::FormatConversionCharSet::kStar,
904 absl::FormatConversionCharSet::d>::New("%*d");
905 ASSERT_TRUE(star);
906 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
907
908 auto dollar =
909 ExtendedParsedFormat<absl::FormatConversionCharSet::d,
910 absl::FormatConversionCharSet::s>::New("%2$s %1$d");
911 ASSERT_TRUE(dollar);
912 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
913 // with reuse
914 dollar = ExtendedParsedFormat<
915 absl::FormatConversionCharSet::d,
916 absl::FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
917 ASSERT_TRUE(dollar);
918 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
919 SummarizeParsedFormat(*dollar));
920 }
921
TEST_F(ParsedFormatTest,UncheckedCorrectWithV)922 TEST_F(ParsedFormatTest, UncheckedCorrectWithV) {
923 auto f =
924 ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New("ABC%vDEF");
925 ASSERT_TRUE(f);
926 EXPECT_EQ("[ABC]{v:1$v}[DEF]", SummarizeParsedFormat(*f));
927
928 std::string format = "%vFFF%vZZZ%f";
929 auto f2 = ExtendedParsedFormat<
930 absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::v,
931 absl::FormatConversionCharSet::kFloating>::New(format);
932
933 ASSERT_TRUE(f2);
934 EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
935
936 f2 = ExtendedParsedFormat<
937 absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::v,
938 absl::FormatConversionCharSet::kFloating>::New("%v %v %f");
939
940 ASSERT_TRUE(f2);
941 EXPECT_EQ("{v:1$v}[ ]{v:2$v}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
942 }
943
TEST_F(ParsedFormatTest,UncheckedIgnoredArgs)944 TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
945 EXPECT_FALSE(
946 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
947 absl::FormatConversionCharSet::s>::New("ABC")));
948 EXPECT_FALSE(
949 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
950 absl::FormatConversionCharSet::s>::New("%dABC")));
951 EXPECT_FALSE(
952 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
953 absl::FormatConversionCharSet::s>::New("ABC%2$s")));
954 auto f = ExtendedParsedFormat<
955 absl::FormatConversionCharSet::d,
956 absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC");
957 ASSERT_TRUE(f);
958 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
959 f = ExtendedParsedFormat<
960 absl::FormatConversionCharSet::d,
961 absl::FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
962 ASSERT_TRUE(f);
963 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
964 f = ExtendedParsedFormat<
965 absl::FormatConversionCharSet::d,
966 absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
967 ASSERT_TRUE(f);
968 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
969 }
970
TEST_F(ParsedFormatTest,UncheckedIgnoredArgsWithV)971 TEST_F(ParsedFormatTest, UncheckedIgnoredArgsWithV) {
972 EXPECT_FALSE(
973 (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
974 absl::FormatConversionCharSet::v>::New("ABC")));
975 EXPECT_FALSE(
976 (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
977 absl::FormatConversionCharSet::v>::New("%vABC")));
978 EXPECT_FALSE((ExtendedParsedFormat<absl::FormatConversionCharSet::v,
979 absl::FormatConversionCharSet::s>::
980 New("ABC%2$s")));
981 auto f = ExtendedParsedFormat<
982 absl::FormatConversionCharSet::v,
983 absl::FormatConversionCharSet::v>::NewAllowIgnored("ABC");
984 ASSERT_TRUE(f);
985 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
986 f = ExtendedParsedFormat<
987 absl::FormatConversionCharSet::v,
988 absl::FormatConversionCharSet::v>::NewAllowIgnored("%vABC");
989 ASSERT_TRUE(f);
990 EXPECT_EQ("{v:1$v}[ABC]", SummarizeParsedFormat(*f));
991 }
992
TEST_F(ParsedFormatTest,UncheckedMultipleTypes)993 TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
994 auto dx =
995 ExtendedParsedFormat<absl::FormatConversionCharSet::d |
996 absl::FormatConversionCharSet::x>::New("%1$d %1$x");
997 EXPECT_TRUE(dx);
998 EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
999
1000 dx = ExtendedParsedFormat<absl::FormatConversionCharSet::d |
1001 absl::FormatConversionCharSet::x>::New("%1$d");
1002 EXPECT_TRUE(dx);
1003 EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
1004 }
1005
TEST_F(ParsedFormatTest,UncheckedIncorrect)1006 TEST_F(ParsedFormatTest, UncheckedIncorrect) {
1007 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(""));
1008
1009 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(
1010 "ABC%dDEF%d"));
1011
1012 std::string format = "%sFFF%dZZZ%f";
1013 EXPECT_FALSE(
1014 (ExtendedParsedFormat<absl::FormatConversionCharSet::s,
1015 absl::FormatConversionCharSet::d,
1016 absl::FormatConversionCharSet::g>::New(format)));
1017 }
1018
TEST_F(ParsedFormatTest,UncheckedIncorrectWithV)1019 TEST_F(ParsedFormatTest, UncheckedIncorrectWithV) {
1020 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New(""));
1021
1022 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New(
1023 "ABC%vDEF%v"));
1024
1025 std::string format = "%vFFF%vZZZ%f";
1026 EXPECT_FALSE(
1027 (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
1028 absl::FormatConversionCharSet::g>::New(format)));
1029 }
1030
TEST_F(ParsedFormatTest,RegressionMixPositional)1031 TEST_F(ParsedFormatTest, RegressionMixPositional) {
1032 EXPECT_FALSE(
1033 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
1034 absl::FormatConversionCharSet::o>::New("%1$d %o")));
1035 }
1036
TEST_F(ParsedFormatTest,DisallowModifiersWithV)1037 TEST_F(ParsedFormatTest, DisallowModifiersWithV) {
1038 auto f = ParsedFormat<'v'>::New("ABC%80vDEF");
1039 EXPECT_EQ(f, nullptr);
1040
1041 f = ParsedFormat<'v'>::New("ABC%0vDEF");
1042 EXPECT_EQ(f, nullptr);
1043
1044 f = ParsedFormat<'v'>::New("ABC%.1vDEF");
1045 EXPECT_EQ(f, nullptr);
1046 }
1047
1048 using FormatWrapperTest = ::testing::Test;
1049
1050 // Plain wrapper for StrFormat.
1051 template <typename... Args>
WrappedFormat(const absl::FormatSpec<Args...> & format,const Args &...args)1052 std::string WrappedFormat(const absl::FormatSpec<Args...>& format,
1053 const Args&... args) {
1054 return StrFormat(format, args...);
1055 }
1056
TEST_F(FormatWrapperTest,ConstexprStringFormat)1057 TEST_F(FormatWrapperTest, ConstexprStringFormat) {
1058 EXPECT_EQ(WrappedFormat("%s there", "hello"), "hello there");
1059 }
1060
TEST_F(FormatWrapperTest,ConstexprStringFormatWithV)1061 TEST_F(FormatWrapperTest, ConstexprStringFormatWithV) {
1062 std::string hello = "hello";
1063 EXPECT_EQ(WrappedFormat("%v there", hello), "hello there");
1064 }
1065
TEST_F(FormatWrapperTest,ParsedFormat)1066 TEST_F(FormatWrapperTest, ParsedFormat) {
1067 ParsedFormat<'s'> format("%s there");
1068 EXPECT_EQ(WrappedFormat(format, "hello"), "hello there");
1069 }
1070
TEST_F(FormatWrapperTest,ParsedFormatWithV)1071 TEST_F(FormatWrapperTest, ParsedFormatWithV) {
1072 std::string hello = "hello";
1073 ParsedFormat<'v'> format("%v there");
1074 EXPECT_EQ(WrappedFormat(format, hello), "hello there");
1075 }
1076
1077 } // namespace
1078 ABSL_NAMESPACE_END
1079 } // namespace absl
1080
1081 namespace {
1082 using FormatExtensionTest = ::testing::Test;
1083
1084 struct Point {
1085 friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
1086 absl::FormatConversionCharSet::kIntegral |
1087 absl::FormatConversionCharSet::v>
AbslFormatConvert(const Point & p,const absl::FormatConversionSpec & spec,absl::FormatSink * s)1088 AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
1089 absl::FormatSink* s) {
1090 if (spec.conversion_char() == absl::FormatConversionChar::s) {
1091 s->Append(absl::StrCat("x=", p.x, " y=", p.y));
1092 } else {
1093 s->Append(absl::StrCat(p.x, ",", p.y));
1094 }
1095 return {true};
1096 }
1097
1098 int x = 10;
1099 int y = 20;
1100 };
1101
TEST_F(FormatExtensionTest,AbslFormatConvertExample)1102 TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
1103 Point p;
1104 EXPECT_EQ(absl::StrFormat("a %s z", p), "a x=10 y=20 z");
1105 EXPECT_EQ(absl::StrFormat("a %d z", p), "a 10,20 z");
1106 EXPECT_EQ(absl::StrFormat("a %v z", p), "a 10,20 z");
1107
1108 // Typed formatting will fail to compile an invalid format.
1109 // StrFormat("%f", p); // Does not compile.
1110 std::string actual;
1111 absl::UntypedFormatSpec f1("%f");
1112 // FormatUntyped will return false for bad character.
1113 EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)}));
1114 }
1115
1116 struct PointStringify {
1117 template <typename FormatSink>
AbslStringify(FormatSink & sink,const PointStringify & p)1118 friend void AbslStringify(FormatSink& sink, const PointStringify& p) {
1119 sink.Append(absl::StrCat("(", p.x, ", ", p.y, ")"));
1120 }
1121
1122 double x = 10.0;
1123 double y = 20.0;
1124 };
1125
TEST_F(FormatExtensionTest,AbslStringifyExample)1126 TEST_F(FormatExtensionTest, AbslStringifyExample) {
1127 PointStringify p;
1128 EXPECT_EQ(absl::StrFormat("a %v z", p), "a (10, 20) z");
1129 }
1130
1131 struct PointStringifyUsingFormat {
1132 template <typename FormatSink>
AbslStringify(FormatSink & sink,const PointStringifyUsingFormat & p)1133 friend void AbslStringify(FormatSink& sink,
1134 const PointStringifyUsingFormat& p) {
1135 absl::Format(&sink, "(%g, %g)", p.x, p.y);
1136 }
1137
1138 double x = 10.0;
1139 double y = 20.0;
1140 };
1141
TEST_F(FormatExtensionTest,AbslStringifyExampleUsingFormat)1142 TEST_F(FormatExtensionTest, AbslStringifyExampleUsingFormat) {
1143 PointStringifyUsingFormat p;
1144 EXPECT_EQ(absl::StrFormat("a %v z", p), "a (10, 20) z");
1145 }
1146
1147 enum class EnumClassWithStringify { Many = 0, Choices = 1 };
1148
1149 template <typename Sink>
AbslStringify(Sink & sink,EnumClassWithStringify e)1150 void AbslStringify(Sink& sink, EnumClassWithStringify e) {
1151 absl::Format(&sink, "%s",
1152 e == EnumClassWithStringify::Many ? "Many" : "Choices");
1153 }
1154
1155 enum EnumWithStringify { Many, Choices };
1156
1157 template <typename Sink>
AbslStringify(Sink & sink,EnumWithStringify e)1158 void AbslStringify(Sink& sink, EnumWithStringify e) {
1159 absl::Format(&sink, "%s", e == EnumWithStringify::Many ? "Many" : "Choices");
1160 }
1161
TEST_F(FormatExtensionTest,AbslStringifyWithEnumWithV)1162 TEST_F(FormatExtensionTest, AbslStringifyWithEnumWithV) {
1163 const auto e_class = EnumClassWithStringify::Choices;
1164 EXPECT_EQ(absl::StrFormat("My choice is %v", e_class),
1165 "My choice is Choices");
1166
1167 const auto e = EnumWithStringify::Choices;
1168 EXPECT_EQ(absl::StrFormat("My choice is %v", e), "My choice is Choices");
1169 }
1170
TEST_F(FormatExtensionTest,AbslStringifyEnumWithD)1171 TEST_F(FormatExtensionTest, AbslStringifyEnumWithD) {
1172 const auto e_class = EnumClassWithStringify::Many;
1173 EXPECT_EQ(absl::StrFormat("My choice is %d", e_class), "My choice is 0");
1174
1175 const auto e = EnumWithStringify::Choices;
1176 EXPECT_EQ(absl::StrFormat("My choice is %d", e), "My choice is 1");
1177 }
1178
1179 enum class EnumWithLargerValue { x = 32 };
1180
1181 template <typename Sink>
AbslStringify(Sink & sink,EnumWithLargerValue e)1182 void AbslStringify(Sink& sink, EnumWithLargerValue e) {
1183 absl::Format(&sink, "%s", "Many");
1184 }
1185
TEST_F(FormatExtensionTest,AbslStringifyEnumOtherSpecifiers)1186 TEST_F(FormatExtensionTest, AbslStringifyEnumOtherSpecifiers) {
1187 const auto e = EnumWithLargerValue::x;
1188 EXPECT_EQ(absl::StrFormat("My choice is %g", e), "My choice is 32");
1189 EXPECT_EQ(absl::StrFormat("My choice is %x", e), "My choice is 20");
1190 }
1191
1192 } // namespace
1193
1194 // Some codegen thunks that we can use to easily dump the generated assembly for
1195 // different StrFormat calls.
1196
CodegenAbslStrFormatInt(int i)1197 std::string CodegenAbslStrFormatInt(int i) { // NOLINT
1198 return absl::StrFormat("%d", i);
1199 }
1200
CodegenAbslStrFormatIntStringInt64(int i,const std::string & s,int64_t i64)1201 std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
1202 int64_t i64) { // NOLINT
1203 return absl::StrFormat("%d %s %d", i, s, i64);
1204 }
1205
CodegenAbslStrAppendFormatInt(std::string * out,int i)1206 void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
1207 absl::StrAppendFormat(out, "%d", i);
1208 }
1209
CodegenAbslStrAppendFormatIntStringInt64(std::string * out,int i,const std::string & s,int64_t i64)1210 void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
1211 const std::string& s,
1212 int64_t i64) { // NOLINT
1213 absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
1214 }
1215