]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Formatting library for C++ - tests of custom Google Test assertions |
2 | // | |
3 | // Copyright (c) 2012 - present, Victor Zverovich | |
4 | // All rights reserved. | |
5 | // | |
6 | // For the license information refer to format.h. | |
7 | ||
8 | #include "gtest-extra.h" | |
9 | ||
9f95a23c | 10 | #include <gtest/gtest-spi.h> |
f67539c2 | 11 | |
9f95a23c TL |
12 | #include <cstring> |
13 | #include <memory> | |
11fdf7f2 | 14 | #include <stdexcept> |
11fdf7f2 | 15 | |
20effc67 | 16 | #include "fmt/os.h" |
11fdf7f2 TL |
17 | #include "util.h" |
18 | ||
11fdf7f2 | 19 | // Tests that assertion macros evaluate their arguments exactly once. |
20effc67 TL |
20 | namespace { |
21 | class single_evaluation_test : public ::testing::Test { | |
11fdf7f2 | 22 | protected: |
20effc67 | 23 | single_evaluation_test() { |
11fdf7f2 TL |
24 | p_ = s_; |
25 | a_ = 0; | |
26 | b_ = 0; | |
27 | } | |
28 | ||
29 | static const char* const s_; | |
30 | static const char* p_; | |
31 | ||
32 | static int a_; | |
33 | static int b_; | |
34 | }; | |
20effc67 | 35 | } // namespace |
11fdf7f2 | 36 | |
20effc67 TL |
37 | const char* const single_evaluation_test::s_ = "01234"; |
38 | const char* single_evaluation_test::p_; | |
39 | int single_evaluation_test::a_; | |
40 | int single_evaluation_test::b_; | |
11fdf7f2 TL |
41 | |
42 | void do_nothing() {} | |
43 | ||
f67539c2 | 44 | FMT_NORETURN void throw_exception() { throw std::runtime_error("test"); } |
11fdf7f2 | 45 | |
f67539c2 TL |
46 | FMT_NORETURN void throw_system_error() { |
47 | throw fmt::system_error(EDOM, "test"); | |
48 | } | |
11fdf7f2 TL |
49 | |
50 | // Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument | |
51 | // exactly once. | |
20effc67 | 52 | TEST_F(single_evaluation_test, failed_expect_throw_msg) { |
11fdf7f2 TL |
53 | EXPECT_NONFATAL_FAILURE( |
54 | EXPECT_THROW_MSG(throw_exception(), std::exception, p_++), "01234"); | |
55 | EXPECT_EQ(s_ + 1, p_); | |
56 | } | |
57 | ||
58 | // Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument | |
59 | // exactly once. | |
20effc67 | 60 | TEST_F(single_evaluation_test, failed_expect_system_error) { |
9f95a23c TL |
61 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++), |
62 | "01234"); | |
11fdf7f2 TL |
63 | EXPECT_EQ(s_ + 1, p_); |
64 | } | |
65 | ||
11fdf7f2 | 66 | // Tests that assertion arguments are evaluated exactly once. |
20effc67 | 67 | TEST_F(single_evaluation_test, exception_tests) { |
11fdf7f2 | 68 | // successful EXPECT_THROW_MSG |
9f95a23c TL |
69 | EXPECT_THROW_MSG( |
70 | { // NOLINT | |
71 | a_++; | |
72 | throw_exception(); | |
73 | }, | |
74 | std::exception, (b_++, "test")); | |
11fdf7f2 TL |
75 | EXPECT_EQ(1, a_); |
76 | EXPECT_EQ(1, b_); | |
77 | ||
78 | // failed EXPECT_THROW_MSG, throws different type | |
9f95a23c TL |
79 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG( |
80 | { // NOLINT | |
81 | a_++; | |
82 | throw_exception(); | |
83 | }, | |
84 | std::logic_error, (b_++, "test")), | |
85 | "throws a different type"); | |
11fdf7f2 TL |
86 | EXPECT_EQ(2, a_); |
87 | EXPECT_EQ(2, b_); | |
88 | ||
89 | // failed EXPECT_THROW_MSG, throws an exception with different message | |
9f95a23c TL |
90 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG( |
91 | { // NOLINT | |
92 | a_++; | |
93 | throw_exception(); | |
94 | }, | |
95 | std::exception, (b_++, "other")), | |
96 | "throws an exception with a different message"); | |
11fdf7f2 TL |
97 | EXPECT_EQ(3, a_); |
98 | EXPECT_EQ(3, b_); | |
99 | ||
100 | // failed EXPECT_THROW_MSG, throws nothing | |
101 | EXPECT_NONFATAL_FAILURE( | |
102 | EXPECT_THROW_MSG(a_++, std::exception, (b_++, "test")), "throws nothing"); | |
103 | EXPECT_EQ(4, a_); | |
104 | EXPECT_EQ(4, b_); | |
105 | } | |
106 | ||
20effc67 | 107 | TEST_F(single_evaluation_test, system_error_tests) { |
11fdf7f2 | 108 | // successful EXPECT_SYSTEM_ERROR |
9f95a23c TL |
109 | EXPECT_SYSTEM_ERROR( |
110 | { // NOLINT | |
111 | a_++; | |
112 | throw_system_error(); | |
113 | }, | |
114 | EDOM, (b_++, "test")); | |
11fdf7f2 TL |
115 | EXPECT_EQ(1, a_); |
116 | EXPECT_EQ(1, b_); | |
117 | ||
118 | // failed EXPECT_SYSTEM_ERROR, throws different type | |
9f95a23c TL |
119 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR( |
120 | { // NOLINT | |
121 | a_++; | |
122 | throw_exception(); | |
123 | }, | |
124 | EDOM, (b_++, "test")), | |
125 | "throws a different type"); | |
11fdf7f2 TL |
126 | EXPECT_EQ(2, a_); |
127 | EXPECT_EQ(2, b_); | |
128 | ||
129 | // failed EXPECT_SYSTEM_ERROR, throws an exception with different message | |
9f95a23c TL |
130 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR( |
131 | { // NOLINT | |
132 | a_++; | |
133 | throw_system_error(); | |
134 | }, | |
135 | EDOM, (b_++, "other")), | |
136 | "throws an exception with a different message"); | |
11fdf7f2 TL |
137 | EXPECT_EQ(3, a_); |
138 | EXPECT_EQ(3, b_); | |
139 | ||
140 | // failed EXPECT_SYSTEM_ERROR, throws nothing | |
9f95a23c TL |
141 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")), |
142 | "throws nothing"); | |
11fdf7f2 TL |
143 | EXPECT_EQ(4, a_); |
144 | EXPECT_EQ(4, b_); | |
145 | } | |
146 | ||
f67539c2 TL |
147 | #if FMT_USE_FCNTL |
148 | // Tests that when EXPECT_WRITE fails, it evaluates its message argument | |
149 | // exactly once. | |
20effc67 | 150 | TEST_F(single_evaluation_test, failed_expect_write) { |
f67539c2 TL |
151 | EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++), |
152 | "01234"); | |
153 | EXPECT_EQ(s_ + 1, p_); | |
154 | } | |
155 | ||
11fdf7f2 | 156 | // Tests that assertion arguments are evaluated exactly once. |
20effc67 | 157 | TEST_F(single_evaluation_test, write_tests) { |
11fdf7f2 | 158 | // successful EXPECT_WRITE |
f67539c2 TL |
159 | EXPECT_WRITE( |
160 | stdout, | |
161 | { // NOLINT | |
162 | a_++; | |
163 | std::printf("test"); | |
164 | }, | |
165 | (b_++, "test")); | |
11fdf7f2 TL |
166 | EXPECT_EQ(1, a_); |
167 | EXPECT_EQ(1, b_); | |
168 | ||
169 | // failed EXPECT_WRITE | |
f67539c2 TL |
170 | EXPECT_NONFATAL_FAILURE(EXPECT_WRITE( |
171 | stdout, | |
172 | { // NOLINT | |
173 | a_++; | |
174 | std::printf("test"); | |
175 | }, | |
176 | (b_++, "other")), | |
9f95a23c | 177 | "Actual: test"); |
11fdf7f2 TL |
178 | EXPECT_EQ(2, a_); |
179 | EXPECT_EQ(2, b_); | |
180 | } | |
181 | ||
f67539c2 | 182 | // Tests EXPECT_WRITE. |
20effc67 | 183 | TEST(gtest_extra_test, expect_write) { |
f67539c2 TL |
184 | EXPECT_WRITE(stdout, do_nothing(), ""); |
185 | EXPECT_WRITE(stdout, std::printf("test"), "test"); | |
186 | EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test"); | |
187 | EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"), | |
188 | "Expected: this\n" | |
189 | " Actual: that"); | |
190 | } | |
191 | ||
20effc67 | 192 | TEST(gtest_extra_test, expect_write_streaming) { |
f67539c2 TL |
193 | EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure"; |
194 | EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other") | |
195 | << "expected failure", | |
196 | "expected failure"); | |
197 | } | |
198 | #endif // FMT_USE_FCNTL | |
199 | ||
11fdf7f2 TL |
200 | // Tests that the compiler will not complain about unreachable code in the |
201 | // EXPECT_THROW_MSG macro. | |
20effc67 | 202 | TEST(gtest_extra_test, expect_throw_no_unreachable_code_warning) { |
11fdf7f2 TL |
203 | int n = 0; |
204 | using std::runtime_error; | |
205 | EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, ""); | |
206 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, runtime_error, ""), ""); | |
207 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(throw 1, runtime_error, ""), ""); | |
9f95a23c TL |
208 | EXPECT_NONFATAL_FAILURE( |
209 | EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), ""); | |
11fdf7f2 TL |
210 | } |
211 | ||
212 | // Tests that the compiler will not complain about unreachable code in the | |
213 | // EXPECT_SYSTEM_ERROR macro. | |
20effc67 | 214 | TEST(gtest_extra_test, expect_system_error_no_unreachable_code_warning) { |
11fdf7f2 TL |
215 | int n = 0; |
216 | EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test"); | |
217 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), ""); | |
218 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), ""); | |
9f95a23c TL |
219 | EXPECT_NONFATAL_FAILURE( |
220 | EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), | |
221 | ""); | |
11fdf7f2 TL |
222 | } |
223 | ||
20effc67 | 224 | TEST(gtest_extra_test, expect_throw_behaves_like_single_statement) { |
11fdf7f2 TL |
225 | if (::testing::internal::AlwaysFalse()) |
226 | EXPECT_THROW_MSG(do_nothing(), std::exception, ""); | |
227 | ||
228 | if (::testing::internal::AlwaysTrue()) | |
229 | EXPECT_THROW_MSG(throw_exception(), std::exception, "test"); | |
230 | else | |
231 | do_nothing(); | |
232 | } | |
233 | ||
20effc67 | 234 | TEST(gtest_extra_test, expect_system_error_behaves_like_single_statement) { |
11fdf7f2 TL |
235 | if (::testing::internal::AlwaysFalse()) |
236 | EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, ""); | |
237 | ||
238 | if (::testing::internal::AlwaysTrue()) | |
239 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test"); | |
240 | else | |
241 | do_nothing(); | |
242 | } | |
243 | ||
20effc67 | 244 | TEST(gtest_extra_test, expect_write_behaves_like_single_statement) { |
11fdf7f2 TL |
245 | if (::testing::internal::AlwaysFalse()) |
246 | EXPECT_WRITE(stdout, std::printf("x"), "x"); | |
247 | ||
248 | if (::testing::internal::AlwaysTrue()) | |
249 | EXPECT_WRITE(stdout, std::printf("x"), "x"); | |
250 | else | |
251 | do_nothing(); | |
252 | } | |
253 | ||
254 | // Tests EXPECT_THROW_MSG. | |
20effc67 | 255 | TEST(gtest_extra_test, expect_throw_msg) { |
11fdf7f2 TL |
256 | EXPECT_THROW_MSG(throw_exception(), std::exception, "test"); |
257 | EXPECT_NONFATAL_FAILURE( | |
258 | EXPECT_THROW_MSG(throw_exception(), std::logic_error, "test"), | |
259 | "Expected: throw_exception() throws an exception of " | |
260 | "type std::logic_error.\n Actual: it throws a different type."); | |
261 | EXPECT_NONFATAL_FAILURE( | |
262 | EXPECT_THROW_MSG(do_nothing(), std::exception, "test"), | |
263 | "Expected: do_nothing() throws an exception of type std::exception.\n" | |
264 | " Actual: it throws nothing."); | |
265 | EXPECT_NONFATAL_FAILURE( | |
266 | EXPECT_THROW_MSG(throw_exception(), std::exception, "other"), | |
267 | "throw_exception() throws an exception with a different message.\n" | |
268 | "Expected: other\n" | |
269 | " Actual: test"); | |
270 | } | |
271 | ||
272 | // Tests EXPECT_SYSTEM_ERROR. | |
20effc67 | 273 | TEST(gtest_extra_test, expect_system_error) { |
11fdf7f2 TL |
274 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test"); |
275 | EXPECT_NONFATAL_FAILURE( | |
276 | EXPECT_SYSTEM_ERROR(throw_exception(), EDOM, "test"), | |
277 | "Expected: throw_exception() throws an exception of " | |
20effc67 | 278 | "type std::system_error.\n Actual: it throws a different type."); |
11fdf7f2 TL |
279 | EXPECT_NONFATAL_FAILURE( |
280 | EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"), | |
20effc67 | 281 | "Expected: do_nothing() throws an exception of type std::system_error.\n" |
11fdf7f2 TL |
282 | " Actual: it throws nothing."); |
283 | EXPECT_NONFATAL_FAILURE( | |
284 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other"), | |
285 | fmt::format( | |
286 | "throw_system_error() throws an exception with a different message.\n" | |
287 | "Expected: {}\n" | |
288 | " Actual: {}", | |
20effc67 TL |
289 | system_error_message(EDOM, "other"), |
290 | system_error_message(EDOM, "test"))); | |
11fdf7f2 TL |
291 | } |
292 | ||
20effc67 | 293 | TEST(gtest_extra_test, expect_throw_msg_streaming) { |
11fdf7f2 TL |
294 | EXPECT_THROW_MSG(throw_exception(), std::exception, "test") |
295 | << "unexpected failure"; | |
296 | EXPECT_NONFATAL_FAILURE( | |
297 | EXPECT_THROW_MSG(throw_exception(), std::exception, "other") | |
9f95a23c TL |
298 | << "expected failure", |
299 | "expected failure"); | |
11fdf7f2 TL |
300 | } |
301 | ||
20effc67 | 302 | TEST(gtest_extra_test, expect_system_error_streaming) { |
11fdf7f2 TL |
303 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test") |
304 | << "unexpected failure"; | |
305 | EXPECT_NONFATAL_FAILURE( | |
306 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other") | |
9f95a23c TL |
307 | << "expected failure", |
308 | "expected failure"); | |
11fdf7f2 TL |
309 | } |
310 | ||
f67539c2 | 311 | #if FMT_USE_FCNTL |
11fdf7f2 TL |
312 | |
313 | using fmt::buffered_file; | |
11fdf7f2 TL |
314 | using fmt::file; |
315 | ||
20effc67 | 316 | TEST(output_redirect_test, scoped_redirect) { |
11fdf7f2 TL |
317 | file read_end, write_end; |
318 | file::pipe(read_end, write_end); | |
319 | { | |
320 | buffered_file file(write_end.fdopen("w")); | |
321 | std::fprintf(file.get(), "[[["); | |
322 | { | |
20effc67 | 323 | output_redirect redir(file.get()); |
11fdf7f2 TL |
324 | std::fprintf(file.get(), "censored"); |
325 | } | |
326 | std::fprintf(file.get(), "]]]"); | |
327 | } | |
328 | EXPECT_READ(read_end, "[[[]]]"); | |
329 | } | |
330 | ||
20effc67 TL |
331 | // Test that output_redirect handles errors in flush correctly. |
332 | TEST(output_redirect_test, flush_error_in_ctor) { | |
11fdf7f2 TL |
333 | file read_end, write_end; |
334 | file::pipe(read_end, write_end); | |
335 | int write_fd = write_end.descriptor(); | |
336 | file write_copy = write_end.dup(write_fd); | |
337 | buffered_file f = write_end.fdopen("w"); | |
338 | // Put a character in a file buffer. | |
339 | EXPECT_EQ('x', fputc('x', f.get())); | |
340 | FMT_POSIX(close(write_fd)); | |
20effc67 TL |
341 | std::unique_ptr<output_redirect> redir{nullptr}; |
342 | EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new output_redirect(f.get())), EBADF, | |
9f95a23c | 343 | "cannot flush stream"); |
f67539c2 | 344 | redir.reset(nullptr); |
11fdf7f2 TL |
345 | write_copy.dup2(write_fd); // "undo" close or dtor will fail |
346 | } | |
347 | ||
20effc67 | 348 | TEST(output_redirect_test, dup_error_in_ctor) { |
11fdf7f2 | 349 | buffered_file f = open_buffered_file(); |
1e59de90 | 350 | int fd = (f.descriptor)(); |
11fdf7f2 TL |
351 | file copy = file::dup(fd); |
352 | FMT_POSIX(close(fd)); | |
20effc67 | 353 | std::unique_ptr<output_redirect> redir{nullptr}; |
9f95a23c | 354 | EXPECT_SYSTEM_ERROR_NOASSERT( |
20effc67 | 355 | redir.reset(new output_redirect(f.get())), EBADF, |
9f95a23c | 356 | fmt::format("cannot duplicate file descriptor {}", fd)); |
11fdf7f2 TL |
357 | copy.dup2(fd); // "undo" close or dtor will fail |
358 | } | |
359 | ||
20effc67 | 360 | TEST(output_redirect_test, restore_and_read) { |
11fdf7f2 TL |
361 | file read_end, write_end; |
362 | file::pipe(read_end, write_end); | |
363 | buffered_file file(write_end.fdopen("w")); | |
364 | std::fprintf(file.get(), "[[["); | |
20effc67 | 365 | output_redirect redir(file.get()); |
11fdf7f2 | 366 | std::fprintf(file.get(), "censored"); |
20effc67 TL |
367 | EXPECT_EQ("censored", redir.restore_and_read()); |
368 | EXPECT_EQ("", redir.restore_and_read()); | |
11fdf7f2 TL |
369 | std::fprintf(file.get(), "]]]"); |
370 | file = buffered_file(); | |
371 | EXPECT_READ(read_end, "[[[]]]"); | |
372 | } | |
373 | ||
374 | // Test that OutputRedirect handles errors in flush correctly. | |
20effc67 | 375 | TEST(output_redirect_test, flush_error_in_restore_and_read) { |
11fdf7f2 TL |
376 | file read_end, write_end; |
377 | file::pipe(read_end, write_end); | |
378 | int write_fd = write_end.descriptor(); | |
379 | file write_copy = write_end.dup(write_fd); | |
380 | buffered_file f = write_end.fdopen("w"); | |
20effc67 | 381 | output_redirect redir(f.get()); |
11fdf7f2 TL |
382 | // Put a character in a file buffer. |
383 | EXPECT_EQ('x', fputc('x', f.get())); | |
384 | FMT_POSIX(close(write_fd)); | |
9f95a23c TL |
385 | EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EBADF, |
386 | "cannot flush stream"); | |
11fdf7f2 TL |
387 | write_copy.dup2(write_fd); // "undo" close or dtor will fail |
388 | } | |
389 | ||
20effc67 | 390 | TEST(output_redirect_test, error_in_dtor) { |
11fdf7f2 TL |
391 | file read_end, write_end; |
392 | file::pipe(read_end, write_end); | |
393 | int write_fd = write_end.descriptor(); | |
394 | file write_copy = write_end.dup(write_fd); | |
395 | buffered_file f = write_end.fdopen("w"); | |
20effc67 | 396 | std::unique_ptr<output_redirect> redir(new output_redirect(f.get())); |
11fdf7f2 TL |
397 | // Put a character in a file buffer. |
398 | EXPECT_EQ('x', fputc('x', f.get())); | |
f67539c2 TL |
399 | EXPECT_WRITE( |
400 | stderr, | |
401 | { | |
402 | // The close function must be called inside EXPECT_WRITE, | |
403 | // otherwise the system may recycle closed file descriptor when | |
404 | // redirecting the output in EXPECT_STDERR and the second close | |
405 | // will break output redirection. | |
406 | FMT_POSIX(close(write_fd)); | |
407 | SUPPRESS_ASSERT(redir.reset(nullptr)); | |
408 | }, | |
20effc67 | 409 | system_error_message(EBADF, "cannot flush stream")); |
9f95a23c | 410 | write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail |
11fdf7f2 TL |
411 | } |
412 | ||
20effc67 | 413 | #endif // FMT_USE_FCNTL |