Home | History | Annotate | Download | only in test
      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