lightweight_test.hpp 19 KB

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