2 * Copyright 2012 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/dynamic.h"
25 #include "folly/json.h"
27 using namespace folly;
29 template <class... Args>
30 std::string fstr(StringPiece fmt, Args&&... args) {
31 return format(fmt, std::forward<Args>(args)...).str();
35 std::string vstr(StringPiece fmt, const C& c) {
36 return vformat(fmt, c).str();
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);
45 char buf2[detail::kMaxOctalLength + 1];
46 sprintf(buf2, "%jo", static_cast<uintmax_t>(u));
48 EXPECT_EQ(std::string(buf2), std::string(p));
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);
57 char buf2[detail::kMaxHexLength + 1];
58 sprintf(buf2, "%jx", static_cast<uintmax_t>(u));
60 EXPECT_EQ(std::string(buf2), std::string(p));
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);
75 tmp.push_back(u & 1 ? '1' : '0');
77 repr.assign(tmp.rbegin(), tmp.rend());
80 EXPECT_EQ(repr, std::string(p));
83 TEST(Format, uintToOctal) {
84 for (unsigned i = 0; i < (1u << 16) + 2; i++) {
89 TEST(Format, uintToHex) {
90 for (unsigned i = 0; i < (1u << 16) + 2; i++) {
95 TEST(Format, uintToBinary) {
96 for (unsigned i = 0; i < (1u << 16) + 2; i++) {
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));
115 EXPECT_EQ("hello ", fstr("{:7}", "hello"));
116 EXPECT_EQ("hello ", fstr("{:<7}", "hello"));
117 EXPECT_EQ(" hello", fstr("{:>7}", "hello"));
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));
124 const std::vector<int> v2 = v1;
125 EXPECT_EQ("0020", fstr("{0[1]:04}", v2));
126 EXPECT_EQ("0020", vstr("{1:04}", v2));
128 const int p[] = {10, 20, 30};
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));
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));
141 EXPECT_EQ("(null)", fstr("{}", q));
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));
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));
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")));
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));
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));
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));
177 // Test writing to stream
178 std::ostringstream os;
179 os << format("{} {}", 42, 23);
180 EXPECT_EQ("42 23", os.str());
182 // Test appending to string
184 format(&s, "{} {}", 42, 23);
185 format(&s, " hello {:X<7}", "world");
186 EXPECT_EQ("42 23 hello worldXX", s);
190 void testFloat(const char* fmt, double val) {
192 sprintf(buf, to<std::string>("%", fmt).c_str(), val);
194 EXPECT_EQ(buf, fstr(to<std::string>("{:", fmt, "}"), val));
198 TEST(Format, Float) {
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));
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));
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));
222 TEST(Format, MultiLevel) {
223 std::vector<std::map<std::string, std::string>> v = {
229 EXPECT_EQ("world", fstr("{[0.hello]}", v));
232 TEST(Format, dynamic) {
233 auto dyn = parseJson(
235 " \"hello\": \"world\",\n"
236 " \"x\": [20, 30],\n"
237 " \"y\": {\"a\" : 42}\n"
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));
244 EXPECT_EQ("(null)", fstr("{}", dynamic(nullptr)));
258 template <> class FormatValue<KeyValue> {
260 explicit FormatValue(const KeyValue& kv) : kv_(kv) { }
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),
275 TEST(Format, Custom) {
276 KeyValue kv { "hello", 42 };
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));
295 TEST(Format, Unformatted) {
297 EXPECT_NE("", fstr("{}", &o));
298 EXPECT_THROW(fstr("{0[0]}", &o), std::invalid_argument);
301 TEST(Format, Nested) {
302 EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, format("{} {}", 3, 4)));
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));
309 int main(int argc, char *argv[]) {
310 testing::InitGoogleTest(&argc, argv);
311 google::ParseCommandLineFlags(&argc, &argv, true);
312 return RUN_ALL_TESTS();