]> git.proxmox.com Git - ceph.git/blame - ceph/src/fmt/test/ranges-test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / fmt / test / ranges-test.cc
CommitLineData
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
30TEST(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
35TEST(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
40TEST(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
46TEST(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
51TEST(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
56TEST(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
61TEST(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
66TEST(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
74struct 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
87template <size_t N>
88auto get(const tuple_like& t) noexcept -> decltype(t.get<N>()) {
89 return t.get<N>();
11fdf7f2
TL
90}
91
92namespace std {
20effc67
TL
93template <>
94struct tuple_size<tuple_like> : std::integral_constant<size_t, 2> {};
11fdf7f2 95
20effc67
TL
96template <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
101TEST(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 107TEST(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
114struct path_like {
115 const path_like* begin() const;
116 const path_like* end() const;
117
118 operator std::string() const;
119};
120
20effc67 121TEST(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
126struct 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
133TEST(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().
143template <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
158template <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
176TEST(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
194struct unformattable {};
195
196TEST(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
203TEST(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
222TEST(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 228struct zstring_sentinel {};
20effc67 229
f67539c2
TL
230bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; }
231bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; }
20effc67 232
f67539c2
TL
233struct zstring {
234 const char* p;
235 const char* begin() const { return p; }
236 zstring_sentinel end() const { return {}; }
237};
20effc67
TL
238
239TEST(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
245TEST(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