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 
10 #include <gtest/gtest-spi.h>
11 
12 #include <cstring>
13 #include <memory>
14 #include <stdexcept>
15 
16 #include "fmt/os.h"
17 #include "util.h"
18 
19 // Tests that assertion macros evaluate their arguments exactly once.
20 namespace {
21 class single_evaluation_test : public ::testing::Test {
22  protected:
single_evaluation_test()23   single_evaluation_test() {
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 };
35 }  // namespace
36 
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_;
41 
do_nothing()42 void do_nothing() {}
43 
throw_exception()44 FMT_NORETURN void throw_exception() { throw std::runtime_error("test"); }
45 
throw_system_error()46 FMT_NORETURN void throw_system_error() {
47   throw fmt::system_error(EDOM, "test");
48 }
49 
50 // Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
51 // exactly once.
TEST_F(single_evaluation_test,failed_expect_throw_msg)52 TEST_F(single_evaluation_test, failed_expect_throw_msg) {
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.
TEST_F(single_evaluation_test,failed_expect_system_error)60 TEST_F(single_evaluation_test, failed_expect_system_error) {
61   EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++),
62                           "01234");
63   EXPECT_EQ(s_ + 1, p_);
64 }
65 
66 // Tests that assertion arguments are evaluated exactly once.
TEST_F(single_evaluation_test,exception_tests)67 TEST_F(single_evaluation_test, exception_tests) {
68   // successful EXPECT_THROW_MSG
69   EXPECT_THROW_MSG(
70       {  // NOLINT
71         a_++;
72         throw_exception();
73       },
74       std::exception, (b_++, "test"));
75   EXPECT_EQ(1, a_);
76   EXPECT_EQ(1, b_);
77 
78   // failed EXPECT_THROW_MSG, throws different type
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");
86   EXPECT_EQ(2, a_);
87   EXPECT_EQ(2, b_);
88 
89   // failed EXPECT_THROW_MSG, throws an exception with different message
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");
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 
TEST_F(single_evaluation_test,system_error_tests)107 TEST_F(single_evaluation_test, system_error_tests) {
108   // successful EXPECT_SYSTEM_ERROR
109   EXPECT_SYSTEM_ERROR(
110       {  // NOLINT
111         a_++;
112         throw_system_error();
113       },
114       EDOM, (b_++, "test"));
115   EXPECT_EQ(1, a_);
116   EXPECT_EQ(1, b_);
117 
118   // failed EXPECT_SYSTEM_ERROR, throws different type
119   EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
120                               {  // NOLINT
121                                 a_++;
122                                 throw_exception();
123                               },
124                               EDOM, (b_++, "test")),
125                           "throws a different type");
126   EXPECT_EQ(2, a_);
127   EXPECT_EQ(2, b_);
128 
129   // failed EXPECT_SYSTEM_ERROR, throws an exception with different message
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");
137   EXPECT_EQ(3, a_);
138   EXPECT_EQ(3, b_);
139 
140   // failed EXPECT_SYSTEM_ERROR, throws nothing
141   EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")),
142                           "throws nothing");
143   EXPECT_EQ(4, a_);
144   EXPECT_EQ(4, b_);
145 }
146 
147 #if FMT_USE_FCNTL
148 // Tests that when EXPECT_WRITE fails, it evaluates its message argument
149 // exactly once.
TEST_F(single_evaluation_test,failed_expect_write)150 TEST_F(single_evaluation_test, failed_expect_write) {
151   EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++),
152                           "01234");
153   EXPECT_EQ(s_ + 1, p_);
154 }
155 
156 // Tests that assertion arguments are evaluated exactly once.
TEST_F(single_evaluation_test,write_tests)157 TEST_F(single_evaluation_test, write_tests) {
158   // successful EXPECT_WRITE
159   EXPECT_WRITE(
160       stdout,
161       {  // NOLINT
162         a_++;
163         std::printf("test");
164       },
165       (b_++, "test"));
166   EXPECT_EQ(1, a_);
167   EXPECT_EQ(1, b_);
168 
169   // failed EXPECT_WRITE
170   EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(
171                               stdout,
172                               {  // NOLINT
173                                 a_++;
174                                 std::printf("test");
175                               },
176                               (b_++, "other")),
177                           "Actual: test");
178   EXPECT_EQ(2, a_);
179   EXPECT_EQ(2, b_);
180 }
181 
182 // Tests EXPECT_WRITE.
TEST(gtest_extra_test,expect_write)183 TEST(gtest_extra_test, expect_write) {
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 
TEST(gtest_extra_test,expect_write_streaming)192 TEST(gtest_extra_test, expect_write_streaming) {
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 
200 // Tests that the compiler will not complain about unreachable code in the
201 // EXPECT_THROW_MSG macro.
TEST(gtest_extra_test,expect_throw_no_unreachable_code_warning)202 TEST(gtest_extra_test, expect_throw_no_unreachable_code_warning) {
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, ""), "");
208   EXPECT_NONFATAL_FAILURE(
209       EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), "");
210 }
211 
212 // Tests that the compiler will not complain about unreachable code in the
213 // EXPECT_SYSTEM_ERROR macro.
TEST(gtest_extra_test,expect_system_error_no_unreachable_code_warning)214 TEST(gtest_extra_test, expect_system_error_no_unreachable_code_warning) {
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, ""), "");
219   EXPECT_NONFATAL_FAILURE(
220       EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"),
221       "");
222 }
223 
TEST(gtest_extra_test,expect_throw_behaves_like_single_statement)224 TEST(gtest_extra_test, expect_throw_behaves_like_single_statement) {
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 
TEST(gtest_extra_test,expect_system_error_behaves_like_single_statement)234 TEST(gtest_extra_test, expect_system_error_behaves_like_single_statement) {
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 
TEST(gtest_extra_test,expect_write_behaves_like_single_statement)244 TEST(gtest_extra_test, expect_write_behaves_like_single_statement) {
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.
TEST(gtest_extra_test,expect_throw_msg)255 TEST(gtest_extra_test, expect_throw_msg) {
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.
TEST(gtest_extra_test,expect_system_error)273 TEST(gtest_extra_test, expect_system_error) {
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 "
278       "type std::system_error.\n  Actual: it throws a different type.");
279   EXPECT_NONFATAL_FAILURE(
280       EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"),
281       "Expected: do_nothing() throws an exception of type std::system_error.\n"
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: {}",
289           system_error_message(EDOM, "other"),
290           system_error_message(EDOM, "test")));
291 }
292 
TEST(gtest_extra_test,expect_throw_msg_streaming)293 TEST(gtest_extra_test, expect_throw_msg_streaming) {
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")
298           << "expected failure",
299       "expected failure");
300 }
301 
TEST(gtest_extra_test,expect_system_error_streaming)302 TEST(gtest_extra_test, expect_system_error_streaming) {
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")
307           << "expected failure",
308       "expected failure");
309 }
310 
311 #if FMT_USE_FCNTL
312 
313 using fmt::buffered_file;
314 using fmt::file;
315 
TEST(output_redirect_test,scoped_redirect)316 TEST(output_redirect_test, scoped_redirect) {
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     {
323       output_redirect redir(file.get());
324       std::fprintf(file.get(), "censored");
325     }
326     std::fprintf(file.get(), "]]]");
327   }
328   EXPECT_READ(read_end, "[[[]]]");
329 }
330 
331 // Test that output_redirect handles errors in flush correctly.
TEST(output_redirect_test,flush_error_in_ctor)332 TEST(output_redirect_test, flush_error_in_ctor) {
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));
341   std::unique_ptr<output_redirect> redir{nullptr};
342   EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new output_redirect(f.get())), EBADF,
343                                "cannot flush stream");
344   redir.reset(nullptr);
345   write_copy.dup2(write_fd);  // "undo" close or dtor will fail
346 }
347 
TEST(output_redirect_test,dup_error_in_ctor)348 TEST(output_redirect_test, dup_error_in_ctor) {
349   buffered_file f = open_buffered_file();
350   int fd = (f.fileno)();
351   file copy = file::dup(fd);
352   FMT_POSIX(close(fd));
353   std::unique_ptr<output_redirect> redir{nullptr};
354   EXPECT_SYSTEM_ERROR_NOASSERT(
355       redir.reset(new output_redirect(f.get())), EBADF,
356       fmt::format("cannot duplicate file descriptor {}", fd));
357   copy.dup2(fd);  // "undo" close or dtor will fail
358 }
359 
TEST(output_redirect_test,restore_and_read)360 TEST(output_redirect_test, restore_and_read) {
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(), "[[[");
365   output_redirect redir(file.get());
366   std::fprintf(file.get(), "censored");
367   EXPECT_EQ("censored", redir.restore_and_read());
368   EXPECT_EQ("", redir.restore_and_read());
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.
TEST(output_redirect_test,flush_error_in_restore_and_read)375 TEST(output_redirect_test, flush_error_in_restore_and_read) {
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");
381   output_redirect redir(f.get());
382   // Put a character in a file buffer.
383   EXPECT_EQ('x', fputc('x', f.get()));
384   FMT_POSIX(close(write_fd));
385   EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EBADF,
386                                "cannot flush stream");
387   write_copy.dup2(write_fd);  // "undo" close or dtor will fail
388 }
389 
TEST(output_redirect_test,error_in_dtor)390 TEST(output_redirect_test, error_in_dtor) {
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");
396   std::unique_ptr<output_redirect> redir(new output_redirect(f.get()));
397   // Put a character in a file buffer.
398   EXPECT_EQ('x', fputc('x', f.get()));
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       },
409       system_error_message(EBADF, "cannot flush stream"));
410   write_copy.dup2(write_fd);  // "undo" close or dtor of buffered_file will fail
411 }
412 
413 #endif  // FMT_USE_FCNTL
414