• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
handle_invalid_parameter(const wchar_t *,const wchar_t *,const wchar_t *,unsigned,uintptr_t)145   static void handle_invalid_parameter(const wchar_t *,
146       const wchar_t *, const wchar_t *, unsigned , uintptr_t) {}
147 
148  public:
SuppressAssert()149   SuppressAssert()
150   : original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)),
151     original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {
152   }
~SuppressAssert()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> {
ScopedMockScopedMock177   ScopedMock() { Mock::instance = this; }
~ScopedMockScopedMock178   ~ScopedMock() { Mock::instance = 0; }
179 };
180 
181 #endif  // FMT_GTEST_EXTRA_H_
182