test_tools.ipp 18 KB

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