]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Formatting library for C++ - the core API |
2 | // | |
3 | // Copyright (c) 2012 - present, Victor Zverovich | |
4 | // All rights reserved. | |
5 | // | |
6 | // For the license information refer to format.h. | |
7 | // | |
8 | // Copyright (c) 2018 - present, Remotion (Igor Schulz) | |
9 | // All Rights Reserved | |
10 | // {fmt} support for ranges, containers and types tuple interface. | |
11 | ||
f67539c2 TL |
12 | #include "fmt/ranges.h" |
13 | ||
20effc67 TL |
14 | #include <map> |
15 | #include <string> | |
16 | #include <vector> | |
f67539c2 | 17 | |
20effc67 | 18 | #include "gtest/gtest.h" |
11fdf7f2 | 19 | |
20effc67 TL |
20 | #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 601 |
21 | # define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY | |
22 | #endif | |
11fdf7f2 | 23 | |
20effc67 TL |
24 | #if !FMT_MSC_VER || FMT_MSC_VER > 1910 |
25 | # define FMT_RANGES_TEST_ENABLE_JOIN | |
26 | # define FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT | |
27 | #endif | |
11fdf7f2 | 28 | |
20effc67 TL |
29 | #ifdef FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY |
30 | TEST(ranges_test, format_array) { | |
31 | int arr[] = {1, 2, 3, 5, 7, 11}; | |
32 | EXPECT_EQ(fmt::format("{}", arr), "[1, 2, 3, 5, 7, 11]"); | |
11fdf7f2 TL |
33 | } |
34 | ||
20effc67 TL |
35 | TEST(ranges_test, format_2d_array) { |
36 | int arr[][2] = {{1, 2}, {3, 5}, {7, 11}}; | |
37 | EXPECT_EQ(fmt::format("{}", arr), "[[1, 2], [3, 5], [7, 11]]"); | |
11fdf7f2 TL |
38 | } |
39 | ||
20effc67 TL |
40 | TEST(ranges_test, format_array_of_literals) { |
41 | const char* arr[] = {"1234", "abcd"}; | |
42 | EXPECT_EQ(fmt::format("{}", arr), "[\"1234\", \"abcd\"]"); | |
11fdf7f2 | 43 | } |
20effc67 | 44 | #endif // FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY |
11fdf7f2 | 45 | |
20effc67 TL |
46 | TEST(ranges_test, format_vector) { |
47 | auto v = std::vector<int>{1, 2, 3, 5, 7, 11}; | |
48 | EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]"); | |
f67539c2 TL |
49 | } |
50 | ||
20effc67 TL |
51 | TEST(ranges_test, format_vector2) { |
52 | auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}}; | |
53 | EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]"); | |
54 | } | |
f67539c2 | 55 | |
20effc67 TL |
56 | TEST(ranges_test, format_map) { |
57 | auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}}; | |
58 | EXPECT_EQ(fmt::format("{}", m), "[(\"one\", 1), (\"two\", 2)]"); | |
59 | } | |
f67539c2 | 60 | |
20effc67 TL |
61 | TEST(ranges_test, format_pair) { |
62 | auto p = std::pair<int, float>(42, 1.5f); | |
63 | EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)"); | |
f67539c2 TL |
64 | } |
65 | ||
20effc67 TL |
66 | TEST(ranges_test, format_tuple) { |
67 | auto t = | |
68 | std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i'); | |
69 | EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')"); | |
70 | EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()"); | |
11fdf7f2 TL |
71 | } |
72 | ||
20effc67 TL |
73 | #ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT |
74 | struct tuple_like { | |
75 | int i; | |
76 | std::string str; | |
77 | ||
78 | template <size_t N> fmt::enable_if_t<N == 0, int> get() const noexcept { | |
79 | return i; | |
80 | } | |
81 | template <size_t N> | |
82 | fmt::enable_if_t<N == 1, fmt::string_view> get() const noexcept { | |
83 | return str; | |
11fdf7f2 TL |
84 | } |
85 | }; | |
86 | ||
20effc67 TL |
87 | template <size_t N> |
88 | auto get(const tuple_like& t) noexcept -> decltype(t.get<N>()) { | |
89 | return t.get<N>(); | |
11fdf7f2 TL |
90 | } |
91 | ||
92 | namespace std { | |
20effc67 TL |
93 | template <> |
94 | struct tuple_size<tuple_like> : std::integral_constant<size_t, 2> {}; | |
11fdf7f2 | 95 | |
20effc67 TL |
96 | template <size_t N> struct tuple_element<N, tuple_like> { |
97 | using type = decltype(std::declval<tuple_like>().get<N>()); | |
11fdf7f2 | 98 | }; |
11fdf7f2 TL |
99 | } // namespace std |
100 | ||
20effc67 TL |
101 | TEST(ranges_test, format_struct) { |
102 | auto t = tuple_like{42, "foo"}; | |
103 | EXPECT_EQ(fmt::format("{}", t), "(42, \"foo\")"); | |
11fdf7f2 | 104 | } |
20effc67 | 105 | #endif // FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT |
11fdf7f2 | 106 | |
20effc67 | 107 | TEST(ranges_test, format_to) { |
9f95a23c | 108 | char buf[10]; |
20effc67 | 109 | auto end = fmt::format_to(buf, "{}", std::vector<int>{1, 2, 3}); |
9f95a23c | 110 | *end = '\0'; |
20effc67 | 111 | EXPECT_STREQ(buf, "[1, 2, 3]"); |
9f95a23c TL |
112 | } |
113 | ||
f67539c2 TL |
114 | struct path_like { |
115 | const path_like* begin() const; | |
116 | const path_like* end() const; | |
117 | ||
118 | operator std::string() const; | |
119 | }; | |
120 | ||
20effc67 | 121 | TEST(ranges_test, path_like) { |
f67539c2 TL |
122 | EXPECT_FALSE((fmt::is_range<path_like, char>::value)); |
123 | } | |
124 | ||
f67539c2 TL |
125 | #ifdef FMT_USE_STRING_VIEW |
126 | struct string_like { | |
127 | const char* begin(); | |
128 | const char* end(); | |
129 | explicit operator fmt::string_view() const { return "foo"; } | |
130 | explicit operator std::string_view() const { return "foo"; } | |
131 | }; | |
132 | ||
20effc67 TL |
133 | TEST(ranges_test, format_string_like) { |
134 | EXPECT_EQ(fmt::format("{}", string_like()), "foo"); | |
f67539c2 TL |
135 | } |
136 | #endif // FMT_USE_STRING_VIEW | |
137 | ||
20effc67 TL |
138 | // A range that provides non-const only begin()/end() to test fmt::join handles |
139 | // that. | |
140 | // | |
141 | // Some ranges (e.g. those produced by range-v3's views::filter()) can cache | |
142 | // information during iteration so they only provide non-const begin()/end(). | |
143 | template <typename T> class non_const_only_range { | |
144 | private: | |
145 | std::vector<T> vec; | |
146 | ||
147 | public: | |
148 | using const_iterator = typename ::std::vector<T>::const_iterator; | |
149 | ||
150 | template <typename... Args> | |
151 | explicit non_const_only_range(Args&&... args) | |
152 | : vec(std::forward<Args>(args)...) {} | |
153 | ||
154 | const_iterator begin() { return vec.begin(); } | |
155 | const_iterator end() { return vec.end(); } | |
156 | }; | |
157 | ||
158 | template <typename T> class noncopyable_range { | |
159 | private: | |
160 | std::vector<T> vec; | |
161 | ||
162 | public: | |
163 | using const_iterator = typename ::std::vector<T>::const_iterator; | |
164 | ||
165 | template <typename... Args> | |
166 | explicit noncopyable_range(Args&&... args) | |
167 | : vec(std::forward<Args>(args)...) {} | |
168 | ||
169 | noncopyable_range(noncopyable_range const&) = delete; | |
170 | noncopyable_range(noncopyable_range&) = delete; | |
171 | ||
172 | const_iterator begin() const { return vec.begin(); } | |
173 | const_iterator end() const { return vec.end(); } | |
174 | }; | |
175 | ||
176 | TEST(ranges_test, range) { | |
177 | noncopyable_range<int> w(3u, 0); | |
178 | EXPECT_EQ(fmt::format("{}", w), "[0, 0, 0]"); | |
179 | EXPECT_EQ(fmt::format("{}", noncopyable_range<int>(3u, 0)), "[0, 0, 0]"); | |
180 | ||
181 | non_const_only_range<int> x(3u, 0); | |
182 | EXPECT_EQ(fmt::format("{}", x), "[0, 0, 0]"); | |
183 | EXPECT_EQ(fmt::format("{}", non_const_only_range<int>(3u, 0)), "[0, 0, 0]"); | |
184 | ||
185 | auto y = std::vector<int>(3u, 0); | |
186 | EXPECT_EQ(fmt::format("{}", y), "[0, 0, 0]"); | |
187 | EXPECT_EQ(fmt::format("{}", std::vector<int>(3u, 0)), "[0, 0, 0]"); | |
188 | ||
189 | const auto z = std::vector<int>(3u, 0); | |
190 | EXPECT_EQ(fmt::format("{}", z), "[0, 0, 0]"); | |
191 | } | |
192 | ||
193 | #if !FMT_MSC_VER || FMT_MSC_VER >= 1927 | |
194 | struct unformattable {}; | |
195 | ||
196 | TEST(ranges_test, unformattable_range) { | |
197 | EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>, | |
198 | fmt::format_context>::value)); | |
199 | } | |
200 | #endif | |
201 | ||
202 | #ifdef FMT_RANGES_TEST_ENABLE_JOIN | |
203 | TEST(ranges_test, join_tuple) { | |
204 | // Value tuple args. | |
205 | auto t1 = std::tuple<char, int, float>('a', 1, 2.0f); | |
206 | EXPECT_EQ(fmt::format("({})", fmt::join(t1, ", ")), "(a, 1, 2)"); | |
207 | ||
208 | // Testing lvalue tuple args. | |
209 | int x = 4; | |
210 | auto t2 = std::tuple<char, int&>('b', x); | |
211 | EXPECT_EQ(fmt::format("{}", fmt::join(t2, " + ")), "b + 4"); | |
212 | ||
213 | // Empty tuple. | |
214 | auto t3 = std::tuple<>(); | |
215 | EXPECT_EQ(fmt::format("{}", fmt::join(t3, "|")), ""); | |
216 | ||
217 | // Single element tuple. | |
218 | auto t4 = std::tuple<float>(4.0f); | |
219 | EXPECT_EQ(fmt::format("{}", fmt::join(t4, "/")), "4"); | |
220 | } | |
221 | ||
222 | TEST(ranges_test, join_initializer_list) { | |
223 | EXPECT_EQ(fmt::format("{}", fmt::join({1, 2, 3}, ", ")), "1, 2, 3"); | |
224 | EXPECT_EQ(fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " ")), | |
225 | "fmt rocks !"); | |
226 | } | |
227 | ||
f67539c2 | 228 | struct zstring_sentinel {}; |
20effc67 | 229 | |
f67539c2 TL |
230 | bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } |
231 | bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } | |
20effc67 | 232 | |
f67539c2 TL |
233 | struct zstring { |
234 | const char* p; | |
235 | const char* begin() const { return p; } | |
236 | zstring_sentinel end() const { return {}; } | |
237 | }; | |
20effc67 TL |
238 | |
239 | TEST(ranges_test, join_sentinel) { | |
240 | auto hello = zstring{"hello"}; | |
241 | EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']"); | |
242 | EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o"); | |
243 | } | |
244 | ||
245 | TEST(ranges_test, join_range) { | |
246 | noncopyable_range<int> w(3u, 0); | |
247 | EXPECT_EQ(fmt::format("{}", fmt::join(w, ",")), "0,0,0"); | |
248 | EXPECT_EQ(fmt::format("{}", fmt::join(noncopyable_range<int>(3u, 0), ",")), | |
249 | "0,0,0"); | |
250 | ||
251 | non_const_only_range<int> x(3u, 0); | |
252 | EXPECT_EQ(fmt::format("{}", fmt::join(x, ",")), "0,0,0"); | |
253 | EXPECT_EQ(fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ",")), | |
254 | "0,0,0"); | |
255 | ||
256 | auto y = std::vector<int>(3u, 0); | |
257 | EXPECT_EQ(fmt::format("{}", fmt::join(y, ",")), "0,0,0"); | |
258 | EXPECT_EQ(fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ",")), | |
259 | "0,0,0"); | |
260 | ||
261 | const auto z = std::vector<int>(3u, 0); | |
262 | EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0"); | |
f67539c2 | 263 | } |
20effc67 | 264 | #endif // FMT_RANGES_TEST_ENABLE_JOIN |