2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "folly/Format.h"
19 #include <glog/logging.h>
20 #include <gflags/gflags.h>
21 #include <gtest/gtest.h>
23 #include "folly/FBVector.h"
24 #include "folly/FileUtil.h"
25 #include "folly/dynamic.h"
26 #include "folly/json.h"
28 using namespace folly;
31 void compareOctal(Uint u) {
32 char buf1[detail::kMaxOctalLength + 1];
33 buf1[detail::kMaxOctalLength] = '\0';
34 char* p = buf1 + detail::uintToOctal(buf1, detail::kMaxOctalLength, u);
36 char buf2[detail::kMaxOctalLength + 1];
37 sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
39 EXPECT_EQ(std::string(buf2), std::string(p));
43 void compareHex(Uint u) {
44 char buf1[detail::kMaxHexLength + 1];
45 buf1[detail::kMaxHexLength] = '\0';
46 char* p = buf1 + detail::uintToHexLower(buf1, detail::kMaxHexLength, u);
48 char buf2[detail::kMaxHexLength + 1];
49 sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
51 EXPECT_EQ(std::string(buf2), std::string(p));
55 void compareBinary(Uint u) {
56 char buf[detail::kMaxBinaryLength + 1];
57 buf[detail::kMaxBinaryLength] = '\0';
58 char* p = buf + detail::uintToBinary(buf, detail::kMaxBinaryLength, u);
66 tmp.push_back(u & 1 ? '1' : '0');
68 repr.assign(tmp.rbegin(), tmp.rend());
71 EXPECT_EQ(repr, std::string(p));
74 TEST(Format, uintToOctal) {
75 for (unsigned i = 0; i < (1u << 16) + 2; i++) {
80 TEST(Format, uintToHex) {
81 for (unsigned i = 0; i < (1u << 16) + 2; i++) {
86 TEST(Format, uintToBinary) {
87 for (unsigned i = 0; i < (1u << 16) + 2; i++) {
92 TEST(Format, Simple) {
93 EXPECT_EQ("hello", sformat("hello"));
94 EXPECT_EQ("42", sformat("{}", 42));
95 EXPECT_EQ("42 42", sformat("{0} {0}", 42));
96 EXPECT_EQ("00042 23 42", sformat("{0:05} {1:3} {0:4}", 42, 23));
97 EXPECT_EQ("hello world hello 42",
98 sformat("{0} {1} {0} {2}", "hello", "world", 42));
99 EXPECT_EQ("XXhelloXX", sformat("{:X^9}", "hello"));
100 EXPECT_EQ("XXX42XXXX", sformat("{:X^9}", 42));
101 EXPECT_EQ("-0xYYYY2a", sformat("{:Y=#9x}", -42));
102 EXPECT_EQ("*", sformat("{}", '*'));
103 EXPECT_EQ("42", sformat("{}", 42));
104 EXPECT_EQ("0042", sformat("{:04}", 42));
106 EXPECT_EQ("hello ", sformat("{:7}", "hello"));
107 EXPECT_EQ("hello ", sformat("{:<7}", "hello"));
108 EXPECT_EQ(" hello", sformat("{:>7}", "hello"));
110 std::vector<int> v1 {10, 20, 30};
111 EXPECT_EQ("0020", sformat("{0[1]:04}", v1));
112 EXPECT_EQ("0020", svformat("{1:04}", v1));
113 EXPECT_EQ("10 20", svformat("{} {}", v1));
115 const std::vector<int> v2 = v1;
116 EXPECT_EQ("0020", sformat("{0[1]:04}", v2));
117 EXPECT_EQ("0020", svformat("{1:04}", v2));
118 EXPECT_THROW(sformat("{0[3]:04}", v2), std::out_of_range);
119 EXPECT_THROW(svformat("{3:04}", v2), std::out_of_range);
120 EXPECT_EQ("0020", sformat("{0[1]:04}", defaulted(v2, 42)));
121 EXPECT_EQ("0020", svformat("{1:04}", defaulted(v2, 42)));
122 EXPECT_EQ("0042", sformat("{0[3]:04}", defaulted(v2, 42)));
123 EXPECT_EQ("0042", svformat("{3:04}", defaulted(v2, 42)));
125 const int p[] = {10, 20, 30};
127 EXPECT_EQ("0020", sformat("{0[1]:04}", p));
128 EXPECT_EQ("0020", svformat("{1:04}", p));
129 EXPECT_EQ("0020", sformat("{0[1]:04}", q));
130 EXPECT_EQ("0020", svformat("{1:04}", q));
131 EXPECT_NE("", sformat("{}", q));
133 EXPECT_EQ("0x", sformat("{}", p).substr(0, 2));
134 EXPECT_EQ("10", svformat("{}", p));
135 EXPECT_EQ("0x", sformat("{}", q).substr(0, 2));
136 EXPECT_EQ("10", svformat("{}", q));
138 EXPECT_EQ("(null)", sformat("{}", q));
140 std::map<int, std::string> m { {10, "hello"}, {20, "world"} };
141 EXPECT_EQ("worldXX", sformat("{[20]:X<7}", m));
142 EXPECT_EQ("worldXX", svformat("{20:X<7}", m));
143 EXPECT_THROW(sformat("{[42]:X<7}", m), std::out_of_range);
144 EXPECT_THROW(svformat("{42:X<7}", m), std::out_of_range);
145 EXPECT_EQ("worldXX", sformat("{[20]:X<7}", defaulted(m, "meow")));
146 EXPECT_EQ("worldXX", svformat("{20:X<7}", defaulted(m, "meow")));
147 EXPECT_EQ("meowXXX", sformat("{[42]:X<7}", defaulted(m, "meow")));
148 EXPECT_EQ("meowXXX", svformat("{42:X<7}", defaulted(m, "meow")));
150 std::map<std::string, std::string> m2 { {"hello", "world"} };
151 EXPECT_EQ("worldXX", sformat("{[hello]:X<7}", m2));
152 EXPECT_EQ("worldXX", svformat("{hello:X<7}", m2));
153 EXPECT_THROW(sformat("{[none]:X<7}", m2), std::out_of_range);
154 EXPECT_THROW(svformat("{none:X<7}", m2), std::out_of_range);
155 EXPECT_EQ("worldXX", sformat("{[hello]:X<7}", defaulted(m2, "meow")));
156 EXPECT_EQ("worldXX", svformat("{hello:X<7}", defaulted(m2, "meow")));
157 EXPECT_EQ("meowXXX", sformat("{[none]:X<7}", defaulted(m2, "meow")));
158 EXPECT_EQ("meowXXX", svformat("{none:X<7}", defaulted(m2, "meow")));
160 // Test indexing in strings
161 EXPECT_EQ("61 62", sformat("{0[0]:x} {0[1]:x}", "abcde"));
162 EXPECT_EQ("61 62", svformat("{0:x} {1:x}", "abcde"));
163 EXPECT_EQ("61 62", sformat("{0[0]:x} {0[1]:x}", std::string("abcde")));
164 EXPECT_EQ("61 62", svformat("{0:x} {1:x}", std::string("abcde")));
167 EXPECT_EQ("true", sformat("{}", true));
168 EXPECT_EQ("1", sformat("{:d}", true));
169 EXPECT_EQ("false", sformat("{}", false));
170 EXPECT_EQ("0", sformat("{:d}", false));
174 std::pair<int, std::string> p {42, "hello"};
175 EXPECT_EQ(" 42 hello ", sformat("{0[0]:6} {0[1]:6}", p));
176 EXPECT_EQ(" 42 hello ", svformat("{:6} {:6}", p));
181 std::tuple<int, std::string, int> t { 42, "hello", 23 };
182 EXPECT_EQ(" 42 hello 23", sformat("{0[0]:6} {0[1]:6} {0[2]:6}", t));
183 EXPECT_EQ(" 42 hello 23", svformat("{:6} {:6} {:6}", t));
186 // Test writing to stream
187 std::ostringstream os;
188 os << format("{} {}", 42, 23);
189 EXPECT_EQ("42 23", os.str());
191 // Test appending to string
193 format(&s, "{} {}", 42, 23);
194 format(&s, " hello {:X<7}", "world");
195 EXPECT_EQ("42 23 hello worldXX", s);
197 // Test writing to FILE. I'd use open_memstream but that's not available
198 // outside of Linux (even though it's in POSIX.1-2008).
201 CHECK_ERR(pipe(fds));
202 SCOPE_EXIT { closeNoInt(fds[1]); };
204 FILE* fp = fdopen(fds[1], "wb");
206 SCOPE_EXIT { fclose(fp); };
207 writeTo(fp, format("{} {}", 42, 23)); // <= 512 bytes (PIPE_BUF)
211 ssize_t n = readFull(fds[0], buf, sizeof(buf));
214 EXPECT_EQ("42 23", std::string(buf, n));
218 TEST(Format, Float) {
220 EXPECT_EQ("1", sformat("{}", 1.0));
221 EXPECT_EQ("0.1", sformat("{}", 0.1));
222 EXPECT_EQ("0.01", sformat("{}", 0.01));
223 EXPECT_EQ("0.001", sformat("{}", 0.001));
224 EXPECT_EQ("0.0001", sformat("{}", 0.0001));
225 EXPECT_EQ("1e-5", sformat("{}", 0.00001));
226 EXPECT_EQ("1e-6", sformat("{}", 0.000001));
228 EXPECT_EQ("10", sformat("{}", 10.0));
229 EXPECT_EQ("100", sformat("{}", 100.0));
230 EXPECT_EQ("1000", sformat("{}", 1000.0));
231 EXPECT_EQ("10000", sformat("{}", 10000.0));
232 EXPECT_EQ("100000", sformat("{}", 100000.0));
233 EXPECT_EQ("1e+6", sformat("{}", 1000000.0));
234 EXPECT_EQ("1e+7", sformat("{}", 10000000.0));
236 EXPECT_EQ("1.00", sformat("{:.2f}", 1.0));
237 EXPECT_EQ("0.10", sformat("{:.2f}", 0.1));
238 EXPECT_EQ("0.01", sformat("{:.2f}", 0.01));
239 EXPECT_EQ("0.00", sformat("{:.2f}", 0.001));
242 TEST(Format, MultiLevel) {
243 std::vector<std::map<std::string, std::string>> v = {
249 EXPECT_EQ("world", sformat("{[0.hello]}", v));
252 TEST(Format, dynamic) {
253 auto dyn = parseJson(
255 " \"hello\": \"world\",\n"
256 " \"x\": [20, 30],\n"
257 " \"y\": {\"a\" : 42}\n"
260 EXPECT_EQ("world", sformat("{0[hello]}", dyn));
261 EXPECT_THROW(sformat("{0[none]}", dyn), std::out_of_range);
262 EXPECT_EQ("world", sformat("{0[hello]}", defaulted(dyn, "meow")));
263 EXPECT_EQ("meow", sformat("{0[none]}", defaulted(dyn, "meow")));
265 EXPECT_EQ("20", sformat("{0[x.0]}", dyn));
266 EXPECT_THROW(sformat("{0[x.2]}", dyn), std::out_of_range);
268 // No support for "deep" defaulting (dyn["x"] is not defaulted)
269 auto v = dyn.at("x");
270 EXPECT_EQ("20", sformat("{0[0]}", v));
271 EXPECT_THROW(sformat("{0[2]}", v), std::out_of_range);
272 EXPECT_EQ("20", sformat("{0[0]}", defaulted(v, 42)));
273 EXPECT_EQ("42", sformat("{0[2]}", defaulted(v, 42)));
275 EXPECT_EQ("42", sformat("{0[y.a]}", dyn));
277 EXPECT_EQ("(null)", sformat("{}", dynamic(nullptr)));
291 template <> class FormatValue<KeyValue> {
293 explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
295 template <class FormatCallback>
296 void format(FormatArg& arg, FormatCallback& cb) const {
297 format_value::formatFormatter(
298 folly::format("<key={}, value={}>", kv_.key, kv_.value),
308 TEST(Format, Custom) {
309 KeyValue kv { "hello", 42 };
311 EXPECT_EQ("<key=hello, value=42>", sformat("{}", kv));
312 EXPECT_EQ("<key=hello, value=42>", sformat("{:10}", kv));
313 EXPECT_EQ("<key=hello", sformat("{:.10}", kv));
314 EXPECT_EQ("<key=hello, value=42>XX", sformat("{:X<23}", kv));
315 EXPECT_EQ("XX<key=hello, value=42>", sformat("{:X>23}", kv));
316 EXPECT_EQ("<key=hello, value=42>", sformat("{0[0]}", &kv));
317 EXPECT_NE("", sformat("{}", &kv));
328 TEST(Format, Unformatted) {
330 EXPECT_NE("", sformat("{}", &o));
331 EXPECT_DEATH(sformat("{0[0]}", &o), "No formatter available for this type");
332 EXPECT_THROW(sformatChecked("{0[0]}", &o), std::invalid_argument);
335 TEST(Format, Nested) {
336 EXPECT_EQ("1 2 3 4", sformat("{} {} {}", 1, 2, format("{} {}", 3, 4)));
338 // not copyable, must hold temporary in scope instead.
339 auto&& saved = format("{} {}", 3, 4);
340 EXPECT_EQ("1 2 3 4", sformat("{} {} {}", 1, 2, saved));
343 TEST(Format, OutOfBounds) {
344 std::vector<int> ints{1, 2, 3, 4, 5};
345 EXPECT_EQ("1 3 5", sformat("{0[0]} {0[2]} {0[4]}", ints));
346 EXPECT_THROW(sformat("{[5]}", ints), std::out_of_range);
347 EXPECT_THROW(sformatChecked("{[5]}", ints), std::out_of_range);
349 std::map<std::string, int> map{{"hello", 0}, {"world", 1}};
350 EXPECT_EQ("hello = 0", sformat("hello = {[hello]}", map));
351 EXPECT_THROW(sformat("{[nope]}", map), std::out_of_range);
352 EXPECT_THROW(svformat("{nope}", map), std::out_of_range);
353 EXPECT_THROW(svformatChecked("{nope}", map), std::out_of_range);
356 TEST(Format, BogusFormatString) {
357 // format() will crash the program if the format string is invalid.
358 EXPECT_DEATH(sformat("}"), "single '}' in format string");
359 EXPECT_DEATH(sformat("foo}bar"), "single '}' in format string");
360 EXPECT_DEATH(sformat("foo{bar"), "missing ending '}'");
361 EXPECT_DEATH(sformat("{[test]"), "missing ending '}'");
362 EXPECT_DEATH(sformat("{-1.3}"), "argument index must be non-negative");
363 EXPECT_DEATH(sformat("{1.3}", 0, 1, 2), "index not allowed");
364 EXPECT_DEATH(sformat("{0} {} {1}", 0, 1, 2),
365 "may not have both default and explicit arg indexes");
367 // formatChecked() should throw exceptions rather than crashing the program
368 EXPECT_THROW(sformatChecked("}"), std::invalid_argument);
369 EXPECT_THROW(sformatChecked("foo}bar"), std::invalid_argument);
370 EXPECT_THROW(sformatChecked("foo{bar"), std::invalid_argument);
371 EXPECT_THROW(sformatChecked("{[test]"), std::invalid_argument);
372 EXPECT_THROW(sformatChecked("{-1.3}"), std::invalid_argument);
373 EXPECT_THROW(sformatChecked("{1.3}", 0, 1, 2), std::invalid_argument);
374 EXPECT_THROW(sformatChecked("{0} {} {1}", 0, 1, 2), std::invalid_argument);
376 // This one fails in detail::enforceWhitespace(), which throws
378 EXPECT_DEATH(sformat("{0[test}"), "Non-whitespace: \\[");
379 EXPECT_THROW(sformatChecked("{0[test}"), std::exception);
382 int main(int argc, char *argv[]) {
383 testing::InitGoogleTest(&argc, argv);
384 google::ParseCommandLineFlags(&argc, &argv, true);
385 return RUN_ALL_TESTS();