revert format()'s behavior of crashing on error
[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 Uint>
41 void compareOctal(Uint u) {
42   char buf1[detail::kMaxOctalLength + 1];
43   buf1[detail::kMaxOctalLength] = '\0';
44   char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
45
46   char buf2[detail::kMaxOctalLength + 1];
47   sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
48
49   EXPECT_EQ(std::string(buf2), std::string(p));
50 }
51
52 template <class Uint>
53 void compareHex(Uint u) {
54   char buf1[detail::kMaxHexLength + 1];
55   buf1[detail::kMaxHexLength] = '\0';
56   char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
57
58   char buf2[detail::kMaxHexLength + 1];
59   sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
60
61   EXPECT_EQ(std::string(buf2), std::string(p));
62 }
63
64 template <class Uint>
65 void compareBinary(Uint u) {
66   char buf[detail::kMaxBinaryLength + 1];
67   buf[detail::kMaxBinaryLength] = '\0';
68   char* p = buf + detail::uintToBinary(buf, detail::kMaxBinaryLength, u);
69
70   std::string repr;
71   if (u == 0) {
72     repr = '0';
73   } else {
74     std::string tmp;
75     for (; u; u >>= 1) {
76       tmp.push_back(u & 1 ? '1' : '0');
77     }
78     repr.assign(tmp.rbegin(), tmp.rend());
79   }
80
81   EXPECT_EQ(repr, std::string(p));
82 }
83
84 TEST(Format, uintToOctal) {
85   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
86     compareOctal(i);
87   }
88 }
89
90 TEST(Format, uintToHex) {
91   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
92     compareHex(i);
93   }
94 }
95
96 TEST(Format, uintToBinary) {
97   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
98     compareBinary(i);
99   }
100 }
101
102 TEST(Format, Simple) {
103   EXPECT_EQ("hello", fstr("hello"));
104   EXPECT_EQ("42", fstr("{}", 42));
105   EXPECT_EQ("42 42", fstr("{0} {0}", 42));
106   EXPECT_EQ("00042  23   42", fstr("{0:05} {1:3} {0:4}", 42, 23));
107   EXPECT_EQ("hello world hello 42",
108             fstr("{0} {1} {0} {2}", "hello", "world", 42));
109   EXPECT_EQ("XXhelloXX", fstr("{:X^9}", "hello"));
110   EXPECT_EQ("XXX42XXXX", fstr("{:X^9}", 42));
111   EXPECT_EQ("-0xYYYY2a", fstr("{:Y=#9x}", -42));
112   EXPECT_EQ("*", fstr("{}", '*'));
113   EXPECT_EQ("42", fstr("{}", 42));
114   EXPECT_EQ("0042", fstr("{:04}", 42));
115
116   EXPECT_EQ("hello  ", fstr("{:7}", "hello"));
117   EXPECT_EQ("hello  ", fstr("{:<7}", "hello"));
118   EXPECT_EQ("  hello", fstr("{:>7}", "hello"));
119
120   std::vector<int> v1 {10, 20, 30};
121   EXPECT_EQ("0020", fstr("{0[1]:04}", v1));
122   EXPECT_EQ("0020", vstr("{1:04}", v1));
123   EXPECT_EQ("10 20", vstr("{} {}", v1));
124
125   const std::vector<int> v2 = v1;
126   EXPECT_EQ("0020", fstr("{0[1]:04}", v2));
127   EXPECT_EQ("0020", vstr("{1:04}", v2));
128
129   const int p[] = {10, 20, 30};
130   const int* q = p;
131   EXPECT_EQ("0020", fstr("{0[1]:04}", p));
132   EXPECT_EQ("0020", vstr("{1:04}", p));
133   EXPECT_EQ("0020", fstr("{0[1]:04}", q));
134   EXPECT_EQ("0020", vstr("{1:04}", q));
135   EXPECT_NE("", fstr("{}", q));
136
137   EXPECT_EQ("0x", fstr("{}", p).substr(0, 2));
138   EXPECT_EQ("10", vstr("{}", p));
139   EXPECT_EQ("0x", fstr("{}", q).substr(0, 2));
140   EXPECT_EQ("10", vstr("{}", q));
141   q = nullptr;
142   EXPECT_EQ("(null)", fstr("{}", q));
143
144   std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
145   EXPECT_EQ("worldXX", fstr("{[20]:X<7}", m));
146   EXPECT_EQ("worldXX", vstr("{20:X<7}", m));
147
148   std::map<std::string, std::string> m2 { {"hello", "world"} };
149   EXPECT_EQ("worldXX", fstr("{[hello]:X<7}", m2));
150   EXPECT_EQ("worldXX", vstr("{hello:X<7}", m2));
151
152   // Test indexing in strings
153   EXPECT_EQ("61 62", fstr("{0[0]:x} {0[1]:x}", "abcde"));
154   EXPECT_EQ("61 62", vstr("{0:x} {1:x}", "abcde"));
155   EXPECT_EQ("61 62", fstr("{0[0]:x} {0[1]:x}", std::string("abcde")));
156   EXPECT_EQ("61 62", vstr("{0:x} {1:x}", std::string("abcde")));
157
158   // Test booleans
159   EXPECT_EQ("true", fstr("{}", true));
160   EXPECT_EQ("1", fstr("{:d}", true));
161   EXPECT_EQ("false", fstr("{}", false));
162   EXPECT_EQ("0", fstr("{:d}", false));
163
164   // Test pairs
165   {
166     std::pair<int, std::string> p {42, "hello"};
167     EXPECT_EQ("    42 hello ", fstr("{0[0]:6} {0[1]:6}", p));
168     EXPECT_EQ("    42 hello ", vstr("{:6} {:6}", p));
169   }
170
171   // Test tuples
172   {
173     std::tuple<int, std::string, int> t { 42, "hello", 23 };
174     EXPECT_EQ("    42 hello      23", fstr("{0[0]:6} {0[1]:6} {0[2]:6}", t));
175     EXPECT_EQ("    42 hello      23", vstr("{:6} {:6} {:6}", t));
176   }
177
178   // Test writing to stream
179   std::ostringstream os;
180   os << format("{} {}", 42, 23);
181   EXPECT_EQ("42 23", os.str());
182
183   // Test appending to string
184   std::string s;
185   format(&s, "{} {}", 42, 23);
186   format(&s, " hello {:X<7}", "world");
187   EXPECT_EQ("42 23 hello worldXX", s);
188
189   // Test writing to FILE. I'd use open_memstream but that's not available
190   // outside of Linux (even though it's in POSIX.1-2008).
191   {
192     int fds[2];
193     CHECK_ERR(pipe(fds));
194     SCOPE_EXIT { closeNoInt(fds[1]); };
195     {
196       FILE* fp = fdopen(fds[1], "wb");
197       PCHECK(fp);
198       SCOPE_EXIT { fclose(fp); };
199       writeTo(fp, format("{} {}", 42, 23));  // <= 512 bytes (PIPE_BUF)
200     }
201
202     char buf[512];
203     ssize_t n = readFull(fds[0], buf, sizeof(buf));
204     CHECK_GE(n, 0);
205
206     EXPECT_EQ("42 23", std::string(buf, n));
207   }
208 }
209
210 TEST(Format, Float) {
211   double d = 1;
212   EXPECT_EQ("1", fstr("{}", 1.0));
213   EXPECT_EQ("0.1", fstr("{}", 0.1));
214   EXPECT_EQ("0.01", fstr("{}", 0.01));
215   EXPECT_EQ("0.001", fstr("{}", 0.001));
216   EXPECT_EQ("0.0001", fstr("{}", 0.0001));
217   EXPECT_EQ("1e-5", fstr("{}", 0.00001));
218   EXPECT_EQ("1e-6", fstr("{}", 0.000001));
219
220   EXPECT_EQ("10", fstr("{}", 10.0));
221   EXPECT_EQ("100", fstr("{}", 100.0));
222   EXPECT_EQ("1000", fstr("{}", 1000.0));
223   EXPECT_EQ("10000", fstr("{}", 10000.0));
224   EXPECT_EQ("100000", fstr("{}", 100000.0));
225   EXPECT_EQ("1e+6", fstr("{}", 1000000.0));
226   EXPECT_EQ("1e+7", fstr("{}", 10000000.0));
227
228   EXPECT_EQ("1.00", fstr("{:.2f}", 1.0));
229   EXPECT_EQ("0.10", fstr("{:.2f}", 0.1));
230   EXPECT_EQ("0.01", fstr("{:.2f}", 0.01));
231   EXPECT_EQ("0.00", fstr("{:.2f}", 0.001));
232 }
233
234 TEST(Format, MultiLevel) {
235   std::vector<std::map<std::string, std::string>> v = {
236     {
237       {"hello", "world"},
238     },
239   };
240
241   EXPECT_EQ("world", fstr("{[0.hello]}", v));
242 }
243
244 TEST(Format, dynamic) {
245   auto dyn = parseJson(
246       "{\n"
247       "  \"hello\": \"world\",\n"
248       "  \"x\": [20, 30],\n"
249       "  \"y\": {\"a\" : 42}\n"
250       "}");
251
252   EXPECT_EQ("world", fstr("{0[hello]}", dyn));
253   EXPECT_EQ("20", fstr("{0[x.0]}", dyn));
254   EXPECT_EQ("42", fstr("{0[y.a]}", dyn));
255
256   EXPECT_EQ("(null)", fstr("{}", dynamic(nullptr)));
257 }
258
259 namespace {
260
261 struct KeyValue {
262   std::string key;
263   int value;
264 };
265
266 }  // namespace
267
268 namespace folly {
269
270 template <> class FormatValue<KeyValue> {
271  public:
272   explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
273
274   template <class FormatCallback>
275   void format(FormatArg& arg, FormatCallback& cb) const {
276     format_value::formatFormatter(
277         folly::format("<key={}, value={}>", kv_.key, kv_.value),
278         arg, cb);
279   }
280
281  private:
282   const KeyValue& kv_;
283 };
284
285 }  // namespace
286
287 TEST(Format, Custom) {
288   KeyValue kv { "hello", 42 };
289
290   EXPECT_EQ("<key=hello, value=42>", fstr("{}", kv));
291   EXPECT_EQ("<key=hello, value=42>", fstr("{:10}", kv));
292   EXPECT_EQ("<key=hello", fstr("{:.10}", kv));
293   EXPECT_EQ("<key=hello, value=42>XX", fstr("{:X<23}", kv));
294   EXPECT_EQ("XX<key=hello, value=42>", fstr("{:X>23}", kv));
295   EXPECT_EQ("<key=hello, value=42>", fstr("{0[0]}", &kv));
296   EXPECT_NE("", fstr("{}", &kv));
297 }
298
299 namespace {
300
301 struct Opaque {
302   int k;
303 };
304
305 } // namespace
306
307 TEST(Format, Unformatted) {
308   Opaque o;
309   EXPECT_NE("", fstr("{}", &o));
310   EXPECT_THROW(fstr("{0[0]}", &o), std::invalid_argument);
311 }
312
313 TEST(Format, Nested) {
314   EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, format("{} {}", 3, 4)));
315   //
316   // not copyable, must hold temporary in scope instead.
317   auto&& saved = format("{} {}", 3, 4);
318   EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, saved));
319 }
320
321 TEST(Format, OutOfBounds) {
322   std::vector<int> ints{1, 2, 3, 4, 5};
323   EXPECT_EQ("1 3 5", fstr("{0[0]} {0[2]} {0[4]}", ints));
324   EXPECT_THROW(fstr("{[5]}", ints), std::out_of_range);
325
326   std::map<std::string, int> map{{"hello", 0}, {"world", 1}};
327   EXPECT_EQ("hello = 0", fstr("hello = {[hello]}", map));
328   EXPECT_THROW(fstr("{[nope]}", map), std::out_of_range);
329   EXPECT_THROW(vstr("{nope}", map), std::out_of_range);
330 }
331
332 TEST(Format, BogusFormatString) {
333   EXPECT_THROW(fstr("}"), std::invalid_argument);
334   EXPECT_THROW(fstr("foo}bar"), std::invalid_argument);
335   EXPECT_THROW(fstr("foo{bar"), std::invalid_argument);
336   EXPECT_THROW(fstr("{[test]"), std::invalid_argument);
337
338   // This one fails in detail::enforceWhitespace(), which throws
339   // std::range_error
340   EXPECT_THROW(fstr("{0[test}"), std::exception);
341 }
342
343 int main(int argc, char *argv[]) {
344   testing::InitGoogleTest(&argc, argv);
345   google::ParseCommandLineFlags(&argc, &argv, true);
346   return RUN_ALL_TESTS();
347 }
348