Adds writer test case for RCU
[folly.git] / folly / test / FormatTest.cpp
1 /*
2  * Copyright 2012-present 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 #include <folly/Utility.h>
19 #include <folly/portability/GTest.h>
20
21 #include <string>
22
23 using namespace folly;
24
25 template <class Uint>
26 void compareOctal(Uint u) {
27   char buf1[detail::kMaxOctalLength + 1];
28   buf1[detail::kMaxOctalLength] = '\0';
29   char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
30
31   char buf2[detail::kMaxOctalLength + 1];
32   EXPECT_LT(snprintf(buf2, sizeof(buf2), "%jo", static_cast<uintmax_t>(u)),
33             sizeof(buf2));
34
35   EXPECT_EQ(std::string(buf2), std::string(p));
36 }
37
38 template <class Uint>
39 void compareHex(Uint u) {
40   char buf1[detail::kMaxHexLength + 1];
41   buf1[detail::kMaxHexLength] = '\0';
42   char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
43
44   char buf2[detail::kMaxHexLength + 1];
45   EXPECT_LT(snprintf(buf2, sizeof(buf2), "%jx", static_cast<uintmax_t>(u)),
46             sizeof(buf2));
47
48   EXPECT_EQ(std::string(buf2), std::string(p));
49 }
50
51 template <class Uint>
52 void compareBinary(Uint u) {
53   char buf[detail::kMaxBinaryLength + 1];
54   buf[detail::kMaxBinaryLength] = '\0';
55   char* p = buf + detail::uintToBinary(buf, detail::kMaxBinaryLength, u);
56
57   std::string repr;
58   if (u == 0) {
59     repr = '0';
60   } else {
61     std::string tmp;
62     for (; u; u >>= 1) {
63       tmp.push_back(u & 1 ? '1' : '0');
64     }
65     repr.assign(tmp.rbegin(), tmp.rend());
66   }
67
68   EXPECT_EQ(repr, std::string(p));
69 }
70
71 TEST(Format, uintToOctal) {
72   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
73     compareOctal(i);
74   }
75 }
76
77 TEST(Format, uintToHex) {
78   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
79     compareHex(i);
80   }
81 }
82
83 TEST(Format, uintToBinary) {
84   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
85     compareBinary(i);
86   }
87 }
88
89 TEST(Format, Simple) {
90   EXPECT_EQ("hello", sformat("hello"));
91   EXPECT_EQ("42", sformat("{}", 42));
92   EXPECT_EQ("42 42", sformat("{0} {0}", 42));
93   EXPECT_EQ("00042  23   42", sformat("{0:05} {1:3} {0:4}", 42, 23));
94   EXPECT_EQ("hello world hello 42",
95             sformat("{0} {1} {0} {2}", "hello", "world", 42));
96   EXPECT_EQ("XXhelloXX", sformat("{:X^9}", "hello"));
97   EXPECT_EQ("XXX42XXXX", sformat("{:X^9}", 42));
98   EXPECT_EQ("-0xYYYY2a", sformat("{:Y=#9x}", -42));
99   EXPECT_EQ("*", sformat("{}", '*'));
100   EXPECT_EQ("42", sformat("{}", 42));
101   EXPECT_EQ("0042", sformat("{:04}", 42));
102
103   EXPECT_EQ("hello  ", sformat("{:7}", "hello"));
104   EXPECT_EQ("hello  ", sformat("{:<7}", "hello"));
105   EXPECT_EQ("  hello", sformat("{:>7}", "hello"));
106
107   EXPECT_EQ("  hi", sformat("{:>*}", 4, "hi"));
108   EXPECT_EQ("   hi!", sformat("{:*}{}", 3, "", "hi!"));
109   EXPECT_EQ("    123", sformat("{:*}", 7, 123));
110   EXPECT_EQ("123    ", sformat("{:<*}", 7, 123));
111   EXPECT_EQ("----<=>----", sformat("{:-^*}", 11, "<=>"));
112   EXPECT_EQ("+++456+++", sformat("{2:+^*0}", 9, "unused", 456));
113
114   std::vector<int> v1 {10, 20, 30};
115   EXPECT_EQ("0020", sformat("{0[1]:04}", v1));
116   EXPECT_EQ("0020", svformat("{1:04}", v1));
117   EXPECT_EQ("10 20", svformat("{} {}", v1));
118
119   const std::vector<int> v2 = v1;
120   EXPECT_EQ("0020", sformat("{0[1]:04}", v2));
121   EXPECT_EQ("0020", svformat("{1:04}", v2));
122   EXPECT_THROW(sformat("{0[3]:04}", v2), std::out_of_range);
123   EXPECT_THROW(svformat("{3:04}", v2), std::out_of_range);
124   EXPECT_EQ("0020", sformat("{0[1]:04}", defaulted(v2, 42)));
125   EXPECT_EQ("0020", svformat("{1:04}", defaulted(v2, 42)));
126   EXPECT_EQ("0042", sformat("{0[3]:04}", defaulted(v2, 42)));
127   EXPECT_EQ("0042", svformat("{3:04}", defaulted(v2, 42)));
128
129   {
130     const int p[] = { 10, 20, 30 };
131     const int* q = p;
132     EXPECT_EQ("0020", sformat("{0[1]:04}", p));
133     EXPECT_EQ("0020", svformat("{1:04}", p));
134     EXPECT_EQ("0020", sformat("{0[1]:04}", q));
135     EXPECT_EQ("0020", svformat("{1:04}", q));
136     EXPECT_NE("", sformat("{}", q));
137
138     EXPECT_EQ("0x", sformat("{}", p).substr(0, 2));
139     EXPECT_EQ("10", svformat("{}", p));
140     EXPECT_EQ("0x", sformat("{}", q).substr(0, 2));
141     EXPECT_EQ("10", svformat("{}", q));
142     q = nullptr;
143     EXPECT_EQ("(null)", sformat("{}", q));
144   }
145
146   std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
147   EXPECT_EQ("worldXX", sformat("{[20]:X<7}", m));
148   EXPECT_EQ("worldXX", svformat("{20:X<7}", m));
149   EXPECT_THROW(sformat("{[42]:X<7}", m), std::out_of_range);
150   EXPECT_THROW(svformat("{42:X<7}", m), std::out_of_range);
151   EXPECT_EQ("worldXX", sformat("{[20]:X<7}", defaulted(m, "meow")));
152   EXPECT_EQ("worldXX", svformat("{20:X<7}", defaulted(m, "meow")));
153   EXPECT_EQ("meowXXX", sformat("{[42]:X<7}", defaulted(m, "meow")));
154   EXPECT_EQ("meowXXX", svformat("{42:X<7}", defaulted(m, "meow")));
155
156   std::map<std::string, std::string> m2 { {"hello", "world"} };
157   EXPECT_EQ("worldXX", sformat("{[hello]:X<7}", m2));
158   EXPECT_EQ("worldXX", svformat("{hello:X<7}", m2));
159   EXPECT_THROW(sformat("{[none]:X<7}", m2), std::out_of_range);
160   EXPECT_THROW(svformat("{none:X<7}", m2), std::out_of_range);
161   EXPECT_EQ("worldXX", sformat("{[hello]:X<7}", defaulted(m2, "meow")));
162   EXPECT_EQ("worldXX", svformat("{hello:X<7}", defaulted(m2, "meow")));
163   EXPECT_EQ("meowXXX", sformat("{[none]:X<7}", defaulted(m2, "meow")));
164   EXPECT_EQ("meowXXX", svformat("{none:X<7}", defaulted(m2, "meow")));
165   try {
166     svformat("{none:X<7}", m2);
167     EXPECT_FALSE(true) << "svformat should throw on missing key";
168   } catch (const FormatKeyNotFoundException& e) {
169     EXPECT_STREQ("none", e.key());
170   }
171
172   // Test indexing in strings
173   EXPECT_EQ("61 62", sformat("{0[0]:x} {0[1]:x}", "abcde"));
174   EXPECT_EQ("61 62", svformat("{0:x} {1:x}", "abcde"));
175   EXPECT_EQ("61 62", sformat("{0[0]:x} {0[1]:x}", std::string("abcde")));
176   EXPECT_EQ("61 62", svformat("{0:x} {1:x}", std::string("abcde")));
177
178   // Test booleans
179   EXPECT_EQ("true", sformat("{}", true));
180   EXPECT_EQ("1", sformat("{:d}", true));
181   EXPECT_EQ("false", sformat("{}", false));
182   EXPECT_EQ("0", sformat("{:d}", false));
183
184   // Test pairs
185   {
186     std::pair<int, std::string> p {42, "hello"};
187     EXPECT_EQ("    42 hello ", sformat("{0[0]:6} {0[1]:6}", p));
188     EXPECT_EQ("    42 hello ", svformat("{:6} {:6}", p));
189   }
190
191   // Test tuples
192   {
193     std::tuple<int, std::string, int> t { 42, "hello", 23 };
194     EXPECT_EQ("    42 hello      23", sformat("{0[0]:6} {0[1]:6} {0[2]:6}", t));
195     EXPECT_EQ("    42 hello      23", svformat("{:6} {:6} {:6}", t));
196   }
197
198   // Test writing to stream
199   std::ostringstream os;
200   os << format("{} {}", 42, 23);
201   EXPECT_EQ("42 23", os.str());
202
203   // Test appending to string
204   std::string s;
205   format(&s, "{} {}", 42, 23);
206   format(&s, " hello {:X<7}", "world");
207   EXPECT_EQ("42 23 hello worldXX", s);
208 }
209
210 TEST(Format, Float) {
211   EXPECT_EQ("1", sformat("{}", 1.0));
212   EXPECT_EQ("0.1", sformat("{}", 0.1));
213   EXPECT_EQ("0.01", sformat("{}", 0.01));
214   EXPECT_EQ("0.001", sformat("{}", 0.001));
215   EXPECT_EQ("0.0001", sformat("{}", 0.0001));
216   EXPECT_EQ("1e-5", sformat("{}", 0.00001));
217   EXPECT_EQ("1e-6", sformat("{}", 0.000001));
218
219   EXPECT_EQ("10", sformat("{}", 10.0));
220   EXPECT_EQ("100", sformat("{}", 100.0));
221   EXPECT_EQ("1000", sformat("{}", 1000.0));
222   EXPECT_EQ("10000", sformat("{}", 10000.0));
223   EXPECT_EQ("100000", sformat("{}", 100000.0));
224   EXPECT_EQ("1e+6", sformat("{}", 1000000.0));
225   EXPECT_EQ("1e+7", sformat("{}", 10000000.0));
226
227   EXPECT_EQ("1.00", sformat("{:.2f}", 1.0));
228   EXPECT_EQ("0.10", sformat("{:.2f}", 0.1));
229   EXPECT_EQ("0.01", sformat("{:.2f}", 0.01));
230   EXPECT_EQ("0.00", sformat("{:.2f}", 0.001));
231
232   EXPECT_EQ("100000. !== 100000", sformat("{:.} !== {:.}", 100000.0, 100000));
233   EXPECT_EQ("100000.", sformat("{:.}", 100000.0));
234   EXPECT_EQ("1e+6", sformat("{:.}", 1000000.0));
235   EXPECT_EQ(" 100000.", sformat("{:8.}", 100000.0));
236   EXPECT_EQ("100000.", sformat("{:4.}", 100000.0));
237   EXPECT_EQ("  100000", sformat("{:8.8}", 100000.0));
238   EXPECT_EQ(" 100000.", sformat("{:8.8.}", 100000.0));
239 }
240
241 TEST(Format, MultiLevel) {
242   std::vector<std::map<std::string, std::string>> v = {
243     {
244       {"hello", "world"},
245     },
246   };
247
248   EXPECT_EQ("world", sformat("{[0.hello]}", v));
249 }
250
251 TEST(Format, separatorDecimalInteger) {
252   EXPECT_EQ("0", sformat("{:,d}", 0));
253   EXPECT_EQ("1", sformat("{:d}", 1));
254   EXPECT_EQ("1", sformat("{:,d}", 1));
255   EXPECT_EQ("1", sformat("{:,}", 1));
256   EXPECT_EQ("123", sformat("{:d}", 123));
257   EXPECT_EQ("123", sformat("{:,d}", 123));
258   EXPECT_EQ("123", sformat("{:,}", 123));
259   EXPECT_EQ("1234", sformat("{:d}", 1234));
260   EXPECT_EQ("1,234", sformat("{:,d}", 1234));
261   EXPECT_EQ("1,234", sformat("{:,}", 1234));
262   EXPECT_EQ("12345678", sformat("{:d}", 12345678));
263   EXPECT_EQ("12,345,678", sformat("{:,d}", 12345678));
264   EXPECT_EQ("12,345,678", sformat("{:,}", 12345678));
265   EXPECT_EQ("-1234", sformat("{:d}", -1234));
266   EXPECT_EQ("-1,234", sformat("{:,d}", -1234));
267   EXPECT_EQ("-1,234", sformat("{:,}", -1234));
268
269   int64_t max_int64_t = std::numeric_limits<int64_t>::max();
270   int64_t min_int64_t = std::numeric_limits<int64_t>::min();
271   uint64_t max_uint64_t = std::numeric_limits<uint64_t>::max();
272   EXPECT_EQ("9223372036854775807", sformat("{:d}", max_int64_t));
273   EXPECT_EQ("9,223,372,036,854,775,807", sformat("{:,d}", max_int64_t));
274   EXPECT_EQ("9,223,372,036,854,775,807", sformat("{:,}", max_int64_t));
275   EXPECT_EQ("-9223372036854775808", sformat("{:d}", min_int64_t));
276   EXPECT_EQ("-9,223,372,036,854,775,808", sformat("{:,d}", min_int64_t));
277   EXPECT_EQ("-9,223,372,036,854,775,808", sformat("{:,}", min_int64_t));
278   EXPECT_EQ("18446744073709551615", sformat("{:d}", max_uint64_t));
279   EXPECT_EQ("18,446,744,073,709,551,615", sformat("{:,d}", max_uint64_t));
280   EXPECT_EQ("18,446,744,073,709,551,615", sformat("{:,}", max_uint64_t));
281
282   EXPECT_EQ("  -1,234", sformat("{: 8,}", -1234));
283   EXPECT_EQ("-001,234", sformat("{:08,d}", -1234));
284   EXPECT_EQ("-00001,234", sformat("{:010,d}", -1234));
285   EXPECT_EQ(" -1,234 ", sformat("{:^ 8,d}", -1234));
286 }
287
288 // Note that sformat("{:n}", ...) uses the current locale setting to insert the
289 // appropriate number separator characters.
290 TEST(Format, separatorNumber) {
291   EXPECT_EQ("0", sformat("{:n}", 0));
292   EXPECT_EQ("1", sformat("{:n}", 1));
293   EXPECT_EQ("123", sformat("{:n}", 123));
294   EXPECT_EQ("1234", sformat("{:n}", 1234));
295   EXPECT_EQ("12345678", sformat("{:n}", 12345678));
296   EXPECT_EQ("-1234", sformat("{:n}", -1234));
297
298   int64_t max_int64_t = std::numeric_limits<int64_t>::max();
299   int64_t min_int64_t = std::numeric_limits<int64_t>::min();
300   uint64_t max_uint64_t = std::numeric_limits<uint64_t>::max();
301   EXPECT_EQ("9223372036854775807", sformat("{:n}", max_int64_t));
302   EXPECT_EQ("-9223372036854775808", sformat("{:n}", min_int64_t));
303   EXPECT_EQ("18446744073709551615", sformat("{:n}", max_uint64_t));
304
305   EXPECT_EQ("   -1234", sformat("{: 8n}", -1234));
306   EXPECT_EQ("-0001234", sformat("{:08n}", -1234));
307   EXPECT_EQ("-000001234", sformat("{:010n}", -1234));
308   EXPECT_EQ(" -1234  ", sformat("{:^ 8n}", -1234));
309 }
310
311 // insertThousandsGroupingUnsafe requires non-const params
312 static void testGrouping(const char* a_str, const char* expected) {
313   char str[256];
314   char* end_ptr = str + snprintf(str, sizeof(str), "%s", a_str);
315   ASSERT_LT(end_ptr, str + sizeof(str));
316   folly::detail::insertThousandsGroupingUnsafe(str, &end_ptr);
317   ASSERT_STREQ(expected, str);
318 }
319
320 TEST(Format, separatorUnit) {
321   testGrouping("0", "0");
322   testGrouping("1", "1");
323   testGrouping("12", "12");
324   testGrouping("123", "123");
325   testGrouping("1234", "1,234");
326   testGrouping("12345", "12,345");
327   testGrouping("123456", "123,456");
328   testGrouping("1234567", "1,234,567");
329   testGrouping("1234567890", "1,234,567,890");
330   testGrouping("9223372036854775807", "9,223,372,036,854,775,807");
331   testGrouping("18446744073709551615", "18,446,744,073,709,551,615");
332 }
333
334
335 namespace {
336
337 struct KeyValue {
338   std::string key;
339   int value;
340 };
341
342 } // namespace
343
344 namespace folly {
345
346 template <> class FormatValue<KeyValue> {
347  public:
348   explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
349
350   template <class FormatCallback>
351   void format(FormatArg& arg, FormatCallback& cb) const {
352     format_value::formatFormatter(
353         folly::format("<key={}, value={}>", kv_.key, kv_.value),
354         arg, cb);
355   }
356
357  private:
358   const KeyValue& kv_;
359 };
360
361 } // namespace folly
362
363 TEST(Format, Custom) {
364   KeyValue kv { "hello", 42 };
365
366   EXPECT_EQ("<key=hello, value=42>", sformat("{}", kv));
367   EXPECT_EQ("<key=hello, value=42>", sformat("{:10}", kv));
368   EXPECT_EQ("<key=hello", sformat("{:.10}", kv));
369   EXPECT_EQ("<key=hello, value=42>XX", sformat("{:X<23}", kv));
370   EXPECT_EQ("XX<key=hello, value=42>", sformat("{:X>23}", kv));
371   EXPECT_EQ("<key=hello, value=42>", sformat("{0[0]}", &kv));
372   EXPECT_NE("", sformat("{}", &kv));
373 }
374
375 namespace {
376
377 struct Opaque {
378   int k;
379 };
380
381 } // namespace
382
383 #define EXPECT_THROW_STR(code, type, str) \
384   do { \
385     bool caught = false; \
386     try { \
387       code; \
388     } catch (const type& e) { \
389       caught = true; \
390       EXPECT_TRUE(strstr(e.what(), (str)) != nullptr) << \
391         "Expected message [" << (str) << "], actual message [" << \
392         e.what(); \
393     } catch (const std::exception& e) { \
394       caught = true; \
395       ADD_FAILURE() << "Caught different exception type; expected " #type \
396         ", caught " << folly::demangle(typeid(e)); \
397     } catch (...) { \
398       caught = true; \
399       ADD_FAILURE() << "Caught unknown exception type; expected " #type; \
400     } \
401     if (!caught) { \
402       ADD_FAILURE() << "Expected exception " #type ", caught nothing"; \
403     } \
404   } while (false)
405
406 #define EXPECT_FORMAT_ERROR(code, str) \
407   EXPECT_THROW_STR(code, folly::BadFormatArg, (str))
408
409 TEST(Format, Unformatted) {
410   Opaque o;
411   EXPECT_NE("", sformat("{}", &o));
412   EXPECT_FORMAT_ERROR(sformat("{0[0]}", &o),
413                       "No formatter available for this type");
414 }
415
416 TEST(Format, Nested) {
417   EXPECT_EQ("1 2 3 4", sformat("{} {} {}", 1, 2, format("{} {}", 3, 4)));
418   //
419   // not copyable, must hold temporary in scope instead.
420   auto&& saved = format("{} {}", 3, 4);
421   EXPECT_EQ("1 2 3 4", sformat("{} {} {}", 1, 2, saved));
422 }
423
424 TEST(Format, OutOfBounds) {
425   std::vector<int> ints{1, 2, 3, 4, 5};
426   EXPECT_EQ("1 3 5", sformat("{0[0]} {0[2]} {0[4]}", ints));
427   EXPECT_THROW(sformat("{[5]}", ints), std::out_of_range);
428
429   std::map<std::string, int> map{{"hello", 0}, {"world", 1}};
430   EXPECT_EQ("hello = 0", sformat("hello = {[hello]}", map));
431   EXPECT_THROW(sformat("{[nope]}", map), std::out_of_range);
432   EXPECT_THROW(svformat("{nope}", map), std::out_of_range);
433 }
434
435 TEST(Format, BogusFormatString) {
436   EXPECT_FORMAT_ERROR(sformat("}"), "single '}' in format string");
437   EXPECT_FORMAT_ERROR(sformat("foo}bar"), "single '}' in format string");
438   EXPECT_FORMAT_ERROR(sformat("foo{bar"), "missing ending '}'");
439   EXPECT_FORMAT_ERROR(sformat("{[test]"), "missing ending '}'");
440   EXPECT_FORMAT_ERROR(sformat("{-1.3}"), "argument index must be non-negative");
441   EXPECT_FORMAT_ERROR(sformat("{1.3}", 0, 1, 2), "index not allowed");
442   EXPECT_FORMAT_ERROR(sformat("{0} {} {1}", 0, 1, 2),
443                "may not have both default and explicit arg indexes");
444   EXPECT_FORMAT_ERROR(sformat("{:*}", 1.2),
445                       "dynamic field width argument must be integral");
446   EXPECT_FORMAT_ERROR(sformat("{} {:*}", "hi"),
447                       "argument index out of range, max=1");
448   EXPECT_FORMAT_ERROR(
449     sformat("{:*0}", 12, "ok"),
450     "cannot provide width arg index without value arg index"
451   );
452   EXPECT_FORMAT_ERROR(
453     sformat("{0:*}", 12, "ok"),
454     "cannot provide value arg index without width arg index"
455   );
456
457   std::vector<int> v{1, 2, 3};
458   EXPECT_FORMAT_ERROR(svformat("{:*}", v),
459                       "dynamic field width not supported in vformat()");
460
461   // This one fails in detail::enforceWhitespace(), which throws
462   // std::range_error
463   EXPECT_THROW_STR(sformat("{0[test}"), std::range_error, "Non-whitespace");
464 }
465
466 template <bool containerMode, class... Args>
467 class TestExtendingFormatter;
468
469 template <bool containerMode, class... Args>
470 class TestExtendingFormatter
471     : public BaseFormatter<TestExtendingFormatter<containerMode, Args...>,
472                            containerMode,
473                            Args...> {
474  private:
475   explicit TestExtendingFormatter(StringPiece& str, Args&&... args)
476       : BaseFormatter<TestExtendingFormatter<containerMode, Args...>,
477                       containerMode,
478                       Args...>(str, std::forward<Args>(args)...) {}
479
480   template <size_t K, class Callback>
481   void doFormatArg(FormatArg& arg, Callback& cb) const {
482     std::string result;
483     auto appender = [&result](StringPiece s) {
484       result.append(s.data(), s.size());
485     };
486     this->template getFormatValue<K>().format(arg, appender);
487     result = sformat("{{{}}}", result);
488     cb(StringPiece(result));
489   }
490
491   friend class BaseFormatter<TestExtendingFormatter<containerMode, Args...>,
492                              containerMode,
493                              Args...>;
494
495   template <class... A>
496   friend std::string texsformat(StringPiece fmt, A&&... arg);
497 };
498
499 template <class... Args>
500 std::string texsformat(StringPiece fmt, Args&&... args) {
501   return TestExtendingFormatter<false, Args...>(
502       fmt, std::forward<Args>(args)...).str();
503 }
504
505 TEST(Format, Extending) {
506   EXPECT_EQ(texsformat("I {} brackets", "love"), "I {love} brackets");
507   EXPECT_EQ(texsformat("I {} nesting", sformat("really {}", "love")),
508             "I {really love} nesting");
509   EXPECT_EQ(
510       sformat("I also {} nesting", texsformat("have an {} for", "affinity")),
511       "I also have an {affinity} for nesting");
512   EXPECT_EQ(texsformat("Extending {} in {}",
513                        texsformat("a {}", "formatter"),
514                        "another formatter"),
515             "Extending {a {formatter}} in {another formatter}");
516 }
517
518 TEST(Format, Temporary) {
519   constexpr StringPiece kStr = "A long string that should go on the heap";
520   auto fmt = format("{}", kStr.str()); // Pass a temporary std::string.
521   EXPECT_EQ(fmt.str(), kStr);
522   // The formatter can be reused.
523   EXPECT_EQ(fmt.str(), kStr);
524 }
525
526 namespace {
527
528 struct NoncopyableInt : MoveOnly {
529   explicit NoncopyableInt(int v) : value(v) {}
530   int value;
531 };
532
533 } // namespace
534
535 namespace folly {
536
537 template <>
538 class FormatValue<NoncopyableInt> {
539  public:
540   explicit FormatValue(const NoncopyableInt& v) : v_(v) {}
541
542   template <class FormatCallback>
543   void format(FormatArg& arg, FormatCallback& cb) const {
544     FormatValue<int>(v_.value).format(arg, cb);
545   }
546
547  private:
548   const NoncopyableInt& v_;
549 };
550
551 } // namespace folly
552
553 TEST(Format, NoncopyableArg) {
554   {
555     // Test that lvalues are held by reference.
556     NoncopyableInt v(1);
557     auto fmt = format("{}", v);
558     EXPECT_EQ(fmt.str(), "1");
559     // The formatter can be reused.
560     EXPECT_EQ(fmt.str(), "1");
561   }
562
563   {
564     // Test that rvalues are moved.
565     auto fmt = format("{}", NoncopyableInt(1));
566     EXPECT_EQ(fmt.str(), "1");
567   }
568 }