STIR  6.3.0
gtest-extra.h
1 // Formatting library for C++ - 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 #ifndef FMT_GTEST_EXTRA_H_
9 #define FMT_GTEST_EXTRA_H_
10 
11 #include <stdlib.h> // _invalid_parameter_handler
12 
13 #include <string>
14 
15 #include "fmt/os.h"
16 #include "gmock/gmock.h"
17 
18 #ifdef _MSC_VER
19 # include <crtdbg.h>
20 #endif
21 
22 #define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
23  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
24  if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
25  std::string gtest_expected_message = expected_message; \
26  bool gtest_caught_expected = false; \
27  try { \
28  GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
29  } catch (expected_exception const& e) { \
30  if (gtest_expected_message != e.what()) { \
31  gtest_ar << #statement \
32  " throws an exception with a different message.\n" \
33  << "Expected: " << gtest_expected_message << "\n" \
34  << " Actual: " << e.what(); \
35  goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
36  } \
37  gtest_caught_expected = true; \
38  } catch (...) { \
39  gtest_ar << "Expected: " #statement \
40  " throws an exception of type " #expected_exception \
41  ".\n Actual: it throws a different type."; \
42  goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
43  } \
44  if (!gtest_caught_expected) { \
45  gtest_ar << "Expected: " #statement \
46  " throws an exception of type " #expected_exception \
47  ".\n Actual: it throws nothing."; \
48  goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
49  } \
50  } else \
51  GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
52  : fail(gtest_ar.failure_message())
53 
54 // Tests that the statement throws the expected exception and the exception's
55 // what() method returns expected message.
56 #define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
57  FMT_TEST_THROW_(statement, expected_exception, expected_message, \
58  GTEST_NONFATAL_FAILURE_)
59 
60 inline std::string system_error_message(int error_code,
61  const std::string& message) {
62  auto ec = std::error_code(error_code, std::generic_category());
63  return std::system_error(ec, message).what();
64 }
65 
66 #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
67  EXPECT_THROW_MSG(statement, std::system_error, \
68  system_error_message(error_code, message))
69 
70 #if FMT_USE_FCNTL
71 
72 // Captures file output by redirecting it to a pipe.
73 // The output it can handle is limited by the pipe capacity.
74 class output_redirect {
75  private:
76  FILE* file_;
77  fmt::file original_; // Original file passed to redirector.
78  fmt::file read_end_; // Read end of the pipe where the output is redirected.
79 
80  void flush();
81  void restore();
82 
83  public:
84  explicit output_redirect(FILE* file, bool flush = true);
85  ~output_redirect() noexcept;
86 
87  output_redirect(const output_redirect&) = delete;
88  void operator=(const output_redirect&) = delete;
89 
90  // Restores the original file, reads output from the pipe into a string
91  // and returns it.
92  std::string restore_and_read();
93 };
94 
95 # define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
96  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
97  if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
98  std::string gtest_expected_output = expected_output; \
99  output_redirect gtest_redir(file); \
100  GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
101  std::string gtest_output = gtest_redir.restore_and_read(); \
102  if (gtest_output != gtest_expected_output) { \
103  gtest_ar << #statement " produces different output.\n" \
104  << "Expected: " << gtest_expected_output << "\n" \
105  << " Actual: " << gtest_output; \
106  goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
107  } \
108  } else \
109  GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
110  : fail(gtest_ar.failure_message())
111 
112 // Tests that the statement writes the expected output to file.
113 # define EXPECT_WRITE(file, statement, expected_output) \
114  FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
115 
116 # ifdef _MSC_VER
117 
118 // Suppresses Windows assertions on invalid file descriptors, making
119 // POSIX functions return proper error codes instead of crashing on Windows.
120 class suppress_assert {
121  private:
122  _invalid_parameter_handler original_handler_;
123  int original_report_mode_;
124 
125  static void handle_invalid_parameter(const wchar_t*, const wchar_t*,
126  const wchar_t*, unsigned, uintptr_t) {}
127 
128  public:
129  suppress_assert()
130  : original_handler_(
131  _set_invalid_parameter_handler(handle_invalid_parameter)),
132  original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {}
133  ~suppress_assert() {
134  _set_invalid_parameter_handler(original_handler_);
135  _CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
136  (void)original_report_mode_;
137  }
138 };
139 
140 # define SUPPRESS_ASSERT(statement) \
141  { \
142  suppress_assert sa; \
143  statement; \
144  }
145 # else
146 # define SUPPRESS_ASSERT(statement) statement
147 # endif // _MSC_VER
148 
149 # define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
150  EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
151 
152 // Attempts to read count characters from a file.
153 std::string read(fmt::file& f, size_t count);
154 
155 # define EXPECT_READ(file, expected_content) \
156  EXPECT_EQ(expected_content, \
157  read(file, fmt::string_view(expected_content).size()))
158 
159 #else
160 # define EXPECT_WRITE(file, statement, expected_output) \
161  do { \
162  (void)(file); \
163  (void)(statement); \
164  (void)(expected_output); \
165  SUCCEED(); \
166  } while (false)
167 #endif // FMT_USE_FCNTL
168 
169 #endif // FMT_GTEST_EXTRA_H_
STL namespace.