add formatChecked(), which does not crash on bad format strings
[folly.git] / folly / test / FormatTest.cpp
1 /*
2  * Copyright 2014 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 using namespace folly;
29
30 template <class... Args>
31 std::string fstr(StringPiece fmt, Args&&... args) {
32   return format(fmt, std::forward<Args>(args)...).str();
33 }
34
35 template <class C>
36 std::string vstr(StringPiece fmt, const C& c) {
37   return vformat(fmt, c).str();
38 }
39
40 template <class... Args>
41 std::string fstrChecked(StringPiece fmt, Args&&... args) {
42   return formatChecked(fmt, std::forward<Args>(args)...).str();
43 }
44
45 template <class C>
46 std::string vstrChecked(StringPiece fmt, const C& c) {
47   return vformatChecked(fmt, c).str();
48 }
49
50 template <class Uint>
51 void compareOctal(Uint u) {
52   char buf1[detail::kMaxOctalLength + 1];
53   buf1[detail::kMaxOctalLength] = '\0';
54   char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
55
56   char buf2[detail::kMaxOctalLength + 1];
57   sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
58
59   EXPECT_EQ(std::string(buf2), std::string(p));
60 }
61
62 template <class Uint>
63 void compareHex(Uint u) {
64   char buf1[detail::kMaxHexLength + 1];
65   buf1[detail::kMaxHexLength] = '\0';
66   char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
67
68   char buf2[detail::kMaxHexLength + 1];
69   sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
70
71   EXPECT_EQ(std::string(buf2), std::string(p));
72 }
73
74 template <class Uint>
75 void compareBinary(Uint u) {
76   char buf[detail::kMaxBinaryLength + 1];
77   buf[detail::kMaxBinaryLength] = '\0';
78   char* p = buf + detail::uintToBinary(buf, detail::kMaxBinaryLength, u);
79
80   std::string repr;
81   if (u == 0) {
82     repr = '0';
83   } else {
84     std::string tmp;
85     for (; u; u >>= 1) {
86       tmp.push_back(u & 1 ? '1' : '0');
87     }
88     repr.assign(tmp.rbegin(), tmp.rend());
89   }
90
91   EXPECT_EQ(repr, std::string(p));
92 }
93
94 TEST(Format, uintToOctal) {
95   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
96     compareOctal(i);
97   }
98 }
99
100 TEST(Format, uintToHex) {
101   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
102     compareHex(i);
103   }
104 }
105
106 TEST(Format, uintToBinary) {
107   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
108     compareBinary(i);
109   }
110 }
111
112 TEST(Format, Simple) {
113   EXPECT_EQ("hello", fstr("hello"));
114   EXPECT_EQ("42", fstr("{}", 42));
115   EXPECT_EQ("42 42", fstr("{0} {0}", 42));
116   EXPECT_EQ("00042  23   42", fstr("{0:05} {1:3} {0:4}", 42, 23));
117   EXPECT_EQ("hello world hello 42",
118             fstr("{0} {1} {0} {2}", "hello", "world", 42));
119   EXPECT_EQ("XXhelloXX", fstr("{:X^9}", "hello"));
120   EXPECT_EQ("XXX42XXXX", fstr("{:X^9}", 42));
121   EXPECT_EQ("-0xYYYY2a", fstr("{:Y=#9x}", -42));
122   EXPECT_EQ("*", fstr("{}", '*'));
123   EXPECT_EQ("42", fstr("{}", 42));
124   EXPECT_EQ("0042", fstr("{:04}", 42));
125
126   EXPECT_EQ("hello  ", fstr("{:7}", "hello"));
127   EXPECT_EQ("hello  ", fstr("{:<7}", "hello"));
128   EXPECT_EQ("  hello", fstr("{:>7}", "hello"));
129
130   std::vector<int> v1 {10, 20, 30};
131   EXPECT_EQ("0020", fstr("{0[1]:04}", v1));
132   EXPECT_EQ("0020", vstr("{1:04}", v1));
133   EXPECT_EQ("10 20", vstr("{} {}", v1));
134
135   const std::vector<int> v2 = v1;
136   EXPECT_EQ("0020", fstr("{0[1]:04}", v2));
137   EXPECT_EQ("0020", vstr("{1:04}", v2));
138
139   const int p[] = {10, 20, 30};
140   const int* q = p;
141   EXPECT_EQ("0020", fstr("{0[1]:04}", p));
142   EXPECT_EQ("0020", vstr("{1:04}", p));
143   EXPECT_EQ("0020", fstr("{0[1]:04}", q));
144   EXPECT_EQ("0020", vstr("{1:04}", q));
145   EXPECT_NE("", fstr("{}", q));
146
147   EXPECT_EQ("0x", fstr("{}", p).substr(0, 2));
148   EXPECT_EQ("10", vstr("{}", p));
149   EXPECT_EQ("0x", fstr("{}", q).substr(0, 2));
150   EXPECT_EQ("10", vstr("{}", q));
151   q = nullptr;
152   EXPECT_EQ("(null)", fstr("{}", q));
153
154   std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
155   EXPECT_EQ("worldXX", fstr("{[20]:X<7}", m));
156   EXPECT_EQ("worldXX", vstr("{20:X<7}", m));
157
158   std::map<std::string, std::string> m2 { {"hello", "world"} };
159   EXPECT_EQ("worldXX", fstr("{[hello]:X<7}", m2));
160   EXPECT_EQ("worldXX", vstr("{hello:X<7}", m2));
161
162   // Test indexing in strings
163   EXPECT_EQ("61 62", fstr("{0[0]:x} {0[1]:x}", "abcde"));
164   EXPECT_EQ("61 62", vstr("{0:x} {1:x}", "abcde"));
165   EXPECT_EQ("61 62", fstr("{0[0]:x} {0[1]:x}", std::string("abcde")));
166   EXPECT_EQ("61 62", vstr("{0:x} {1:x}", std::string("abcde")));
167
168   // Test booleans
169   EXPECT_EQ("true", fstr("{}", true));
170   EXPECT_EQ("1", fstr("{:d}", true));
171   EXPECT_EQ("false", fstr("{}", false));
172   EXPECT_EQ("0", fstr("{:d}", false));
173
174   // Test pairs
175   {
176     std::pair<int, std::string> p {42, "hello"};
177     EXPECT_EQ("    42 hello ", fstr("{0[0]:6} {0[1]:6}", p));
178     EXPECT_EQ("    42 hello ", vstr("{: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", fstr("{0[0]:6} {0[1]:6} {0[2]:6}", t));
185     EXPECT_EQ("    42 hello      23", vstr("{: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", fstr("{}", 1.0));
223   EXPECT_EQ("0.1", fstr("{}", 0.1));
224   EXPECT_EQ("0.01", fstr("{}", 0.01));
225   EXPECT_EQ("0.001", fstr("{}", 0.001));
226   EXPECT_EQ("0.0001", fstr("{}", 0.0001));
227   EXPECT_EQ("1e-5", fstr("{}", 0.00001));
228   EXPECT_EQ("1e-6", fstr("{}", 0.000001));
229
230   EXPECT_EQ("10", fstr("{}", 10.0));
231   EXPECT_EQ("100", fstr("{}", 100.0));
232   EXPECT_EQ("1000", fstr("{}", 1000.0));
233   EXPECT_EQ("10000", fstr("{}", 10000.0));
234   EXPECT_EQ("100000", fstr("{}", 100000.0));
235   EXPECT_EQ("1e+6", fstr("{}", 1000000.0));
236   EXPECT_EQ("1e+7", fstr("{}", 10000000.0));
237
238   EXPECT_EQ("1.00", fstr("{:.2f}", 1.0));
239   EXPECT_EQ("0.10", fstr("{:.2f}", 0.1));
240   EXPECT_EQ("0.01", fstr("{:.2f}", 0.01));
241   EXPECT_EQ("0.00", fstr("{:.2f}", 0.001));
242 }
243
244 TEST(Format, MultiLevel) {
245   std::vector<std::map<std::string, std::string>> v = {
246     {
247       {"hello", "world"},
248     },
249   };
250
251   EXPECT_EQ("world", fstr("{[0.hello]}", v));
252 }
253
254 TEST(Format, dynamic) {
255   auto dyn = parseJson(
256       "{\n"
257       "  \"hello\": \"world\",\n"
258       "  \"x\": [20, 30],\n"
259       "  \"y\": {\"a\" : 42}\n"
260       "}");
261
262   EXPECT_EQ("world", fstr("{0[hello]}", dyn));
263   EXPECT_EQ("20", fstr("{0[x.0]}", dyn));
264   EXPECT_EQ("42", fstr("{0[y.a]}", dyn));
265
266   EXPECT_EQ("(null)", fstr("{}", dynamic(nullptr)));
267 }
268
269 namespace {
270
271 struct KeyValue {
272   std::string key;
273   int value;
274 };
275
276 }  // namespace
277
278 namespace folly {
279
280 template <> class FormatValue<KeyValue> {
281  public:
282   explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
283
284   template <class FormatCallback>
285   void format(FormatArg& arg, FormatCallback& cb) const {
286     format_value::formatFormatter(
287         folly::format("<key={}, value={}>", kv_.key, kv_.value),
288         arg, cb);
289   }
290
291  private:
292   const KeyValue& kv_;
293 };
294
295 }  // namespace
296
297 TEST(Format, Custom) {
298   KeyValue kv { "hello", 42 };
299
300   EXPECT_EQ("<key=hello, value=42>", fstr("{}", kv));
301   EXPECT_EQ("<key=hello, value=42>", fstr("{:10}", kv));
302   EXPECT_EQ("<key=hello", fstr("{:.10}", kv));
303   EXPECT_EQ("<key=hello, value=42>XX", fstr("{:X<23}", kv));
304   EXPECT_EQ("XX<key=hello, value=42>", fstr("{:X>23}", kv));
305   EXPECT_EQ("<key=hello, value=42>", fstr("{0[0]}", &kv));
306   EXPECT_NE("", fstr("{}", &kv));
307 }
308
309 namespace {
310
311 struct Opaque {
312   int k;
313 };
314
315 } // namespace
316
317 TEST(Format, Unformatted) {
318   Opaque o;
319   EXPECT_NE("", fstr("{}", &o));
320   EXPECT_DEATH(fstr("{0[0]}", &o), "No formatter available for this type");
321   EXPECT_THROW(fstrChecked("{0[0]}", &o), std::invalid_argument);
322 }
323
324 TEST(Format, Nested) {
325   EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, format("{} {}", 3, 4)));
326   //
327   // not copyable, must hold temporary in scope instead.
328   auto&& saved = format("{} {}", 3, 4);
329   EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, saved));
330 }
331
332 TEST(Format, OutOfBounds) {
333   std::vector<int> ints{1, 2, 3, 4, 5};
334   EXPECT_EQ("1 3 5", fstr("{0[0]} {0[2]} {0[4]}", ints));
335   EXPECT_THROW(fstr("{[5]}", ints), std::out_of_range);
336   EXPECT_THROW(fstrChecked("{[5]}", ints), std::out_of_range);
337
338   std::map<std::string, int> map{{"hello", 0}, {"world", 1}};
339   EXPECT_EQ("hello = 0", fstr("hello = {[hello]}", map));
340   EXPECT_THROW(fstr("{[nope]}", map), std::out_of_range);
341   EXPECT_THROW(vstr("{nope}", map), std::out_of_range);
342   EXPECT_THROW(vstrChecked("{nope}", map), std::out_of_range);
343 }
344
345 TEST(Format, BogusFormatString) {
346   // format() will crash the program if the format string is invalid.
347   EXPECT_DEATH(fstr("}"), "single '}' in format string");
348   EXPECT_DEATH(fstr("foo}bar"), "single '}' in format string");
349   EXPECT_DEATH(fstr("foo{bar"), "missing ending '}'");
350   EXPECT_DEATH(fstr("{[test]"), "missing ending '}'");
351   EXPECT_DEATH(fstr("{-1.3}"), "argument index must be non-negative");
352   EXPECT_DEATH(fstr("{1.3}", 0, 1, 2), "index not allowed");
353   EXPECT_DEATH(fstr("{0} {} {1}", 0, 1, 2),
354                "may not have both default and explicit arg indexes");
355
356   // formatChecked() should throw exceptions rather than crashing the program
357   EXPECT_THROW(fstrChecked("}"), std::invalid_argument);
358   EXPECT_THROW(fstrChecked("foo}bar"), std::invalid_argument);
359   EXPECT_THROW(fstrChecked("foo{bar"), std::invalid_argument);
360   EXPECT_THROW(fstrChecked("{[test]"), std::invalid_argument);
361   EXPECT_THROW(fstrChecked("{-1.3}"), std::invalid_argument);
362   EXPECT_THROW(fstrChecked("{1.3}", 0, 1, 2), std::invalid_argument);
363   EXPECT_THROW(fstrChecked("{0} {} {1}", 0, 1, 2), std::invalid_argument);
364
365   // This one fails in detail::enforceWhitespace(), which throws
366   // std::range_error
367   EXPECT_DEATH(fstr("{0[test}"), "Non-whitespace: \\[");
368   EXPECT_THROW(fstrChecked("{0[test}"), std::exception);
369 }
370
371 int main(int argc, char *argv[]) {
372   testing::InitGoogleTest(&argc, argv);
373   google::ParseCommandLineFlags(&argc, &argv, true);
374   return RUN_ALL_TESTS();
375 }
376