c34fd49c0f8560196223b798efe095535625ad18
[folly.git] / folly / test / FormatTest.cpp
1 /*
2  * Copyright 2012 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/dynamic.h"
25 #include "folly/json.h"
26
27 using namespace folly;
28
29 template <class... Args>
30 std::string fstr(StringPiece fmt, Args&&... args) {
31   return format(fmt, std::forward<Args>(args)...).str();
32 }
33
34 template <class C>
35 std::string vstr(StringPiece fmt, const C& c) {
36   return vformat(fmt, c).str();
37 }
38
39 template <class Uint>
40 void compareOctal(Uint u) {
41   char buf1[detail::kMaxOctalLength + 1];
42   buf1[detail::kMaxOctalLength] = '\0';
43   char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
44
45   char buf2[detail::kMaxOctalLength + 1];
46   sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
47
48   EXPECT_EQ(std::string(buf2), std::string(p));
49 }
50
51 template <class Uint>
52 void compareHex(Uint u) {
53   char buf1[detail::kMaxHexLength + 1];
54   buf1[detail::kMaxHexLength] = '\0';
55   char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
56
57   char buf2[detail::kMaxHexLength + 1];
58   sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
59
60   EXPECT_EQ(std::string(buf2), std::string(p));
61 }
62
63 template <class Uint>
64 void compareBinary(Uint u) {
65   char buf[detail::kMaxBinaryLength + 1];
66   buf[detail::kMaxBinaryLength] = '\0';
67   char* p = buf + detail::uintToBinary(buf, detail::kMaxBinaryLength, u);
68
69   std::string repr;
70   if (u == 0) {
71     repr = '0';
72   } else {
73     std::string tmp;
74     for (; u; u >>= 1) {
75       tmp.push_back(u & 1 ? '1' : '0');
76     }
77     repr.assign(tmp.rbegin(), tmp.rend());
78   }
79
80   EXPECT_EQ(repr, std::string(p));
81 }
82
83 TEST(Format, uintToOctal) {
84   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
85     compareOctal(i);
86   }
87 }
88
89 TEST(Format, uintToHex) {
90   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
91     compareHex(i);
92   }
93 }
94
95 TEST(Format, uintToBinary) {
96   for (unsigned i = 0; i < (1u << 16) + 2; i++) {
97     compareBinary(i);
98   }
99 }
100
101 TEST(Format, Simple) {
102   EXPECT_EQ("hello", fstr("hello"));
103   EXPECT_EQ("42", fstr("{}", 42));
104   EXPECT_EQ("42 42", fstr("{0} {0}", 42));
105   EXPECT_EQ("00042  23   42", fstr("{0:05} {1:3} {0:4}", 42, 23));
106   EXPECT_EQ("hello world hello 42",
107             fstr("{0} {1} {0} {2}", "hello", "world", 42));
108   EXPECT_EQ("XXhelloXX", fstr("{:X^9}", "hello"));
109   EXPECT_EQ("XXX42XXXX", fstr("{:X^9}", 42));
110   EXPECT_EQ("-0xYYYY2a", fstr("{:Y=#9x}", -42));
111   EXPECT_EQ("*", fstr("{}", '*'));
112   EXPECT_EQ("42", fstr("{}", 42));
113   EXPECT_EQ("0042", fstr("{:04}", 42));
114
115   EXPECT_EQ("hello  ", fstr("{:7}", "hello"));
116   EXPECT_EQ("hello  ", fstr("{:<7}", "hello"));
117   EXPECT_EQ("  hello", fstr("{:>7}", "hello"));
118
119   std::vector<int> v1 {10, 20, 30};
120   EXPECT_EQ("0020", fstr("{0[1]:04}", v1));
121   EXPECT_EQ("0020", vstr("{1:04}", v1));
122   EXPECT_EQ("10 20", vstr("{} {}", v1));
123
124   const std::vector<int> v2 = v1;
125   EXPECT_EQ("0020", fstr("{0[1]:04}", v2));
126   EXPECT_EQ("0020", vstr("{1:04}", v2));
127
128   const int p[] = {10, 20, 30};
129   const int* q = p;
130   EXPECT_EQ("0020", fstr("{0[1]:04}", p));
131   EXPECT_EQ("0020", vstr("{1:04}", p));
132   EXPECT_EQ("0020", fstr("{0[1]:04}", q));
133   EXPECT_EQ("0020", vstr("{1:04}", q));
134   EXPECT_NE("", fstr("{}", q));
135
136   EXPECT_EQ("0x", fstr("{}", p).substr(0, 2));
137   EXPECT_EQ("10", vstr("{}", p));
138   EXPECT_EQ("0x", fstr("{}", q).substr(0, 2));
139   EXPECT_EQ("10", vstr("{}", q));
140   q = nullptr;
141   EXPECT_EQ("(null)", fstr("{}", q));
142
143   std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
144   EXPECT_EQ("worldXX", fstr("{[20]:X<7}", m));
145   EXPECT_EQ("worldXX", vstr("{20:X<7}", m));
146
147   std::map<std::string, std::string> m2 { {"hello", "world"} };
148   EXPECT_EQ("worldXX", fstr("{[hello]:X<7}", m2));
149   EXPECT_EQ("worldXX", vstr("{hello:X<7}", m2));
150
151   // Test indexing in strings
152   EXPECT_EQ("61 62", fstr("{0[0]:x} {0[1]:x}", "abcde"));
153   EXPECT_EQ("61 62", vstr("{0:x} {1:x}", "abcde"));
154   EXPECT_EQ("61 62", fstr("{0[0]:x} {0[1]:x}", std::string("abcde")));
155   EXPECT_EQ("61 62", vstr("{0:x} {1:x}", std::string("abcde")));
156
157   // Test booleans
158   EXPECT_EQ("true", fstr("{}", true));
159   EXPECT_EQ("1", fstr("{:d}", true));
160   EXPECT_EQ("false", fstr("{}", false));
161   EXPECT_EQ("0", fstr("{:d}", false));
162
163   // Test pairs
164   {
165     std::pair<int, std::string> p {42, "hello"};
166     EXPECT_EQ("    42 hello ", fstr("{0[0]:6} {0[1]:6}", p));
167     EXPECT_EQ("    42 hello ", vstr("{:6} {:6}", p));
168   }
169
170   // Test tuples
171   {
172     std::tuple<int, std::string, int> t { 42, "hello", 23 };
173     EXPECT_EQ("    42 hello      23", fstr("{0[0]:6} {0[1]:6} {0[2]:6}", t));
174     EXPECT_EQ("    42 hello      23", vstr("{:6} {:6} {:6}", t));
175   }
176
177   // Test writing to stream
178   std::ostringstream os;
179   os << format("{} {}", 42, 23);
180   EXPECT_EQ("42 23", os.str());
181
182   // Test appending to string
183   std::string s;
184   format(&s, "{} {}", 42, 23);
185   format(&s, " hello {:X<7}", "world");
186   EXPECT_EQ("42 23 hello worldXX", s);
187 }
188
189 namespace {
190 void testFloat(const char* fmt, double val) {
191   char buf[100];
192   sprintf(buf, to<std::string>("%", fmt).c_str(), val);
193
194   EXPECT_EQ(buf, fstr(to<std::string>("{:", fmt, "}"), val));
195 }
196 }  // namespace
197
198 TEST(Format, Float) {
199   double d = 1;
200   EXPECT_EQ("1", fstr("{}", 1.0));
201   EXPECT_EQ("0.1", fstr("{}", 0.1));
202   EXPECT_EQ("0.01", fstr("{}", 0.01));
203   EXPECT_EQ("0.001", fstr("{}", 0.001));
204   EXPECT_EQ("0.0001", fstr("{}", 0.0001));
205   EXPECT_EQ("1e-5", fstr("{}", 0.00001));
206   EXPECT_EQ("1e-6", fstr("{}", 0.000001));
207
208   EXPECT_EQ("10", fstr("{}", 10.0));
209   EXPECT_EQ("100", fstr("{}", 100.0));
210   EXPECT_EQ("1000", fstr("{}", 1000.0));
211   EXPECT_EQ("10000", fstr("{}", 10000.0));
212   EXPECT_EQ("100000", fstr("{}", 100000.0));
213   EXPECT_EQ("1e+6", fstr("{}", 1000000.0));
214   EXPECT_EQ("1e+7", fstr("{}", 10000000.0));
215
216   EXPECT_EQ("1.00", fstr("{:.2f}", 1.0));
217   EXPECT_EQ("0.10", fstr("{:.2f}", 0.1));
218   EXPECT_EQ("0.01", fstr("{:.2f}", 0.01));
219   EXPECT_EQ("0.00", fstr("{:.2f}", 0.001));
220 }
221
222 TEST(Format, MultiLevel) {
223   std::vector<std::map<std::string, std::string>> v = {
224     {
225       {"hello", "world"},
226     },
227   };
228
229   EXPECT_EQ("world", fstr("{[0.hello]}", v));
230 }
231
232 TEST(Format, dynamic) {
233   auto dyn = parseJson(
234       "{\n"
235       "  \"hello\": \"world\",\n"
236       "  \"x\": [20, 30],\n"
237       "  \"y\": {\"a\" : 42}\n"
238       "}");
239
240   EXPECT_EQ("world", fstr("{0[hello]}", dyn));
241   EXPECT_EQ("20", fstr("{0[x.0]}", dyn));
242   EXPECT_EQ("42", fstr("{0[y.a]}", dyn));
243
244   EXPECT_EQ("(null)", fstr("{}", dynamic(nullptr)));
245 }
246
247 namespace {
248
249 struct KeyValue {
250   std::string key;
251   int value;
252 };
253
254 }  // namespace
255
256 namespace folly {
257
258 template <> class FormatValue<KeyValue> {
259  public:
260   explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
261
262   template <class FormatCallback>
263   void format(FormatArg& arg, FormatCallback& cb) const {
264     format_value::formatFormatter(
265         folly::format("<key={}, value={}>", kv_.key, kv_.value),
266         arg, cb);
267   }
268
269  private:
270   const KeyValue& kv_;
271 };
272
273 }  // namespace
274
275 TEST(Format, Custom) {
276   KeyValue kv { "hello", 42 };
277
278   EXPECT_EQ("<key=hello, value=42>", fstr("{}", kv));
279   EXPECT_EQ("<key=hello, value=42>", fstr("{:10}", kv));
280   EXPECT_EQ("<key=hello", fstr("{:.10}", kv));
281   EXPECT_EQ("<key=hello, value=42>XX", fstr("{:X<23}", kv));
282   EXPECT_EQ("XX<key=hello, value=42>", fstr("{:X>23}", kv));
283   EXPECT_EQ("<key=hello, value=42>", fstr("{0[0]}", &kv));
284   EXPECT_NE("", fstr("{}", &kv));
285 }
286
287 namespace {
288
289 struct Opaque {
290   int k;
291 };
292
293 } // namespace
294
295 TEST(Format, Unformatted) {
296   Opaque o;
297   EXPECT_NE("", fstr("{}", &o));
298   EXPECT_THROW(fstr("{0[0]}", &o), std::invalid_argument);
299 }
300
301 TEST(Format, Nested) {
302   EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, format("{} {}", 3, 4)));
303   //
304   // not copyable, must hold temporary in scope instead.
305   auto&& saved = format("{} {}", 3, 4);
306   EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, saved));
307 }
308
309 int main(int argc, char *argv[]) {
310   testing::InitGoogleTest(&argc, argv);
311   google::ParseCommandLineFlags(&argc, &argv, true);
312   return RUN_ALL_TESTS();
313 }
314