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 // Posix positional substitution.
642 EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"),
643 "veni, vidi, vici!");
644 // Length modifiers are ignored.
645 EXPECT_EQ(StrFormat("%hhd", int{1}), "1");
646 EXPECT_EQ(StrFormat("%hd", int{1}), "1");
647 EXPECT_EQ(StrFormat("%ld", int{1}), "1");
648 EXPECT_EQ(StrFormat("%lld", int{1}), "1");
649 EXPECT_EQ(StrFormat("%Ld", int{1}), "1");
650 EXPECT_EQ(StrFormat("%jd", int{1}), "1");
651 EXPECT_EQ(StrFormat("%zd", int{1}), "1");
652 EXPECT_EQ(StrFormat("%td", int{1}), "1");
653 EXPECT_EQ(StrFormat("%qd", int{1}), "1");
654
655 // Bool is handled correctly depending on whether %v is used
656 EXPECT_EQ(StrFormat("%v", true), "true");
657 EXPECT_EQ(StrFormat("%v", false), "false");
658 EXPECT_EQ(StrFormat("%d", true), "1");
659 }
660
661 using str_format_internal::ExtendedParsedFormat;
662 using str_format_internal::ParsedFormatBase;
663
664 struct SummarizeConsumer {
665 std::string* out;
SummarizeConsumerabsl::__anon42b928b60111::SummarizeConsumer666 explicit SummarizeConsumer(std::string* out) : out(out) {}
667
Appendabsl::__anon42b928b60111::SummarizeConsumer668 bool Append(string_view s) {
669 *out += "[" + std::string(s) + "]";
670 return true;
671 }
672
ConvertOneabsl::__anon42b928b60111::SummarizeConsumer673 bool ConvertOne(const str_format_internal::UnboundConversion& conv,
674 string_view s) {
675 *out += "{";
676 *out += std::string(s);
677 *out += ":";
678 *out += std::to_string(conv.arg_position) + "$";
679 if (conv.width.is_from_arg()) {
680 *out += std::to_string(conv.width.get_from_arg()) + "$*";
681 }
682 if (conv.precision.is_from_arg()) {
683 *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
684 }
685 *out += str_format_internal::FormatConversionCharToChar(conv.conv);
686 *out += "}";
687 return true;
688 }
689 };
690
SummarizeParsedFormat(const ParsedFormatBase & pc)691 std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
692 std::string out;
693 if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
694 return out;
695 }
696
697 using ParsedFormatTest = ::testing::Test;
698
TEST_F(ParsedFormatTest,SimpleChecked)699 TEST_F(ParsedFormatTest, SimpleChecked) {
700 EXPECT_EQ("[ABC]{d:1$d}[DEF]",
701 SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF")));
702 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}",
703 SummarizeParsedFormat(ParsedFormat<'s', 'd', 'f'>("%sFFF%dZZZ%f")));
704 EXPECT_EQ("{s:1$s}[ ]{.*d:3$.2$*d}",
705 SummarizeParsedFormat(ParsedFormat<'s', '*', 'd'>("%s %.*d")));
706 }
707
TEST_F(ParsedFormatTest,SimpleCheckedWithV)708 TEST_F(ParsedFormatTest, SimpleCheckedWithV) {
709 EXPECT_EQ("[ABC]{v:1$v}[DEF]",
710 SummarizeParsedFormat(ParsedFormat<'v'>("ABC%vDEF")));
711 EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}",
712 SummarizeParsedFormat(ParsedFormat<'v', 'v', 'f'>("%vFFF%vZZZ%f")));
713 EXPECT_EQ("{v:1$v}[ ]{.*d:3$.2$*d}",
714 SummarizeParsedFormat(ParsedFormat<'v', '*', 'd'>("%v %.*d")));
715 }
716
TEST_F(ParsedFormatTest,SimpleUncheckedCorrect)717 TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) {
718 auto f = ParsedFormat<'d'>::New("ABC%dDEF");
719 ASSERT_TRUE(f);
720 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
721
722 std::string format = "%sFFF%dZZZ%f";
723 auto f2 = ParsedFormat<'s', 'd', 'f'>::New(format);
724
725 ASSERT_TRUE(f2);
726 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
727
728 f2 = ParsedFormat<'s', 'd', 'f'>::New("%s %d %f");
729
730 ASSERT_TRUE(f2);
731 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
732
733 auto star = ParsedFormat<'*', 'd'>::New("%*d");
734 ASSERT_TRUE(star);
735 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
736
737 auto dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d");
738 ASSERT_TRUE(dollar);
739 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
740 // with reuse
741 dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d %1$d");
742 ASSERT_TRUE(dollar);
743 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
744 SummarizeParsedFormat(*dollar));
745 }
746
TEST_F(ParsedFormatTest,SimpleUncheckedCorrectWithV)747 TEST_F(ParsedFormatTest, SimpleUncheckedCorrectWithV) {
748 auto f = ParsedFormat<'v'>::New("ABC%vDEF");
749 ASSERT_TRUE(f);
750 EXPECT_EQ("[ABC]{v:1$v}[DEF]", SummarizeParsedFormat(*f));
751
752 std::string format = "%vFFF%vZZZ%f";
753 auto f2 = ParsedFormat<'v', 'v', 'f'>::New(format);
754
755 ASSERT_TRUE(f2);
756 EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
757
758 f2 = ParsedFormat<'v', 'v', 'f'>::New("%v %v %f");
759
760 ASSERT_TRUE(f2);
761 EXPECT_EQ("{v:1$v}[ ]{v:2$v}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
762 }
763
TEST_F(ParsedFormatTest,SimpleUncheckedIgnoredArgs)764 TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
765 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC")));
766 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("%dABC")));
767 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC%2$s")));
768 auto f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC");
769 ASSERT_TRUE(f);
770 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
771 f = ParsedFormat<'d', 's'>::NewAllowIgnored("%dABC");
772 ASSERT_TRUE(f);
773 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
774 f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC%2$s");
775 ASSERT_TRUE(f);
776 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
777 }
778
TEST_F(ParsedFormatTest,SimpleUncheckedIgnoredArgsWithV)779 TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgsWithV) {
780 EXPECT_FALSE((ParsedFormat<'v', 'v'>::New("ABC")));
781 EXPECT_FALSE((ParsedFormat<'v', 'v'>::New("%vABC")));
782 EXPECT_FALSE((ParsedFormat<'v', 's'>::New("ABC%2$s")));
783 auto f = ParsedFormat<'v', 'v'>::NewAllowIgnored("ABC");
784 ASSERT_TRUE(f);
785 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
786 f = ParsedFormat<'v', 'v'>::NewAllowIgnored("%vABC");
787 ASSERT_TRUE(f);
788 EXPECT_EQ("{v:1$v}[ABC]", SummarizeParsedFormat(*f));
789 }
790
TEST_F(ParsedFormatTest,SimpleUncheckedUnsupported)791 TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) {
792 EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x"));
793 EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x"));
794 }
795
TEST_F(ParsedFormatTest,SimpleUncheckedIncorrect)796 TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
797 EXPECT_FALSE(ParsedFormat<'d'>::New(""));
798
799 EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d"));
800
801 std::string format = "%sFFF%dZZZ%f";
802 EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
803 }
804
TEST_F(ParsedFormatTest,SimpleUncheckedIncorrectWithV)805 TEST_F(ParsedFormatTest, SimpleUncheckedIncorrectWithV) {
806 EXPECT_FALSE(ParsedFormat<'v'>::New(""));
807
808 EXPECT_FALSE(ParsedFormat<'v'>::New("ABC%vDEF%v"));
809
810 std::string format = "%vFFF%vZZZ%f";
811 EXPECT_FALSE((ParsedFormat<'v', 'v', 'g'>::New(format)));
812 }
813
814 #if defined(__cpp_nontype_template_parameter_auto)
815
816 template <auto T>
817 std::true_type IsValidParsedFormatArgTest(ParsedFormat<T>*);
818
819 template <auto T>
820 std::false_type IsValidParsedFormatArgTest(...);
821
822 template <auto T>
823 using IsValidParsedFormatArg = decltype(IsValidParsedFormatArgTest<T>(nullptr));
824
TEST_F(ParsedFormatTest,OnlyValidTypesAllowed)825 TEST_F(ParsedFormatTest, OnlyValidTypesAllowed) {
826 ASSERT_TRUE(IsValidParsedFormatArg<'c'>::value);
827
828 ASSERT_TRUE(IsValidParsedFormatArg<FormatConversionCharSet::d>::value);
829
830 ASSERT_TRUE(IsValidParsedFormatArg<absl::FormatConversionCharSet::d |
831 absl::FormatConversionCharSet::x>::value);
832 ASSERT_TRUE(
833 IsValidParsedFormatArg<absl::FormatConversionCharSet::kIntegral>::value);
834
835 // This is an easy mistake to make, however, this will reduce to an integer
836 // which has no meaning, so we need to ensure it doesn't compile.
837 ASSERT_FALSE(IsValidParsedFormatArg<'x' | 'd'>::value);
838
839 // For now, we disallow construction based on ConversionChar (rather than
840 // CharSet)
841 ASSERT_FALSE(IsValidParsedFormatArg<absl::FormatConversionChar::d>::value);
842 }
843
TEST_F(ParsedFormatTest,ExtendedTyping)844 TEST_F(ParsedFormatTest, ExtendedTyping) {
845 EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::d>::New(""));
846 ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::d>::New("%d"));
847 auto v1 = ParsedFormat<'d', absl::FormatConversionCharSet::s>::New("%d%s");
848 ASSERT_TRUE(v1);
849 auto v2 = ParsedFormat<absl::FormatConversionCharSet::d, 's'>::New("%d%s");
850 ASSERT_TRUE(v2);
851 auto v3 = ParsedFormat<absl::FormatConversionCharSet::d |
852 absl::FormatConversionCharSet::s,
853 's'>::New("%d%s");
854 ASSERT_TRUE(v3);
855 auto v4 = ParsedFormat<absl::FormatConversionCharSet::d |
856 absl::FormatConversionCharSet::s,
857 's'>::New("%s%s");
858 ASSERT_TRUE(v4);
859 }
860
TEST_F(ParsedFormatTest,ExtendedTypingWithV)861 TEST_F(ParsedFormatTest, ExtendedTypingWithV) {
862 EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::v>::New(""));
863 ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::v>::New("%v"));
864 auto v1 = ParsedFormat<'v', absl::FormatConversionCharSet::v>::New("%v%v");
865 ASSERT_TRUE(v1);
866 auto v2 = ParsedFormat<absl::FormatConversionCharSet::v, 'v'>::New("%v%v");
867 ASSERT_TRUE(v2);
868 auto v3 = ParsedFormat<absl::FormatConversionCharSet::v |
869 absl::FormatConversionCharSet::v,
870 'v'>::New("%v%v");
871 ASSERT_TRUE(v3);
872 auto v4 = ParsedFormat<absl::FormatConversionCharSet::v |
873 absl::FormatConversionCharSet::v,
874 'v'>::New("%v%v");
875 ASSERT_TRUE(v4);
876 }
877 #endif
878
TEST_F(ParsedFormatTest,UncheckedCorrect)879 TEST_F(ParsedFormatTest, UncheckedCorrect) {
880 auto f =
881 ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New("ABC%dDEF");
882 ASSERT_TRUE(f);
883 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
884
885 std::string format = "%sFFF%dZZZ%f";
886 auto f2 = ExtendedParsedFormat<
887 absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
888 absl::FormatConversionCharSet::kFloating>::New(format);
889
890 ASSERT_TRUE(f2);
891 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
892
893 f2 = ExtendedParsedFormat<
894 absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
895 absl::FormatConversionCharSet::kFloating>::New("%s %d %f");
896
897 ASSERT_TRUE(f2);
898 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
899
900 auto star =
901 ExtendedParsedFormat<absl::FormatConversionCharSet::kStar,
902 absl::FormatConversionCharSet::d>::New("%*d");
903 ASSERT_TRUE(star);
904 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
905
906 auto dollar =
907 ExtendedParsedFormat<absl::FormatConversionCharSet::d,
908 absl::FormatConversionCharSet::s>::New("%2$s %1$d");
909 ASSERT_TRUE(dollar);
910 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
911 // with reuse
912 dollar = ExtendedParsedFormat<
913 absl::FormatConversionCharSet::d,
914 absl::FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
915 ASSERT_TRUE(dollar);
916 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
917 SummarizeParsedFormat(*dollar));
918 }
919
TEST_F(ParsedFormatTest,UncheckedCorrectWithV)920 TEST_F(ParsedFormatTest, UncheckedCorrectWithV) {
921 auto f =
922 ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New("ABC%vDEF");
923 ASSERT_TRUE(f);
924 EXPECT_EQ("[ABC]{v:1$v}[DEF]", SummarizeParsedFormat(*f));
925
926 std::string format = "%vFFF%vZZZ%f";
927 auto f2 = ExtendedParsedFormat<
928 absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::v,
929 absl::FormatConversionCharSet::kFloating>::New(format);
930
931 ASSERT_TRUE(f2);
932 EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
933
934 f2 = ExtendedParsedFormat<
935 absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::v,
936 absl::FormatConversionCharSet::kFloating>::New("%v %v %f");
937
938 ASSERT_TRUE(f2);
939 EXPECT_EQ("{v:1$v}[ ]{v:2$v}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
940 }
941
TEST_F(ParsedFormatTest,UncheckedIgnoredArgs)942 TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
943 EXPECT_FALSE(
944 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
945 absl::FormatConversionCharSet::s>::New("ABC")));
946 EXPECT_FALSE(
947 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
948 absl::FormatConversionCharSet::s>::New("%dABC")));
949 EXPECT_FALSE(
950 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
951 absl::FormatConversionCharSet::s>::New("ABC%2$s")));
952 auto f = ExtendedParsedFormat<
953 absl::FormatConversionCharSet::d,
954 absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC");
955 ASSERT_TRUE(f);
956 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
957 f = ExtendedParsedFormat<
958 absl::FormatConversionCharSet::d,
959 absl::FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
960 ASSERT_TRUE(f);
961 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
962 f = ExtendedParsedFormat<
963 absl::FormatConversionCharSet::d,
964 absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
965 ASSERT_TRUE(f);
966 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
967 }
968
TEST_F(ParsedFormatTest,UncheckedIgnoredArgsWithV)969 TEST_F(ParsedFormatTest, UncheckedIgnoredArgsWithV) {
970 EXPECT_FALSE(
971 (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
972 absl::FormatConversionCharSet::v>::New("ABC")));
973 EXPECT_FALSE(
974 (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
975 absl::FormatConversionCharSet::v>::New("%vABC")));
976 EXPECT_FALSE((ExtendedParsedFormat<absl::FormatConversionCharSet::v,
977 absl::FormatConversionCharSet::s>::
978 New("ABC%2$s")));
979 auto f = ExtendedParsedFormat<
980 absl::FormatConversionCharSet::v,
981 absl::FormatConversionCharSet::v>::NewAllowIgnored("ABC");
982 ASSERT_TRUE(f);
983 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
984 f = ExtendedParsedFormat<
985 absl::FormatConversionCharSet::v,
986 absl::FormatConversionCharSet::v>::NewAllowIgnored("%vABC");
987 ASSERT_TRUE(f);
988 EXPECT_EQ("{v:1$v}[ABC]", SummarizeParsedFormat(*f));
989 }
990
TEST_F(ParsedFormatTest,UncheckedMultipleTypes)991 TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
992 auto dx =
993 ExtendedParsedFormat<absl::FormatConversionCharSet::d |
994 absl::FormatConversionCharSet::x>::New("%1$d %1$x");
995 EXPECT_TRUE(dx);
996 EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
997
998 dx = ExtendedParsedFormat<absl::FormatConversionCharSet::d |
999 absl::FormatConversionCharSet::x>::New("%1$d");
1000 EXPECT_TRUE(dx);
1001 EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
1002 }
1003
TEST_F(ParsedFormatTest,UncheckedIncorrect)1004 TEST_F(ParsedFormatTest, UncheckedIncorrect) {
1005 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(""));
1006
1007 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(
1008 "ABC%dDEF%d"));
1009
1010 std::string format = "%sFFF%dZZZ%f";
1011 EXPECT_FALSE(
1012 (ExtendedParsedFormat<absl::FormatConversionCharSet::s,
1013 absl::FormatConversionCharSet::d,
1014 absl::FormatConversionCharSet::g>::New(format)));
1015 }
1016
TEST_F(ParsedFormatTest,UncheckedIncorrectWithV)1017 TEST_F(ParsedFormatTest, UncheckedIncorrectWithV) {
1018 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New(""));
1019
1020 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New(
1021 "ABC%vDEF%v"));
1022
1023 std::string format = "%vFFF%vZZZ%f";
1024 EXPECT_FALSE(
1025 (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
1026 absl::FormatConversionCharSet::g>::New(format)));
1027 }
1028
TEST_F(ParsedFormatTest,RegressionMixPositional)1029 TEST_F(ParsedFormatTest, RegressionMixPositional) {
1030 EXPECT_FALSE(
1031 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
1032 absl::FormatConversionCharSet::o>::New("%1$d %o")));
1033 }
1034
TEST_F(ParsedFormatTest,DisallowModifiersWithV)1035 TEST_F(ParsedFormatTest, DisallowModifiersWithV) {
1036 auto f = ParsedFormat<'v'>::New("ABC%80vDEF");
1037 EXPECT_EQ(f, nullptr);
1038
1039 f = ParsedFormat<'v'>::New("ABC%0vDEF");
1040 EXPECT_EQ(f, nullptr);
1041
1042 f = ParsedFormat<'v'>::New("ABC%.1vDEF");
1043 EXPECT_EQ(f, nullptr);
1044 }
1045
1046 using FormatWrapperTest = ::testing::Test;
1047
1048 // Plain wrapper for StrFormat.
1049 template <typename... Args>
WrappedFormat(const absl::FormatSpec<Args...> & format,const Args &...args)1050 std::string WrappedFormat(const absl::FormatSpec<Args...>& format,
1051 const Args&... args) {
1052 return StrFormat(format, args...);
1053 }
1054
TEST_F(FormatWrapperTest,ConstexprStringFormat)1055 TEST_F(FormatWrapperTest, ConstexprStringFormat) {
1056 EXPECT_EQ(WrappedFormat("%s there", "hello"), "hello there");
1057 }
1058
TEST_F(FormatWrapperTest,ConstexprStringFormatWithV)1059 TEST_F(FormatWrapperTest, ConstexprStringFormatWithV) {
1060 std::string hello = "hello";
1061 EXPECT_EQ(WrappedFormat("%v there", hello), "hello there");
1062 }
1063
TEST_F(FormatWrapperTest,ParsedFormat)1064 TEST_F(FormatWrapperTest, ParsedFormat) {
1065 ParsedFormat<'s'> format("%s there");
1066 EXPECT_EQ(WrappedFormat(format, "hello"), "hello there");
1067 }
1068
TEST_F(FormatWrapperTest,ParsedFormatWithV)1069 TEST_F(FormatWrapperTest, ParsedFormatWithV) {
1070 std::string hello = "hello";
1071 ParsedFormat<'v'> format("%v there");
1072 EXPECT_EQ(WrappedFormat(format, hello), "hello there");
1073 }
1074
1075 } // namespace
1076 ABSL_NAMESPACE_END
1077 } // namespace absl
1078
1079 namespace {
1080 using FormatExtensionTest = ::testing::Test;
1081
1082 struct Point {
1083 friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
1084 absl::FormatConversionCharSet::kIntegral |
1085 absl::FormatConversionCharSet::v>
AbslFormatConvert(const Point & p,const absl::FormatConversionSpec & spec,absl::FormatSink * s)1086 AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
1087 absl::FormatSink* s) {
1088 if (spec.conversion_char() == absl::FormatConversionChar::s) {
1089 s->Append(absl::StrCat("x=", p.x, " y=", p.y));
1090 } else {
1091 s->Append(absl::StrCat(p.x, ",", p.y));
1092 }
1093 return {true};
1094 }
1095
1096 int x = 10;
1097 int y = 20;
1098 };
1099
TEST_F(FormatExtensionTest,AbslFormatConvertExample)1100 TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
1101 Point p;
1102 EXPECT_EQ(absl::StrFormat("a %s z", p), "a x=10 y=20 z");
1103 EXPECT_EQ(absl::StrFormat("a %d z", p), "a 10,20 z");
1104 EXPECT_EQ(absl::StrFormat("a %v z", p), "a 10,20 z");
1105
1106 // Typed formatting will fail to compile an invalid format.
1107 // StrFormat("%f", p); // Does not compile.
1108 std::string actual;
1109 absl::UntypedFormatSpec f1("%f");
1110 // FormatUntyped will return false for bad character.
1111 EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)}));
1112 }
1113
1114 struct PointStringify {
1115 template <typename FormatSink>
AbslStringify(FormatSink & sink,const PointStringify & p)1116 friend void AbslStringify(FormatSink& sink, const PointStringify& p) {
1117 sink.Append(absl::StrCat("(", p.x, ", ", p.y, ")"));
1118 }
1119
1120 double x = 10.0;
1121 double y = 20.0;
1122 };
1123
TEST_F(FormatExtensionTest,AbslStringifyExample)1124 TEST_F(FormatExtensionTest, AbslStringifyExample) {
1125 PointStringify p;
1126 EXPECT_EQ(absl::StrFormat("a %v z", p), "a (10, 20) z");
1127 }
1128
1129 struct PointStringifyUsingFormat {
1130 template <typename FormatSink>
AbslStringify(FormatSink & sink,const PointStringifyUsingFormat & p)1131 friend void AbslStringify(FormatSink& sink,
1132 const PointStringifyUsingFormat& p) {
1133 absl::Format(&sink, "(%g, %g)", p.x, p.y);
1134 }
1135
1136 double x = 10.0;
1137 double y = 20.0;
1138 };
1139
TEST_F(FormatExtensionTest,AbslStringifyExampleUsingFormat)1140 TEST_F(FormatExtensionTest, AbslStringifyExampleUsingFormat) {
1141 PointStringifyUsingFormat p;
1142 EXPECT_EQ(absl::StrFormat("a %v z", p), "a (10, 20) z");
1143 }
1144
1145 enum class EnumClassWithStringify { Many = 0, Choices = 1 };
1146
1147 template <typename Sink>
AbslStringify(Sink & sink,EnumClassWithStringify e)1148 void AbslStringify(Sink& sink, EnumClassWithStringify e) {
1149 absl::Format(&sink, "%s",
1150 e == EnumClassWithStringify::Many ? "Many" : "Choices");
1151 }
1152
1153 enum EnumWithStringify { Many, Choices };
1154
1155 template <typename Sink>
AbslStringify(Sink & sink,EnumWithStringify e)1156 void AbslStringify(Sink& sink, EnumWithStringify e) {
1157 absl::Format(&sink, "%s", e == EnumWithStringify::Many ? "Many" : "Choices");
1158 }
1159
TEST_F(FormatExtensionTest,AbslStringifyWithEnumWithV)1160 TEST_F(FormatExtensionTest, AbslStringifyWithEnumWithV) {
1161 const auto e_class = EnumClassWithStringify::Choices;
1162 EXPECT_EQ(absl::StrFormat("My choice is %v", e_class),
1163 "My choice is Choices");
1164
1165 const auto e = EnumWithStringify::Choices;
1166 EXPECT_EQ(absl::StrFormat("My choice is %v", e), "My choice is Choices");
1167 }
1168
TEST_F(FormatExtensionTest,AbslStringifyEnumWithD)1169 TEST_F(FormatExtensionTest, AbslStringifyEnumWithD) {
1170 const auto e_class = EnumClassWithStringify::Many;
1171 EXPECT_EQ(absl::StrFormat("My choice is %d", e_class), "My choice is 0");
1172
1173 const auto e = EnumWithStringify::Choices;
1174 EXPECT_EQ(absl::StrFormat("My choice is %d", e), "My choice is 1");
1175 }
1176
1177 enum class EnumWithLargerValue { x = 32 };
1178
1179 template <typename Sink>
AbslStringify(Sink & sink,EnumWithLargerValue e)1180 void AbslStringify(Sink& sink, EnumWithLargerValue e) {
1181 absl::Format(&sink, "%s", "Many");
1182 }
1183
TEST_F(FormatExtensionTest,AbslStringifyEnumOtherSpecifiers)1184 TEST_F(FormatExtensionTest, AbslStringifyEnumOtherSpecifiers) {
1185 const auto e = EnumWithLargerValue::x;
1186 EXPECT_EQ(absl::StrFormat("My choice is %g", e), "My choice is 32");
1187 EXPECT_EQ(absl::StrFormat("My choice is %x", e), "My choice is 20");
1188 }
1189
1190 } // namespace
1191
1192 // Some codegen thunks that we can use to easily dump the generated assembly for
1193 // different StrFormat calls.
1194
CodegenAbslStrFormatInt(int i)1195 std::string CodegenAbslStrFormatInt(int i) { // NOLINT
1196 return absl::StrFormat("%d", i);
1197 }
1198
CodegenAbslStrFormatIntStringInt64(int i,const std::string & s,int64_t i64)1199 std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
1200 int64_t i64) { // NOLINT
1201 return absl::StrFormat("%d %s %d", i, s, i64);
1202 }
1203
CodegenAbslStrAppendFormatInt(std::string * out,int i)1204 void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
1205 absl::StrAppendFormat(out, "%d", i);
1206 }
1207
CodegenAbslStrAppendFormatIntStringInt64(std::string * out,int i,const std::string & s,int64_t i64)1208 void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
1209 const std::string& s,
1210 int64_t i64) { // NOLINT
1211 absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
1212 }
1213