lightweight_test.hpp 16 KB

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