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