• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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