test_tools.ipp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  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. #ifdef BOOST_MSVC
  262. #pragma warning(push)
  263. #pragma warning(disable : 4702) // There is intentionally unreachable code
  264. #endif
  265. bool
  266. report_assertion( assertion_result const& ar,
  267. lazy_ostream const& assertion_descr,
  268. const_string file_name,
  269. std::size_t line_num,
  270. tool_level tl,
  271. check_type ct,
  272. std::size_t num_args, ... )
  273. {
  274. using namespace unit_test;
  275. if( !framework::test_in_progress() ) {
  276. // in case no test is in progress, we do not throw anything:
  277. // raising an exception here may result in raising an exception in a destructor of a global fixture
  278. // which will abort the process
  279. // We flag this as aborted instead
  280. //BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID,
  281. // std::runtime_error( "Can't use testing tools outside of test case implementation." ) );
  282. framework::test_aborted();
  283. return false;
  284. }
  285. if( !!ar )
  286. tl = PASS;
  287. log_level ll;
  288. char const* prefix;
  289. char const* suffix;
  290. switch( tl ) {
  291. case PASS:
  292. ll = log_successful_tests;
  293. prefix = "check ";
  294. suffix = " has passed";
  295. break;
  296. case WARN:
  297. ll = log_warnings;
  298. prefix = "condition ";
  299. suffix = " is not satisfied";
  300. break;
  301. case CHECK:
  302. ll = log_all_errors;
  303. prefix = "check ";
  304. suffix = " has failed";
  305. break;
  306. case REQUIRE:
  307. ll = log_fatal_errors;
  308. prefix = "critical check ";
  309. suffix = " has failed";
  310. break;
  311. default:
  312. return true;
  313. }
  314. unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
  315. va_list args;
  316. va_start( args, num_args );
  317. format_report( unit_test_log, ar, assertion_descr, tl, ct, num_args, args, prefix, suffix );
  318. va_end( args );
  319. unit_test_log << unit_test::log::end();
  320. switch( tl ) {
  321. case PASS:
  322. framework::assertion_result( AR_PASSED );
  323. return true;
  324. case WARN:
  325. framework::assertion_result( AR_TRIGGERED );
  326. return false;
  327. case CHECK:
  328. framework::assertion_result( AR_FAILED );
  329. return false;
  330. case REQUIRE:
  331. framework::assertion_result( AR_FAILED );
  332. framework::test_unit_aborted( framework::current_test_unit() );
  333. BOOST_TEST_I_THROW( execution_aborted() );
  334. // the previous line either throws or aborts and the return below is not reached
  335. // return false;
  336. BOOST_TEST_UNREACHABLE_RETURN(false);
  337. }
  338. return true;
  339. }
  340. #ifdef BOOST_MSVC
  341. #pragma warning(pop)
  342. #endif
  343. //____________________________________________________________________________//
  344. assertion_result
  345. format_assertion_result( const_string expr_val, const_string details )
  346. {
  347. assertion_result res(false);
  348. bool starts_new_line = first_char( expr_val ) == '\n';
  349. if( !starts_new_line && !expr_val.is_empty() )
  350. res.message().stream() << " [" << expr_val << "]";
  351. if( !details.is_empty() ) {
  352. if( first_char(details) != '[' )
  353. res.message().stream() << ": ";
  354. else
  355. res.message().stream() << " ";
  356. res.message().stream() << details;
  357. }
  358. if( starts_new_line )
  359. res.message().stream() << "." << expr_val;
  360. return res;
  361. }
  362. //____________________________________________________________________________//
  363. BOOST_TEST_DECL std::string
  364. prod_report_format( assertion_result const& ar, unit_test::lazy_ostream const& assertion_descr, check_type ct, std::size_t num_args, ... )
  365. {
  366. std::ostringstream msg_buff;
  367. va_list args;
  368. va_start( args, num_args );
  369. format_report( msg_buff, ar, assertion_descr, CHECK, ct, num_args, args, "assertion ", " failed" );
  370. va_end( args );
  371. return msg_buff.str();
  372. }
  373. //____________________________________________________________________________//
  374. assertion_result
  375. equal_impl( char const* left, char const* right )
  376. {
  377. return (left && right) ? std::strcmp( left, right ) == 0 : (left == right);
  378. }
  379. //____________________________________________________________________________//
  380. #if !defined( BOOST_NO_CWCHAR )
  381. assertion_result
  382. equal_impl( wchar_t const* left, wchar_t const* right )
  383. {
  384. return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right);
  385. }
  386. #endif // !defined( BOOST_NO_CWCHAR )
  387. //____________________________________________________________________________//
  388. bool
  389. is_defined_impl( const_string symbol_name, const_string symbol_value )
  390. {
  391. symbol_value.trim_left( 2 );
  392. return symbol_name != symbol_value;
  393. }
  394. //____________________________________________________________________________//
  395. // ************************************************************************** //
  396. // ************** context_frame ************** //
  397. // ************************************************************************** //
  398. context_frame::context_frame( ::boost::unit_test::lazy_ostream const& context_descr )
  399. : m_frame_id( unit_test::framework::add_context( context_descr, true ) )
  400. {
  401. }
  402. //____________________________________________________________________________//
  403. context_frame::~context_frame()
  404. {
  405. unit_test::framework::clear_context( m_frame_id );
  406. }
  407. //____________________________________________________________________________//
  408. context_frame::operator bool()
  409. {
  410. return true;
  411. }
  412. //____________________________________________________________________________//
  413. } // namespace tt_detail
  414. // ************************************************************************** //
  415. // ************** output_test_stream ************** //
  416. // ************************************************************************** //
  417. struct output_test_stream::Impl
  418. {
  419. std::fstream m_pattern;
  420. bool m_match_or_save;
  421. bool m_text_or_binary;
  422. std::string m_synced_string;
  423. char get_char()
  424. {
  425. char res = 0;
  426. do {
  427. m_pattern.get( res );
  428. } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() );
  429. return res;
  430. }
  431. void check_and_fill( assertion_result& res )
  432. {
  433. if( !res.p_predicate_value )
  434. res.message() << "Output content: \"" << m_synced_string << '\"';
  435. }
  436. };
  437. //____________________________________________________________________________//
  438. output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary )
  439. : m_pimpl( new Impl )
  440. {
  441. if( !pattern_file_name.is_empty() ) {
  442. std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out;
  443. if( !text_or_binary )
  444. m |= std::ios::binary;
  445. m_pimpl->m_pattern.open( pattern_file_name.begin(), m );
  446. if( !m_pimpl->m_pattern.is_open() )
  447. BOOST_TEST_FRAMEWORK_MESSAGE( "Can't open pattern file " << pattern_file_name << " for " << (match_or_save ? "reading" : "writing") );
  448. }
  449. m_pimpl->m_match_or_save = match_or_save;
  450. m_pimpl->m_text_or_binary = text_or_binary;
  451. }
  452. //____________________________________________________________________________//
  453. output_test_stream::~output_test_stream()
  454. {
  455. delete m_pimpl;
  456. }
  457. //____________________________________________________________________________//
  458. assertion_result
  459. output_test_stream::is_empty( bool flush_stream )
  460. {
  461. sync();
  462. assertion_result res( m_pimpl->m_synced_string.empty() );
  463. m_pimpl->check_and_fill( res );
  464. if( flush_stream )
  465. flush();
  466. return res;
  467. }
  468. //____________________________________________________________________________//
  469. assertion_result
  470. output_test_stream::check_length( std::size_t length_, bool flush_stream )
  471. {
  472. sync();
  473. assertion_result res( m_pimpl->m_synced_string.length() == length_ );
  474. m_pimpl->check_and_fill( res );
  475. if( flush_stream )
  476. flush();
  477. return res;
  478. }
  479. //____________________________________________________________________________//
  480. assertion_result
  481. output_test_stream::is_equal( const_string arg, bool flush_stream )
  482. {
  483. sync();
  484. assertion_result res( const_string( m_pimpl->m_synced_string ) == arg );
  485. m_pimpl->check_and_fill( res );
  486. if( flush_stream )
  487. flush();
  488. return res;
  489. }
  490. //____________________________________________________________________________//
  491. std::string pretty_print_log(std::string str) {
  492. static const std::string to_replace[] = { "\r", "\n" };
  493. static const std::string replacement[] = { "\\r", "\\n" };
  494. return unit_test::utils::replace_all_occurrences_of(
  495. str,
  496. to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]),
  497. replacement, replacement + sizeof(replacement)/sizeof(replacement[0]));
  498. }
  499. assertion_result
  500. output_test_stream::match_pattern( bool flush_stream )
  501. {
  502. const std::string::size_type n_chars_presuffix = 10;
  503. sync();
  504. assertion_result result( true );
  505. const std::string stream_string_repr = get_stream_string_representation();
  506. if( !m_pimpl->m_pattern.is_open() ) {
  507. result = false;
  508. result.message() << "Pattern file can't be opened!";
  509. }
  510. else {
  511. if( m_pimpl->m_match_or_save ) {
  512. int offset = 0;
  513. std::vector<char> last_elements;
  514. for ( std::string::size_type i = 0; static_cast<int>(i + offset) < static_cast<int>(stream_string_repr.length()); ++i ) {
  515. char c = m_pimpl->get_char();
  516. if( last_elements.size() <= n_chars_presuffix ) {
  517. last_elements.push_back( c );
  518. }
  519. else {
  520. last_elements[ i % last_elements.size() ] = c;
  521. }
  522. bool is_same = !m_pimpl->m_pattern.fail() &&
  523. !m_pimpl->m_pattern.eof() &&
  524. (stream_string_repr[i+offset] == c);
  525. if( !is_same ) {
  526. result = false;
  527. std::string::size_type prefix_size = (std::min)( i + offset, n_chars_presuffix );
  528. std::string::size_type suffix_size = (std::min)( stream_string_repr.length() - i - offset,
  529. n_chars_presuffix );
  530. // try to log area around the mismatch
  531. std::string substr = stream_string_repr.substr(0, i+offset);
  532. std::size_t line = std::count(substr.begin(), substr.end(), '\n');
  533. std::size_t column = i + offset - substr.rfind('\n');
  534. result.message()
  535. << "Mismatch at position " << i
  536. << " (line " << line
  537. << ", column " << column
  538. << "): '" << pretty_print_log(std::string(1, stream_string_repr[i+offset])) << "' != '" << pretty_print_log(std::string(1, c)) << "' :\n";
  539. // we already escape this substring because we need its actual size for the pretty print
  540. // of the difference location.
  541. std::string sub_str_prefix(pretty_print_log(stream_string_repr.substr( i + offset - prefix_size, prefix_size )));
  542. // we need this substring as is because we compute the best matching substrings on it.
  543. std::string sub_str_suffix(stream_string_repr.substr( i + offset, suffix_size));
  544. result.message() << "... " << sub_str_prefix + pretty_print_log(sub_str_suffix) << " ..." << '\n';
  545. result.message() << "... ";
  546. for( std::size_t j = 0; j < last_elements.size() ; j++ )
  547. result.message() << pretty_print_log(std::string(1, last_elements[(i + j + 1) % last_elements.size()]));
  548. std::vector<char> last_elements_ordered;
  549. last_elements_ordered.push_back(c);
  550. for( std::string::size_type counter = 0; counter < suffix_size - 1 ; counter++ ) {
  551. char c2 = m_pimpl->get_char();
  552. if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() )
  553. break;
  554. result.message() << pretty_print_log(std::string(1, c2));
  555. last_elements_ordered.push_back(c2);
  556. }
  557. // tries to find the best substring matching in the remainder of the
  558. // two strings
  559. std::size_t max_nb_char_in_common = 0;
  560. std::size_t best_pattern_start_index = 0;
  561. std::size_t best_stream_start_index = 0;
  562. for( std::size_t pattern_start_index = best_pattern_start_index;
  563. pattern_start_index < last_elements_ordered.size();
  564. pattern_start_index++ ) {
  565. for( std::size_t stream_start_index = best_stream_start_index;
  566. stream_start_index < sub_str_suffix.size();
  567. stream_start_index++ ) {
  568. std::size_t max_size = (std::min)( last_elements_ordered.size() - pattern_start_index, sub_str_suffix.size() - stream_start_index );
  569. if( max_nb_char_in_common > max_size )
  570. break; // safely break to go to the outer loop
  571. std::size_t nb_char_in_common = 0;
  572. for( std::size_t k = 0; k < max_size; k++) {
  573. if( last_elements_ordered[pattern_start_index + k] == sub_str_suffix[stream_start_index + k] )
  574. nb_char_in_common ++;
  575. else
  576. break; // we take fully matching substring only
  577. }
  578. if( nb_char_in_common > max_nb_char_in_common ) {
  579. max_nb_char_in_common = nb_char_in_common;
  580. best_pattern_start_index = pattern_start_index;
  581. best_stream_start_index = stream_start_index;
  582. }
  583. }
  584. }
  585. // indicates with more precision the location of the mismatchs in "ascii arts" ...
  586. result.message() << " ...\n... ";
  587. for( std::string::size_type j = 0; j < sub_str_prefix.size(); j++) {
  588. result.message() << ' ';
  589. }
  590. result.message() << '~'; // places the first tilde at the current char that mismatches
  591. 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
  592. std::string s1(pretty_print_log(std::string(1, last_elements_ordered[(std::min)(k, best_pattern_start_index)])));
  593. std::string s2(pretty_print_log(std::string(1, sub_str_suffix[(std::min)(k, best_stream_start_index)])));
  594. for( int h = static_cast<int>((std::max)(s1.size(), s2.size())); h > 0; h--)
  595. result.message() << "~";
  596. }
  597. if( m_pimpl->m_pattern.eof() ) {
  598. result.message() << " (reference string shorter than current stream)";
  599. }
  600. result.message() << "\n";
  601. // no need to continue if the EOF is reached
  602. if( m_pimpl->m_pattern.eof() ) {
  603. break;
  604. }
  605. // first char is a replicat of c, so we do not copy it.
  606. for(std::string::size_type counter = 0; counter < last_elements_ordered.size() - 1 ; counter++)
  607. last_elements[ (i + 1 + counter) % last_elements.size() ] = last_elements_ordered[counter + 1];
  608. i += last_elements_ordered.size()-1;
  609. offset += best_stream_start_index - best_pattern_start_index;
  610. }
  611. }
  612. // not needed anymore
  613. /*
  614. if(offset > 0 && false) {
  615. m_pimpl->m_pattern.ignore(
  616. static_cast<std::streamsize>( offset ));
  617. }
  618. */
  619. }
  620. else {
  621. m_pimpl->m_pattern.write( stream_string_repr.c_str(),
  622. static_cast<std::streamsize>( stream_string_repr.length() ) );
  623. m_pimpl->m_pattern.flush();
  624. }
  625. }
  626. if( flush_stream )
  627. flush();
  628. return result;
  629. }
  630. //____________________________________________________________________________//
  631. void
  632. output_test_stream::flush()
  633. {
  634. m_pimpl->m_synced_string.erase();
  635. #ifndef BOOST_NO_STRINGSTREAM
  636. str( std::string() );
  637. #else
  638. seekp( 0, std::ios::beg );
  639. #endif
  640. }
  641. std::string
  642. output_test_stream::get_stream_string_representation() const {
  643. return m_pimpl->m_synced_string;
  644. }
  645. //____________________________________________________________________________//
  646. std::size_t
  647. output_test_stream::length()
  648. {
  649. sync();
  650. return m_pimpl->m_synced_string.length();
  651. }
  652. //____________________________________________________________________________//
  653. void
  654. output_test_stream::sync()
  655. {
  656. #ifdef BOOST_NO_STRINGSTREAM
  657. m_pimpl->m_synced_string.assign( str(), pcount() );
  658. freeze( false );
  659. #else
  660. m_pimpl->m_synced_string = str();
  661. #endif
  662. }
  663. //____________________________________________________________________________//
  664. } // namespace test_tools
  665. } // namespace boost
  666. #include <boost/test/detail/enable_warnings.hpp>
  667. #endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER