test_tools.ipp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  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/test_tools.hpp>
  17. #include <boost/test/unit_test_log.hpp>
  18. #include <boost/test/tools/context.hpp>
  19. #include <boost/test/tools/output_test_stream.hpp>
  20. #include <boost/test/tools/detail/fwd.hpp>
  21. #include <boost/test/tools/detail/print_helper.hpp>
  22. #include <boost/test/framework.hpp>
  23. #include <boost/test/tree/test_unit.hpp>
  24. #include <boost/test/execution_monitor.hpp> // execution_aborted
  25. #include <boost/test/detail/throw_exception.hpp>
  26. #include <boost/test/utils/algorithm.hpp>
  27. // Boost
  28. #include <boost/config.hpp>
  29. // STL
  30. #include <fstream>
  31. #include <string>
  32. #include <cstring>
  33. #include <cctype>
  34. #include <cwchar>
  35. #include <stdexcept>
  36. #include <vector>
  37. #include <utility>
  38. #include <ios>
  39. // !! should we use #include <cstdarg>
  40. #include <stdarg.h>
  41. #include <boost/test/detail/suppress_warnings.hpp>
  42. //____________________________________________________________________________//
  43. # ifdef BOOST_NO_STDC_NAMESPACE
  44. namespace std { using ::strcmp; using ::strlen; using ::isprint; }
  45. #if !defined( BOOST_NO_CWCHAR )
  46. namespace std { using ::wcscmp; }
  47. #endif
  48. # endif
  49. namespace boost {
  50. namespace unit_test {
  51. // local static variable, needed here for visibility reasons
  52. lazy_ostream lazy_ostream::inst = lazy_ostream();
  53. }}
  54. namespace boost {
  55. namespace test_tools {
  56. namespace tt_detail {
  57. // ************************************************************************** //
  58. // ************** print_log_value ************** //
  59. // ************************************************************************** //
  60. void
  61. print_log_value<bool>::operator()( std::ostream& ostr, bool t )
  62. {
  63. ostr << std::boolalpha << t;
  64. }
  65. void
  66. print_log_value<char>::operator()( std::ostream& ostr, char t )
  67. {
  68. if( (std::isprint)( static_cast<unsigned char>(t) ) )
  69. ostr << '\'' << t << '\'';
  70. else
  71. ostr << std::hex
  72. #if BOOST_TEST_USE_STD_LOCALE
  73. << std::showbase
  74. #else
  75. << "0x"
  76. #endif
  77. << static_cast<int>(t);
  78. }
  79. //____________________________________________________________________________//
  80. void
  81. print_log_value<unsigned char>::operator()( std::ostream& ostr, unsigned char t )
  82. {
  83. ostr << std::hex
  84. // showbase is only available for new style streams:
  85. #if BOOST_TEST_USE_STD_LOCALE
  86. << std::showbase
  87. #else
  88. << "0x"
  89. #endif
  90. << static_cast<int>(t);
  91. }
  92. //____________________________________________________________________________//
  93. void
  94. print_log_value<wchar_t>::operator()( std::ostream& ostr, wchar_t r )
  95. {
  96. std::mbstate_t state;
  97. std::string mb(MB_CUR_MAX, '\0');
  98. std::size_t ret = std::wcrtomb(&mb[0], r, &state);
  99. if( ret > 0) {
  100. ostr << mb;
  101. }
  102. else {
  103. ostr << "(wchar_t unable to convert)";
  104. }
  105. }
  106. //____________________________________________________________________________//
  107. void
  108. print_log_value<char const*>::operator()( std::ostream& ostr, char const* t )
  109. {
  110. ostr << ( t ? t : "null string" );
  111. }
  112. //____________________________________________________________________________//
  113. void
  114. print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* t )
  115. {
  116. if(t) {
  117. ostr << static_cast<const void*>(t);
  118. }
  119. else {
  120. ostr << "null w-string";
  121. }
  122. }
  123. //____________________________________________________________________________//
  124. // ************************************************************************** //
  125. // ************** TOOL BOX Implementation ************** //
  126. // ************************************************************************** //
  127. using ::boost::unit_test::lazy_ostream;
  128. static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " };
  129. static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " };
  130. template<typename OutStream>
  131. void
  132. format_report( OutStream& os, assertion_result const& pr, unit_test::lazy_ostream const& assertion_descr,
  133. tool_level tl, check_type ct,
  134. std::size_t num_args, va_list args,
  135. char const* prefix, char const* suffix )
  136. {
  137. using namespace unit_test;
  138. switch( ct ) {
  139. case CHECK_PRED:
  140. os << prefix << assertion_descr << suffix;
  141. if( !pr.has_empty_message() )
  142. os << ". " << pr.message();
  143. break;
  144. case CHECK_BUILT_ASSERTION: {
  145. os << prefix << assertion_descr << suffix;
  146. if( tl != PASS ) {
  147. const_string details_message = pr.message();
  148. if( !details_message.is_empty() ) {
  149. os << details_message;
  150. }
  151. }
  152. break;
  153. }
  154. case CHECK_MSG:
  155. if( tl == PASS )
  156. os << prefix << "'" << assertion_descr << "'" << suffix;
  157. else
  158. os << assertion_descr;
  159. if( !pr.has_empty_message() )
  160. os << ". " << pr.message();
  161. break;
  162. case CHECK_EQUAL:
  163. case CHECK_NE:
  164. case CHECK_LT:
  165. case CHECK_LE:
  166. case CHECK_GT:
  167. case CHECK_GE: {
  168. char const* arg1_descr = va_arg( args, char const* );
  169. lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
  170. char const* arg2_descr = va_arg( args, char const* );
  171. lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* );
  172. os << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix;
  173. if( tl != PASS )
  174. os << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ;
  175. if( !pr.has_empty_message() )
  176. os << ". " << pr.message();
  177. break;
  178. }
  179. case CHECK_CLOSE:
  180. case CHECK_CLOSE_FRACTION: {
  181. char const* arg1_descr = va_arg( args, char const* );
  182. lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* );
  183. char const* arg2_descr = va_arg( args, char const* );
  184. lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* );
  185. /* toler_descr = */ va_arg( args, char const* );
  186. lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* );
  187. os << "difference{" << pr.message()
  188. << "} between " << arg1_descr << "{" << *arg1_val
  189. << "} and " << arg2_descr << "{" << *arg2_val
  190. << ( tl == PASS ? "} doesn't exceed " : "} exceeds " )
  191. << *toler_val;
  192. if( ct == CHECK_CLOSE )
  193. os << "%";
  194. break;
  195. }
  196. case CHECK_SMALL: {
  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. os << "absolute value of " << arg1_descr << "{" << *arg1_val << "}"
  202. << ( tl == PASS ? " doesn't exceed " : " exceeds " )
  203. << *toler_val;
  204. if( !pr.has_empty_message() )
  205. os << ". " << pr.message();
  206. break;
  207. }
  208. case CHECK_PRED_WITH_ARGS: {
  209. std::vector< std::pair<char const*, lazy_ostream const*> > args_copy;
  210. args_copy.reserve( num_args );
  211. for( std::size_t i = 0; i < num_args; ++i ) {
  212. char const* desc = va_arg( args, char const* );
  213. lazy_ostream const* value = va_arg( args, lazy_ostream const* );
  214. args_copy.push_back( std::make_pair( desc, value ) );
  215. }
  216. os << prefix << assertion_descr;
  217. // print predicate call description
  218. os << "( ";
  219. for( std::size_t i = 0; i < num_args; ++i ) {
  220. os << args_copy[i].first;
  221. if( i != num_args-1 )
  222. os << ", ";
  223. }
  224. os << " )" << suffix;
  225. if( tl != PASS ) {
  226. os << " for ( ";
  227. for( std::size_t i = 0; i < num_args; ++i ) {
  228. os << *args_copy[i].second;
  229. if( i != num_args-1 )
  230. os << ", ";
  231. }
  232. os << " )";
  233. }
  234. if( !pr.has_empty_message() )
  235. os << ". " << pr.message();
  236. break;
  237. }
  238. case CHECK_EQUAL_COLL: {
  239. char const* left_begin_descr = va_arg( args, char const* );
  240. char const* left_end_descr = va_arg( args, char const* );
  241. char const* right_begin_descr = va_arg( args, char const* );
  242. char const* right_end_descr = va_arg( args, char const* );
  243. os << prefix << "{ " << left_begin_descr << ", " << left_end_descr << " } == { "
  244. << right_begin_descr << ", " << right_end_descr << " }"
  245. << suffix;
  246. if( !pr.has_empty_message() )
  247. os << ". " << pr.message();
  248. break;
  249. }
  250. case CHECK_BITWISE_EQUAL: {
  251. char const* left_descr = va_arg( args, char const* );
  252. char const* right_descr = va_arg( args, char const* );
  253. os << prefix << left_descr << " =.= " << right_descr << suffix;
  254. if( !pr.has_empty_message() )
  255. os << ". " << pr.message();
  256. break;
  257. }
  258. }
  259. }
  260. //____________________________________________________________________________//
  261. bool
  262. report_assertion( assertion_result const& ar,
  263. lazy_ostream const& assertion_descr,
  264. const_string file_name,
  265. std::size_t line_num,
  266. tool_level tl,
  267. check_type ct,
  268. std::size_t num_args, ... )
  269. {
  270. using namespace unit_test;
  271. if( !framework::test_in_progress() ) {
  272. // in case no test is in progress, we do not throw anything:
  273. // raising an exception here may result in raising an exception in a destructor of a global fixture
  274. // which will abort the process
  275. // We flag this as aborted instead
  276. //BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID,
  277. // std::runtime_error( "Can't use testing tools outside of test case implementation." ) );
  278. framework::test_aborted();
  279. return false;
  280. }
  281. if( !!ar )
  282. tl = PASS;
  283. log_level ll;
  284. char const* prefix;
  285. char const* suffix;
  286. switch( tl ) {
  287. case PASS:
  288. ll = log_successful_tests;
  289. prefix = "check ";
  290. suffix = " has passed";
  291. break;
  292. case WARN:
  293. ll = log_warnings;
  294. prefix = "condition ";
  295. suffix = " is not satisfied";
  296. break;
  297. case CHECK:
  298. ll = log_all_errors;
  299. prefix = "check ";
  300. suffix = " has failed";
  301. break;
  302. case REQUIRE:
  303. ll = log_fatal_errors;
  304. prefix = "critical check ";
  305. suffix = " has failed";
  306. break;
  307. default:
  308. return true;
  309. }
  310. unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
  311. va_list args;
  312. va_start( args, num_args );
  313. format_report( unit_test_log, ar, assertion_descr, tl, ct, num_args, args, prefix, suffix );
  314. va_end( args );
  315. unit_test_log << unit_test::log::end();
  316. switch( tl ) {
  317. case PASS:
  318. framework::assertion_result( AR_PASSED );
  319. return true;
  320. case WARN:
  321. framework::assertion_result( AR_TRIGGERED );
  322. return false;
  323. case CHECK:
  324. framework::assertion_result( AR_FAILED );
  325. return false;
  326. case REQUIRE:
  327. framework::assertion_result( AR_FAILED );
  328. framework::test_unit_aborted( framework::current_test_unit() );
  329. BOOST_TEST_I_THROW( execution_aborted() );
  330. // the previous line either throws or aborts and the return below is not reached
  331. // return false;
  332. BOOST_TEST_UNREACHABLE_RETURN(false);
  333. }
  334. return true;
  335. }
  336. //____________________________________________________________________________//
  337. assertion_result
  338. format_assertion_result( const_string expr_val, const_string details )
  339. {
  340. assertion_result res(false);
  341. bool starts_new_line = first_char( expr_val ) == '\n';
  342. if( !starts_new_line && !expr_val.is_empty() )
  343. res.message().stream() << " [" << expr_val << "]";
  344. if( !details.is_empty() ) {
  345. if( first_char(details) != '[' )
  346. res.message().stream() << ": ";
  347. else
  348. res.message().stream() << " ";
  349. res.message().stream() << details;
  350. }
  351. if( starts_new_line )
  352. res.message().stream() << "." << expr_val;
  353. return res;
  354. }
  355. //____________________________________________________________________________//
  356. BOOST_TEST_DECL std::string
  357. prod_report_format( assertion_result const& ar, unit_test::lazy_ostream const& assertion_descr, check_type ct, std::size_t num_args, ... )
  358. {
  359. std::ostringstream msg_buff;
  360. va_list args;
  361. va_start( args, num_args );
  362. format_report( msg_buff, ar, assertion_descr, CHECK, ct, num_args, args, "assertion ", " failed" );
  363. va_end( args );
  364. return msg_buff.str();
  365. }
  366. //____________________________________________________________________________//
  367. assertion_result
  368. equal_impl( char const* left, char const* right )
  369. {
  370. return (left && right) ? std::strcmp( left, right ) == 0 : (left == right);
  371. }
  372. //____________________________________________________________________________//
  373. #if !defined( BOOST_NO_CWCHAR )
  374. assertion_result
  375. equal_impl( wchar_t const* left, wchar_t const* right )
  376. {
  377. return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right);
  378. }
  379. #endif // !defined( BOOST_NO_CWCHAR )
  380. //____________________________________________________________________________//
  381. bool
  382. is_defined_impl( const_string symbol_name, const_string symbol_value )
  383. {
  384. symbol_value.trim_left( 2 );
  385. return symbol_name != symbol_value;
  386. }
  387. //____________________________________________________________________________//
  388. // ************************************************************************** //
  389. // ************** context_frame ************** //
  390. // ************************************************************************** //
  391. context_frame::context_frame( ::boost::unit_test::lazy_ostream const& context_descr )
  392. : m_frame_id( unit_test::framework::add_context( context_descr, true ) )
  393. {
  394. }
  395. //____________________________________________________________________________//
  396. context_frame::~context_frame()
  397. {
  398. unit_test::framework::clear_context( m_frame_id );
  399. }
  400. //____________________________________________________________________________//
  401. context_frame::operator bool()
  402. {
  403. return true;
  404. }
  405. //____________________________________________________________________________//
  406. } // namespace tt_detail
  407. // ************************************************************************** //
  408. // ************** output_test_stream ************** //
  409. // ************************************************************************** //
  410. struct output_test_stream::Impl
  411. {
  412. std::fstream m_pattern;
  413. bool m_match_or_save;
  414. bool m_text_or_binary;
  415. std::string m_synced_string;
  416. char get_char()
  417. {
  418. char res = 0;
  419. do {
  420. m_pattern.get( res );
  421. } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() );
  422. return res;
  423. }
  424. void check_and_fill( assertion_result& res )
  425. {
  426. if( !res.p_predicate_value )
  427. res.message() << "Output content: \"" << m_synced_string << '\"';
  428. }
  429. };
  430. //____________________________________________________________________________//
  431. output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary )
  432. : m_pimpl( new Impl )
  433. {
  434. if( !pattern_file_name.is_empty() ) {
  435. std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out;
  436. if( !text_or_binary )
  437. m |= std::ios::binary;
  438. m_pimpl->m_pattern.open( pattern_file_name.begin(), m );
  439. if( !m_pimpl->m_pattern.is_open() )
  440. BOOST_TEST_FRAMEWORK_MESSAGE( "Can't open pattern file " << pattern_file_name << " for " << (match_or_save ? "reading" : "writing") );
  441. }
  442. m_pimpl->m_match_or_save = match_or_save;
  443. m_pimpl->m_text_or_binary = text_or_binary;
  444. }
  445. //____________________________________________________________________________//
  446. output_test_stream::~output_test_stream()
  447. {
  448. delete m_pimpl;
  449. }
  450. //____________________________________________________________________________//
  451. assertion_result
  452. output_test_stream::is_empty( bool flush_stream )
  453. {
  454. sync();
  455. assertion_result res( m_pimpl->m_synced_string.empty() );
  456. m_pimpl->check_and_fill( res );
  457. if( flush_stream )
  458. flush();
  459. return res;
  460. }
  461. //____________________________________________________________________________//
  462. assertion_result
  463. output_test_stream::check_length( std::size_t length_, bool flush_stream )
  464. {
  465. sync();
  466. assertion_result res( m_pimpl->m_synced_string.length() == length_ );
  467. m_pimpl->check_and_fill( res );
  468. if( flush_stream )
  469. flush();
  470. return res;
  471. }
  472. //____________________________________________________________________________//
  473. assertion_result
  474. output_test_stream::is_equal( const_string arg, bool flush_stream )
  475. {
  476. sync();
  477. assertion_result res( const_string( m_pimpl->m_synced_string ) == arg );
  478. m_pimpl->check_and_fill( res );
  479. if( flush_stream )
  480. flush();
  481. return res;
  482. }
  483. //____________________________________________________________________________//
  484. std::string pretty_print_log(std::string str) {
  485. static const std::string to_replace[] = { "\r", "\n" };
  486. static const std::string replacement[] = { "\\r", "\\n" };
  487. return unit_test::utils::replace_all_occurrences_of(
  488. str,
  489. to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]),
  490. replacement, replacement + sizeof(replacement)/sizeof(replacement[0]));
  491. }
  492. assertion_result
  493. output_test_stream::match_pattern( bool flush_stream )
  494. {
  495. const std::string::size_type n_chars_presuffix = 10;
  496. sync();
  497. assertion_result result( true );
  498. const std::string stream_string_repr = get_stream_string_representation();
  499. if( !m_pimpl->m_pattern.is_open() ) {
  500. result = false;
  501. result.message() << "Pattern file can't be opened!";
  502. }
  503. else {
  504. if( m_pimpl->m_match_or_save ) {
  505. int offset = 0;
  506. std::vector<char> last_elements;
  507. for ( std::string::size_type i = 0; static_cast<int>(i + offset) < static_cast<int>(stream_string_repr.length()); ++i ) {
  508. char c = m_pimpl->get_char();
  509. if( last_elements.size() <= n_chars_presuffix ) {
  510. last_elements.push_back( c );
  511. }
  512. else {
  513. last_elements[ i % last_elements.size() ] = c;
  514. }
  515. bool is_same = !m_pimpl->m_pattern.fail() &&
  516. !m_pimpl->m_pattern.eof() &&
  517. (stream_string_repr[i+offset] == c);
  518. if( !is_same ) {
  519. result = false;
  520. std::string::size_type prefix_size = (std::min)( i + offset, n_chars_presuffix );
  521. std::string::size_type suffix_size = (std::min)( stream_string_repr.length() - i - offset,
  522. n_chars_presuffix );
  523. // try to log area around the mismatch
  524. std::string substr = stream_string_repr.substr(0, i+offset);
  525. std::size_t line = std::count(substr.begin(), substr.end(), '\n');
  526. std::size_t column = i + offset - substr.rfind('\n');
  527. result.message()
  528. << "Mismatch at position " << i
  529. << " (line " << line
  530. << ", column " << column
  531. << "): '" << pretty_print_log(std::string(1, stream_string_repr[i+offset])) << "' != '" << pretty_print_log(std::string(1, c)) << "' :\n";
  532. // we already escape this substring because we need its actual size for the pretty print
  533. // of the difference location.
  534. std::string sub_str_prefix(pretty_print_log(stream_string_repr.substr( i + offset - prefix_size, prefix_size )));
  535. // we need this substring as is because we compute the best matching substrings on it.
  536. std::string sub_str_suffix(stream_string_repr.substr( i + offset, suffix_size));
  537. result.message() << "... " << sub_str_prefix + pretty_print_log(sub_str_suffix) << " ..." << '\n';
  538. result.message() << "... ";
  539. for( std::size_t j = 0; j < last_elements.size() ; j++ )
  540. result.message() << pretty_print_log(std::string(1, last_elements[(i + j + 1) % last_elements.size()]));
  541. std::vector<char> last_elements_ordered;
  542. last_elements_ordered.push_back(c);
  543. for( std::string::size_type counter = 0; counter < suffix_size - 1 ; counter++ ) {
  544. char c2 = m_pimpl->get_char();
  545. if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() )
  546. break;
  547. result.message() << pretty_print_log(std::string(1, c2));
  548. last_elements_ordered.push_back(c2);
  549. }
  550. // tries to find the best substring matching in the remainder of the
  551. // two strings
  552. std::size_t max_nb_char_in_common = 0;
  553. std::size_t best_pattern_start_index = 0;
  554. std::size_t best_stream_start_index = 0;
  555. for( std::size_t pattern_start_index = best_pattern_start_index;
  556. pattern_start_index < last_elements_ordered.size();
  557. pattern_start_index++ ) {
  558. for( std::size_t stream_start_index = best_stream_start_index;
  559. stream_start_index < sub_str_suffix.size();
  560. stream_start_index++ ) {
  561. std::size_t max_size = (std::min)( last_elements_ordered.size() - pattern_start_index, sub_str_suffix.size() - stream_start_index );
  562. if( max_nb_char_in_common > max_size )
  563. break; // safely break to go to the outer loop
  564. std::size_t nb_char_in_common = 0;
  565. for( std::size_t k = 0; k < max_size; k++) {
  566. if( last_elements_ordered[pattern_start_index + k] == sub_str_suffix[stream_start_index + k] )
  567. nb_char_in_common ++;
  568. else
  569. break; // we take fully matching substring only
  570. }
  571. if( nb_char_in_common > max_nb_char_in_common ) {
  572. max_nb_char_in_common = nb_char_in_common;
  573. best_pattern_start_index = pattern_start_index;
  574. best_stream_start_index = stream_start_index;
  575. }
  576. }
  577. }
  578. // indicates with more precision the location of the mismatchs in "ascii arts" ...
  579. result.message() << " ...\n... ";
  580. for( std::string::size_type j = 0; j < sub_str_prefix.size(); j++) {
  581. result.message() << ' ';
  582. }
  583. result.message() << '~'; // places the first tilde at the current char that mismatches
  584. for( std::size_t k = 1; k < (std::max)(best_pattern_start_index, best_stream_start_index); k++ ) { // 1 is for the current char c
  585. std::string s1(pretty_print_log(std::string(1, last_elements_ordered[(std::min)(k, best_pattern_start_index)])));
  586. std::string s2(pretty_print_log(std::string(1, sub_str_suffix[(std::min)(k, best_stream_start_index)])));
  587. for( int h = static_cast<int>((std::max)(s1.size(), s2.size())); h > 0; h--)
  588. result.message() << "~";
  589. }
  590. if( m_pimpl->m_pattern.eof() ) {
  591. result.message() << " (reference string shorter than current stream)";
  592. }
  593. result.message() << "\n";
  594. // no need to continue if the EOF is reached
  595. if( m_pimpl->m_pattern.eof() ) {
  596. break;
  597. }
  598. // first char is a replicat of c, so we do not copy it.
  599. for(std::string::size_type counter = 0; counter < last_elements_ordered.size() - 1 ; counter++)
  600. last_elements[ (i + 1 + counter) % last_elements.size() ] = last_elements_ordered[counter + 1];
  601. i += last_elements_ordered.size()-1;
  602. offset += best_stream_start_index - best_pattern_start_index;
  603. }
  604. }
  605. // not needed anymore
  606. /*
  607. if(offset > 0 && false) {
  608. m_pimpl->m_pattern.ignore(
  609. static_cast<std::streamsize>( offset ));
  610. }
  611. */
  612. }
  613. else {
  614. m_pimpl->m_pattern.write( stream_string_repr.c_str(),
  615. static_cast<std::streamsize>( stream_string_repr.length() ) );
  616. m_pimpl->m_pattern.flush();
  617. }
  618. }
  619. if( flush_stream )
  620. flush();
  621. return result;
  622. }
  623. //____________________________________________________________________________//
  624. void
  625. output_test_stream::flush()
  626. {
  627. m_pimpl->m_synced_string.erase();
  628. #ifndef BOOST_NO_STRINGSTREAM
  629. str( std::string() );
  630. #else
  631. seekp( 0, std::ios::beg );
  632. #endif
  633. }
  634. std::string
  635. output_test_stream::get_stream_string_representation() const {
  636. return m_pimpl->m_synced_string;
  637. }
  638. //____________________________________________________________________________//
  639. std::size_t
  640. output_test_stream::length()
  641. {
  642. sync();
  643. return m_pimpl->m_synced_string.length();
  644. }
  645. //____________________________________________________________________________//
  646. void
  647. output_test_stream::sync()
  648. {
  649. #ifdef BOOST_NO_STRINGSTREAM
  650. m_pimpl->m_synced_string.assign( str(), pcount() );
  651. freeze( false );
  652. #else
  653. m_pimpl->m_synced_string = str();
  654. #endif
  655. }
  656. //____________________________________________________________________________//
  657. } // namespace test_tools
  658. } // namespace boost
  659. #include <boost/test/detail/enable_warnings.hpp>
  660. #endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER