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