1 /* 2 Custom Google Test assertions. 3 4 Copyright (c) 2012-2014, Victor Zverovich 5 All rights reserved. 6 7 Redistribution and use in source and binary forms, with or without 8 modification, are permitted provided that the following conditions are met: 9 10 1. Redistributions of source code must retain the above copyright notice, this 11 list of conditions and the following disclaimer. 12 2. Redistributions in binary form must reproduce the above copyright notice, 13 this list of conditions and the following disclaimer in the documentation 14 and/or other materials provided with the distribution. 15 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #ifndef FMT_GTEST_EXTRA_H_ 29 #define FMT_GTEST_EXTRA_H_ 30 31 #include <string> 32 #include <gmock/gmock.h> 33 34 #include "fmt/format.h" 35 36 #ifndef FMT_USE_FILE_DESCRIPTORS 37 # define FMT_USE_FILE_DESCRIPTORS 0 38 #endif 39 40 #if FMT_USE_FILE_DESCRIPTORS 41 # include "fmt/posix.h" 42 #endif 43 44 #define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \ 45 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ 46 if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \ 47 std::string gtest_expected_message = expected_message; \ 48 bool gtest_caught_expected = false; \ 49 try { \ 50 GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ 51 } \ 52 catch (expected_exception const& e) { \ 53 if (gtest_expected_message != e.what()) { \ 54 gtest_ar \ 55 << #statement " throws an exception with a different message.\n" \ 56 << "Expected: " << gtest_expected_message << "\n" \ 57 << " Actual: " << e.what(); \ 58 goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ 59 } \ 60 gtest_caught_expected = true; \ 61 } \ 62 catch (...) { \ 63 gtest_ar << \ 64 "Expected: " #statement " throws an exception of type " \ 65 #expected_exception ".\n Actual: it throws a different type."; \ 66 goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ 67 } \ 68 if (!gtest_caught_expected) { \ 69 gtest_ar << \ 70 "Expected: " #statement " throws an exception of type " \ 71 #expected_exception ".\n Actual: it throws nothing."; \ 72 goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ 73 } \ 74 } else \ 75 GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ 76 fail(gtest_ar.failure_message()) 77 78 // Tests that the statement throws the expected exception and the exception's 79 // what() method returns expected message. 80 #define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \ 81 FMT_TEST_THROW_(statement, expected_exception, \ 82 expected_message, GTEST_NONFATAL_FAILURE_) 83 84 std::string format_system_error(int error_code, fmt::StringRef message); 85 86 #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ 87 EXPECT_THROW_MSG(statement, fmt::SystemError, \ 88 format_system_error(error_code, message)) 89 90 #if FMT_USE_FILE_DESCRIPTORS 91 92 // Captures file output by redirecting it to a pipe. 93 // The output it can handle is limited by the pipe capacity. 94 class OutputRedirect { 95 private: 96 FILE *file_; 97 fmt::File original_; // Original file passed to redirector. 98 fmt::File read_end_; // Read end of the pipe where the output is redirected. 99 100 GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect); 101 102 void flush(); 103 void restore(); 104 105 public: 106 explicit OutputRedirect(FILE *file); 107 ~OutputRedirect() FMT_NOEXCEPT; 108 109 // Restores the original file, reads output from the pipe into a string 110 // and returns it. 111 std::string restore_and_read(); 112 }; 113 114 #define FMT_TEST_WRITE_(statement, expected_output, file, fail) \ 115 GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ 116 if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \ 117 std::string gtest_expected_output = expected_output; \ 118 OutputRedirect gtest_redir(file); \ 119 GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ 120 std::string gtest_output = gtest_redir.restore_and_read(); \ 121 if (gtest_output != gtest_expected_output) { \ 122 gtest_ar \ 123 << #statement " produces different output.\n" \ 124 << "Expected: " << gtest_expected_output << "\n" \ 125 << " Actual: " << gtest_output; \ 126 goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ 127 } \ 128 } else \ 129 GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ 130 fail(gtest_ar.failure_message()) 131 132 // Tests that the statement writes the expected output to file. 133 #define EXPECT_WRITE(file, statement, expected_output) \ 134 FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_) 135 136 #ifdef _MSC_VER 137 138 // Suppresses Windows assertions on invalid file descriptors, making 139 // POSIX functions return proper error codes instead of crashing on Windows. 140 class SuppressAssert { 141 private: 142 _invalid_parameter_handler original_handler_; 143 int original_report_mode_; 144 145 static void handle_invalid_parameter(const wchar_t *, 146 const wchar_t *, const wchar_t *, unsigned , uintptr_t) {} 147 148 public: 149 SuppressAssert() 150 : original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)), 151 original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) { 152 } 153 ~SuppressAssert() { 154 _set_invalid_parameter_handler(original_handler_); 155 _CrtSetReportMode(_CRT_ASSERT, original_report_mode_); 156 } 157 }; 158 159 # define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; } 160 #else 161 # define SUPPRESS_ASSERT(statement) statement 162 #endif // _MSC_VER 163 164 #define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \ 165 EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message) 166 167 // Attempts to read count characters from a file. 168 std::string read(fmt::File &f, std::size_t count); 169 170 #define EXPECT_READ(file, expected_content) \ 171 EXPECT_EQ(expected_content, read(file, std::strlen(expected_content))) 172 173 #endif // FMT_USE_FILE_DESCRIPTORS 174 175 template <typename Mock> 176 struct ScopedMock : testing::StrictMock<Mock> { 177 ScopedMock() { Mock::instance = this; } 178 ~ScopedMock() { Mock::instance = 0; } 179 }; 180 181 #endif // FMT_GTEST_EXTRA_H_ 182