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

source code of include/boost/test/impl/test_tools.ipp