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