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 | |
29 | using namespace folly; |
30 | |
31 | TEST(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 | |
61 | TEST(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 | |
89 | namespace { |
90 | |
91 | template <class T> |
92 | void 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 | |
103 | TEST(FormatOther, fbvector) { |
104 | testFormatSeq<fbvector<int>>(); |
105 | } |
106 | |
107 | TEST(FormatOther, small_vector) { |
108 | testFormatSeq<small_vector<int, 2>>(); |
109 | } |
110 | |
111 | int main(int argc, char* argv[]) { |
112 | testing::InitGoogleTest(&argc, argv); |
113 | gflags::ParseCommandLineFlags(&argc, &argv, true); |
114 | return RUN_ALL_TESTS(); |
115 | } |
116 | |