LCOV - code coverage report
Current view: top level - opt/homebrew/include/boost/test/impl - test_tools.ipp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 64 382 16.8 %
Date: 2026-06-25 07:23:51 Functions: 3 39 7.7 %

          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

Generated by: LCOV version 1.16