1/*
2 * Copyright 2015-present 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
21#include <folly/FBVector.h>
22#include <folly/FileUtil.h>
23#include <folly/Portability.h>
24#include <folly/dynamic.h>
25#include <folly/json.h>
26#include <folly/portability/GTest.h>
27#include <folly/small_vector.h>
28
29using namespace folly;
30
31TEST(FormatOther, file) {
32 // Test writing to FILE. I'd use open_memstream but that's not available
33 // outside of Linux (even though it's in POSIX.1-2008).
34 {
35 int fds[2];
36 CHECK_ERR(pipe(fds));
37 SCOPE_EXIT {
38 // fclose on Windows automatically closes the underlying
39 // file descriptor.
40 if (!kIsWindows) {
41 closeNoInt(fds[1]);
42 }
43 };
44 {
45 FILE* fp = fdopen(fds[1], "wb");
46 PCHECK(fp);
47 SCOPE_EXIT {
48 fclose(fp);
49 };
50 writeTo(fp, format("{} {}", 42, 23)); // <= 512 bytes (PIPE_BUF)
51 }
52
53 char buf[512];
54 ssize_t n = readFull(fds[0], buf, sizeof(buf));
55 CHECK_GE(n, 0);
56
57 EXPECT_EQ("42 23", std::string(buf, n));
58 }
59}
60
61TEST(FormatOther, dynamic) {
62 auto dyn = parseJson(
63 "{\n"
64 " \"hello\": \"world\",\n"
65 " \"x\": [20, 30],\n"
66 " \"y\": {\"a\" : 42}\n"
67 "}");
68
69 EXPECT_EQ("world", sformat("{0[hello]}", dyn));
70 EXPECT_THROW(sformat("{0[none]}", dyn), std::out_of_range);
71 EXPECT_EQ("world", sformat("{0[hello]}", defaulted(dyn, "meow")));
72 EXPECT_EQ("meow", sformat("{0[none]}", defaulted(dyn, "meow")));
73
74 EXPECT_EQ("20", sformat("{0[x.0]}", dyn));
75 EXPECT_THROW(sformat("{0[x.2]}", dyn), std::out_of_range);
76
77 // No support for "deep" defaulting (dyn["x"] is not defaulted)
78 auto v = dyn.at("x");
79 EXPECT_EQ("20", sformat("{0[0]}", v));
80 EXPECT_THROW(sformat("{0[2]}", v), std::out_of_range);
81 EXPECT_EQ("20", sformat("{0[0]}", defaulted(v, 42)));
82 EXPECT_EQ("42", sformat("{0[2]}", defaulted(v, 42)));
83
84 EXPECT_EQ("42", sformat("{0[y.a]}", dyn));
85
86 EXPECT_EQ("(null)", sformat("{}", dynamic(nullptr)));
87}
88
89namespace {
90
91template <class T>
92void testFormatSeq() {
93 T v{10, 20, 30};
94 EXPECT_EQ("30 10", sformat("{0[2]} {0[0]}", v));
95 EXPECT_EQ("0020", sformat("{0[1]:04}", v));
96 EXPECT_EQ("0020", svformat("{1:04}", v));
97 EXPECT_EQ("10 20", svformat("{} {}", v));
98 EXPECT_EQ("10 20 0030", svformat("{} {} {:04}", v));
99}
100
101} // namespace
102
103TEST(FormatOther, fbvector) {
104 testFormatSeq<fbvector<int>>();
105}
106
107TEST(FormatOther, small_vector) {
108 testFormatSeq<small_vector<int, 2>>();
109}
110
111int main(int argc, char* argv[]) {
112 testing::InitGoogleTest(&argc, argv);
113 gflags::ParseCommandLineFlags(&argc, &argv, true);
114 return RUN_ALL_TESTS();
115}
116