]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/fmt/test/format-impl-test.cc
import ceph 14.2.5
[ceph.git] / ceph / src / seastar / fmt / test / format-impl-test.cc
1 // Formatting library for C++ - formatting library implementation tests
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7
8 #define FMT_NOEXCEPT
9 #undef FMT_SHARED
10 #include "test-assert.h"
11
12 // Include format.cc instead of format.h to test implementation.
13 #include "../src/format.cc"
14 #include "fmt/color.h"
15 #include "fmt/printf.h"
16
17 #include <algorithm>
18 #include <cstring>
19
20 #include "gmock.h"
21 #include "gtest-extra.h"
22 #include "util.h"
23
24 #undef min
25 #undef max
26
27 #if FMT_HAS_CPP_ATTRIBUTE(noreturn)
28 # define FMT_NORETURN [[noreturn]]
29 #else
30 # define FMT_NORETURN
31 #endif
32
33 using fmt::internal::fp;
34
35 template <bool is_iec559>
36 void test_construct_from_double() {
37 fmt::print("warning: double is not IEC559, skipping FP tests\n");
38 }
39
40 template <>
41 void test_construct_from_double<true>() {
42 auto v = fp(1.23);
43 EXPECT_EQ(v.f, 0x13ae147ae147aeu);
44 EXPECT_EQ(v.e, -52);
45 }
46
47 TEST(FPTest, ConstructFromDouble) {
48 test_construct_from_double<std::numeric_limits<double>::is_iec559>();
49 }
50
51 TEST(FPTest, Normalize) {
52 auto v = fp(0xbeef, 42);
53 v.normalize();
54 EXPECT_EQ(0xbeef000000000000, v.f);
55 EXPECT_EQ(-6, v.e);
56 }
57
58 TEST(FPTest, ComputeBoundariesSubnormal) {
59 auto v = fp(0xbeef, 42);
60 fp lower, upper;
61 v.compute_boundaries(lower, upper);
62 EXPECT_EQ(0xbeee800000000000, lower.f);
63 EXPECT_EQ(-6, lower.e);
64 EXPECT_EQ(0xbeef800000000000, upper.f);
65 EXPECT_EQ(-6, upper.e);
66 }
67
68 TEST(FPTest, ComputeBoundaries) {
69 auto v = fp(0x10000000000000, 42);
70 fp lower, upper;
71 v.compute_boundaries(lower, upper);
72 EXPECT_EQ(0x7ffffffffffffe00, lower.f);
73 EXPECT_EQ(31, lower.e);
74 EXPECT_EQ(0x8000000000000400, upper.f);
75 EXPECT_EQ(31, upper.e);
76 }
77
78 TEST(FPTest, Subtract) {
79 auto v = fp(123, 1) - fp(102, 1);
80 EXPECT_EQ(v.f, 21u);
81 EXPECT_EQ(v.e, 1);
82 }
83
84 TEST(FPTest, Multiply) {
85 auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
86 EXPECT_EQ(v.f, 123u * 56u);
87 EXPECT_EQ(v.e, 4 + 7 + 64);
88 v = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
89 EXPECT_EQ(v.f, (123 * 567 + 1u) / 2);
90 EXPECT_EQ(v.e, 4 + 8 + 64);
91 }
92
93 TEST(FPTest, GetCachedPower) {
94 typedef std::numeric_limits<double> limits;
95 for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
96 int dec_exp = 0;
97 auto fp = fmt::internal::get_cached_power(exp, dec_exp);
98 EXPECT_LE(exp, fp.e);
99 int dec_exp_step = 8;
100 EXPECT_LE(fp.e, exp + dec_exp_step * log2(10));
101 EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(fp.f, fp.e));
102 }
103 }
104
105 TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
106 fmt::memory_buffer buf;
107 grisu2_format(4.2f, buf, fmt::core_format_specs());
108 }
109
110 template <typename T>
111 struct ValueExtractor: fmt::internal::function<T> {
112 T operator()(T value) {
113 return value;
114 }
115
116 template <typename U>
117 FMT_NORETURN T operator()(U) {
118 throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name()));
119 }
120 };
121
122 TEST(FormatTest, ArgConverter) {
123 long long value = std::numeric_limits<long long>::max();
124 auto arg = fmt::internal::make_arg<fmt::format_context>(value);
125 visit(fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
126 arg);
127 EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
128 }
129
130 TEST(FormatTest, FormatNegativeNaN) {
131 double nan = std::numeric_limits<double>::quiet_NaN();
132 if (std::signbit(-nan))
133 EXPECT_EQ("-nan", fmt::format("{}", -nan));
134 else
135 fmt::print("Warning: compiler doesn't handle negative NaN correctly");
136 }
137
138 TEST(FormatTest, StrError) {
139 char *message = FMT_NULL;
140 char buffer[BUFFER_SIZE];
141 EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0),
142 "invalid buffer");
143 EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
144 "invalid buffer");
145 buffer[0] = 'x';
146 #if defined(_GNU_SOURCE) && !defined(__COVERITY__)
147 // Use invalid error code to make sure that safe_strerror returns an error
148 // message in the buffer rather than a pointer to a static string.
149 int error_code = -1;
150 #else
151 int error_code = EDOM;
152 #endif
153
154 int result = fmt::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
155 EXPECT_EQ(result, 0);
156 std::size_t message_size = std::strlen(message);
157 EXPECT_GE(BUFFER_SIZE - 1u, message_size);
158 EXPECT_EQ(get_system_error(error_code), message);
159
160 // safe_strerror never uses buffer on MinGW.
161 #ifndef __MINGW32__
162 result = fmt::safe_strerror(error_code, message = buffer, message_size);
163 EXPECT_EQ(ERANGE, result);
164 result = fmt::safe_strerror(error_code, message = buffer, 1);
165 EXPECT_EQ(buffer, message); // Message should point to buffer.
166 EXPECT_EQ(ERANGE, result);
167 EXPECT_STREQ("", message);
168 #endif
169 }
170
171 TEST(FormatTest, FormatErrorCode) {
172 std::string msg = "error 42", sep = ": ";
173 {
174 fmt::memory_buffer buffer;
175 format_to(buffer, "garbage");
176 fmt::format_error_code(buffer, 42, "test");
177 EXPECT_EQ("test: " + msg, to_string(buffer));
178 }
179 {
180 fmt::memory_buffer buffer;
181 std::string prefix(
182 fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
183 fmt::format_error_code(buffer, 42, prefix);
184 EXPECT_EQ(msg, to_string(buffer));
185 }
186 int codes[] = {42, -1};
187 for (std::size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) {
188 // Test maximum buffer size.
189 msg = fmt::format("error {}", codes[i]);
190 fmt::memory_buffer buffer;
191 std::string prefix(
192 fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
193 fmt::format_error_code(buffer, codes[i], prefix);
194 EXPECT_EQ(prefix + sep + msg, to_string(buffer));
195 std::size_t size = fmt::inline_buffer_size;
196 EXPECT_EQ(size, buffer.size());
197 buffer.resize(0);
198 // Test with a message that doesn't fit into the buffer.
199 prefix += 'x';
200 fmt::format_error_code(buffer, codes[i], prefix);
201 EXPECT_EQ(msg, to_string(buffer));
202 }
203 }
204
205 TEST(FormatTest, CountCodePoints) {
206 EXPECT_EQ(4, fmt::internal::count_code_points(fmt::u8string_view("ёжик")));
207 }
208
209 TEST(ColorsTest, Colors) {
210 EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
211 "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
212 EXPECT_WRITE(stdout, fmt::print(fg(fmt::color::blue), "blue"),
213 "\x1b[38;2;000;000;255mblue\x1b[0m");
214 EXPECT_WRITE(
215 stdout,
216 fmt::print(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
217 "\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
218 EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::bold, "bold"),
219 "\x1b[1mbold\x1b[0m");
220 EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::italic, "italic"),
221 "\x1b[3mitalic\x1b[0m");
222 EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::underline, "underline"),
223 "\x1b[4munderline\x1b[0m");
224 EXPECT_WRITE(stdout,
225 fmt::print(fmt::emphasis::strikethrough, "strikethrough"),
226 "\x1b[9mstrikethrough\x1b[0m");
227 EXPECT_WRITE(
228 stdout,
229 fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
230 "\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
231 EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
232 "\x1b[1mbold error\x1b[0m");
233 EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
234 "\x1b[38;2;000;000;255mblue log\x1b[0m");
235 EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
236 }