]> git.proxmox.com Git - ceph.git/blame - ceph/src/fmt/test/std-format-test.cc
buildsys: change download over to reef release
[ceph.git] / ceph / src / fmt / test / std-format-test.cc
CommitLineData
f67539c2
TL
1#include <format>
2
20effc67 3#include "gtest/gtest.h"
f67539c2 4
20effc67 5TEST(std_format_test, escaping) {
f67539c2
TL
6 using namespace std;
7 string s = format("{0}-{{", 8); // s == "8-{"
8 EXPECT_EQ(s, "8-{");
9}
10
20effc67 11TEST(std_format_test, indexing) {
f67539c2
TL
12 using namespace std;
13 string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing
14 string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing
15 EXPECT_EQ(s0, "a to b");
16 EXPECT_EQ(s1, "b to a");
17 // Error: mixing automatic and manual indexing
18 EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error);
19 // Error: mixing automatic and manual indexing
20 EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error);
21}
22
20effc67 23TEST(std_format_test, alignment) {
f67539c2
TL
24 using namespace std;
25 char c = 120;
26 string s0 = format("{:6}", 42); // s0 == " 42"
27 string s1 = format("{:6}", 'x'); // s1 == "x "
28 string s2 = format("{:*<6}", 'x'); // s2 == "x*****"
29 string s3 = format("{:*>6}", 'x'); // s3 == "*****x"
30 string s4 = format("{:*^6}", 'x'); // s4 == "**x***"
31 // Error: '=' with charT and no integer presentation type
32 EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error);
33 string s6 = format("{:6d}", c); // s6 == " 120"
34 string s7 = format("{:6}", true); // s9 == "true "
35 EXPECT_EQ(s0, " 42");
36 EXPECT_EQ(s1, "x ");
37 EXPECT_EQ(s2, "x*****");
38 EXPECT_EQ(s3, "*****x");
39 EXPECT_EQ(s4, "**x***");
40 EXPECT_EQ(s6, " 120");
41 EXPECT_EQ(s7, "true ");
42}
43
20effc67 44TEST(std_format_test, float) {
f67539c2
TL
45 using namespace std;
46 double inf = numeric_limits<double>::infinity();
47 double nan = numeric_limits<double>::quiet_NaN();
48 string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1"
49 string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1"
50 string s2 =
51 format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf"
52 string s3 =
53 format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan"
54 EXPECT_EQ(s0, "1 +1 1 1");
55 EXPECT_EQ(s1, "-1 -1 -1 -1");
56 EXPECT_EQ(s2, "inf +inf inf inf");
57 EXPECT_EQ(s3, "nan +nan nan nan");
58}
59
20effc67 60TEST(std_format_test, int) {
f67539c2
TL
61 using namespace std;
62 string s0 = format("{}", 42); // s0 == "42"
63 string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a"
64 string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A"
20effc67 65 string s3 = format("{:L}", 1234); // s3 == "1234" (depends on the locale)
f67539c2
TL
66 EXPECT_EQ(s0, "42");
67 EXPECT_EQ(s1, "101010 42 52 2a");
68 EXPECT_EQ(s2, "0x2a 0X2A");
69 EXPECT_EQ(s3, "1234");
70}
71
72#include <format>
73
74enum color { red, green, blue };
75
76const char* color_names[] = {"red", "green", "blue"};
77
78template <> struct std::formatter<color> : std::formatter<const char*> {
79 auto format(color c, format_context& ctx) {
80 return formatter<const char*>::format(color_names[c], ctx);
81 }
82};
83
84struct err {};
85
20effc67 86TEST(std_format_test, formatter) {
f67539c2
TL
87 std::string s0 = std::format("{}", 42); // OK: library-provided formatter
88 // std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled
89 // formatter
90 std::string s2 = std::format("{}", red); // OK: user-provided formatter
91 // std::string s3 = std::format("{}", err{}); // Ill-formed: disabled
92 // formatter
93 EXPECT_EQ(s0, "42");
94 EXPECT_EQ(s2, "red");
95}
96
97struct S {
98 int value;
99};
100
101template <> struct std::formatter<S> {
102 size_t width_arg_id = 0;
103
104 // Parses a width argument id in the format { <digit> }.
105 constexpr auto parse(format_parse_context& ctx) {
20effc67
TL
106 constexpr auto is_ascii_digit = [](const char c) {
107 return c >= '0' && c <= '9';
108 };
109
f67539c2
TL
110 auto iter = ctx.begin();
111 // auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; };
112 auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; };
113 if (get_char() != '{') return iter;
114 ++iter;
115 char c = get_char();
20effc67 116 if (!is_ascii_digit(c) || (++iter, get_char()) != '}')
f67539c2 117 throw format_error("invalid format");
20effc67 118 width_arg_id = fmt::detail::to_unsigned(c - '0');
f67539c2
TL
119 ctx.check_arg_id(width_arg_id);
120 return ++iter;
121 }
122
123 // Formats S with width given by the argument width_arg_id.
124 auto format(S s, format_context& ctx) {
125 int width = visit_format_arg(
126 [](auto value) -> int {
127 using type = decltype(value);
128 if constexpr (!is_integral_v<type> || is_same_v<type, bool>)
129 throw format_error("width is not integral");
130 // else if (value < 0 || value > numeric_limits<int>::max())
131 else if (fmt::detail::is_negative(value) ||
132 value > numeric_limits<int>::max())
133 throw format_error("invalid width");
134 else
135 return static_cast<int>(value);
136 },
137 ctx.arg(width_arg_id));
138 return format_to(ctx.out(), "{0:{1}}", s.value, width);
139 }
140};
141
20effc67 142TEST(std_format_test, parsing) {
f67539c2
TL
143 std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42"
144 EXPECT_EQ(s, " 42");
145}
146
147#if FMT_USE_INT128
148template <> struct std::formatter<__int128_t> : std::formatter<long long> {
149 auto format(__int128_t n, format_context& ctx) {
150 // Format as a long long since we only want to check if it is possible to
151 // specialize formatter for __int128_t.
152 return formatter<long long>::format(static_cast<long long>(n), ctx);
153 }
154};
155
20effc67 156TEST(std_format_test, int128) {
f67539c2
TL
157 __int128_t n = 42;
158 auto s = std::format("{}", n);
159 EXPECT_EQ(s, "42");
160}
161#endif // FMT_USE_INT128