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