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