1 #ifndef BOOST_CORE_LIGHTWEIGHT_TEST_HPP
2 #define BOOST_CORE_LIGHTWEIGHT_TEST_HPP
3 
4 // MS compatible compilers support #pragma once
5 
6 #if defined(_MSC_VER)
7 # pragma once
8 #endif
9 
10 //
11 //  boost/core/lightweight_test.hpp - lightweight test library
12 //
13 //  Copyright (c) 2002, 2009, 2014 Peter Dimov
14 //  Copyright (2) Beman Dawes 2010, 2011
15 //  Copyright (3) Ion Gaztanaga 2013
16 //
17 //  Copyright 2018 Glen Joseph Fernandes
18 //  (glenjofe@gmail.com)
19 //
20 //  Distributed under the Boost Software License, Version 1.0.
21 //  See accompanying file LICENSE_1_0.txt or copy at
22 //  http://www.boost.org/LICENSE_1_0.txt
23 //
24 
25 #include <boost/current_function.hpp>
26 #include <boost/config.hpp>
27 #include <exception>
28 #include <iostream>
29 #include <iterator>
30 #include <cstdlib>
31 #include <cstring>
32 #include <cstddef>
33 
34 #if defined(_MSC_VER) && defined(_CPPLIB_VER) && defined(_DEBUG)
35 # include <crtdbg.h>
36 #endif
37 
38 //  IDE's like Visual Studio perform better if output goes to std::cout or
39 //  some other stream, so allow user to configure output stream:
40 #ifndef BOOST_LIGHTWEIGHT_TEST_OSTREAM
41 # define BOOST_LIGHTWEIGHT_TEST_OSTREAM std::cerr
42 #endif
43 
44 namespace boost
45 {
46 
47 namespace detail
48 {
49 
50 class test_result {
51 public:
test_result()52     test_result()
53         : report_(false)
54         , errors_(0) {
55 #if defined(_MSC_VER) && (_MSC_VER > 1310)
56         // disable message boxes on assert(), abort()
57         ::_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
58 #endif
59 #if defined(_MSC_VER) && defined(_CPPLIB_VER) && defined(_DEBUG)
60         // disable message boxes on iterator debugging violations
61         _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
62         _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
63 #endif
64     }
65 
~test_result()66     ~test_result() {
67         if (!report_) {
68             BOOST_LIGHTWEIGHT_TEST_OSTREAM << "main() should return report_errors()" << std::endl;
69             std::abort();
70         }
71     }
72 
errors()73     int& errors() {
74         return errors_;
75     }
76 
done()77     void done() {
78         report_ = true;
79     }
80 
81 private:
82     bool report_;
83     int errors_;
84 };
85 
test_results()86 inline test_result& test_results()
87 {
88     static test_result instance;
89     return instance;
90 }
91 
test_errors()92 inline int& test_errors()
93 {
94     return test_results().errors();
95 }
96 
test_impl(char const * expr,char const * file,int line,char const * function,bool v)97 inline bool test_impl(char const * expr, char const * file, int line, char const * function, bool v)
98 {
99     if( v )
100     {
101         test_results();
102         return true;
103     }
104     else
105     {
106         BOOST_LIGHTWEIGHT_TEST_OSTREAM
107           << file << "(" << line << "): test '" << expr << "' failed in function '"
108           << function << "'" << std::endl;
109         ++test_results().errors();
110         return false;
111     }
112 }
113 
error_impl(char const * msg,char const * file,int line,char const * function)114 inline void error_impl(char const * msg, char const * file, int line, char const * function)
115 {
116     BOOST_LIGHTWEIGHT_TEST_OSTREAM
117       << file << "(" << line << "): " << msg << " in function '"
118       << function << "'" << std::endl;
119     ++test_results().errors();
120 }
121 
throw_failed_impl(const char * expr,char const * excep,char const * file,int line,char const * function)122 inline void throw_failed_impl(const char* expr, char const * excep, char const * file, int line, char const * function)
123 {
124    BOOST_LIGHTWEIGHT_TEST_OSTREAM
125     << file << "(" << line << "): expression '" << expr << "' did not throw exception '" << excep << "' in function '"
126     << function << "'" << std::endl;
127    ++test_results().errors();
128 }
129 
no_throw_failed_impl(const char * expr,const char * file,int line,const char * function)130 inline void no_throw_failed_impl(const char* expr, const char* file, int line, const char* function)
131 {
132     BOOST_LIGHTWEIGHT_TEST_OSTREAM
133         << file << "(" << line << "): expression '" << expr << "' threw an exception in function '"
134         << function << "'" << std::endl;
135    ++test_results().errors();
136 }
137 
no_throw_failed_impl(const char * expr,const char * what,const char * file,int line,const char * function)138 inline void no_throw_failed_impl(const char* expr, const char* what, const char* file, int line, const char* function)
139 {
140     BOOST_LIGHTWEIGHT_TEST_OSTREAM
141         << file << "(" << line << "): expression '" << expr << "' threw an exception in function '"
142         << function << "': " << what << std::endl;
143    ++test_results().errors();
144 }
145 
146 // In the comparisons below, it is possible that T and U are signed and unsigned integer types, which generates warnings in some compilers.
147 // A cleaner fix would require common_type trait or some meta-programming, which would introduce a dependency on Boost.TypeTraits. To avoid
148 // the dependency we just disable the warnings.
149 #if defined(__clang__) && defined(__has_warning)
150 # if __has_warning("-Wsign-compare")
151 #  pragma clang diagnostic push
152 #  pragma clang diagnostic ignored "-Wsign-compare"
153 # endif
154 #elif defined(_MSC_VER)
155 # pragma warning(push)
156 # pragma warning(disable: 4389)
157 #elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
158 # pragma GCC diagnostic push
159 # pragma GCC diagnostic ignored "-Wsign-compare"
160 #endif
161 
162 // specialize test output for char pointers to avoid printing as cstring
test_output_impl(const T & v)163 template <class T> inline const T& test_output_impl(const T& v) { return v; }
test_output_impl(const char * v)164 inline const void* test_output_impl(const char* v) { return v; }
test_output_impl(const unsigned char * v)165 inline const void* test_output_impl(const unsigned char* v) { return v; }
test_output_impl(const signed char * v)166 inline const void* test_output_impl(const signed char* v) { return v; }
test_output_impl(char * v)167 inline const void* test_output_impl(char* v) { return v; }
test_output_impl(unsigned char * v)168 inline const void* test_output_impl(unsigned char* v) { return v; }
test_output_impl(signed char * v)169 inline const void* test_output_impl(signed char* v) { return v; }
test_output_impl(T volatile * v)170 template<class T> inline const void* test_output_impl(T volatile* v) { return const_cast<T*>(v); }
171 
172 #if !defined( BOOST_NO_CXX11_NULLPTR )
test_output_impl(std::nullptr_t)173 inline const void* test_output_impl(std::nullptr_t) { return nullptr; }
174 #endif
175 
176 // predicates
177 
178 struct lw_test_eq
179 {
180     template <typename T, typename U>
operator ()boost::detail::lw_test_eq181     bool operator()(const T& t, const U& u) const { return t == u; }
182 };
183 
184 struct lw_test_ne
185 {
186     template <typename T, typename U>
operator ()boost::detail::lw_test_ne187     bool operator()(const T& t, const U& u) const { return t != u; }
188 };
189 
190 struct lw_test_lt
191 {
192     template <typename T, typename U>
operator ()boost::detail::lw_test_lt193     bool operator()(const T& t, const U& u) const { return t < u; }
194 };
195 
196 struct lw_test_le
197 {
198     template <typename T, typename U>
operator ()boost::detail::lw_test_le199     bool operator()(const T& t, const U& u) const { return t <= u; }
200 };
201 
202 struct lw_test_gt
203 {
204     template <typename T, typename U>
operator ()boost::detail::lw_test_gt205     bool operator()(const T& t, const U& u) const { return t > u; }
206 };
207 
208 struct lw_test_ge
209 {
210     template <typename T, typename U>
operator ()boost::detail::lw_test_ge211     bool operator()(const T& t, const U& u) const { return t >= u; }
212 };
213 
214 // lwt_predicate_name
215 
lwt_predicate_name(T const &)216 template<class T> char const * lwt_predicate_name( T const& )
217 {
218     return "~=";
219 }
220 
lwt_predicate_name(lw_test_eq const &)221 inline char const * lwt_predicate_name( lw_test_eq const& )
222 {
223     return "==";
224 }
225 
lwt_predicate_name(lw_test_ne const &)226 inline char const * lwt_predicate_name( lw_test_ne const& )
227 {
228     return "!=";
229 }
230 
lwt_predicate_name(lw_test_lt const &)231 inline char const * lwt_predicate_name( lw_test_lt const& )
232 {
233     return "<";
234 }
235 
lwt_predicate_name(lw_test_le const &)236 inline char const * lwt_predicate_name( lw_test_le const& )
237 {
238     return "<=";
239 }
240 
lwt_predicate_name(lw_test_gt const &)241 inline char const * lwt_predicate_name( lw_test_gt const& )
242 {
243     return ">";
244 }
245 
lwt_predicate_name(lw_test_ge const &)246 inline char const * lwt_predicate_name( lw_test_ge const& )
247 {
248     return ">=";
249 }
250 
251 //
252 
253 template<class BinaryPredicate, class T, class U>
test_with_impl(BinaryPredicate pred,char const * expr1,char const * expr2,char const * file,int line,char const * function,T const & t,U const & u)254 inline bool test_with_impl(BinaryPredicate pred, char const * expr1, char const * expr2,
255                            char const * file, int line, char const * function,
256                            T const & t, U const & u)
257 {
258     if( pred(t, u) )
259     {
260         test_results();
261         return true;
262     }
263     else
264     {
265         BOOST_LIGHTWEIGHT_TEST_OSTREAM
266             << file << "(" << line << "): test '" << expr1 << " " << lwt_predicate_name(pred) << " " << expr2
267             << "' ('" << test_output_impl(t) << "' " << lwt_predicate_name(pred) << " '" << test_output_impl(u)
268             << "') failed in function '" << function << "'" << std::endl;
269         ++test_results().errors();
270         return false;
271     }
272 }
273 
test_cstr_eq_impl(char const * expr1,char const * expr2,char const * file,int line,char const * function,char const * const t,char const * const u)274 inline bool test_cstr_eq_impl( char const * expr1, char const * expr2,
275   char const * file, int line, char const * function, char const * const t, char const * const u )
276 {
277     if( std::strcmp(t, u) == 0 )
278     {
279         test_results();
280         return true;
281     }
282     else
283     {
284         BOOST_LIGHTWEIGHT_TEST_OSTREAM
285             << file << "(" << line << "): test '" << expr1 << " == " << expr2 << "' ('" << t
286             << "' == '" << u << "') failed in function '" << function << "'" << std::endl;
287         ++test_results().errors();
288         return false;
289     }
290 }
291 
test_cstr_ne_impl(char const * expr1,char const * expr2,char const * file,int line,char const * function,char const * const t,char const * const u)292 inline bool test_cstr_ne_impl( char const * expr1, char const * expr2,
293   char const * file, int line, char const * function, char const * const t, char const * const u )
294 {
295     if( std::strcmp(t, u) != 0 )
296     {
297         test_results();
298         return true;
299     }
300     else
301     {
302         BOOST_LIGHTWEIGHT_TEST_OSTREAM
303             << file << "(" << line << "): test '" << expr1 << " != " << expr2 << "' ('" << t
304             << "' != '" << u << "') failed in function '" << function << "'" << std::endl;
305         ++test_results().errors();
306         return false;
307     }
308 }
309 
310 template<class FormattedOutputFunction, class InputIterator1, class InputIterator2>
test_all_eq_impl(FormattedOutputFunction & output,char const * file,int line,char const * function,InputIterator1 first_begin,InputIterator1 first_end,InputIterator2 second_begin,InputIterator2 second_end)311 bool test_all_eq_impl(FormattedOutputFunction& output,
312                       char const * file, int line, char const * function,
313                       InputIterator1 first_begin, InputIterator1 first_end,
314                       InputIterator2 second_begin, InputIterator2 second_end)
315 {
316     InputIterator1 first_it = first_begin;
317     InputIterator2 second_it = second_begin;
318     typename std::iterator_traits<InputIterator1>::difference_type first_index = 0;
319     typename std::iterator_traits<InputIterator2>::difference_type second_index = 0;
320     std::size_t error_count = 0;
321     const std::size_t max_count = 8;
322     do
323     {
324         while ((first_it != first_end) && (second_it != second_end) && (*first_it == *second_it))
325         {
326             ++first_it;
327             ++second_it;
328             ++first_index;
329             ++second_index;
330         }
331         if ((first_it == first_end) || (second_it == second_end))
332         {
333             break; // do-while
334         }
335         if (error_count == 0)
336         {
337             output << file << "(" << line << "): Container contents differ in function '" << function << "':";
338         }
339         else if (error_count >= max_count)
340         {
341             output << " ...";
342             break;
343         }
344         output << " [" << first_index << "] '" << test_output_impl(*first_it) << "' != '" << test_output_impl(*second_it) << "'";
345         ++first_it;
346         ++second_it;
347         ++first_index;
348         ++second_index;
349         ++error_count;
350     } while (first_it != first_end);
351 
352     first_index += std::distance(first_it, first_end);
353     second_index += std::distance(second_it, second_end);
354     if (first_index != second_index)
355     {
356         if (error_count == 0)
357         {
358             output << file << "(" << line << "): Container sizes differ in function '" << function << "': size(" << first_index << ") != size(" << second_index << ")";
359         }
360         else
361         {
362             output << " [*] size(" << first_index << ") != size(" << second_index << ")";
363         }
364         ++error_count;
365     }
366 
367     if (error_count == 0)
368     {
369         test_results();
370         return true;
371     }
372     else
373     {
374         output << std::endl;
375         ++test_results().errors();
376         return false;
377     }
378 }
379 
380 template<class FormattedOutputFunction, class InputIterator1, class InputIterator2, typename BinaryPredicate>
test_all_with_impl(FormattedOutputFunction & output,char const * file,int line,char const * function,InputIterator1 first_begin,InputIterator1 first_end,InputIterator2 second_begin,InputIterator2 second_end,BinaryPredicate predicate)381 bool test_all_with_impl(FormattedOutputFunction& output,
382                         char const * file, int line, char const * function,
383                         InputIterator1 first_begin, InputIterator1 first_end,
384                         InputIterator2 second_begin, InputIterator2 second_end,
385                         BinaryPredicate predicate)
386 {
387     InputIterator1 first_it = first_begin;
388     InputIterator2 second_it = second_begin;
389     typename std::iterator_traits<InputIterator1>::difference_type first_index = 0;
390     typename std::iterator_traits<InputIterator2>::difference_type second_index = 0;
391     std::size_t error_count = 0;
392     const std::size_t max_count = 8;
393     do
394     {
395         while ((first_it != first_end) && (second_it != second_end) && predicate(*first_it, *second_it))
396         {
397             ++first_it;
398             ++second_it;
399             ++first_index;
400             ++second_index;
401         }
402         if ((first_it == first_end) || (second_it == second_end))
403         {
404             break; // do-while
405         }
406         if (error_count == 0)
407         {
408             output << file << "(" << line << "): Container contents differ in function '" << function << "':";
409         }
410         else if (error_count >= max_count)
411         {
412             output << " ...";
413             break;
414         }
415         output << " [" << first_index << "]";
416         ++first_it;
417         ++second_it;
418         ++first_index;
419         ++second_index;
420         ++error_count;
421     } while (first_it != first_end);
422 
423     first_index += std::distance(first_it, first_end);
424     second_index += std::distance(second_it, second_end);
425     if (first_index != second_index)
426     {
427         if (error_count == 0)
428         {
429             output << file << "(" << line << "): Container sizes differ in function '" << function << "': size(" << first_index << ") != size(" << second_index << ")";
430         }
431         else
432         {
433             output << " [*] size(" << first_index << ") != size(" << second_index << ")";
434         }
435         ++error_count;
436     }
437 
438     if (error_count == 0)
439     {
440         test_results();
441         return true;
442     }
443     else
444     {
445         output << std::endl;
446         ++test_results().errors();
447         return false;
448     }
449 }
450 
451 #if defined(__clang__) && defined(__has_warning)
452 # if __has_warning("-Wsign-compare")
453 #  pragma clang diagnostic pop
454 # endif
455 #elif defined(_MSC_VER)
456 # pragma warning(pop)
457 #elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
458 # pragma GCC diagnostic pop
459 #endif
460 
461 } // namespace detail
462 
report_errors()463 inline int report_errors()
464 {
465     boost::detail::test_result& result = boost::detail::test_results();
466     result.done();
467 
468     int errors = result.errors();
469 
470     if( errors == 0 )
471     {
472         BOOST_LIGHTWEIGHT_TEST_OSTREAM
473           << "No errors detected." << std::endl;
474     }
475     else
476     {
477         BOOST_LIGHTWEIGHT_TEST_OSTREAM
478           << errors << " error" << (errors == 1? "": "s") << " detected." << std::endl;
479     }
480 
481     // `return report_errors();` from main only supports 8 bit exit codes
482     return errors < 256? errors: 255;
483 }
484 
485 } // namespace boost
486 
487 #define BOOST_TEST(expr) ( ::boost::detail::test_impl(#expr, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (expr)? true: false) )
488 #define BOOST_TEST_NOT(expr) BOOST_TEST(!(expr))
489 
490 #define BOOST_ERROR(msg) ( ::boost::detail::error_impl(msg, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION) )
491 
492 #define BOOST_TEST_WITH(expr1,expr2,predicate) ( ::boost::detail::test_with_impl(predicate, #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
493 
494 #define BOOST_TEST_EQ(expr1,expr2) ( ::boost::detail::test_with_impl(::boost::detail::lw_test_eq(), #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
495 #define BOOST_TEST_NE(expr1,expr2) ( ::boost::detail::test_with_impl(::boost::detail::lw_test_ne(), #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
496 
497 #define BOOST_TEST_LT(expr1,expr2) ( ::boost::detail::test_with_impl(::boost::detail::lw_test_lt(), #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
498 #define BOOST_TEST_LE(expr1,expr2) ( ::boost::detail::test_with_impl(::boost::detail::lw_test_le(), #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
499 #define BOOST_TEST_GT(expr1,expr2) ( ::boost::detail::test_with_impl(::boost::detail::lw_test_gt(), #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
500 #define BOOST_TEST_GE(expr1,expr2) ( ::boost::detail::test_with_impl(::boost::detail::lw_test_ge(), #expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
501 
502 #define BOOST_TEST_CSTR_EQ(expr1,expr2) ( ::boost::detail::test_cstr_eq_impl(#expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
503 #define BOOST_TEST_CSTR_NE(expr1,expr2) ( ::boost::detail::test_cstr_ne_impl(#expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
504 
505 #define BOOST_TEST_ALL_EQ(begin1, end1, begin2, end2) ( ::boost::detail::test_all_eq_impl(BOOST_LIGHTWEIGHT_TEST_OSTREAM, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, begin1, end1, begin2, end2) )
506 #define BOOST_TEST_ALL_WITH(begin1, end1, begin2, end2, predicate) ( ::boost::detail::test_all_with_impl(BOOST_LIGHTWEIGHT_TEST_OSTREAM, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, begin1, end1, begin2, end2, predicate) )
507 
508 #ifndef BOOST_NO_EXCEPTIONS
509    #define BOOST_TEST_THROWS( EXPR, EXCEP )                           \
510       try {                                                           \
511          EXPR;                                                        \
512          ::boost::detail::throw_failed_impl                           \
513          (#EXPR, #EXCEP, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \
514       }                                                               \
515       catch(EXCEP const&) {                                           \
516          ::boost::detail::test_results();                             \
517       }                                                               \
518       catch(...) {                                                    \
519          ::boost::detail::throw_failed_impl                           \
520          (#EXPR, #EXCEP, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \
521       }                                                               \
522    //
523 #else
524    #define BOOST_TEST_THROWS( EXPR, EXCEP )
525 #endif
526 
527 #ifndef BOOST_NO_EXCEPTIONS
528 #  define BOOST_TEST_NO_THROW(EXPR)                                    \
529     try {                                                              \
530         EXPR;                                                          \
531     } catch (const std::exception& e) {                                \
532         ::boost::detail::no_throw_failed_impl                          \
533         (#EXPR, e.what(), __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \
534     } catch (...) {                                                    \
535         ::boost::detail::no_throw_failed_impl                          \
536         (#EXPR, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION);           \
537     }
538     //
539 #else
540 #  define BOOST_TEST_NO_THROW(EXPR) { EXPR; }
541 #endif
542 
543 #endif // #ifndef BOOST_CORE_LIGHTWEIGHT_TEST_HPP
544