1// (C) Copyright Gennadiy Rozental 2005-2008. 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: 54633 $ 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#include <boost/test/unit_test_suite_impl.hpp> 25 26// Boost 27#include <boost/config.hpp> 28 29// STL 30#include <fstream> 31#include <string> 32#include <cstring> 33#include <cctype> 34#include <cwchar> 35#include <stdexcept> 36#include <ios> 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 56// ************************************************************************** // 57// ************** print_log_value ************** // 58// ************************************************************************** // 59 60void 61print_log_value<char>::operator()( std::ostream& ostr, char t ) 62{ 63 if( (std::isprint)( static_cast<unsigned char>(t) ) ) 64 ostr << '\'' << t << '\''; 65 else 66 ostr << std::hex 67#if BOOST_TEST_USE_STD_LOCALE 68 << std::showbase 69#else 70 << "0x" 71#endif 72 << static_cast<int>(t); 73} 74 75//____________________________________________________________________________// 76 77void 78print_log_value<unsigned char>::operator()( std::ostream& ostr, unsigned char t ) 79{ 80 ostr << std::hex 81 // showbase is only available for new style streams: 82#if BOOST_TEST_USE_STD_LOCALE 83 << std::showbase 84#else 85 << "0x" 86#endif 87 << static_cast<int>(t); 88} 89 90//____________________________________________________________________________// 91 92void 93print_log_value<char const*>::operator()( std::ostream& ostr, char const* t ) 94{ 95 ostr << ( t ? t : "null string" ); 96} 97 98//____________________________________________________________________________// 99 100void 101print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* t ) 102{ 103 ostr << ( t ? t : L"null string" ); 104} 105 106//____________________________________________________________________________// 107 108namespace tt_detail { 109 110// ************************************************************************** // 111// ************** TOOL BOX Implementation ************** // 112// ************************************************************************** // 113 114using ::boost::unit_test::lazy_ostream; 115 116bool 117check_impl( predicate_result const& pr, lazy_ostream const& check_descr, 118 const_string file_name, std::size_t line_num, 119 tool_level tl, check_type ct, 120 std::size_t num_of_args, ... ) 121{ 122 using namespace unit_test; 123 124 if( !framework::is_initialized() ) 125 throw std::runtime_error( "can't use testing tools before framework is initialized" ); 126 127 if( !!pr ) 128 tl = PASS; 129 130 log_level ll; 131 char const* prefix; 132 char const* suffix; 133 134 switch( tl ) { 135 case PASS: 136 ll = log_successful_tests; 137 prefix = "check "; 138 suffix = " passed"; 139 break; 140 case WARN: 141 ll = log_warnings; 142 prefix = "condition "; 143 suffix = " is not satisfied"; 144 break; 145 case CHECK: 146 ll = log_all_errors; 147 prefix = "check "; 148 suffix = " failed"; 149 break; 150 case REQUIRE: 151 ll = log_fatal_errors; 152 prefix = "critical check "; 153 suffix = " failed"; 154 break; 155 default: 156 return true; 157 } 158 159 switch( ct ) { 160 case CHECK_PRED: 161 unit_test_log << unit_test::log::begin( file_name, line_num ) 162 << ll << prefix << check_descr << suffix; 163 164 if( !pr.has_empty_message() ) 165 unit_test_log << ". " << pr.message(); 166 167 unit_test_log << unit_test::log::end(); 168 break; 169 170 case CHECK_MSG: 171 unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; 172 173 if( tl == PASS ) 174 unit_test_log << prefix << "'" << check_descr << "'" << suffix; 175 else 176 unit_test_log << check_descr; 177 178 if( !pr.has_empty_message() ) 179 unit_test_log << ". " << pr.message(); 180 181 unit_test_log << unit_test::log::end(); 182 break; 183 184 case CHECK_EQUAL: 185 case CHECK_NE: 186 case CHECK_LT: 187 case CHECK_LE: 188 case CHECK_GT: 189 case CHECK_GE: { 190 static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " }; 191 static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " }; 192 193 va_list args; 194 195 va_start( args, num_of_args ); 196 char const* arg1_descr = va_arg( args, char const* ); 197 lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); 198 char const* arg2_descr = va_arg( args, char const* ); 199 lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* ); 200 201 unit_test_log << unit_test::log::begin( file_name, line_num ) 202 << ll << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix; 203 204 if( tl != PASS ) 205 unit_test_log << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ; 206 207 va_end( args ); 208 209 if( !pr.has_empty_message() ) 210 unit_test_log << ". " << pr.message(); 211 212 unit_test_log << unit_test::log::end(); 213 break; 214 } 215 216 case CHECK_CLOSE: 217 case CHECK_CLOSE_FRACTION: { 218 va_list args; 219 220 va_start( args, num_of_args ); 221 char const* arg1_descr = va_arg( args, char const* ); 222 lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); 223 char const* arg2_descr = va_arg( args, char const* ); 224 lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* ); 225 /* toler_descr = */ va_arg( args, char const* ); 226 lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* ); 227 228 unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; 229 230 unit_test_log << "difference{" << pr.message() << (ct == CHECK_CLOSE ? "%" : "") 231 << "} between " << arg1_descr << "{" << *arg1_val 232 << "} and " << arg2_descr << "{" << *arg2_val 233 << ( tl == PASS ? "} doesn't exceed " : "} exceeds " ) 234 << *toler_val; 235 if( ct == CHECK_CLOSE ) 236 unit_test_log << "%"; 237 238 va_end( args ); 239 240 unit_test_log << unit_test::log::end(); 241 break; 242 } 243 case CHECK_SMALL: { 244 va_list args; 245 246 va_start( args, num_of_args ); 247 char const* arg1_descr = va_arg( args, char const* ); 248 lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); 249 /* toler_descr = */ va_arg( args, char const* ); 250 lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* ); 251 252 unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; 253 254 unit_test_log << "absolute value of " << arg1_descr << "{" << *arg1_val << "}" 255 << ( tl == PASS ? " doesn't exceed " : " exceeds " ) 256 << *toler_val; 257 258 va_end( args ); 259 260 if( !pr.has_empty_message() ) 261 unit_test_log << ". " << pr.message(); 262 263 unit_test_log << unit_test::log::end(); 264 break; 265 } 266 267 case CHECK_PRED_WITH_ARGS: { 268 unit_test_log << unit_test::log::begin( file_name, line_num ) 269 << ll << prefix << check_descr; 270 271 // print predicate call description 272 { 273 va_list args; 274 va_start( args, num_of_args ); 275 276 unit_test_log << "( "; 277 for( std::size_t i = 0; i < num_of_args; ++i ) { 278 unit_test_log << va_arg( args, char const* ); 279 va_arg( args, lazy_ostream const* ); // skip argument value; 280 281 if( i != num_of_args-1 ) 282 unit_test_log << ", "; 283 } 284 unit_test_log << " )" << suffix; 285 va_end( args ); 286 } 287 288 if( tl != PASS ) { 289 va_list args; 290 va_start( args, num_of_args ); 291 292 unit_test_log << " for ( "; 293 for( std::size_t i = 0; i < num_of_args; ++i ) { 294 va_arg( args, char const* ); // skip argument description; 295 unit_test_log << *va_arg( args, lazy_ostream const* ); 296 297 if( i != num_of_args-1 ) 298 unit_test_log << ", "; 299 } 300 unit_test_log << " )"; 301 va_end( args ); 302 } 303 304 if( !pr.has_empty_message() ) 305 unit_test_log << ". " << pr.message(); 306 307 unit_test_log << unit_test::log::end(); 308 break; 309 } 310 311 case CHECK_EQUAL_COLL: { 312 va_list args; 313 314 va_start( args, num_of_args ); 315 char const* left_begin_descr = va_arg( args, char const* ); 316 char const* left_end_descr = va_arg( args, char const* ); 317 char const* right_begin_descr = va_arg( args, char const* ); 318 char const* right_end_descr = va_arg( args, char const* ); 319 320 unit_test_log << unit_test::log::begin( file_name, line_num ) 321 << ll << prefix 322 << "{ " << left_begin_descr << ", " << left_end_descr << " } == { " 323 << right_begin_descr << ", " << right_end_descr << " }" 324 << suffix; 325 326 va_end( args ); 327 328 if( !pr.has_empty_message() ) 329 unit_test_log << ". " << pr.message(); 330 331 unit_test_log << unit_test::log::end(); 332 break; 333 } 334 335 case CHECK_BITWISE_EQUAL: { 336 va_list args; 337 338 va_start( args, num_of_args ); 339 char const* left_descr = va_arg( args, char const* ); 340 char const* right_descr = va_arg( args, char const* ); 341 342 unit_test_log << unit_test::log::begin( file_name, line_num ) 343 << ll << prefix << left_descr << " =.= " << right_descr << suffix; 344 345 va_end( args ); 346 347 if( !pr.has_empty_message() ) 348 unit_test_log << ". " << pr.message(); 349 350 unit_test_log << unit_test::log::end(); 351 break; 352 } 353 } 354 355 switch( tl ) { 356 case PASS: 357 framework::assertion_result( true ); 358 return true; 359 360 case WARN: 361 return false; 362 363 case CHECK: 364 framework::assertion_result( false ); 365 return false; 366 367 case REQUIRE: 368 framework::assertion_result( false ); 369 370 framework::test_unit_aborted( framework::current_test_case() ); 371 372 throw execution_aborted(); 373 } 374 375 return true; 376} 377 378//____________________________________________________________________________// 379 380predicate_result 381equal_impl( char const* left, char const* right ) 382{ 383 return (left && right) ? std::strcmp( left, right ) == 0 : (left == right); 384} 385 386//____________________________________________________________________________// 387 388#if !defined( BOOST_NO_CWCHAR ) 389 390predicate_result 391equal_impl( wchar_t const* left, wchar_t const* right ) 392{ 393 return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right); 394} 395 396#endif // !defined( BOOST_NO_CWCHAR ) 397 398//____________________________________________________________________________// 399 400bool 401is_defined_impl( const_string symbol_name, const_string symbol_value ) 402{ 403 symbol_value.trim_left( 2 ); 404 return symbol_name != symbol_value; 405} 406 407//____________________________________________________________________________// 408 409} // namespace tt_detail 410 411// ************************************************************************** // 412// ************** output_test_stream ************** // 413// ************************************************************************** // 414 415struct output_test_stream::Impl 416{ 417 std::fstream m_pattern; 418 bool m_match_or_save; 419 bool m_text_or_binary; 420 std::string m_synced_string; 421 422 char get_char() 423 { 424 char res; 425 do { 426 m_pattern.get( res ); 427 } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() ); 428 429 return res; 430 } 431 432 void check_and_fill( predicate_result& res ) 433 { 434 if( !res.p_predicate_value ) 435 res.message() << "Output content: \"" << m_synced_string << '\"'; 436 } 437}; 438 439//____________________________________________________________________________// 440 441output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary ) 442: m_pimpl( new Impl ) 443{ 444 if( !pattern_file_name.is_empty() ) { 445 std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out; 446 if( !text_or_binary ) 447 m |= std::ios::binary; 448 449 m_pimpl->m_pattern.open( pattern_file_name.begin(), m ); 450 451 BOOST_WARN_MESSAGE( m_pimpl->m_pattern.is_open(), 452 "Can't open pattern file " << pattern_file_name 453 << " for " << (match_or_save ? "reading" : "writing") ); 454 } 455 456 m_pimpl->m_match_or_save = match_or_save; 457 m_pimpl->m_text_or_binary = text_or_binary; 458} 459 460//____________________________________________________________________________// 461 462output_test_stream::~output_test_stream() 463{ 464 delete m_pimpl; 465} 466 467//____________________________________________________________________________// 468 469predicate_result 470output_test_stream::is_empty( bool flush_stream ) 471{ 472 sync(); 473 474 result_type res( m_pimpl->m_synced_string.empty() ); 475 476 m_pimpl->check_and_fill( res ); 477 478 if( flush_stream ) 479 flush(); 480 481 return res; 482} 483 484//____________________________________________________________________________// 485 486predicate_result 487output_test_stream::check_length( std::size_t length_, bool flush_stream ) 488{ 489 sync(); 490 491 result_type res( m_pimpl->m_synced_string.length() == length_ ); 492 493 m_pimpl->check_and_fill( res ); 494 495 if( flush_stream ) 496 flush(); 497 498 return res; 499} 500 501//____________________________________________________________________________// 502 503predicate_result 504output_test_stream::is_equal( const_string arg, bool flush_stream ) 505{ 506 sync(); 507 508 result_type res( const_string( m_pimpl->m_synced_string ) == arg ); 509 510 m_pimpl->check_and_fill( res ); 511 512 if( flush_stream ) 513 flush(); 514 515 return res; 516} 517 518//____________________________________________________________________________// 519 520predicate_result 521output_test_stream::match_pattern( bool flush_stream ) 522{ 523 sync(); 524 525 result_type result( true ); 526 527 if( !m_pimpl->m_pattern.is_open() ) { 528 result = false; 529 result.message() << "Pattern file can't be opened!"; 530 } 531 else { 532 if( m_pimpl->m_match_or_save ) { 533 for ( std::string::size_type i = 0; i < m_pimpl->m_synced_string.length(); ++i ) { 534 char c = m_pimpl->get_char(); 535 536 result = !m_pimpl->m_pattern.fail() && 537 !m_pimpl->m_pattern.eof() && 538 (m_pimpl->m_synced_string[i] == c); 539 540 if( !result ) { 541 std::string::size_type suffix_size = (std::min)( m_pimpl->m_synced_string.length() - i, 542 static_cast<std::string::size_type>(5) ); 543 544 // try to log area around the mismatch 545 result.message() << "Mismatch at position " << i << '\n' 546 << "..." << m_pimpl->m_synced_string.substr( i, suffix_size ) << "..." << '\n' 547 << "..." << c; 548 549 std::string::size_type counter = suffix_size; 550 while( --counter ) { 551 char c = m_pimpl->get_char(); 552 553 if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() ) 554 break; 555 556 result.message() << c; 557 } 558 559 result.message() << "..."; 560 561 // skip rest of the bytes. May help for further matching 562 m_pimpl->m_pattern.ignore( 563 static_cast<std::streamsize>( m_pimpl->m_synced_string.length() - i - suffix_size) ); 564 break; 565 } 566 } 567 } 568 else { 569 m_pimpl->m_pattern.write( m_pimpl->m_synced_string.c_str(), 570 static_cast<std::streamsize>( m_pimpl->m_synced_string.length() ) ); 571 m_pimpl->m_pattern.flush(); 572 } 573 } 574 575 if( flush_stream ) 576 flush(); 577 578 return result; 579} 580 581//____________________________________________________________________________// 582 583void 584output_test_stream::flush() 585{ 586 m_pimpl->m_synced_string.erase(); 587 588#ifndef BOOST_NO_STRINGSTREAM 589 str( std::string() ); 590#else 591 seekp( 0, std::ios::beg ); 592#endif 593} 594 595//____________________________________________________________________________// 596 597std::size_t 598output_test_stream::length() 599{ 600 sync(); 601 602 return m_pimpl->m_synced_string.length(); 603} 604 605//____________________________________________________________________________// 606 607void 608output_test_stream::sync() 609{ 610#ifdef BOOST_NO_STRINGSTREAM 611 m_pimpl->m_synced_string.assign( str(), pcount() ); 612 freeze( false ); 613#else 614 m_pimpl->m_synced_string = str(); 615#endif 616} 617 618//____________________________________________________________________________// 619 620} // namespace test_tools 621 622} // namespace boost 623 624//____________________________________________________________________________// 625 626#include <boost/test/detail/enable_warnings.hpp> 627 628#endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER 629