Copyright 2014->2015
[folly.git] / folly / test / FormatTest.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/Format.h>
18
19 #include <glog/logging.h>
20 #include <gflags/gflags.h>
21 #include <gtest/gtest.h>
22
23 #include <folly/FBVector.h>
24 #include <folly/FileUtil.h>
25 #include <folly/dynamic.h>
26 #include <folly/json.h>
27
28 #include <string>
29
30 using namespace folly;
31
32 template <class Uint>
33 void compareOctal(Uint u) {
34   char buf1[detail::kMaxOctalLength + 1];
35   buf1[detail::kMaxOctalLength] = '\0';
36   char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
37
38   char buf2[detail::kMaxOctalLength + 1];
39   sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
40
41   EXPECT_EQ(std::string(buf2), std::string(p));
42 }
43
44 template <class Uint>
45 void compareHex(Uint u) {
46   char buf1[detail::kMaxHexLength + 1];
47   buf1[detail::kMaxHexLength] = '\0';
48   char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
49
50   char buf2[detail::kMaxHexLength + 1];
51   sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
52
53   EXPECT_EQ(std::string(buf2), std::string(p));
54 }
55
56 template <class Uint>
57 void compareBinary(Uint u) {
58   char buf[detail::kMaxBinaryLength + 1];
59   buf[detail::kMaxBinaryLength] = '\0';
60   char* p = buf + detail::uintToBinary(buf, detail::kMaxBinaryLength, u);
61
62   std::string repr;
63   if (u == 0) {
64     repr = '0';
65   } else {
66     std::string tmp;
67     for (; u; u >>= 1) {
68       tmp.push_back(u & 1 ? '1' : '0');
69     }
70     repr.assign(tmp.rbegin(), tmp.rend());
71   }
72
73   EXPECT_EQ(repr, std::string(p));
74 }
75
76 TEST(Format, uintToOctal) {
77   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
78     compareOctal(i);
79   }
80 }
81
82 TEST(Format, uintToHex) {
83   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
84     compareHex(i);
85   }
86 }
87
88 TEST(Format, uintToBinary) {
89   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
90     compareBinary(i);
91   }
92 }
93
94 TEST(Format, Simple) {
95   EXPECT_EQ("hello", sformat("hello"));
96   EXPECT_EQ("42", sformat("{}", 42));
97   EXPECT_EQ("42 42", sformat("{0} {0}", 42));
98   EXPECT_EQ("00042  23   42", sformat("{0:05} {1:3} {0:4}", 42, 23));
99   EXPECT_EQ("hello world hello 42",
100             sformat("{0} {1} {0} {2}", "hello", "world", 42));
101   EXPECT_EQ("XXhelloXX", sformat("{:X^9}", "hello"));
102   EXPECT_EQ("XXX42XXXX", sformat("{:X^9}", 42));
103   EXPECT_EQ("-0xYYYY2a", sformat("{:Y=#9x}", -42));
104   EXPECT_EQ("*", sformat("{}", '*'));
105   EXPECT_EQ("42", sformat("{}", 42));
106   EXPECT_EQ("0042", sformat("{:04}", 42));
107
108   EXPECT_EQ("hello  ", sformat("{:7}", "hello"));
109   EXPECT_EQ("hello  ", sformat("{:<7}", "hello"));
110   EXPECT_EQ("  hello", sformat("{:>7}", "hello"));
111
112   std::vector<int> v1 {10, 20, 30};
113   EXPECT_EQ("0020", sformat("{0[1]:04}", v1));
114   EXPECT_EQ("0020", svformat("{1:04}", v1));
115   EXPECT_EQ("10 20", svformat("{} {}", v1));
116
117   const std::vector<int> v2 = v1;
118   EXPECT_EQ("0020", sformat("{0[1]:04}", v2));
119   EXPECT_EQ("0020", svformat("{1:04}", v2));
120   EXPECT_THROW(sformat("{0[3]:04}", v2), std::out_of_range);
121   EXPECT_THROW(svformat("{3:04}", v2), std::out_of_range);
122   EXPECT_EQ("0020", sformat("{0[1]:04}", defaulted(v2, 42)));
123   EXPECT_EQ("0020", svformat("{1:04}", defaulted(v2, 42)));
124   EXPECT_EQ("0042", sformat("{0[3]:04}", defaulted(v2, 42)));
125   EXPECT_EQ("0042", svformat("{3:04}", defaulted(v2, 42)));
126
127   const int p[] = {10, 20, 30};
128   const int* q = p;
129   EXPECT_EQ("0020", sformat("{0[1]:04}", p));
130   EXPECT_EQ("0020", svformat("{1:04}", p));
131   EXPECT_EQ("0020", sformat("{0[1]:04}", q));
132   EXPECT_EQ("0020", svformat("{1:04}", q));
133   EXPECT_NE("", sformat("{}", q));
134
135   EXPECT_EQ("0x", sformat("{}", p).substr(0, 2));
136   EXPECT_EQ("10", svformat("{}", p));
137   EXPECT_EQ("0x", sformat("{}", q).substr(0, 2));
138   EXPECT_EQ("10", svformat("{}", q));
139   q = nullptr;
140   EXPECT_EQ("(null)", sformat("{}", q));
141
142   std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
143   EXPECT_EQ("worldXX", sformat("{[20]:X<7}", m));
144   EXPECT_EQ("worldXX", svformat("{20:X<7}", m));
145   EXPECT_THROW(sformat("{[42]:X<7}", m), std::out_of_range);
146   EXPECT_THROW(svformat("{42:X<7}", m), std::out_of_range);
147   EXPECT_EQ("worldXX", sformat("{[20]:X<7}", defaulted(m, "meow")));
148   EXPECT_EQ("worldXX", svformat("{20:X<7}", defaulted(m, "meow")));
149   EXPECT_EQ("meowXXX", sformat("{[42]:X<7}", defaulted(m, "meow")));
150   EXPECT_EQ("meowXXX", svformat("{42:X<7}", defaulted(m, "meow")));
151
152   std::map<std::string, std::string> m2 { {"hello", "world"} };
153   EXPECT_EQ("worldXX", sformat("{[hello]:X<7}", m2));
154   EXPECT_EQ("worldXX", svformat("{hello:X<7}", m2));
155   EXPECT_THROW(sformat("{[none]:X<7}", m2), std::out_of_range);
156   EXPECT_THROW(svformat("{none:X<7}", m2), std::out_of_range);
157   EXPECT_EQ("worldXX", sformat("{[hello]:X<7}", defaulted(m2, "meow")));
158   EXPECT_EQ("worldXX", svformat("{hello:X<7}", defaulted(m2, "meow")));
159   EXPECT_EQ("meowXXX", sformat("{[none]:X<7}", defaulted(m2, "meow")));
160   EXPECT_EQ("meowXXX", svformat("{none:X<7}", defaulted(m2, "meow")));
161
162   // Test indexing in strings
163   EXPECT_EQ("61 62", sformat("{0[0]:x} {0[1]:x}", "abcde"));
164   EXPECT_EQ("61 62", svformat("{0:x} {1:x}", "abcde"));
165   EXPECT_EQ("61 62", sformat("{0[0]:x} {0[1]:x}", std::string("abcde")));
166   EXPECT_EQ("61 62", svformat("{0:x} {1:x}", std::string("abcde")));
167
168   // Test booleans
169   EXPECT_EQ("true", sformat("{}", true));
170   EXPECT_EQ("1", sformat("{:d}", true));
171   EXPECT_EQ("false", sformat("{}", false));
172   EXPECT_EQ("0", sformat("{:d}", false));
173
174   // Test pairs
175   {
176     std::pair<int, std::string> p {42, "hello"};
177     EXPECT_EQ("    42 hello ", sformat("{0[0]:6} {0[1]:6}", p));
178     EXPECT_EQ("    42 hello ", svformat("{:6} {:6}", p));
179   }
180
181   // Test tuples
182   {
183     std::tuple<int, std::string, int> t { 42, "hello", 23 };
184     EXPECT_EQ("    42 hello      23", sformat("{0[0]:6} {0[1]:6} {0[2]:6}", t));
185     EXPECT_EQ("    42 hello      23", svformat("{:6} {:6} {:6}", t));
186   }
187
188   // Test writing to stream
189   std::ostringstream os;
190   os << format("{} {}", 42, 23);
191   EXPECT_EQ("42 23", os.str());
192
193   // Test appending to string
194   std::string s;
195   format(&s, "{} {}", 42, 23);
196   format(&s, " hello {:X<7}", "world");
197   EXPECT_EQ("42 23 hello worldXX", s);
198
199   // Test writing to FILE. I'd use open_memstream but that's not available
200   // outside of Linux (even though it's in POSIX.1-2008).
201   {
202     int fds[2];
203     CHECK_ERR(pipe(fds));
204     SCOPE_EXIT { closeNoInt(fds[1]); };
205     {
206       FILE* fp = fdopen(fds[1], "wb");
207       PCHECK(fp);
208       SCOPE_EXIT { fclose(fp); };
209       writeTo(fp, format("{} {}", 42, 23));  // <= 512 bytes (PIPE_BUF)
210     }
211
212     char buf[512];
213     ssize_t n = readFull(fds[0], buf, sizeof(buf));
214     CHECK_GE(n, 0);
215
216     EXPECT_EQ("42 23", std::string(buf, n));
217   }
218 }
219
220 TEST(Format, Float) {
221   double d = 1;
222   EXPECT_EQ("1", sformat("{}", 1.0));
223   EXPECT_EQ("0.1", sformat("{}", 0.1));
224   EXPECT_EQ("0.01", sformat("{}", 0.01));
225   EXPECT_EQ("0.001", sformat("{}", 0.001));
226   EXPECT_EQ("0.0001", sformat("{}", 0.0001));
227   EXPECT_EQ("1e-5", sformat("{}", 0.00001));
228   EXPECT_EQ("1e-6", sformat("{}", 0.000001));
229
230   EXPECT_EQ("10", sformat("{}", 10.0));
231   EXPECT_EQ("100", sformat("{}", 100.0));
232   EXPECT_EQ("1000", sformat("{}", 1000.0));
233   EXPECT_EQ("10000", sformat("{}", 10000.0));
234   EXPECT_EQ("100000", sformat("{}", 100000.0));
235   EXPECT_EQ("1e+6", sformat("{}", 1000000.0));
236   EXPECT_EQ("1e+7", sformat("{}", 10000000.0));
237
238   EXPECT_EQ("1.00", sformat("{:.2f}", 1.0));
239   EXPECT_EQ("0.10", sformat("{:.2f}", 0.1));
240   EXPECT_EQ("0.01", sformat("{:.2f}", 0.01));
241   EXPECT_EQ("0.00", sformat("{:.2f}", 0.001));
242
243   EXPECT_EQ("100000. !== 100000", sformat("{:.} !== {:.}", 100000.0, 100000));
244   EXPECT_EQ("100000.", sformat("{:.}", 100000.0));
245   EXPECT_EQ("1e+6", sformat("{:.}", 1000000.0));
246   EXPECT_EQ(" 100000.", sformat("{:8.}", 100000.0));
247   EXPECT_EQ("100000.", sformat("{:4.}", 100000.0));
248   EXPECT_EQ("  100000", sformat("{:8.8}", 100000.0));
249   EXPECT_EQ(" 100000.", sformat("{:8.8.}", 100000.0));
250 }
251
252 TEST(Format, MultiLevel) {
253   std::vector<std::map<std::string, std::string>> v = {
254     {
255       {"hello", "world"},
256     },
257   };
258
259   EXPECT_EQ("world", sformat("{[0.hello]}", v));
260 }
261
262 TEST(Format, dynamic) {
263   auto dyn = parseJson(
264       "{\n"
265       "  \"hello\": \"world\",\n"
266       "  \"x\": [20, 30],\n"
267       "  \"y\": {\"a\" : 42}\n"
268       "}");
269
270   EXPECT_EQ("world", sformat("{0[hello]}", dyn));
271   EXPECT_THROW(sformat("{0[none]}", dyn), std::out_of_range);
272   EXPECT_EQ("world", sformat("{0[hello]}", defaulted(dyn, "meow")));
273   EXPECT_EQ("meow", sformat("{0[none]}", defaulted(dyn, "meow")));
274
275   EXPECT_EQ("20", sformat("{0[x.0]}", dyn));
276   EXPECT_THROW(sformat("{0[x.2]}", dyn), std::out_of_range);
277
278   // No support for "deep" defaulting (dyn["x"] is not defaulted)
279   auto v = dyn.at("x");
280   EXPECT_EQ("20", sformat("{0[0]}", v));
281   EXPECT_THROW(sformat("{0[2]}", v), std::out_of_range);
282   EXPECT_EQ("20", sformat("{0[0]}", defaulted(v, 42)));
283   EXPECT_EQ("42", sformat("{0[2]}", defaulted(v, 42)));
284
285   EXPECT_EQ("42", sformat("{0[y.a]}", dyn));
286
287   EXPECT_EQ("(null)", sformat("{}", dynamic(nullptr)));
288 }
289
290 TEST(Format, separatorDecimalInteger) {
291   EXPECT_EQ("0", sformat("{:,d}", 0));
292   EXPECT_EQ("1", sformat("{:d}", 1));
293   EXPECT_EQ("1", sformat("{:,d}", 1));
294   EXPECT_EQ("1", sformat("{:,}", 1));
295   EXPECT_EQ("123", sformat("{:d}", 123));
296   EXPECT_EQ("123", sformat("{:,d}", 123));
297   EXPECT_EQ("123", sformat("{:,}", 123));
298   EXPECT_EQ("1234", sformat("{:d}", 1234));
299   EXPECT_EQ("1,234", sformat("{:,d}", 1234));
300   EXPECT_EQ("1,234", sformat("{:,}", 1234));
301   EXPECT_EQ("12345678", sformat("{:d}", 12345678));
302   EXPECT_EQ("12,345,678", sformat("{:,d}", 12345678));
303   EXPECT_EQ("12,345,678", sformat("{:,}", 12345678));
304   EXPECT_EQ("-1234", sformat("{:d}", -1234));
305   EXPECT_EQ("-1,234", sformat("{:,d}", -1234));
306   EXPECT_EQ("-1,234", sformat("{:,}", -1234));
307
308   int64_t max_int64_t = std::numeric_limits<int64_t>::max();
309   int64_t min_int64_t = std::numeric_limits<int64_t>::min();
310   uint64_t max_uint64_t = std::numeric_limits<uint64_t>::max();
311   EXPECT_EQ("9223372036854775807", sformat("{:d}", max_int64_t));
312   EXPECT_EQ("9,223,372,036,854,775,807", sformat("{:,d}", max_int64_t));
313   EXPECT_EQ("9,223,372,036,854,775,807", sformat("{:,}", max_int64_t));
314   EXPECT_EQ("-9223372036854775808", sformat("{:d}", min_int64_t));
315   EXPECT_EQ("-9,223,372,036,854,775,808", sformat("{:,d}", min_int64_t));
316   EXPECT_EQ("-9,223,372,036,854,775,808", sformat("{:,}", min_int64_t));
317   EXPECT_EQ("18446744073709551615", sformat("{:d}", max_uint64_t));
318   EXPECT_EQ("18,446,744,073,709,551,615", sformat("{:,d}", max_uint64_t));
319   EXPECT_EQ("18,446,744,073,709,551,615", sformat("{:,}", max_uint64_t));
320
321   EXPECT_EQ("  -1,234", sformat("{: 8,}", -1234));
322   EXPECT_EQ("-001,234", sformat("{:08,d}", -1234));
323   EXPECT_EQ("-00001,234", sformat("{:010,d}", -1234));
324   EXPECT_EQ(" -1,234 ", sformat("{:^ 8,d}", -1234));
325 }
326
327 // Note that sformat("{:n}", ...) uses the current locale setting to insert the
328 // appropriate number separator characters.
329 TEST(Format, separatorNumber) {
330   EXPECT_EQ("0", sformat("{:n}", 0));
331   EXPECT_EQ("1", sformat("{:n}", 1));
332   EXPECT_EQ("123", sformat("{:n}", 123));
333   EXPECT_EQ("1234", sformat("{:n}", 1234));
334   EXPECT_EQ("12345678", sformat("{:n}", 12345678));
335   EXPECT_EQ("-1234", sformat("{:n}", -1234));
336
337   int64_t max_int64_t = std::numeric_limits<int64_t>::max();
338   int64_t min_int64_t = std::numeric_limits<int64_t>::min();
339   uint64_t max_uint64_t = std::numeric_limits<uint64_t>::max();
340   EXPECT_EQ("9223372036854775807", sformat("{:n}", max_int64_t));
341   EXPECT_EQ("-9223372036854775808", sformat("{:n}", min_int64_t));
342   EXPECT_EQ("18446744073709551615", sformat("{:n}", max_uint64_t));
343
344   EXPECT_EQ("   -1234", sformat("{: 8n}", -1234));
345   EXPECT_EQ("-0001234", sformat("{:08n}", -1234));
346   EXPECT_EQ("-000001234", sformat("{:010n}", -1234));
347   EXPECT_EQ(" -1234  ", sformat("{:^ 8n}", -1234));
348 }
349
350 // insertThousandsGroupingUnsafe requires non-const params
351 static void testGrouping(const char* a_str, const char* expected) {
352   char str[256];
353   strcpy(str, a_str);
354   char * end_ptr = str + strlen(str);
355   folly::detail::insertThousandsGroupingUnsafe(str, &end_ptr);
356   ASSERT_STREQ(expected, str);
357 }
358
359 TEST(Format, separatorUnit) {
360   testGrouping("0", "0");
361   testGrouping("1", "1");
362   testGrouping("12", "12");
363   testGrouping("123", "123");
364   testGrouping("1234", "1,234");
365   testGrouping("12345", "12,345");
366   testGrouping("123456", "123,456");
367   testGrouping("1234567", "1,234,567");
368   testGrouping("1234567890", "1,234,567,890");
369   testGrouping("9223372036854775807", "9,223,372,036,854,775,807");
370   testGrouping("18446744073709551615", "18,446,744,073,709,551,615");
371 }
372
373
374 namespace {
375
376 struct KeyValue {
377   std::string key;
378   int value;
379 };
380
381 }  // namespace
382
383 namespace folly {
384
385 template <> class FormatValue<KeyValue> {
386  public:
387   explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
388
389   template <class FormatCallback>
390   void format(FormatArg& arg, FormatCallback& cb) const {
391     format_value::formatFormatter(
392         folly::format("<key={}, value={}>", kv_.key, kv_.value),
393         arg, cb);
394   }
395
396  private:
397   const KeyValue& kv_;
398 };
399
400 }  // namespace
401
402 TEST(Format, Custom) {
403   KeyValue kv { "hello", 42 };
404
405   EXPECT_EQ("<key=hello, value=42>", sformat("{}", kv));
406   EXPECT_EQ("<key=hello, value=42>", sformat("{:10}", kv));
407   EXPECT_EQ("<key=hello", sformat("{:.10}", kv));
408   EXPECT_EQ("<key=hello, value=42>XX", sformat("{:X<23}", kv));
409   EXPECT_EQ("XX<key=hello, value=42>", sformat("{:X>23}", kv));
410   EXPECT_EQ("<key=hello, value=42>", sformat("{0[0]}", &kv));
411   EXPECT_NE("", sformat("{}", &kv));
412 }
413
414 namespace {
415
416 struct Opaque {
417   int k;
418 };
419
420 } // namespace
421
422 TEST(Format, Unformatted) {
423   Opaque o;
424   EXPECT_NE("", sformat("{}", &o));
425   EXPECT_DEATH(sformat("{0[0]}", &o), "No formatter available for this type");
426   EXPECT_THROW(sformatChecked("{0[0]}", &o), std::invalid_argument);
427 }
428
429 TEST(Format, Nested) {
430   EXPECT_EQ("1 2 3 4", sformat("{} {} {}", 1, 2, format("{} {}", 3, 4)));
431   //
432   // not copyable, must hold temporary in scope instead.
433   auto&& saved = format("{} {}", 3, 4);
434   EXPECT_EQ("1 2 3 4", sformat("{} {} {}", 1, 2, saved));
435 }
436
437 TEST(Format, OutOfBounds) {
438   std::vector<int> ints{1, 2, 3, 4, 5};
439   EXPECT_EQ("1 3 5", sformat("{0[0]} {0[2]} {0[4]}", ints));
440   EXPECT_THROW(sformat("{[5]}", ints), std::out_of_range);
441   EXPECT_THROW(sformatChecked("{[5]}", ints), std::out_of_range);
442
443   std::map<std::string, int> map{{"hello", 0}, {"world", 1}};
444   EXPECT_EQ("hello = 0", sformat("hello = {[hello]}", map));
445   EXPECT_THROW(sformat("{[nope]}", map), std::out_of_range);
446   EXPECT_THROW(svformat("{nope}", map), std::out_of_range);
447   EXPECT_THROW(svformatChecked("{nope}", map), std::out_of_range);
448 }
449
450 TEST(Format, BogusFormatString) {
451   // format() will crash the program if the format string is invalid.
452   EXPECT_DEATH(sformat("}"), "single '}' in format string");
453   EXPECT_DEATH(sformat("foo}bar"), "single '}' in format string");
454   EXPECT_DEATH(sformat("foo{bar"), "missing ending '}'");
455   EXPECT_DEATH(sformat("{[test]"), "missing ending '}'");
456   EXPECT_DEATH(sformat("{-1.3}"), "argument index must be non-negative");
457   EXPECT_DEATH(sformat("{1.3}", 0, 1, 2), "index not allowed");
458   EXPECT_DEATH(sformat("{0} {} {1}", 0, 1, 2),
459                "may not have both default and explicit arg indexes");
460
461   // formatChecked() should throw exceptions rather than crashing the program
462   EXPECT_THROW(sformatChecked("}"), std::invalid_argument);
463   EXPECT_THROW(sformatChecked("foo}bar"), std::invalid_argument);
464   EXPECT_THROW(sformatChecked("foo{bar"), std::invalid_argument);
465   EXPECT_THROW(sformatChecked("{[test]"), std::invalid_argument);
466   EXPECT_THROW(sformatChecked("{-1.3}"), std::invalid_argument);
467   EXPECT_THROW(sformatChecked("{1.3}", 0, 1, 2), std::invalid_argument);
468   EXPECT_THROW(sformatChecked("{0} {} {1}", 0, 1, 2), std::invalid_argument);
469
470   // This one fails in detail::enforceWhitespace(), which throws
471   // std::range_error
472   EXPECT_DEATH(sformat("{0[test}"), "Non-whitespace: \\[");
473   EXPECT_THROW(sformatChecked("{0[test}"), std::exception);
474 }
475
476 template <bool containerMode, class... Args>
477 class TestExtendingFormatter;
478
479 template <bool containerMode, class... Args>
480 class TestExtendingFormatter
481     : public BaseFormatter<TestExtendingFormatter<containerMode, Args...>,
482                            containerMode,
483                            Args...> {
484  private:
485   explicit TestExtendingFormatter(StringPiece& str, Args&&... args)
486       : BaseFormatter<TestExtendingFormatter<containerMode, Args...>,
487                       containerMode,
488                       Args...>(str, std::forward<Args>(args)...) {}
489
490   template <size_t K, class Callback>
491   void doFormatArg(FormatArg& arg, Callback& cb) const {
492     std::string result;
493     auto appender = [&result](StringPiece s) {
494       result.append(s.data(), s.size());
495     };
496     std::get<K>(this->values_).format(arg, appender);
497     result = sformat("{{{}}}", result);
498     cb(StringPiece(result));
499   }
500
501   friend class BaseFormatter<TestExtendingFormatter<containerMode, Args...>,
502                              containerMode,
503                              Args...>;
504
505   template <class... A>
506   friend std::string texsformat(StringPiece fmt, A&&... arg);
507 };
508
509 template <class... Args>
510 std::string texsformat(StringPiece fmt, Args&&... args) {
511   return TestExtendingFormatter<false, Args...>(
512       fmt, std::forward<Args>(args)...).str();
513 }
514
515 TEST(Format, Extending) {
516   EXPECT_EQ(texsformat("I {} brackets", "love"), "I {love} brackets");
517   EXPECT_EQ(texsformat("I {} nesting", sformat("really {}", "love")),
518             "I {really love} nesting");
519   EXPECT_EQ(
520       sformat("I also {} nesting", texsformat("have an {} for", "affinity")),
521       "I also have an {affinity} for nesting");
522   EXPECT_EQ(texsformat("Extending {} in {}",
523                        texsformat("a {}", "formatter"),
524                        "another formatter"),
525             "Extending {a {formatter}} in {another formatter}");
526 }
527
528 int main(int argc, char *argv[]) {
529   testing::InitGoogleTest(&argc, argv);
530   gflags::ParseCommandLineFlags(&argc, &argv, true);
531   return RUN_ALL_TESTS();
532 }