]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 | ||
eafe8130 TL |
27 | #if FMT_HAS_CPP_ATTRIBUTE(noreturn) |
28 | # define FMT_NORETURN [[noreturn]] | |
29 | #else | |
30 | # define FMT_NORETURN | |
31 | #endif | |
32 | ||
11fdf7f2 TL |
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 | ||
eafe8130 TL |
105 | TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) { |
106 | fmt::memory_buffer buf; | |
107 | grisu2_format(4.2f, buf, fmt::core_format_specs()); | |
108 | } | |
109 | ||
11fdf7f2 TL |
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(); | |
eafe8130 | 132 | if (std::signbit(-nan)) |
11fdf7f2 TL |
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) { | |
eafe8130 | 139 | char *message = FMT_NULL; |
11fdf7f2 | 140 | char buffer[BUFFER_SIZE]; |
eafe8130 TL |
141 | EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0), |
142 | "invalid buffer"); | |
11fdf7f2 TL |
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); | |
eafe8130 | 155 | EXPECT_EQ(result, 0); |
11fdf7f2 TL |
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) { | |
eafe8130 | 210 | EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), |
11fdf7f2 | 211 | "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); |
eafe8130 | 212 | EXPECT_WRITE(stdout, fmt::print(fg(fmt::color::blue), "blue"), |
11fdf7f2 | 213 | "\x1b[38;2;000;000;255mblue\x1b[0m"); |
eafe8130 TL |
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"); | |
11fdf7f2 | 236 | } |