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