]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // boost/endian/detail/lightweight_test.hpp --------------------------------------------// |
2 | ||
3 | #ifndef BOOST_ENDIAN_LIGHTWEIGHT_TEST_HPP | |
4 | #define BOOST_ENDIAN_LIGHTWEIGHT_TEST_HPP | |
5 | ||
6 | // MS compatible compilers support #pragma once | |
7 | ||
8 | #if defined(_MSC_VER) | |
9 | # pragma once | |
10 | #endif | |
11 | ||
12 | // | |
13 | // Copyright (c) 2002, 2009, 2014 Peter Dimov | |
14 | // Copyright (2) Beman Dawes 2010, 2011, 2015 | |
15 | // Copyright (3) Ion Gaztanaga 2013 | |
16 | // | |
17 | // Distributed under the Boost Software License, Version 1.0. | |
18 | // See http://www.boost.org/LICENSE_1_0.txt | |
19 | // | |
20 | ||
21 | #include <boost/assert.hpp> | |
22 | #include <boost/current_function.hpp> | |
23 | #include <boost/core/no_exceptions_support.hpp> | |
24 | #include <cstring> // for memcmp | |
25 | #include <iostream> | |
26 | ||
27 | // IDE's like Visual Studio perform better if output goes to std::cout or | |
28 | // some other stream, so allow user to configure output stream: | |
29 | #ifndef BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
30 | # define BOOST_LIGHTWEIGHT_TEST_OSTREAM std::cerr | |
31 | #endif | |
32 | ||
33 | namespace boost | |
34 | { | |
35 | namespace endian | |
36 | { | |
37 | namespace detail | |
38 | { | |
39 | ||
40 | struct report_errors_reminder | |
41 | { | |
42 | bool called_report_errors_function; | |
43 | ||
44 | report_errors_reminder() : called_report_errors_function(false) {} | |
45 | ||
46 | ~report_errors_reminder() | |
47 | { | |
48 | BOOST_ASSERT(called_report_errors_function); // verify report_errors() was called | |
49 | } | |
50 | }; | |
51 | ||
52 | inline report_errors_reminder& report_errors_remind() | |
53 | { | |
54 | static report_errors_reminder r; | |
55 | return r; | |
56 | } | |
57 | ||
58 | inline int & test_errors() | |
59 | { | |
60 | static int x = 0; | |
61 | report_errors_remind(); | |
62 | return x; | |
63 | } | |
64 | ||
65 | inline void test_failed_impl(char const * expr, char const * file, int line, char const * function) | |
66 | { | |
67 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
68 | << file << "(" << line << "): test '" << expr << "' failed in function '" | |
69 | << function << "'" << std::endl; | |
70 | ++test_errors(); | |
71 | } | |
72 | ||
73 | inline void error_impl(char const * msg, char const * file, int line, char const * function) | |
74 | { | |
75 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
76 | << file << "(" << line << "): " << msg << " in function '" | |
77 | << function << "'" << std::endl; | |
78 | ++test_errors(); | |
79 | } | |
80 | ||
81 | inline void throw_failed_impl(char const * excep, char const * file, int line, char const * function) | |
82 | { | |
83 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
84 | << file << "(" << line << "): Exception '" << excep << "' not thrown in function '" | |
85 | << function << "'" << std::endl; | |
86 | ++test_errors(); | |
87 | } | |
88 | ||
89 | template<class T, class U> inline void test_eq_impl( char const * expr1, char const * expr2, | |
90 | char const * file, int line, char const * function, T const & t, U const & u ) | |
91 | { | |
92 | if( t == u ) | |
93 | { | |
94 | report_errors_remind(); | |
95 | } | |
96 | else | |
97 | { | |
98 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
99 | << file << "(" << line << "): test '" << expr1 << " == " << expr2 | |
100 | << "' failed in function '" << function << "': " | |
101 | << "'" << t << "' != '" << u << "'" << std::endl; | |
102 | ++test_errors(); | |
103 | } | |
104 | } | |
105 | ||
106 | template<class T, class U> inline void test_ne_impl( char const * expr1, char const * expr2, | |
107 | char const * file, int line, char const * function, T const & t, U const & u ) | |
108 | { | |
109 | if( t != u ) | |
110 | { | |
111 | report_errors_remind(); | |
112 | } | |
113 | else | |
114 | { | |
115 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
116 | << file << "(" << line << "): test '" << expr1 << " != " << expr2 | |
117 | << "' failed in function '" << function << "': " | |
118 | << "'" << t << "' == '" << u << "'" << std::endl; | |
119 | ++test_errors(); | |
120 | } | |
121 | } | |
122 | ||
123 | template <class T> | |
124 | std::string to_hex(const T& x) | |
125 | { | |
126 | const char hex[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; | |
127 | std::string tmp; | |
128 | const unsigned char* p = reinterpret_cast<const unsigned char*>(&x); | |
129 | const unsigned char* e = p + sizeof(T); | |
130 | ||
131 | for (; p < e; ++p) | |
132 | { | |
133 | tmp += hex[*p >> 4]; // high-order nibble | |
134 | tmp += hex[*p & 0x0f]; // low-order nibble | |
135 | } | |
136 | return tmp; | |
137 | } | |
138 | ||
139 | template<class T, class U> inline bool test_memcmp_eq_impl(char const * expr1, | |
140 | char const * expr2, char const * file, int line, char const * function, T const & t, | |
141 | U const & u) | |
142 | { | |
143 | BOOST_ASSERT(sizeof(T) == sizeof(U)); | |
144 | if (sizeof(T) == sizeof(U) | |
145 | && std::memcmp(&t, &u, sizeof(T)) == 0) | |
146 | { | |
147 | report_errors_remind(); | |
148 | return true; | |
149 | } | |
150 | else | |
151 | { | |
152 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
153 | << file << "(" << line << "): test 'std::memcmp(" << expr1 << ", " << expr2 | |
154 | << ") == 0' fails in function '" << function << "': " | |
155 | << " with values '" << to_hex(t) << "' and '" << to_hex(u) << "'" << std::endl; | |
156 | ++test_errors(); | |
157 | return false; | |
158 | } | |
159 | } | |
160 | ||
161 | } // namespace detail | |
162 | ||
163 | inline int report_errors() | |
164 | { | |
165 | boost::endian::detail::report_errors_remind().called_report_errors_function = true; | |
166 | ||
167 | int errors = boost::endian::detail::test_errors(); | |
168 | ||
169 | if( errors == 0 ) | |
170 | { | |
171 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
172 | << "No errors detected." << std::endl; | |
173 | return 0; | |
174 | } | |
175 | else | |
176 | { | |
177 | BOOST_LIGHTWEIGHT_TEST_OSTREAM | |
178 | << errors << " error" << (errors == 1? "": "s") << " detected." << std::endl; | |
179 | return 1; | |
180 | } | |
181 | } | |
182 | ||
183 | } // namespace endian | |
184 | } // namespace boost | |
185 | ||
186 | ////////////////////////////////////////////////////////////////////////////////////////// | |
187 | // TODO: Should all test macros return bool? See BOOST_TEST_MEM_EQ usage in fp_exaustive_test,cpp | |
188 | ////////////////////////////////////////////////////////////////////////////////////////// | |
189 | ||
190 | ||
191 | #define BOOST_TEST(expr) \ | |
192 | ((expr)? (void)0: ::boost::endian::detail::test_failed_impl(#expr, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION)) | |
193 | ||
194 | #define BOOST_ERROR(msg) \ | |
195 | ( ::boost::endian::detail::error_impl(msg, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION) ) | |
196 | ||
197 | #define BOOST_TEST_EQ(expr1,expr2) \ | |
198 | ( ::boost::endian::detail::test_eq_impl(#expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) ) | |
199 | #define BOOST_TEST_NE(expr1,expr2) \ | |
200 | ( ::boost::endian::detail::test_ne_impl(#expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) ) | |
201 | ||
202 | #define BOOST_TEST_MEM_EQ(expr1,expr2) \ | |
203 | (::boost::endian::detail::test_memcmp_eq_impl(#expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2)) | |
204 | ||
205 | #ifndef BOOST_NO_EXCEPTIONS | |
206 | #define BOOST_TEST_THROWS( EXPR, EXCEP ) \ | |
207 | try { \ | |
208 | EXPR; \ | |
209 | ::boost::detail::throw_failed_impl \ | |
210 | (#EXCEP, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \ | |
211 | } \ | |
212 | catch(EXCEP const&) { \ | |
213 | } \ | |
214 | catch(...) { \ | |
215 | ::boost::detail::throw_failed_impl \ | |
216 | (#EXCEP, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \ | |
217 | } \ | |
218 | // | |
219 | #else | |
220 | #define BOOST_TEST_THROWS( EXPR, EXCEP ) | |
221 | #endif | |
222 | ||
223 | #endif // #ifndef BOOST_ENDIAN_LIGHTWEIGHT_TEST_HPP |