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