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