test_tools.ipp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. // (C) Copyright Gennadiy Rozental 2001.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. // File : $RCSfile$
  8. //
  9. // Version : $Revision$
  10. //
  11. // Description : supplies offline implementation for the Test Tools
  12. // ***************************************************************************
  13. #ifndef BOOST_TEST_TEST_TOOLS_IPP_012205GER
  14. #define BOOST_TEST_TEST_TOOLS_IPP_012205GER
  15. // Boost.Test
  16. #include <boost/test/unit_test_log.hpp>
  17. #include <boost/test/tools/context.hpp>
  18. #include <boost/test/tools/output_test_stream.hpp>
  19. #include <boost/test/tools/detail/fwd.hpp>
  20. #include <boost/test/tools/detail/print_helper.hpp>
  21. #include <boost/test/framework.hpp>
  22. #include <boost/test/tree/test_unit.hpp>
  23. #include <boost/test/execution_monitor.hpp> // execution_aborted
  24. #include <boost/test/detail/throw_exception.hpp>
  25. // Boost
  26. #include <boost/config.hpp>
  27. // STL
  28. #include <fstream>
  29. #include <string>
  30. #include <cstring>
  31. #include <cctype>
  32. #include <cwchar>
  33. #include <stdexcept>
  34. #include <vector>
  35. #include <utility>
  36. #include <ios>
  37. // !! should we use #include <cstdarg>
  38. #include <stdarg.h>
  39. #include <boost/test/detail/suppress_warnings.hpp>
  40. //____________________________________________________________________________//
  41. # ifdef BOOST_NO_STDC_NAMESPACE
  42. namespace std { using ::strcmp; using ::strlen; using ::isprint; }
  43. #if !defined( BOOST_NO_CWCHAR )
  44. namespace std { using ::wcscmp; }
  45. #endif
  46. # endif
  47. namespace boost {
  48. namespace test_tools {
  49. namespace tt_detail {
  50. // ************************************************************************** //
  51. // ************** print_log_value ************** //
  52. // ************************************************************************** //
  53. void
  54. print_log_value<char>::operator()( std::ostream& ostr, char t )
  55. {
  56. if( (std::isprint)( static_cast<unsigned char>(t) ) )
  57. ostr << '\'' << t << '\'';
  58. else
  59. ostr << std::hex
  60. #if BOOST_TEST_USE_STD_LOCALE
  61. << std::showbase
  62. #else
  63. << "0x"
  64. #endif
  65. << static_cast<int>(t);
  66. }
  67. //____________________________________________________________________________//
  68. void
  69. print_log_value<unsigned char>::operator()( std::ostream& ostr, unsigned char t )
  70. {
  71. ostr << std::hex
  72. // showbase is only available for new style streams:
  73. #if BOOST_TEST_USE_STD_LOCALE
  74. << std::showbase
  75. #else
  76. << "0x"
  77. #endif
  78. << static_cast<int>(t);
  79. }
  80. //____________________________________________________________________________//
  81. void
  82. print_log_value<char const*>::operator()( std::ostream& ostr, char const* t )
  83. {
  84. ostr << ( t ? t : "null string" );
  85. }
  86. //____________________________________________________________________________//
  87. void
  88. print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* t )
  89. {
  90. ostr << ( t ? t : L"null string" );
  91. }
  92. //____________________________________________________________________________//
  93. // ************************************************************************** //
  94. // ************** TOOL BOX Implementation ************** //
  95. // ************************************************************************** //
  96. using ::boost::unit_test::lazy_ostream;
  97. static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " };
  98. static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " };
  99. template<typename OutStream>
  100. void
  101. format_report( OutStream& os, assertion_result const& pr, unit_test::lazy_ostream const& assertion_descr,
  102. tool_level tl, check_type ct,
  103. std::size_t num_args, va_list args,
  104. char const* prefix, char const* suffix )
  105. {
  106. using namespace unit_test;
  107. switch( ct ) {
  108. case CHECK_PRED:
  109. os << prefix << assertion_descr << suffix;
  110. if( !pr.has_empty_message() )
  111. os << ". " << pr.message();
  112. break;
  113. case CHECK_BUILT_ASSERTION: {
  114. os << prefix << assertion_descr << suffix;
  115. if( tl != PASS ) {
  116. const_string details_message = pr.message();
  117. if( !details_message.is_empty() ) {
  118. os << details_message;
  119. }
  120. }
  121. break;
  122. }
  123. case CHECK_MSG:
  124. if( tl == PASS )
  125. os << prefix << "'" << assertion_descr << "'" << suffix;
  126. else
  127. os << assertion_descr;
  128. if( !pr.has_empty_message() )
  129. os << ". " << pr.message();
  130. break;
  131. case CHECK_EQUAL:
  132. case CHECK_NE:
  133. case CHECK_LT:
  134. case CHECK_LE:
  135. case CHECK_GT:
  136. case CHECK_GE: {
  137. char const* arg1_descr = va_arg( args, char const* );
  138. lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
  139. char const* arg2_descr = va_arg( args, char const* );
  140. lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* );
  141. os << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix;
  142. if( tl != PASS )
  143. os << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ;
  144. if( !pr.has_empty_message() )
  145. os << ". " << pr.message();
  146. break;
  147. }
  148. case CHECK_CLOSE:
  149. case CHECK_CLOSE_FRACTION: {
  150. char const* arg1_descr = va_arg( args, char const* );
  151. lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
  152. char const* arg2_descr = va_arg( args, char const* );
  153. lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* );
  154. /* toler_descr = */ va_arg( args, char const* );
  155. lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* );
  156. os << "difference{" << pr.message()
  157. << "} between " << arg1_descr << "{" << *arg1_val
  158. << "} and " << arg2_descr << "{" << *arg2_val
  159. << ( tl == PASS ? "} doesn't exceed " : "} exceeds " )
  160. << *toler_val;
  161. if( ct == CHECK_CLOSE )
  162. os << "%";
  163. break;
  164. }
  165. case CHECK_SMALL: {
  166. char const* arg1_descr = va_arg( args, char const* );
  167. lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
  168. /* toler_descr = */ va_arg( args, char const* );
  169. lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* );
  170. os << "absolute value of " << arg1_descr << "{" << *arg1_val << "}"
  171. << ( tl == PASS ? " doesn't exceed " : " exceeds " )
  172. << *toler_val;
  173. if( !pr.has_empty_message() )
  174. os << ". " << pr.message();
  175. break;
  176. }
  177. case CHECK_PRED_WITH_ARGS: {
  178. std::vector< std::pair<char const*, lazy_ostream const*> > args_copy;
  179. args_copy.reserve( num_args );
  180. for( std::size_t i = 0; i < num_args; ++i ) {
  181. char const* desc = va_arg( args, char const* );
  182. lazy_ostream const* value = va_arg( args, lazy_ostream const* );
  183. args_copy.push_back( std::make_pair( desc, value ) );
  184. }
  185. os << prefix << assertion_descr;
  186. // print predicate call description
  187. os << "( ";
  188. for( std::size_t i = 0; i < num_args; ++i ) {
  189. os << args_copy[i].first;
  190. if( i != num_args-1 )
  191. os << ", ";
  192. }
  193. os << " )" << suffix;
  194. if( tl != PASS ) {
  195. os << " for ( ";
  196. for( std::size_t i = 0; i < num_args; ++i ) {
  197. os << *args_copy[i].second;
  198. if( i != num_args-1 )
  199. os << ", ";
  200. }
  201. os << " )";
  202. }
  203. if( !pr.has_empty_message() )
  204. os << ". " << pr.message();
  205. break;
  206. }
  207. case CHECK_EQUAL_COLL: {
  208. char const* left_begin_descr = va_arg( args, char const* );
  209. char const* left_end_descr = va_arg( args, char const* );
  210. char const* right_begin_descr = va_arg( args, char const* );
  211. char const* right_end_descr = va_arg( args, char const* );
  212. os << prefix << "{ " << left_begin_descr << ", " << left_end_descr << " } == { "
  213. << right_begin_descr << ", " << right_end_descr << " }"
  214. << suffix;
  215. if( !pr.has_empty_message() )
  216. os << ". " << pr.message();
  217. break;
  218. }
  219. case CHECK_BITWISE_EQUAL: {
  220. char const* left_descr = va_arg( args, char const* );
  221. char const* right_descr = va_arg( args, char const* );
  222. os << prefix << left_descr << " =.= " << right_descr << suffix;
  223. if( !pr.has_empty_message() )
  224. os << ". " << pr.message();
  225. break;
  226. }
  227. }
  228. }
  229. //____________________________________________________________________________//
  230. bool
  231. report_assertion( assertion_result const& ar,
  232. lazy_ostream const& assertion_descr,
  233. const_string file_name,
  234. std::size_t line_num,
  235. tool_level tl,
  236. check_type ct,
  237. std::size_t num_args, ... )
  238. {
  239. using namespace unit_test;
  240. BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID,
  241. std::runtime_error( "Can't use testing tools outside of test case implementation." ) );
  242. if( !!ar )
  243. tl = PASS;
  244. log_level ll;
  245. char const* prefix;
  246. char const* suffix;
  247. switch( tl ) {
  248. case PASS:
  249. ll = log_successful_tests;
  250. prefix = "check ";
  251. suffix = " has passed";
  252. break;
  253. case WARN:
  254. ll = log_warnings;
  255. prefix = "condition ";
  256. suffix = " is not satisfied";
  257. break;
  258. case CHECK:
  259. ll = log_all_errors;
  260. prefix = "check ";
  261. suffix = " has failed";
  262. break;
  263. case REQUIRE:
  264. ll = log_fatal_errors;
  265. prefix = "critical check ";
  266. suffix = " has failed";
  267. break;
  268. default:
  269. return true;
  270. }
  271. unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
  272. va_list args;
  273. va_start( args, num_args );
  274. format_report( unit_test_log, ar, assertion_descr, tl, ct, num_args, args, prefix, suffix );
  275. va_end( args );
  276. unit_test_log << unit_test::log::end();
  277. switch( tl ) {
  278. case PASS:
  279. framework::assertion_result( AR_PASSED );
  280. return true;
  281. case WARN:
  282. framework::assertion_result( AR_TRIGGERED );
  283. return false;
  284. case CHECK:
  285. framework::assertion_result( AR_FAILED );
  286. return false;
  287. case REQUIRE:
  288. framework::assertion_result( AR_FAILED );
  289. framework::test_unit_aborted( framework::current_test_case() );
  290. BOOST_TEST_I_THROW( execution_aborted() );
  291. }
  292. return true;
  293. }
  294. //____________________________________________________________________________//
  295. assertion_result
  296. format_assertion_result( const_string expr_val, const_string details )
  297. {
  298. assertion_result res(false);
  299. bool starts_new_line = first_char( expr_val ) == '\n';
  300. if( !starts_new_line && !expr_val.is_empty() )
  301. res.message().stream() << " [" << expr_val << "]";
  302. if( !details.is_empty() ) {
  303. if( first_char(details) != '[' )
  304. res.message().stream() << ". ";
  305. else
  306. res.message().stream() << " ";
  307. res.message().stream() << details;
  308. }
  309. if( starts_new_line )
  310. res.message().stream() << "." << expr_val;
  311. return res;
  312. }
  313. //____________________________________________________________________________//
  314. BOOST_TEST_DECL std::string
  315. prod_report_format( assertion_result const& ar, unit_test::lazy_ostream const& assertion_descr, check_type ct, std::size_t num_args, ... )
  316. {
  317. std::ostringstream msg_buff;
  318. va_list args;
  319. va_start( args, num_args );
  320. format_report( msg_buff, ar, assertion_descr, CHECK, ct, num_args, args, "assertion ", " failed" );
  321. va_end( args );
  322. return msg_buff.str();
  323. }
  324. //____________________________________________________________________________//
  325. assertion_result
  326. equal_impl( char const* left, char const* right )
  327. {
  328. return (left && right) ? std::strcmp( left, right ) == 0 : (left == right);
  329. }
  330. //____________________________________________________________________________//
  331. #if !defined( BOOST_NO_CWCHAR )
  332. assertion_result
  333. equal_impl( wchar_t const* left, wchar_t const* right )
  334. {
  335. return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right);
  336. }
  337. #endif // !defined( BOOST_NO_CWCHAR )
  338. //____________________________________________________________________________//
  339. bool
  340. is_defined_impl( const_string symbol_name, const_string symbol_value )
  341. {
  342. symbol_value.trim_left( 2 );
  343. return symbol_name != symbol_value;
  344. }
  345. //____________________________________________________________________________//
  346. // ************************************************************************** //
  347. // ************** context_frame ************** //
  348. // ************************************************************************** //
  349. context_frame::context_frame( ::boost::unit_test::lazy_ostream const& context_descr )
  350. : m_frame_id( unit_test::framework::add_context( context_descr, true ) )
  351. {
  352. }
  353. //____________________________________________________________________________//
  354. context_frame::~context_frame()
  355. {
  356. unit_test::framework::clear_context( m_frame_id );
  357. }
  358. //____________________________________________________________________________//
  359. context_frame::operator bool()
  360. {
  361. return true;
  362. }
  363. //____________________________________________________________________________//
  364. } // namespace tt_detail
  365. // ************************************************************************** //
  366. // ************** output_test_stream ************** //
  367. // ************************************************************************** //
  368. struct output_test_stream::Impl
  369. {
  370. std::fstream m_pattern;
  371. bool m_match_or_save;
  372. bool m_text_or_binary;
  373. std::string m_synced_string;
  374. char get_char()
  375. {
  376. char res;
  377. do {
  378. m_pattern.get( res );
  379. } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() );
  380. return res;
  381. }
  382. void check_and_fill( assertion_result& res )
  383. {
  384. if( !res.p_predicate_value )
  385. res.message() << "Output content: \"" << m_synced_string << '\"';
  386. }
  387. };
  388. //____________________________________________________________________________//
  389. output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary )
  390. : m_pimpl( new Impl )
  391. {
  392. if( !pattern_file_name.is_empty() ) {
  393. std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out;
  394. if( !text_or_binary )
  395. m |= std::ios::binary;
  396. m_pimpl->m_pattern.open( pattern_file_name.begin(), m );
  397. if( !m_pimpl->m_pattern.is_open() )
  398. BOOST_TEST_MESSAGE( "Can't open pattern file " << pattern_file_name << " for " << (match_or_save ? "reading" : "writing") );
  399. }
  400. m_pimpl->m_match_or_save = match_or_save;
  401. m_pimpl->m_text_or_binary = text_or_binary;
  402. }
  403. //____________________________________________________________________________//
  404. output_test_stream::~output_test_stream()
  405. {
  406. delete m_pimpl;
  407. }
  408. //____________________________________________________________________________//
  409. assertion_result
  410. output_test_stream::is_empty( bool flush_stream )
  411. {
  412. sync();
  413. assertion_result res( m_pimpl->m_synced_string.empty() );
  414. m_pimpl->check_and_fill( res );
  415. if( flush_stream )
  416. flush();
  417. return res;
  418. }
  419. //____________________________________________________________________________//
  420. assertion_result
  421. output_test_stream::check_length( std::size_t length_, bool flush_stream )
  422. {
  423. sync();
  424. assertion_result res( m_pimpl->m_synced_string.length() == length_ );
  425. m_pimpl->check_and_fill( res );
  426. if( flush_stream )
  427. flush();
  428. return res;
  429. }
  430. //____________________________________________________________________________//
  431. assertion_result
  432. output_test_stream::is_equal( const_string arg, bool flush_stream )
  433. {
  434. sync();
  435. assertion_result res( const_string( m_pimpl->m_synced_string ) == arg );
  436. m_pimpl->check_and_fill( res );
  437. if( flush_stream )
  438. flush();
  439. return res;
  440. }
  441. //____________________________________________________________________________//
  442. assertion_result
  443. output_test_stream::match_pattern( bool flush_stream )
  444. {
  445. sync();
  446. assertion_result result( true );
  447. if( !m_pimpl->m_pattern.is_open() ) {
  448. result = false;
  449. result.message() << "Pattern file can't be opened!";
  450. }
  451. else {
  452. if( m_pimpl->m_match_or_save ) {
  453. for ( std::string::size_type i = 0; i < m_pimpl->m_synced_string.length(); ++i ) {
  454. char c = m_pimpl->get_char();
  455. result = !m_pimpl->m_pattern.fail() &&
  456. !m_pimpl->m_pattern.eof() &&
  457. (m_pimpl->m_synced_string[i] == c);
  458. if( !result ) {
  459. std::string::size_type suffix_size = (std::min)( m_pimpl->m_synced_string.length() - i,
  460. static_cast<std::string::size_type>(5) );
  461. // try to log area around the mismatch
  462. result.message() << "Mismatch at position " << i << '\n'
  463. << "..." << m_pimpl->m_synced_string.substr( i, suffix_size ) << "..." << '\n'
  464. << "..." << c;
  465. std::string::size_type counter = suffix_size;
  466. while( --counter ) {
  467. char c2 = m_pimpl->get_char();
  468. if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() )
  469. break;
  470. result.message() << c2;
  471. }
  472. result.message() << "...";
  473. // skip rest of the bytes. May help for further matching
  474. m_pimpl->m_pattern.ignore(
  475. static_cast<std::streamsize>( m_pimpl->m_synced_string.length() - i - suffix_size) );
  476. break;
  477. }
  478. }
  479. }
  480. else {
  481. m_pimpl->m_pattern.write( m_pimpl->m_synced_string.c_str(),
  482. static_cast<std::streamsize>( m_pimpl->m_synced_string.length() ) );
  483. m_pimpl->m_pattern.flush();
  484. }
  485. }
  486. if( flush_stream )
  487. flush();
  488. return result;
  489. }
  490. //____________________________________________________________________________//
  491. void
  492. output_test_stream::flush()
  493. {
  494. m_pimpl->m_synced_string.erase();
  495. #ifndef BOOST_NO_STRINGSTREAM
  496. str( std::string() );
  497. #else
  498. seekp( 0, std::ios::beg );
  499. #endif
  500. }
  501. //____________________________________________________________________________//
  502. std::size_t
  503. output_test_stream::length()
  504. {
  505. sync();
  506. return m_pimpl->m_synced_string.length();
  507. }
  508. //____________________________________________________________________________//
  509. void
  510. output_test_stream::sync()
  511. {
  512. #ifdef BOOST_NO_STRINGSTREAM
  513. m_pimpl->m_synced_string.assign( str(), pcount() );
  514. freeze( false );
  515. #else
  516. m_pimpl->m_synced_string = str();
  517. #endif
  518. }
  519. //____________________________________________________________________________//
  520. } // namespace test_tools
  521. } // namespace boost
  522. #include <boost/test/detail/enable_warnings.hpp>
  523. #endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER