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