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