1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #include "precomp.hpp" 43 #include "opencv2/core/core_c.h" 44 45 #include <ctype.h> 46 #include <stdarg.h> 47 #include <stdlib.h> 48 #include <fcntl.h> 49 #include <time.h> 50 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 51 #include <io.h> 52 53 #include <windows.h> 54 #undef small 55 #undef min 56 #undef max 57 #undef abs 58 59 #ifdef _MSC_VER 60 #include <eh.h> 61 #endif 62 63 #else 64 #include <unistd.h> 65 #endif 66 67 namespace cvtest 68 { 69 70 /*****************************************************************************************\ 71 * Exception and memory handlers * 72 \*****************************************************************************************/ 73 74 // a few platform-dependent declarations 75 76 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 77 #ifdef _MSC_VER 78 static void SEHTranslator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp ) 79 { 80 TS::FailureCode code = TS::FAIL_EXCEPTION; 81 switch( pExp->ExceptionRecord->ExceptionCode ) 82 { 83 case EXCEPTION_ACCESS_VIOLATION: 84 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 85 case EXCEPTION_DATATYPE_MISALIGNMENT: 86 case EXCEPTION_FLT_STACK_CHECK: 87 case EXCEPTION_STACK_OVERFLOW: 88 case EXCEPTION_IN_PAGE_ERROR: 89 code = TS::FAIL_MEMORY_EXCEPTION; 90 break; 91 case EXCEPTION_FLT_DENORMAL_OPERAND: 92 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 93 case EXCEPTION_FLT_INEXACT_RESULT: 94 case EXCEPTION_FLT_INVALID_OPERATION: 95 case EXCEPTION_FLT_OVERFLOW: 96 case EXCEPTION_FLT_UNDERFLOW: 97 case EXCEPTION_INT_DIVIDE_BY_ZERO: 98 case EXCEPTION_INT_OVERFLOW: 99 code = TS::FAIL_ARITHM_EXCEPTION; 100 break; 101 case EXCEPTION_BREAKPOINT: 102 case EXCEPTION_ILLEGAL_INSTRUCTION: 103 case EXCEPTION_INVALID_DISPOSITION: 104 case EXCEPTION_NONCONTINUABLE_EXCEPTION: 105 case EXCEPTION_PRIV_INSTRUCTION: 106 case EXCEPTION_SINGLE_STEP: 107 code = TS::FAIL_EXCEPTION; 108 } 109 throw code; 110 } 111 #endif 112 113 #else 114 115 #include <signal.h> 116 #include <setjmp.h> 117 118 static const int tsSigId[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT, -1 }; 119 120 static jmp_buf tsJmpMark; 121 122 static void signalHandler( int sig_code ) 123 { 124 TS::FailureCode code = TS::FAIL_EXCEPTION; 125 switch( sig_code ) 126 { 127 case SIGFPE: 128 code = TS::FAIL_ARITHM_EXCEPTION; 129 break; 130 case SIGSEGV: 131 case SIGBUS: 132 code = TS::FAIL_ARITHM_EXCEPTION; 133 break; 134 case SIGILL: 135 code = TS::FAIL_EXCEPTION; 136 } 137 138 longjmp( tsJmpMark, (int)code ); 139 } 140 141 #endif 142 143 144 // reads 16-digit hexadecimal number (i.e. 64-bit integer) 145 int64 readSeed( const char* str ) 146 { 147 int64 val = 0; 148 if( str && strlen(str) == 16 ) 149 { 150 for( int i = 0; str[i]; i++ ) 151 { 152 int c = tolower(str[i]); 153 if( !isxdigit(c) ) 154 return 0; 155 val = val * 16 + 156 (str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10); 157 } 158 } 159 return val; 160 } 161 162 163 /*****************************************************************************************\ 164 * Base Class for Tests * 165 \*****************************************************************************************/ 166 167 BaseTest::BaseTest() 168 { 169 ts = TS::ptr(); 170 test_case_count = -1; 171 } 172 173 BaseTest::~BaseTest() 174 { 175 clear(); 176 } 177 178 void BaseTest::clear() 179 { 180 } 181 182 183 const CvFileNode* BaseTest::find_param( CvFileStorage* fs, const char* param_name ) 184 { 185 CvFileNode* node = cvGetFileNodeByName(fs, 0, get_name().c_str()); 186 return node ? cvGetFileNodeByName( fs, node, param_name ) : 0; 187 } 188 189 190 int BaseTest::read_params( CvFileStorage* ) 191 { 192 return 0; 193 } 194 195 196 bool BaseTest::can_do_fast_forward() 197 { 198 return true; 199 } 200 201 202 void BaseTest::safe_run( int start_from ) 203 { 204 read_params( ts->get_file_storage() ); 205 ts->update_context( 0, -1, true ); 206 ts->update_context( this, -1, true ); 207 208 if( !::testing::GTEST_FLAG(catch_exceptions) ) 209 run( start_from ); 210 else 211 { 212 try 213 { 214 #if !defined WIN32 && !defined _WIN32 215 int _code = setjmp( tsJmpMark ); 216 if( !_code ) 217 run( start_from ); 218 else 219 throw TS::FailureCode(_code); 220 #else 221 run( start_from ); 222 #endif 223 } 224 catch (const cv::Exception& exc) 225 { 226 const char* errorStr = cvErrorStr(exc.code); 227 char buf[1 << 16]; 228 229 sprintf( buf, "OpenCV Error:\n\t%s (%s) in %s, file %s, line %d", 230 errorStr, exc.err.c_str(), exc.func.size() > 0 ? 231 exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line ); 232 ts->printf(TS::LOG, "%s\n", buf); 233 234 ts->set_failed_test_info( TS::FAIL_ERROR_IN_CALLED_FUNC ); 235 } 236 catch (const TS::FailureCode& fc) 237 { 238 std::string errorStr = TS::str_from_code(fc); 239 ts->printf(TS::LOG, "General failure:\n\t%s (%d)\n", errorStr.c_str(), fc); 240 241 ts->set_failed_test_info( fc ); 242 } 243 catch (...) 244 { 245 ts->printf(TS::LOG, "Unknown failure\n"); 246 247 ts->set_failed_test_info( TS::FAIL_EXCEPTION ); 248 } 249 } 250 251 ts->set_gtest_status(); 252 } 253 254 255 void BaseTest::run( int start_from ) 256 { 257 int test_case_idx, count = get_test_case_count(); 258 int64 t_start = cvGetTickCount(); 259 double freq = cv::getTickFrequency(); 260 bool ff = can_do_fast_forward(); 261 int progress = 0, code; 262 int64 t1 = t_start; 263 264 for( test_case_idx = ff && start_from >= 0 ? start_from : 0; 265 count < 0 || test_case_idx < count; test_case_idx++ ) 266 { 267 ts->update_context( this, test_case_idx, ff ); 268 progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) ); 269 270 code = prepare_test_case( test_case_idx ); 271 if( code < 0 || ts->get_err_code() < 0 ) 272 return; 273 274 if( code == 0 ) 275 continue; 276 277 run_func(); 278 279 if( ts->get_err_code() < 0 ) 280 return; 281 282 if( validate_test_results( test_case_idx ) < 0 || ts->get_err_code() < 0 ) 283 return; 284 } 285 } 286 287 288 void BaseTest::run_func(void) 289 { 290 assert(0); 291 } 292 293 294 int BaseTest::get_test_case_count(void) 295 { 296 return test_case_count; 297 } 298 299 300 int BaseTest::prepare_test_case( int ) 301 { 302 return 0; 303 } 304 305 306 int BaseTest::validate_test_results( int ) 307 { 308 return 0; 309 } 310 311 312 int BaseTest::update_progress( int progress, int test_case_idx, int count, double dt ) 313 { 314 int width = 60 - (int)get_name().size(); 315 if( count > 0 ) 316 { 317 int t = cvRound( ((double)test_case_idx * width)/count ); 318 if( t > progress ) 319 { 320 ts->printf( TS::CONSOLE, "." ); 321 progress = t; 322 } 323 } 324 else if( cvRound(dt) > progress ) 325 { 326 ts->printf( TS::CONSOLE, "." ); 327 progress = cvRound(dt); 328 } 329 330 return progress; 331 } 332 333 334 BadArgTest::BadArgTest() 335 { 336 test_case_idx = -1; 337 // oldErrorCbk = 0; 338 // oldErrorCbkData = 0; 339 } 340 341 BadArgTest::~BadArgTest(void) 342 { 343 } 344 345 int BadArgTest::run_test_case( int expected_code, const string& _descr ) 346 { 347 int errcount = 0; 348 bool thrown = false; 349 const char* descr = _descr.c_str() ? _descr.c_str() : ""; 350 351 try 352 { 353 run_func(); 354 } 355 catch(const cv::Exception& e) 356 { 357 thrown = true; 358 if( e.code != expected_code ) 359 { 360 ts->printf(TS::LOG, "%s (test case #%d): the error code %d is different from the expected %d\n", 361 descr, test_case_idx, e.code, expected_code); 362 errcount = 1; 363 } 364 } 365 catch(...) 366 { 367 thrown = true; 368 ts->printf(TS::LOG, "%s (test case #%d): unknown exception was thrown (the function has likely crashed)\n", 369 descr, test_case_idx); 370 errcount = 1; 371 } 372 373 if(!thrown) 374 { 375 ts->printf(TS::LOG, "%s (test case #%d): no expected exception was thrown\n", 376 descr, test_case_idx); 377 errcount = 1; 378 } 379 test_case_idx++; 380 381 return errcount; 382 } 383 384 /*****************************************************************************************\ 385 * Base Class for Test System * 386 \*****************************************************************************************/ 387 388 /******************************** Constructors/Destructors ******************************/ 389 390 TSParams::TSParams() 391 { 392 rng_seed = (uint64)-1; 393 use_optimized = true; 394 test_case_count_scale = 1; 395 } 396 397 398 TestInfo::TestInfo() 399 { 400 test = 0; 401 code = 0; 402 rng_seed = rng_seed0 = 0; 403 test_case_idx = -1; 404 } 405 406 407 TS::TS() 408 { 409 } // ctor 410 411 412 TS::~TS() 413 { 414 } // dtor 415 416 417 string TS::str_from_code( const TS::FailureCode code ) 418 { 419 switch( code ) 420 { 421 case OK: return "Ok"; 422 case FAIL_GENERIC: return "Generic/Unknown"; 423 case FAIL_MISSING_TEST_DATA: return "No test data"; 424 case FAIL_INVALID_TEST_DATA: return "Invalid test data"; 425 case FAIL_ERROR_IN_CALLED_FUNC: return "cvError invoked"; 426 case FAIL_EXCEPTION: return "Hardware/OS exception"; 427 case FAIL_MEMORY_EXCEPTION: return "Invalid memory access"; 428 case FAIL_ARITHM_EXCEPTION: return "Arithmetic exception"; 429 case FAIL_MEMORY_CORRUPTION_BEGIN: return "Corrupted memblock (beginning)"; 430 case FAIL_MEMORY_CORRUPTION_END: return "Corrupted memblock (end)"; 431 case FAIL_MEMORY_LEAK: return "Memory leak"; 432 case FAIL_INVALID_OUTPUT: return "Invalid function output"; 433 case FAIL_MISMATCH: return "Unexpected output"; 434 case FAIL_BAD_ACCURACY: return "Bad accuracy"; 435 case FAIL_HANG: return "Infinite loop(?)"; 436 case FAIL_BAD_ARG_CHECK: return "Incorrect handling of bad arguments"; 437 default: 438 ; 439 } 440 return "Generic/Unknown"; 441 } 442 443 static int tsErrorCallback( int status, const char* func_name, const char* err_msg, const char* file_name, int line, TS* ts ) 444 { 445 ts->printf(TS::LOG, "OpenCV Error:\n\t%s (%s) in %s, file %s, line %d\n", cvErrorStr(status), err_msg, func_name[0] != 0 ? func_name : "unknown function", file_name, line); 446 return 0; 447 } 448 449 /************************************** Running tests **********************************/ 450 451 void TS::init( const string& modulename ) 452 { 453 char* datapath_dir = getenv("OPENCV_TEST_DATA_PATH"); 454 455 if( datapath_dir ) 456 { 457 char buf[1024]; 458 size_t l = strlen(datapath_dir); 459 bool haveSlash = l > 0 && (datapath_dir[l-1] == '/' || datapath_dir[l-1] == '\\'); 460 sprintf( buf, "%s%s%s/", datapath_dir, haveSlash ? "" : "/", modulename.c_str() ); 461 data_path = string(buf); 462 } 463 464 cv::redirectError((cv::ErrorCallback)tsErrorCallback, this); 465 466 if( ::testing::GTEST_FLAG(catch_exceptions) ) 467 { 468 #if defined WIN32 || defined _WIN32 469 #ifdef _MSC_VER 470 _set_se_translator( SEHTranslator ); 471 #endif 472 #else 473 for( int i = 0; tsSigId[i] >= 0; i++ ) 474 signal( tsSigId[i], signalHandler ); 475 #endif 476 } 477 else 478 { 479 #if defined WIN32 || defined _WIN32 480 #ifdef _MSC_VER 481 _set_se_translator( 0 ); 482 #endif 483 #else 484 for( int i = 0; tsSigId[i] >= 0; i++ ) 485 signal( tsSigId[i], SIG_DFL ); 486 #endif 487 } 488 489 if( params.use_optimized == 0 ) 490 cv::setUseOptimized(false); 491 492 rng = RNG(params.rng_seed); 493 } 494 495 496 void TS::set_gtest_status() 497 { 498 TS::FailureCode code = get_err_code(); 499 if( code >= 0 ) 500 return SUCCEED(); 501 502 char seedstr[32]; 503 sprintf(seedstr, "%08x%08x", (unsigned)(current_test_info.rng_seed>>32), 504 (unsigned)(current_test_info.rng_seed)); 505 506 string logs = ""; 507 if( !output_buf[SUMMARY_IDX].empty() ) 508 logs += "\n-----------------------------------\n\tSUM: " + output_buf[SUMMARY_IDX]; 509 if( !output_buf[LOG_IDX].empty() ) 510 logs += "\n-----------------------------------\n\tLOG:\n" + output_buf[LOG_IDX]; 511 if( !output_buf[CONSOLE_IDX].empty() ) 512 logs += "\n-----------------------------------\n\tCONSOLE: " + output_buf[CONSOLE_IDX]; 513 logs += "\n-----------------------------------\n"; 514 515 FAIL() << "\n\tfailure reason: " << str_from_code(code) << 516 "\n\ttest case #" << current_test_info.test_case_idx << 517 "\n\tseed: " << seedstr << logs; 518 } 519 520 521 CvFileStorage* TS::get_file_storage() { return 0; } 522 523 void TS::update_context( BaseTest* test, int test_case_idx, bool update_ts_context ) 524 { 525 if( current_test_info.test != test ) 526 { 527 for( int i = 0; i <= CONSOLE_IDX; i++ ) 528 output_buf[i] = string(); 529 rng = RNG(params.rng_seed); 530 current_test_info.rng_seed0 = current_test_info.rng_seed = rng.state; 531 } 532 533 current_test_info.test = test; 534 current_test_info.test_case_idx = test_case_idx; 535 current_test_info.code = 0; 536 cvSetErrStatus( CV_StsOk ); 537 if( update_ts_context ) 538 current_test_info.rng_seed = rng.state; 539 } 540 541 542 void TS::set_failed_test_info( int fail_code ) 543 { 544 if( current_test_info.code >= 0 ) 545 current_test_info.code = TS::FailureCode(fail_code); 546 } 547 548 #if defined _MSC_VER && _MSC_VER < 1400 549 #undef vsnprintf 550 #define vsnprintf _vsnprintf 551 #endif 552 553 void TS::vprintf( int streams, const char* fmt, va_list l ) 554 { 555 char str[1 << 14]; 556 vsnprintf( str, sizeof(str)-1, fmt, l ); 557 558 for( int i = 0; i < MAX_IDX; i++ ) 559 if( (streams & (1 << i)) ) 560 { 561 output_buf[i] += std::string(str); 562 // in the new GTest-based framework we do not use 563 // any output files (except for the automatically generated xml report). 564 // if a test fails, all the buffers are printed, so we do not want to duplicate the information and 565 // thus only add the new information to a single buffer and return from the function. 566 break; 567 } 568 } 569 570 571 void TS::printf( int streams, const char* fmt, ... ) 572 { 573 if( streams ) 574 { 575 va_list l; 576 va_start( l, fmt ); 577 vprintf( streams, fmt, l ); 578 va_end( l ); 579 } 580 } 581 582 583 TS ts; 584 TS* TS::ptr() { return &ts; } 585 586 void fillGradient(Mat& img, int delta) 587 { 588 const int ch = img.channels(); 589 CV_Assert(!img.empty() && img.depth() == CV_8U && ch <= 4); 590 591 int n = 255 / delta; 592 int r, c, i; 593 for(r=0; r<img.rows; r++) 594 { 595 int kR = r % (2*n); 596 int valR = (kR<=n) ? delta*kR : delta*(2*n-kR); 597 for(c=0; c<img.cols; c++) 598 { 599 int kC = c % (2*n); 600 int valC = (kC<=n) ? delta*kC : delta*(2*n-kC); 601 uchar vals[] = {uchar(valR), uchar(valC), uchar(200*r/img.rows), uchar(255)}; 602 uchar *p = img.ptr(r, c); 603 for(i=0; i<ch; i++) p[i] = vals[i]; 604 } 605 } 606 } 607 608 void smoothBorder(Mat& img, const Scalar& color, int delta) 609 { 610 const int ch = img.channels(); 611 CV_Assert(!img.empty() && img.depth() == CV_8U && ch <= 4); 612 613 Scalar s; 614 uchar *p = NULL; 615 int n = 100/delta; 616 int nR = std::min(n, (img.rows+1)/2), nC = std::min(n, (img.cols+1)/2); 617 618 int r, c, i; 619 for(r=0; r<nR; r++) 620 { 621 double k1 = r*delta/100., k2 = 1-k1; 622 for(c=0; c<img.cols; c++) 623 { 624 p = img.ptr(r, c); 625 for(i=0; i<ch; i++) s[i] = p[i]; 626 s = s * k1 + color * k2; 627 for(i=0; i<ch; i++) p[i] = uchar(s[i]); 628 } 629 for(c=0; c<img.cols; c++) 630 { 631 p = img.ptr(img.rows-r-1, c); 632 for(i=0; i<ch; i++) s[i] = p[i]; 633 s = s * k1 + color * k2; 634 for(i=0; i<ch; i++) p[i] = uchar(s[i]); 635 } 636 } 637 638 for(r=0; r<img.rows; r++) 639 { 640 for(c=0; c<nC; c++) 641 { 642 double k1 = c*delta/100., k2 = 1-k1; 643 p = img.ptr(r, c); 644 for(i=0; i<ch; i++) s[i] = p[i]; 645 s = s * k1 + color * k2; 646 for(i=0; i<ch; i++) p[i] = uchar(s[i]); 647 } 648 for(c=0; c<n; c++) 649 { 650 double k1 = c*delta/100., k2 = 1-k1; 651 p = img.ptr(r, img.cols-c-1); 652 for(i=0; i<ch; i++) s[i] = p[i]; 653 s = s * k1 + color * k2; 654 for(i=0; i<ch; i++) p[i] = uchar(s[i]); 655 } 656 } 657 } 658 659 } //namespace cvtest 660 661 bool test_ipp_check = false; 662 663 void checkIppStatus() 664 { 665 if (test_ipp_check) 666 { 667 int status = cv::ipp::getIppStatus(); 668 EXPECT_LE(0, status) << cv::ipp::getIppErrorLocation().c_str(); 669 } 670 } 671 672 void parseCustomOptions(int argc, char **argv) 673 { 674 const char * const command_line_keys = 675 "{ ipp test_ipp_check |false |check whether IPP works without failures }" 676 "{ h help |false |print help info }"; 677 678 cv::CommandLineParser parser(argc, argv, command_line_keys); 679 if (parser.get<bool>("help")) 680 { 681 std::cout << "\nAvailable options besides google test option: \n"; 682 parser.printMessage(); 683 } 684 685 test_ipp_check = parser.get<bool>("test_ipp_check"); 686 if (!test_ipp_check) 687 test_ipp_check = getenv("OPENCV_IPP_CHECK") != NULL; 688 } 689 690 /* End of file. */ 691