| /* |
| Custom Google Test assertions. |
| |
| Copyright (c) 2012-2014, Victor Zverovich |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are met: |
| |
| 1. Redistributions of source code must retain the above copyright notice, this |
| list of conditions and the following disclaimer. |
| 2. Redistributions in binary form must reproduce the above copyright notice, |
| this list of conditions and the following disclaimer in the documentation |
| and/or other materials provided with the distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef FMT_GTEST_EXTRA_H_ |
| #define FMT_GTEST_EXTRA_H_ |
| |
| #include <string> |
| #include <gmock/gmock.h> |
| |
| #include "fmt/format.h" |
| |
| #ifndef FMT_USE_FILE_DESCRIPTORS |
| # define FMT_USE_FILE_DESCRIPTORS 0 |
| #endif |
| |
| #if FMT_USE_FILE_DESCRIPTORS |
| # include "fmt/posix.h" |
| #endif |
| |
| #define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \ |
| GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ |
| if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \ |
| std::string gtest_expected_message = expected_message; \ |
| bool gtest_caught_expected = false; \ |
| try { \ |
| GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ |
| } \ |
| catch (expected_exception const& e) { \ |
| if (gtest_expected_message != e.what()) { \ |
| gtest_ar \ |
| << #statement " throws an exception with a different message.\n" \ |
| << "Expected: " << gtest_expected_message << "\n" \ |
| << " Actual: " << e.what(); \ |
| goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ |
| } \ |
| gtest_caught_expected = true; \ |
| } \ |
| catch (...) { \ |
| gtest_ar << \ |
| "Expected: " #statement " throws an exception of type " \ |
| #expected_exception ".\n Actual: it throws a different type."; \ |
| goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ |
| } \ |
| if (!gtest_caught_expected) { \ |
| gtest_ar << \ |
| "Expected: " #statement " throws an exception of type " \ |
| #expected_exception ".\n Actual: it throws nothing."; \ |
| goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ |
| } \ |
| } else \ |
| GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ |
| fail(gtest_ar.failure_message()) |
| |
| // Tests that the statement throws the expected exception and the exception's |
| // what() method returns expected message. |
| #define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \ |
| FMT_TEST_THROW_(statement, expected_exception, \ |
| expected_message, GTEST_NONFATAL_FAILURE_) |
| |
| std::string format_system_error(int error_code, fmt::StringRef message); |
| |
| #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ |
| EXPECT_THROW_MSG(statement, fmt::SystemError, \ |
| format_system_error(error_code, message)) |
| |
| #if FMT_USE_FILE_DESCRIPTORS |
| |
| // Captures file output by redirecting it to a pipe. |
| // The output it can handle is limited by the pipe capacity. |
| class OutputRedirect { |
| private: |
| FILE *file_; |
| fmt::File original_; // Original file passed to redirector. |
| fmt::File read_end_; // Read end of the pipe where the output is redirected. |
| |
| GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect); |
| |
| void flush(); |
| void restore(); |
| |
| public: |
| explicit OutputRedirect(FILE *file); |
| ~OutputRedirect() FMT_NOEXCEPT; |
| |
| // Restores the original file, reads output from the pipe into a string |
| // and returns it. |
| std::string restore_and_read(); |
| }; |
| |
| #define FMT_TEST_WRITE_(statement, expected_output, file, fail) \ |
| GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ |
| if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \ |
| std::string gtest_expected_output = expected_output; \ |
| OutputRedirect gtest_redir(file); \ |
| GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ |
| std::string gtest_output = gtest_redir.restore_and_read(); \ |
| if (gtest_output != gtest_expected_output) { \ |
| gtest_ar \ |
| << #statement " produces different output.\n" \ |
| << "Expected: " << gtest_expected_output << "\n" \ |
| << " Actual: " << gtest_output; \ |
| goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ |
| } \ |
| } else \ |
| GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ |
| fail(gtest_ar.failure_message()) |
| |
| // Tests that the statement writes the expected output to file. |
| #define EXPECT_WRITE(file, statement, expected_output) \ |
| FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_) |
| |
| #ifdef _MSC_VER |
| |
| // Suppresses Windows assertions on invalid file descriptors, making |
| // POSIX functions return proper error codes instead of crashing on Windows. |
| class SuppressAssert { |
| private: |
| _invalid_parameter_handler original_handler_; |
| int original_report_mode_; |
| |
| static void handle_invalid_parameter(const wchar_t *, |
| const wchar_t *, const wchar_t *, unsigned , uintptr_t) {} |
| |
| public: |
| SuppressAssert() |
| : original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)), |
| original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) { |
| } |
| ~SuppressAssert() { |
| _set_invalid_parameter_handler(original_handler_); |
| _CrtSetReportMode(_CRT_ASSERT, original_report_mode_); |
| } |
| }; |
| |
| # define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; } |
| #else |
| # define SUPPRESS_ASSERT(statement) statement |
| #endif // _MSC_VER |
| |
| #define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \ |
| EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message) |
| |
| // Attempts to read count characters from a file. |
| std::string read(fmt::File &f, std::size_t count); |
| |
| #define EXPECT_READ(file, expected_content) \ |
| EXPECT_EQ(expected_content, read(file, std::strlen(expected_content))) |
| |
| #endif // FMT_USE_FILE_DESCRIPTORS |
| |
| template <typename Mock> |
| struct ScopedMock : testing::StrictMock<Mock> { |
| ScopedMock() { Mock::instance = this; } |
| ~ScopedMock() { Mock::instance = 0; } |
| }; |
| |
| #endif // FMT_GTEST_EXTRA_H_ |