1// (C) Copyright Gennadiy Rozental 2005. 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: test_tools.ipp,v $ 9// 10// Version : $Revision: 1.1.1.1 $ 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/output_test_stream.hpp> 22#include <boost/test/framework.hpp> 23#include <boost/test/execution_monitor.hpp> // execution_aborted 24 25// Boost 26#include <boost/config.hpp> 27 28// STL 29#include <fstream> 30#include <string> 31#include <cstring> 32#include <cctype> 33#include <cwchar> 34#ifdef BOOST_STANDARD_IOSTREAMS 35#include <ios> 36#endif 37 38// !! should we use #include <cstdarg> 39#include <stdarg.h> 40 41#include <boost/test/detail/suppress_warnings.hpp> 42 43//____________________________________________________________________________// 44 45# ifdef BOOST_NO_STDC_NAMESPACE 46namespace std { using ::strcmp; using ::strlen; using ::isprint; } 47#if !defined( BOOST_NO_CWCHAR ) 48namespace std { using ::wcscmp; } 49#endif 50# endif 51 52namespace boost { 53 54namespace test_tools { 55 56namespace tt_detail { 57 58// ************************************************************************** // 59// ************** TOOL BOX Implementation ************** // 60// ************************************************************************** // 61 62void 63check_impl( predicate_result const& pr, wrap_stringstream& check_descr, 64 const_string file_name, std::size_t line_num, 65 tool_level tl, check_type ct, 66 std::size_t num_of_args, ... ) 67{ 68 using namespace unit_test; 69 70 if( !!pr ) 71 tl = PASS; 72 73 log_level ll; 74 char const* prefix; 75 char const* suffix; 76 77 if( tl == PASS ) 78 framework::assertion_result( true ); 79 else if( tl != WARN ) 80 framework::assertion_result( false ); 81 82 switch( tl ) { 83 case PASS: 84 ll = log_successful_tests; 85 prefix = "check "; 86 suffix = " passed"; 87 break; 88 case WARN: 89 ll = log_warnings; 90 prefix = "condition "; 91 suffix = " is not satisfied"; 92 break; 93 case CHECK: 94 ll = log_all_errors; 95 prefix = "check "; 96 suffix = " failed"; 97 break; 98 case REQUIRE: 99 ll = log_fatal_errors; 100 prefix = "critical test "; 101 suffix = " failed"; 102 break; 103 default: 104 return; 105 } 106 107 switch( ct ) { 108 case CHECK_PRED: 109 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) 110 << ll << prefix << check_descr.str() << suffix; 111 112 if( !pr.has_empty_message() ) 113 unit_test_log << ". " << pr.message(); 114 115 unit_test_log << unit_test::log::end(); 116 break; 117 case CHECK_MSG: 118 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) << ll; 119 120 if( tl == PASS ) 121 unit_test_log << prefix << "'" << check_descr.str() << "'" << suffix; 122 else 123 unit_test_log << check_descr.str(); 124 125 if( !pr.has_empty_message() ) 126 unit_test_log << ". " << pr.message(); 127 128 unit_test_log << unit_test::log::end(); 129 break; 130 case MSG_ONLY: 131 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) 132 << log_messages << check_descr.str() << unit_test::log::end(); 133 break; 134 case SET_CHECKPOINT: 135 unit_test_log << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) << unit_test::log::checkpoint( check_descr.str() ); 136 break; 137 case CHECK_EQUAL: { 138 va_list args; 139 140 va_start( args, num_of_args ); 141 char const* arg1_descr = va_arg( args, char const* ); 142 char const* arg1_val = va_arg( args, char const* ); 143 char const* arg2_descr = va_arg( args, char const* ); 144 char const* arg2_val = va_arg( args, char const* ); 145 146 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) 147 << ll << prefix << arg1_descr << " == " << arg2_descr << suffix; 148 149 if( tl != PASS ) 150 unit_test_log << " [" << arg1_val << " != " << arg2_val << "]" ; 151 152 va_end( args ); 153 154 if( !pr.has_empty_message() ) 155 unit_test_log << ". " << pr.message(); 156 157 unit_test_log << unit_test::log::end(); 158 break; 159 } 160 case CHECK_CLOSE: { 161 va_list args; 162 163 va_start( args, num_of_args ); 164 char const* arg1_descr = va_arg( args, char const* ); 165 char const* arg1_val = va_arg( args, char const* ); 166 char const* arg2_descr = va_arg( args, char const* ); 167 char const* arg2_val = va_arg( args, char const* ); 168 /* toler_descr = */ va_arg( args, char const* ); 169 char const* toler_val = va_arg( args, char const* ); 170 171 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) << ll; 172 173 unit_test_log << "difference between " << arg1_descr << "{" << arg1_val << "}" 174 << " and " << arg2_descr << "{" << arg2_val << "}" 175 << ( tl == PASS ? " doesn't exceed " : " exceeds " ) 176 << toler_val << "%", 177 178 va_end( args ); 179 180 if( !pr.has_empty_message() ) 181 unit_test_log << ". " << pr.message(); 182 183 unit_test_log << unit_test::log::end(); 184 break; 185 } 186 case CHECK_SMALL: { 187 va_list args; 188 189 va_start( args, num_of_args ); 190 char const* arg1_descr = va_arg( args, char const* ); 191 char const* arg1_val = va_arg( args, char const* ); 192 /* toler_descr = */ va_arg( args, char const* ); 193 char const* toler_val = va_arg( args, char const* ); 194 195 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) << ll; 196 197 unit_test_log << "absolute value of " << arg1_descr << "{" << arg1_val << "}" 198 << ( tl == PASS ? " doesn't exceed " : " exceeds " ) 199 << toler_val, 200 201 va_end( args ); 202 203 if( !pr.has_empty_message() ) 204 unit_test_log << ". " << pr.message(); 205 206 unit_test_log << unit_test::log::end(); 207 break; 208 } 209 case CHECK_PRED_WITH_ARGS: { 210 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) 211 << ll << prefix << check_descr.str(); 212 213 // print predicate call description 214 { 215 va_list args; 216 va_start( args, num_of_args ); 217 218 unit_test_log << "( "; 219 for( std::size_t i = 0; i < num_of_args; ++i ) { 220 unit_test_log << va_arg( args, char const* ); 221 va_arg( args, char const* ); // skip argument value; 222 223 if( i != num_of_args-1 ) 224 unit_test_log << ", "; 225 } 226 unit_test_log << " )" << suffix; 227 va_end( args ); 228 } 229 230 if( tl != PASS ) { 231 va_list args; 232 va_start( args, num_of_args ); 233 234 unit_test_log << " for ( "; 235 for( std::size_t i = 0; i < num_of_args; ++i ) { 236 va_arg( args, char const* ); // skip argument description; 237 unit_test_log << va_arg( args, char const* ); 238 239 if( i != num_of_args-1 ) 240 unit_test_log << ", "; 241 } 242 unit_test_log << " )"; 243 va_end( args ); 244 } 245 246 if( !pr.has_empty_message() ) 247 unit_test_log << ". " << pr.message(); 248 249 unit_test_log << unit_test::log::end(); 250 break; 251 } 252 case CHECK_EQUAL_COLL: { 253 va_list args; 254 255 va_start( args, num_of_args ); 256 char const* left_begin_descr = va_arg( args, char const* ); 257 char const* left_end_descr = va_arg( args, char const* ); 258 char const* right_begin_descr = va_arg( args, char const* ); 259 char const* right_end_descr = va_arg( args, char const* ); 260 261 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) 262 << ll << prefix 263 << "{ " << left_begin_descr << ", " << left_end_descr << " } == { " 264 << right_begin_descr << ", " << right_end_descr << " }" 265 << suffix; 266 267 va_end( args ); 268 269 if( !pr.has_empty_message() ) 270 unit_test_log << ". " << pr.message(); 271 272 unit_test_log << unit_test::log::end(); 273 break; 274 } 275 case CHECK_BITWISE_EQUAL: { 276 va_list args; 277 278 va_start( args, num_of_args ); 279 char const* left_descr = va_arg( args, char const* ); 280 char const* right_descr = va_arg( args, char const* ); 281 282 unit_test_log << unit_test::log::begin() << unit_test::log::file( file_name ) << unit_test::log::line( line_num ) 283 << ll << prefix << left_descr << " =.= " << right_descr << suffix; 284 285 va_end( args ); 286 287 if( !pr.has_empty_message() ) 288 unit_test_log << ". " << pr.message(); 289 290 unit_test_log << unit_test::log::end(); 291 break; 292 } 293 } 294 295 if( tl == REQUIRE ) { 296 framework::test_unit_aborted(); 297 298 throw execution_aborted(); 299 } 300} 301 302//____________________________________________________________________________// 303 304predicate_result 305equal_impl( char const* left, char const* right ) 306{ 307 return (left && right) ? std::strcmp( left, right ) == 0 : (left == right); 308} 309 310//____________________________________________________________________________// 311 312#if !defined( BOOST_NO_CWCHAR ) 313 314predicate_result 315equal_impl( wchar_t const* left, wchar_t const* right ) 316{ 317 return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right); 318} 319 320#endif // !defined( BOOST_NO_CWCHAR ) 321 322//____________________________________________________________________________// 323 324bool 325is_defined_impl( const_string symbol_name, const_string symbol_value ) 326{ 327 symbol_value.trim_left( 2 ); 328 return symbol_name != symbol_value; 329} 330 331//____________________________________________________________________________// 332 333// ************************************************************************** // 334// ************** log print helper ************** // 335// ************************************************************************** // 336 337void 338print_log_value<char>::operator()( std::ostream& ostr, char t ) 339{ 340 if( (std::isprint)( t ) ) 341 ostr << '\'' << t << '\''; 342 else 343 ostr << std::hex 344 // showbase is only available for new style streams: 345#ifndef BOOST_NO_STD_LOCALE 346 << std::showbase 347#else 348 << "0x" 349#endif 350 << (int)t; 351} 352 353//____________________________________________________________________________// 354 355void 356print_log_value<unsigned char>::operator()( std::ostream& ostr, unsigned char t ) 357{ 358 ostr << std::hex 359 // showbase is only available for new style streams: 360#ifndef BOOST_NO_STD_LOCALE 361 << std::showbase 362#else 363 << "0x" 364#endif 365 << (int)t; 366} 367 368//____________________________________________________________________________// 369 370void 371print_log_value<char const*>::operator()( std::ostream& ostr, char const* t ) 372{ 373 ostr << ( t ? t : "null string" ); 374} 375 376//____________________________________________________________________________// 377 378void 379print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* t ) 380{ 381 ostr << ( t ? t : L"null string" ); 382} 383 384//____________________________________________________________________________// 385 386} // namespace tt_detail 387 388// ************************************************************************** // 389// ************** output_test_stream ************** // 390// ************************************************************************** // 391 392struct output_test_stream::Impl 393{ 394 std::fstream m_pattern; 395 bool m_match_or_save; 396 std::string m_synced_string; 397 398 char get_char() 399 { 400 char res; 401 do { 402 m_pattern.get( res ); 403 } while( res == '\r' && !m_pattern.fail() && !m_pattern.eof() ); 404 405 return res; 406 } 407 408 void check_and_fill( predicate_result& res ) 409 { 410 if( !res.p_predicate_value ) 411 res.message() << "Output content: \"" << m_synced_string << '\"'; 412 } 413}; 414 415//____________________________________________________________________________// 416 417output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save ) 418: m_pimpl( new Impl ) 419{ 420 if( !pattern_file_name.is_empty() ) { 421 m_pimpl->m_pattern.open( pattern_file_name.begin(), match_or_save ? std::ios::in : std::ios::out ); 422 423 BOOST_WARN_MESSAGE( m_pimpl->m_pattern.is_open(), 424 "Couldn't open pattern file " << pattern_file_name 425 << " for " << ( m_pimpl->m_match_or_save ? "reading" : "writing") ); 426 } 427 428 m_pimpl->m_match_or_save = match_or_save; 429} 430 431//____________________________________________________________________________// 432 433output_test_stream::~output_test_stream() 434{ 435 delete m_pimpl; 436} 437 438//____________________________________________________________________________// 439 440predicate_result 441output_test_stream::is_empty( bool flush_stream ) 442{ 443 sync(); 444 445 result_type res( m_pimpl->m_synced_string.empty() ); 446 447 m_pimpl->check_and_fill( res ); 448 449 if( flush_stream ) 450 flush(); 451 452 return res; 453} 454 455//____________________________________________________________________________// 456 457predicate_result 458output_test_stream::check_length( std::size_t length_, bool flush_stream ) 459{ 460 sync(); 461 462 result_type res( m_pimpl->m_synced_string.length() == length_ ); 463 464 m_pimpl->check_and_fill( res ); 465 466 if( flush_stream ) 467 flush(); 468 469 return res; 470} 471 472//____________________________________________________________________________// 473 474predicate_result 475output_test_stream::is_equal( const_string arg, bool flush_stream ) 476{ 477 sync(); 478 479 result_type res( const_string( m_pimpl->m_synced_string ) == arg ); 480 481 m_pimpl->check_and_fill( res ); 482 483 if( flush_stream ) 484 flush(); 485 486 return res; 487} 488 489//____________________________________________________________________________// 490 491predicate_result 492output_test_stream::match_pattern( bool flush_stream ) 493{ 494 sync(); 495 496 result_type result( true ); 497 498 if( !m_pimpl->m_pattern.is_open() ) { 499 result = false; 500 result.message() << "I/O failure"; 501 } 502 else { 503 if( m_pimpl->m_match_or_save ) { 504 for ( std::string::size_type i = 0; i < m_pimpl->m_synced_string.length(); ++i ) { 505 char c = m_pimpl->get_char(); 506 507 result = !m_pimpl->m_pattern.fail() && 508 !m_pimpl->m_pattern.eof() && 509 (m_pimpl->m_synced_string[i] == c); 510 511 if( !result ) { 512 std::string::size_type suffix_size = (std::min)( m_pimpl->m_synced_string.length() - i, 513 static_cast<std::string::size_type>(5) ); 514 515 // try to log area around the mismatch 516 result.message() << "Mismatch at position " << i << '\n' 517 << "..." << m_pimpl->m_synced_string.substr( i, suffix_size ) << "..." << '\n' 518 << "..." << c; 519 520 std::string::size_type counter = suffix_size; 521 while( --counter ) { 522 char c = m_pimpl->get_char(); 523 524 if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() ) 525 break; 526 527 result.message() << c; 528 } 529 530 result.message() << "..."; 531 532 // skip rest of the bytes. May help for further matching 533 m_pimpl->m_pattern.ignore( m_pimpl->m_synced_string.length() - i - suffix_size ); 534 break; 535 } 536 } 537 } 538 else { 539 m_pimpl->m_pattern.write( m_pimpl->m_synced_string.c_str(), 540 static_cast<std::streamsize>( m_pimpl->m_synced_string.length() ) ); 541 m_pimpl->m_pattern.flush(); 542 } 543 } 544 545 if( flush_stream ) 546 flush(); 547 548 return result; 549} 550 551//____________________________________________________________________________// 552 553void 554output_test_stream::flush() 555{ 556 m_pimpl->m_synced_string.erase(); 557 558#ifndef BOOST_NO_STRINGSTREAM 559 str( std::string() ); 560#else 561 seekp( 0, std::ios::beg ); 562#endif 563} 564 565//____________________________________________________________________________// 566 567std::size_t 568output_test_stream::length() 569{ 570 sync(); 571 572 return m_pimpl->m_synced_string.length(); 573} 574 575//____________________________________________________________________________// 576 577void 578output_test_stream::sync() 579{ 580#ifdef BOOST_NO_STRINGSTREAM 581 m_pimpl->m_synced_string.assign( str(), pcount() ); 582 freeze( false ); 583#elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x530) ) 584 m_pimpl->m_synced_string.assign( str().c_str(), tellp() ); 585#else 586 m_pimpl->m_synced_string = str(); 587#endif 588} 589 590//____________________________________________________________________________// 591 592} // namespace test_tools 593 594} // namespace boost 595 596//____________________________________________________________________________// 597 598#include <boost/test/detail/enable_warnings.hpp> 599 600// *************************************************************************** 601// Revision History : 602// 603// $Log: test_tools.ipp,v $ 604// Revision 1.1.1.1 2006/03/20 20:15:27 ewalkup 605// boost libraries 606// 607// Revision 1.9 2005/06/22 22:03:05 dgregor 608// More explicit scoping needed for GCC 2.95.3 609// 610// Revision 1.8 2005/04/30 17:56:31 rogeeff 611// switch to stdarg.h to workarround como issues 612// 613// Revision 1.7 2005/03/23 21:02:23 rogeeff 614// Sunpro CC 5.3 fixes 615// 616// Revision 1.6 2005/02/21 10:14:04 rogeeff 617// CHECK_SMALL tool implemented 618// 619// Revision 1.5 2005/02/20 08:27:07 rogeeff 620// This a major update for Boost.Test framework. See release docs for complete list of fixes/updates 621// 622// Revision 1.4 2005/02/02 12:08:14 rogeeff 623// namespace log added for log manipulators 624// 625// Revision 1.3 2005/02/01 06:40:07 rogeeff 626// copyright update 627// old log entries removed 628// minor stilistic changes 629// depricated tools removed 630// 631// Revision 1.2 2005/01/30 03:18:27 rogeeff 632// test tools implementation completely reworked. All tools inplemented through single vararg function 633// 634// Revision 1.1 2005/01/22 19:22:12 rogeeff 635// implementation moved into headers section to eliminate dependency of included/minimal component on src directory 636// 637// Revision 1.43 2005/01/19 06:40:05 vawjr 638// deleted redundant \r in many \r\r\n sequences of the source. VC8.0 doesn't like them 639// 640// Revision 1.42 2005/01/18 08:30:08 rogeeff 641// unit_test_log rework: 642// eliminated need for ::instance() 643// eliminated need for << end and ...END macro 644// straitend interface between log and formatters 645// change compiler like formatter name 646// minimized unit_test_log interface and reworked to use explicit calls 647// 648// *************************************************************************** 649 650#endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER 651