1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
47 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
53 CvTest* CvTest::first = 0;
54 CvTest* CvTest::last = 0;
55 int CvTest::test_count = 0;
57 /*****************************************************************************************\
58 * Exception and memory handlers *
59 \*****************************************************************************************/
61 // a few platform-dependent declarations
63 #define CV_TS_NORMAL 0
68 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
76 static void cv_seh_translator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp )
78 int code = CvTS::FAIL_EXCEPTION;
79 switch( pExp->ExceptionRecord->ExceptionCode )
81 case EXCEPTION_ACCESS_VIOLATION:
82 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
83 case EXCEPTION_DATATYPE_MISALIGNMENT:
84 case EXCEPTION_FLT_STACK_CHECK:
85 case EXCEPTION_STACK_OVERFLOW:
86 case EXCEPTION_IN_PAGE_ERROR:
87 code = CvTS::FAIL_MEMORY_EXCEPTION;
89 case EXCEPTION_FLT_DENORMAL_OPERAND:
90 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
91 case EXCEPTION_FLT_INEXACT_RESULT:
92 case EXCEPTION_FLT_INVALID_OPERATION:
93 case EXCEPTION_FLT_OVERFLOW:
94 case EXCEPTION_FLT_UNDERFLOW:
95 case EXCEPTION_INT_DIVIDE_BY_ZERO:
96 case EXCEPTION_INT_OVERFLOW:
97 code = CvTS::FAIL_ARITHM_EXCEPTION;
99 case EXCEPTION_BREAKPOINT:
100 case EXCEPTION_ILLEGAL_INSTRUCTION:
101 case EXCEPTION_INVALID_DISPOSITION:
102 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
103 case EXCEPTION_PRIV_INSTRUCTION:
104 case EXCEPTION_SINGLE_STEP:
105 code = CvTS::FAIL_EXCEPTION;
111 static void change_color( int color )
113 static int normal_attributes = -1;
114 HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
117 if( normal_attributes < 0 )
119 CONSOLE_SCREEN_BUFFER_INFO info;
120 GetConsoleScreenBufferInfo( hstdout, &info );
121 normal_attributes = info.wAttributes;
124 SetConsoleTextAttribute( hstdout,
125 (WORD)(color == CV_TS_NORMAL ? normal_attributes :
126 ((color & CV_TS_BLUE ? FOREGROUND_BLUE : 0)|
127 (color & CV_TS_GREEN ? FOREGROUND_GREEN : 0)|
128 (color & CV_TS_RED ? FOREGROUND_RED : 0)|FOREGROUND_INTENSITY)) );
135 static const int cv_ts_sig_id[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT, -1 };
137 static jmp_buf cv_ts_jmp_mark;
139 void cv_signal_handler( int sig_code )
141 int code = CvTS::FAIL_EXCEPTION;
145 code = CvTS::FAIL_ARITHM_EXCEPTION;
149 code = CvTS::FAIL_ARITHM_EXCEPTION;
152 code = CvTS::FAIL_EXCEPTION;
155 longjmp( cv_ts_jmp_mark, code );
158 static void change_color( int color )
160 static const uchar ansi_tab[] = { 30, 34, 32, 36, 31, 35, 33, 37 };
164 if( color != CV_TS_NORMAL )
165 code = ansi_tab[color & (CV_TS_BLUE|CV_TS_GREEN|CV_TS_RED)];
166 sprintf( buf, "\x1b[%dm", code );
167 fputs( buf, stdout );
172 /***************************** memory manager *****************************/
174 typedef struct CvTestAllocBlock
176 struct CvTestAllocBlock* prev;
177 struct CvTestAllocBlock* next;
186 class CvTestMemoryManager
189 CvTestMemoryManager( CvTS* ts );
190 virtual ~CvTestMemoryManager();
192 virtual void clear_and_check( int min_index = -1 );
193 virtual void start_tracking( int index_to_stop_at=-1 );
194 virtual void stop_tracking_and_check();
195 int get_alloc_index() { return index; }
197 static void* alloc_proxy( size_t size, void* userdata );
198 static int free_proxy( void* ptr, void* userdata );
201 virtual void* alloc( size_t size );
202 virtual int free( void* ptr );
203 virtual int free_block( CvTestAllocBlock* block );
208 int index_to_stop_at;
209 const char* guard_pattern;
212 enum { MAX_MARKS = 1024 };
213 int marks[MAX_MARKS];
216 CvTestAllocBlock* first;
217 CvTestAllocBlock* last;
221 void* CvTestMemoryManager::alloc_proxy( size_t size, void* userdata )
223 return ((CvTestMemoryManager*)userdata)->alloc( size );
227 int CvTestMemoryManager::free_proxy( void* ptr, void* userdata )
229 return ((CvTestMemoryManager*)userdata)->free( ptr );
233 CvTestMemoryManager::CvTestMemoryManager( CvTS* _test_system )
236 guard_pattern = "THIS IS A GUARD PATTERN!";
237 guard_size = (int)strlen(guard_pattern);
238 block_align = CV_MALLOC_ALIGN;
243 index_to_stop_at = -1;
248 CvTestMemoryManager::~CvTestMemoryManager()
254 void CvTestMemoryManager::clear_and_check( int min_index )
256 int alloc_index = -1;
257 CvTestAllocBlock* block;
258 int leak_size = 0, leak_block_count = 0, mem_size = 0;
261 while( marks_top > 0 && marks[marks_top - 1] >= min_index )
264 for( block = last; block != 0; )
266 CvTestAllocBlock* prev = block->prev;
267 if( block->index < min_index )
269 leak_size += (int)block->size;
271 alloc_index = block->index;
272 mem_addr = block->data;
273 mem_size = (int)block->size;
278 if( leak_block_count > 0 )
280 ts->set_failed_test_info( CvTS::FAIL_MEMORY_LEAK, alloc_index );
281 ts->printf( CvTS::LOG, "Memory leaks: %u blocks, %u bytes total\n"
282 "%s leaked block: %p, %u bytes\n",
283 leak_block_count, leak_size, leak_block_count > 1 ? "The first" : "The",
284 mem_addr, mem_size );
287 index = block ? block->index + 1 : 0;
291 void CvTestMemoryManager::start_tracking( int _index_to_stop_at )
294 marks[marks_top++] = index;
295 assert( marks_top <= MAX_MARKS );
297 index_to_stop_at = _index_to_stop_at >= index ? _index_to_stop_at : -1;
301 void CvTestMemoryManager::stop_tracking_and_check()
305 int min_index = marks[--marks_top];
306 clear_and_check( min_index );
311 int CvTestMemoryManager::free_block( CvTestAllocBlock* block )
314 char* data = block->data;
316 if( block->origin == 0 || ((size_t)block->origin & (sizeof(double)-1)) != 0 )
317 code = CvTS::FAIL_MEMORY_CORRUPTION_BEGIN;
319 if( memcmp( data - guard_size, guard_pattern, guard_size ) != 0 )
320 code = CvTS::FAIL_MEMORY_CORRUPTION_BEGIN;
321 else if( memcmp( data + block->size, guard_pattern, guard_size ) != 0 )
322 code = CvTS::FAIL_MEMORY_CORRUPTION_END;
327 block->prev->next = block->next;
328 else if( first == block )
332 block->next->prev = block->prev;
333 else if( last == block )
336 free( block->origin );
340 ts->set_failed_test_info( code, block->index );
341 ts->printf( CvTS::LOG, "Corrupted block (%s): %p, %u bytes\n",
342 code == CvTS::FAIL_MEMORY_CORRUPTION_BEGIN ? "beginning" : "end",
343 block->data, block->size );
350 void* CvTestMemoryManager::alloc( size_t size )
353 CvTestAllocBlock* block;
354 size_t new_size = sizeof(*block) + size + guard_size*2 + block_align + sizeof(size_t)*2;
355 char* ptr = (char*)malloc( new_size );
360 data = (char*)cvAlignPtr( ptr + sizeof(size_t) + sizeof(*block) + guard_size, block_align );
361 block = (CvTestAllocBlock*)cvAlignPtr( data - guard_size -
362 sizeof(size_t) - sizeof(*block), sizeof(size_t) );
367 block->next = block->prev = 0;
368 memcpy( data - guard_size, guard_pattern, guard_size );
369 memcpy( data + size, guard_pattern, guard_size );
371 if( track_blocks > 0 )
376 if( index == index_to_stop_at )
380 #if defined WIN32 || defined _WIN32
381 MessageBox( NULL, "The block that is corrupted and/or not deallocated has been just allocated\n"
382 "Press Ok to start debugging", "Memory Manager", MB_ICONERROR|MB_OK|MB_SYSTEMMODAL );
388 block->index = index++;
393 last = last->next = block;
395 first = last = block;
404 int CvTestMemoryManager::free( void* ptr )
406 char* data = (char*)ptr;
407 CvTestAllocBlock* block = (CvTestAllocBlock*)
408 cvAlignPtr( data - guard_size - sizeof(size_t) - sizeof(*block), sizeof(size_t) );
410 int code = free_block( block );
411 if( code < 0 && ts->is_debug_mode() )
417 /***************************** error handler *****************************/
420 static int cvTestErrorCallback( int status, const char* func_name, const char* err_msg,
421 const char* file_name, int line, void* userdata )
423 if( status < 0 && status != CV_StsBackTrace && status != CV_StsAutoTrace )
424 ((CvTS*)userdata)->set_failed_test_info( CvTS::FAIL_ERROR_IN_CALLED_FUNC );
426 // print error message
427 return cvStdErrReport( status, func_name, err_msg, file_name, line, 0 );
431 /*****************************************************************************************\
432 * Base Class for Tests *
433 \*****************************************************************************************/
435 CvTest::CvTest( const char* _test_name, const char* _test_funcs, const char* _test_descr ) :
436 name(_test_name ? _test_name : ""), tested_functions(_test_funcs ? _test_funcs : ""),
437 description(_test_descr ? _test_descr : ""), ts(0)
448 timing_param_names = 0;
449 timing_param_current = 0;
450 timing_param_seqs = 0;
451 timing_param_idxs = 0;
452 timing_param_count = -1;
454 test_case_count = -1;
455 support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
463 CvTest* CvTest::get_first_test()
470 if( timing_param_current )
471 free( timing_param_current );
472 if( timing_param_seqs )
473 free( timing_param_seqs );
474 if( timing_param_idxs )
475 free( timing_param_idxs );
477 timing_param_current = 0;
478 timing_param_seqs = 0;
479 timing_param_idxs = 0;
480 timing_param_count = -1;
484 int CvTest::init( CvTS* _test_system )
488 return read_params( ts->get_file_storage() );
492 const char* CvTest::get_parent_name( const char* name, char* buffer )
494 const char* dash_pos = strrchr( name ? name : "", '-' );
498 if( name != (const char*)buffer )
499 strncpy( buffer, name, dash_pos - name );
500 buffer[dash_pos - name] = '\0';
505 const CvFileNode* CvTest::find_param( CvFileStorage* fs, const char* param_name )
508 const char* name = get_name();
509 CvFileNode* node = 0;
515 node = cvGetFileNodeByName( fs, 0, name );
518 node = cvGetFileNodeByName( fs, node, param_name );
522 name = get_parent_name( name, buffer );
529 void CvTest::start_write_param( CvFileStorage* fs )
533 cvStartWriteStruct( fs, get_name(), CV_NODE_MAP );
539 void CvTest::write_param( CvFileStorage* fs, const char* paramname, int val )
541 if( !ts->find_written_param( this, paramname, CV_NODE_INT, &val) )
543 start_write_param( fs );
544 cvWriteInt( fs, paramname, val );
549 void CvTest::write_param( CvFileStorage* fs, const char* paramname, double val )
551 if( !ts->find_written_param( this, paramname, CV_NODE_REAL, &val) )
553 start_write_param( fs );
554 cvWriteReal( fs, paramname, val );
559 void CvTest::write_param( CvFileStorage* fs, const char* paramname, const char* val )
561 if( !ts->find_written_param( this, paramname, CV_NODE_STRING, &val) )
563 start_write_param( fs );
564 cvWriteString( fs, paramname, val );
569 void CvTest::write_string_list( CvFileStorage* fs, const char* paramname, const char** val, int count )
573 start_write_param( fs );
578 cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
579 for( i = 0; i < count && val[i] != 0; i++ )
580 cvWriteString( fs, 0, val[i] );
581 cvEndWriteStruct( fs );
586 void CvTest::write_int_list( CvFileStorage* fs, const char* paramname,
587 const int* val, int count, int stop_value )
591 start_write_param( fs );
596 cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
597 for( i = 0; i < count && val[i] != stop_value; i++ )
598 cvWriteInt( fs, 0, val[i] );
599 cvEndWriteStruct( fs );
604 void CvTest::write_real_list( CvFileStorage* fs, const char* paramname,
605 const double* val, int count, double stop_value )
609 start_write_param( fs );
614 cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
615 for( i = 0; i < count && val[i] != stop_value; i++ )
616 cvWriteReal( fs, 0, val[i] );
617 cvEndWriteStruct( fs );
622 int CvTest::read_params( CvFileStorage* fs )
626 if(fs == NULL) return code;
628 if( ts->get_testing_mode() == CvTS::TIMING_MODE )
630 timing_param_names = find_param( fs, "timing_params" );
631 if( CV_NODE_IS_SEQ(timing_param_names->tag) )
633 CvSeq* seq = timing_param_names->data.seq;
635 cvStartReadSeq( seq, &reader );
638 timing_param_count = seq->total;
639 timing_param_seqs = (const CvFileNode**)malloc( timing_param_count*sizeof(timing_param_seqs[0]));
640 timing_param_idxs = (int*)malloc( timing_param_count*sizeof(timing_param_idxs[0]));
641 timing_param_current = (const CvFileNode**)malloc( timing_param_count*sizeof(timing_param_current[0]));
644 for( i = 0; i < timing_param_count; i++ )
646 CvFileNode* param_name = (CvFileNode*)(reader.ptr);
648 if( !CV_NODE_IS_STRING(param_name->tag) )
650 ts->printf( CvTS::LOG, "ERROR: name of timing parameter #%d is not a string\n", i );
655 timing_param_idxs[i] = 0;
656 timing_param_current[i] = 0;
657 timing_param_seqs[i] = find_param( fs, param_name->data.str.ptr );
658 if( !timing_param_seqs[i] )
660 ts->printf( CvTS::LOG, "ERROR: timing parameter %s is not found\n", param_name->data.str.ptr );
665 if( CV_NODE_IS_SEQ(timing_param_seqs[i]->tag) )
666 test_case_count *= timing_param_seqs[i]->data.seq->total;
668 CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
671 if( i < timing_param_count )
672 timing_param_count = 0;
676 ts->printf( CvTS::LOG, "ERROR: \"timing_params\" is not found" );
685 int CvTest::get_next_timing_param_tuple()
690 if( timing_param_count <= 0 || !timing_param_names || !timing_param_seqs )
693 increment = timing_param_current[0] != 0; // if already have some valid test tuple, move to the next
694 for( i = 0; i < timing_param_count; i++ )
696 const CvFileNode* node = timing_param_seqs[i];
697 int total = CV_NODE_IS_SEQ(node->tag) ? node->data.seq->total : 1;
698 int new_idx = timing_param_idxs[i];
700 if( !timing_param_current[i] )
701 timing_param_idxs[i] = new_idx = 0;
705 if( new_idx >= total )
711 if( !timing_param_current[i] || new_idx != timing_param_idxs[i] )
713 if( CV_NODE_IS_SEQ(node->tag) )
714 timing_param_current[i] = (CvFileNode*)cvGetSeqElem( node->data.seq, new_idx );
716 timing_param_current[i] = node;
717 timing_param_idxs[i] = new_idx;
721 return !increment; // return 0 in case of overflow (i.e. if there is no more test cases)
725 const CvFileNode* CvTest::find_timing_param( const char* paramname )
727 if( timing_param_names )
731 cvStartReadSeq( timing_param_names->data.seq, &reader, 0 );
733 for( i = 0; i < timing_param_count; i++ )
735 const char* ptr = ((const CvFileNode*)(reader.ptr))->data.str.ptr;
736 if( ptr[0] == paramname[0] && strcmp(ptr, paramname) == 0 )
737 return timing_param_current[i];
738 CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
745 int CvTest::write_defaults(CvTS* _ts)
749 write_default_params( ts->get_file_storage() );
751 cvEndWriteStruct( ts->get_file_storage() );
756 int CvTest::write_default_params( CvFileStorage* fs )
758 if( ts->get_testing_mode() == CvTS::TIMING_MODE )
759 write_string_list( fs, "timing_params", default_timing_param_names, timing_param_count );
764 bool CvTest::can_do_fast_forward()
770 int CvTest::get_support_testing_modes()
772 return support_testing_modes;
775 void CvTest::safe_run( int start_from )
777 if(ts->is_debug_mode())
783 #if !defined WIN32 && !defined _WIN32
784 int _code = setjmp( cv_ts_jmp_mark );
793 catch (const cv::Exception& exc)
795 const char* errorStr = cvErrorStr(exc.code);
798 sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d",
799 errorStr, exc.err.c_str(), exc.func.size() > 0 ?
800 exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line );
801 ts->printf(CvTS::LOG, "%s\n", buf);
802 ts->set_failed_test_info( CvTS::FAIL_ERROR_IN_CALLED_FUNC );
806 ts->set_failed_test_info( CvTS::FAIL_EXCEPTION );
812 void CvTest::run( int start_from )
814 int i, test_case_idx, count = get_test_case_count();
815 int64 t_start = cvGetTickCount();
816 double freq = cv::getTickFrequency();
817 bool ff = can_do_fast_forward();
818 int progress = 0, code;
819 std::vector<double> v_cpe, v_time;
822 for( test_case_idx = ff && start_from >= 0 ? start_from : 0;
823 count < 0 || test_case_idx < count; test_case_idx++ )
825 ts->update_context( this, test_case_idx, ff );
826 progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) );
828 int64 t00 = 0, t0 = 0, t2 = 0, t3 = 0;
829 double t_acc = 0, t_cpu_acc = 0;
831 if( ts->get_testing_mode() == CvTS::TIMING_MODE )
833 const int iterations = 20;
834 code = prepare_test_case( test_case_idx );
836 if( code < 0 || ts->get_err_code() < 0 )
845 for( i = 0; i < iterations; i++ )
849 t0 = cv::getTickCount();
850 t2 = cv::getCPUTickCount();
852 t3 = cv::getCPUTickCount();
853 t1 = cv::getTickCount();
854 if( ts->get_err_code() < 0 )
857 if( t3 - t2 > 0 && t1 - t0 > 1 )
863 v_cpe.push_back((double)(t3 - t2));
864 v_time.push_back((double)(t1 - t0));
865 if( i >= 5 && t1 - t00 > freq*5 )
869 sort(v_cpe.begin(), v_cpe.end());
870 sort(v_time.begin(), v_time.end());
872 t_cpu_acc = v_cpe[i/2];
874 print_time( test_case_idx, t_acc, t_cpu_acc );
878 code = prepare_test_case( test_case_idx );
879 if( code < 0 || ts->get_err_code() < 0 )
886 if( ts->get_err_code() < 0 )
889 if( validate_test_results( test_case_idx ) < 0 || ts->get_err_code() < 0 )
896 void CvTest::run_func()
902 int CvTest::get_test_case_count()
904 return test_case_count;
908 int CvTest::prepare_test_case( int )
914 int CvTest::validate_test_results( int )
920 void CvTest::print_time( int /*test_case_idx*/, double /*time_usecs*/, double /*time_cpu_clocks*/ )
925 int CvTest::update_progress( int progress, int test_case_idx, int count, double dt )
927 int width = 60 - (int)strlen(get_name());
930 int t = cvRound( ((double)test_case_idx * width)/count );
933 ts->printf( CvTS::CONSOLE, "." );
937 else if( cvRound(dt) > progress )
939 ts->printf( CvTS::CONSOLE, "." );
940 progress = cvRound(dt);
947 CvBadArgTest::CvBadArgTest( const char* _test_name, const char* _test_funcs, const char* _test_descr )
948 : CvTest( _test_name, _test_funcs, _test_descr )
952 freq = cv::getTickFrequency();
955 CvBadArgTest::~CvBadArgTest()
959 int CvBadArgTest::run_test_case( int expected_code, const char* descr )
961 double new_t = (double)cv::getTickCount(), dt;
962 if( test_case_idx < 0 )
970 dt = (new_t - t)/(freq*1000);
973 progress = update_progress(progress, test_case_idx, 0, dt);
984 catch(const cv::Exception& e)
987 if( e.code != expected_code )
989 ts->printf(CvTS::LOG, "%s (test case #%d): the error code %d is different from the expected %d\n",
990 descr, test_case_idx, e.code, expected_code);
997 ts->printf(CvTS::LOG, "%s (test case #%d): unknown exception was thrown (the function has likely crashed)\n",
998 descr, test_case_idx);
1003 ts->printf(CvTS::LOG, "%s (test case #%d): no expected exception was thrown\n",
1004 descr, test_case_idx);
1012 /*****************************************************************************************\
1013 * Base Class for Test System *
1014 \*****************************************************************************************/
1016 /******************************** Constructors/Destructors ******************************/
1021 version = CV_TS_VERSION;
1024 memory_manager = new CvTestMemoryManager(this);
1025 cvSetMemoryManager( CvTestMemoryManager::alloc_proxy,
1026 CvTestMemoryManager::free_proxy,
1028 ostrm_suffixes[SUMMARY_IDX] = ".sum";
1029 ostrm_suffixes[LOG_IDX] = ".log";
1030 ostrm_suffixes[CSV_IDX] = ".csv";
1031 ostrm_suffixes[CONSOLE_IDX] = 0;
1032 ostrm_base_name = 0;
1033 memset( output_streams, 0, sizeof(output_streams) );
1034 memset( ¶ms, 0, sizeof(params) );
1035 selected_tests = new CvTestPtrVec();
1036 failed_tests = new CvTestInfoVec();
1037 written_params = new CvTestPtrVec();
1038 logbufsize = 1 << 18; // 256K
1040 logbuf = new char[logbufsize];
1051 for( test = get_first_test(); test != 0; test = test->get_next() )
1054 for( i = 0; i <= CONSOLE_IDX; i++ )
1058 else if( i == CONSOLE_IDX )
1061 if( i < CONSOLE_IDX && output_streams[i].f )
1063 fclose( output_streams[i].f );
1064 output_streams[i].f = 0;
1067 if( i == LOG_IDX && output_streams[i].default_handle > 0 )
1069 dup2( output_streams[i].default_handle, 2 );
1070 output_streams[i].default_handle = 0;
1072 output_streams[i].enable = 1;
1074 cvReleaseFileStorage( &fs );
1075 selected_tests->clear();
1076 failed_tests->clear();
1077 if( ostrm_base_name )
1079 free( ostrm_base_name );
1080 ostrm_base_name = 0;
1082 params.rng_seed = (uint64)-1;
1083 params.debug_mode = -1;
1084 params.print_only_failed = 0;
1085 params.skip_header = 0;
1086 params.test_mode = CORRECTNESS_CHECK_MODE;
1087 params.timing_mode = MIN_TIME;
1088 params.use_optimized = -1;
1089 params.color_terminal = 1;
1091 if( memory_manager )
1092 memory_manager->clear_and_check();
1101 if( written_params )
1103 for( int i = 0; i < written_params->size(); i++ )
1104 free( written_params->at(i) );
1105 delete written_params;
1108 delete selected_tests;
1109 delete failed_tests;
1114 const char* CvTS::str_from_code( int code )
1118 case OK: return "Ok";
1119 case FAIL_GENERIC: return "Generic/Unknown";
1120 case FAIL_MISSING_TEST_DATA: return "No test data";
1121 case FAIL_INVALID_TEST_DATA: return "Invalid test data";
1122 case FAIL_ERROR_IN_CALLED_FUNC: return "cvError invoked";
1123 case FAIL_EXCEPTION: return "Hardware/OS exception";
1124 case FAIL_MEMORY_EXCEPTION: return "Invalid memory access";
1125 case FAIL_ARITHM_EXCEPTION: return "Arithmetic exception";
1126 case FAIL_MEMORY_CORRUPTION_BEGIN: return "Corrupted memblock (beginning)";
1127 case FAIL_MEMORY_CORRUPTION_END: return "Corrupted memblock (end)";
1128 case FAIL_MEMORY_LEAK: return "Memory leak";
1129 case FAIL_INVALID_OUTPUT: return "Invalid function output";
1130 case FAIL_MISMATCH: return "Unexpected output";
1131 case FAIL_BAD_ACCURACY: return "Bad accuracy";
1132 case FAIL_HANG: return "Infinite loop(?)";
1133 case FAIL_BAD_ARG_CHECK: return "Incorrect handling of bad arguments";
1134 default: return "Generic/Unknown";
1138 /************************************** Running tests **********************************/
1140 void CvTS::make_output_stream_base_name( const char* config_name )
1142 int k, len = (int)strlen( config_name );
1144 if( ostrm_base_name )
1145 free( ostrm_base_name );
1147 for( k = len-1; k >= 0; k-- )
1149 char c = config_name[k];
1150 if( c == '.' || c == '/' || c == '\\' || c == ':' )
1154 if( k > 0 && config_name[k] == '.' )
1157 ostrm_base_name = (char*)malloc( len + 1 );
1158 memcpy( ostrm_base_name, config_name, len );
1159 ostrm_base_name[len] = '\0';
1163 void CvTS::set_handlers( bool on )
1167 cvSetErrMode( CV_ErrModeParent );
1168 cvRedirectError( cvStdErrReport );
1169 #if defined WIN32 || defined _WIN32
1171 _set_se_translator( cv_seh_translator );
1174 for( int i = 0; cv_ts_sig_id[i] >= 0; i++ )
1175 signal( cv_ts_sig_id[i], cv_signal_handler );
1180 cvSetErrMode( CV_ErrModeLeaf );
1181 cvRedirectError( cvGuiBoxReport );
1182 #if defined WIN32 || defined _WIN32
1184 _set_se_translator( 0 );
1187 for( int i = 0; cv_ts_sig_id[i] >= 0; i++ )
1188 signal( cv_ts_sig_id[i], SIG_DFL );
1194 void CvTS::set_data_path( const char* data_path )
1196 if( data_path == params.data_path )
1199 if( params.data_path )
1200 delete[] params.data_path;
1203 int size = (int)strlen(data_path)+1;
1204 bool append_slash = data_path[size-1] != '/' && data_path[size-1] != '\\';
1205 params.data_path = new char[size+1];
1206 memcpy( params.data_path, data_path, size );
1208 strcat( params.data_path, "/" );
1213 typedef struct CvTsParamVal
1215 const char* fullname;
1220 int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype, const void* val )
1222 const char* testname = test->get_name();
1223 bool add_to_list = test->get_func_list()[0] == '\0';
1225 int paramname_len = (int)strlen(paramname);
1226 int paramval_len = valtype == CV_NODE_INT ? (int)sizeof(int) :
1227 valtype == CV_NODE_REAL ? (int)sizeof(double) : -1;
1228 const char* name = CvTest::get_parent_name( testname, buffer );
1233 if( paramval_len < 0 )
1235 assert(0); // unsupported parameter type
1241 int i, len = (int)strlen(buffer);
1243 memcpy( buffer + len + 1, paramname, paramname_len + 1 );
1244 for( i = 0; i < written_params->size(); i++ )
1246 CvTsParamVal* param = (CvTsParamVal*)written_params->at(i);
1247 if( strcmp( param->fullname, buffer ) == 0 )
1249 if( (paramval_len > 0 && memcmp( param->val, val, paramval_len ) == 0) ||
1250 (paramval_len < 0 && strcmp( (const char*)param->val, (const char*)val ) == 0) )
1255 if( i < written_params->size() )
1258 name = CvTest::get_parent_name( buffer, buffer );
1263 int bufsize, fullname_len = (int)strlen(testname) + paramname_len + 2;
1264 CvTsParamVal* param;
1265 if( paramval_len < 0 )
1266 paramval_len = (int)strlen((const char*)val) + 1;
1267 bufsize = sizeof(*param) + fullname_len + paramval_len;
1268 param = (CvTsParamVal*)malloc(bufsize);
1269 param->fullname = (const char*)(param + 1);
1270 param->val = param->fullname + fullname_len;
1271 sprintf( (char*)param->fullname, "%s.%s", testname, paramname );
1272 memcpy( (void*)param->val, val, paramval_len );
1273 written_params->push( param );
1281 #define MAX_PATH 1024
1284 static int CV_CDECL cmp_test_names( const void* a, const void* b )
1286 return strcmp( (*(const CvTest**)a)->get_name(), (*(const CvTest**)b)->get_name() );
1289 int CvTS::run( int argc, char** argv )
1291 time( &start_time );
1293 int i, write_params = 0;
1295 CvTestPtrVec all_tests;
1298 // 0. reset all the parameters, reorder tests
1301 #if defined WIN32 || defined _WIN32
1302 cv::setBreakOnError(true);
1305 for( test = get_first_test(), i = 0; test != 0; test = test->get_next(), i++ )
1306 all_tests.push(test);
1308 if( all_tests.size() > 0 && all_tests.data() )
1309 qsort( all_tests.data(), all_tests.size(), sizeof(CvTest*), cmp_test_names );
1311 // 1. parse command line options
1312 for( i = 1; i < argc; i++ )
1314 if( strcmp( argv[i], "-h" ) == 0 || strcmp( argv[i], "--help" ) == 0 )
1319 else if( strcmp( argv[i], "-f" ) == 0 )
1320 config_name = argv[++i];
1321 else if( strcmp( argv[i], "-w" ) == 0 )
1323 else if( strcmp( argv[i], "-t" ) == 0 )
1324 params.test_mode = TIMING_MODE;
1325 else if( strcmp( argv[i], "-O0" ) == 0 || strcmp( argv[i], "-O1" ) == 0 )
1326 params.use_optimized = argv[i][2] - '0';
1327 else if( strcmp( argv[i], "-l" ) == 0 )
1329 else if( strcmp( argv[i], "-d" ) == 0 )
1330 set_data_path(argv[++i]);
1331 else if( strcmp( argv[i], "-nc" ) == 0 )
1332 params.color_terminal = 0;
1333 else if( strcmp( argv[i], "-r" ) == 0 )
1334 params.debug_mode = 0;
1335 else if( strcmp( argv[i], "-tn" ) == 0 )
1337 params.test_filter_pattern = argv[++i];
1338 params.test_filter_mode = CHOOSE_TESTS;
1343 //#if !defined WIN32 && !defined _WIN32
1346 char * confname = getenv("configname");
1348 config_name = confname;
1351 if( !params.data_path || !params.data_path[0] )
1353 char* datapath = getenv("datapath");
1355 set_data_path(datapath);
1358 // this is the fallback for the current OpenCV autotools setup
1359 if( !params.data_path || !params.data_path[0] )
1361 char* srcdir = getenv("srcdir");
1365 sprintf( buf, "%s/../../opencv_extra/testdata/", srcdir );
1375 printf( LOG, "ERROR: output config name is not specified\n" );
1378 fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_WRITE );
1381 printf( LOG, "ERROR: could not open config file %s\n", config_name );
1384 cvWriteComment( fs, CV_TS_VERSION " config file", 0 );
1385 cvStartWriteStruct( fs, "common", CV_NODE_MAP );
1386 write_default_params( fs );
1387 cvEndWriteStruct( fs );
1389 for( i = 0; i < all_tests.size(); i++ )
1391 test = (CvTest*)all_tests[i];
1392 if( !(test->get_support_testing_modes() & get_testing_mode()) )
1394 test->write_defaults( this );
1397 cvReleaseFileStorage( &fs );
1402 printf( LOG, "WARNING: config name is not specified, using default parameters\n" );
1405 // 2. read common parameters of test system
1406 fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_READ );
1409 printf( LOG, "ERROR: could not open config file %s", config_name );
1414 if( params.test_mode == CORRECTNESS_CHECK_MODE || fs )
1416 // in the case of algorithmic tests we always run read_params,
1417 // even if there is no config file
1418 if( read_params(fs) < 0 )
1422 if( !ostrm_base_name )
1423 make_output_stream_base_name( config_name ? config_name : argv[0] );
1425 ostream_testname_mask = -1; // disable printing test names at initial stage
1427 // 3. open file streams
1428 for( i = 0; i < CONSOLE_IDX; i++ )
1430 char filename[MAX_PATH];
1431 sprintf( filename, "%s%s", ostrm_base_name, ostrm_suffixes[i] );
1432 output_streams[i].f = fopen( filename, "wt" );
1433 if( !output_streams[i].f )
1435 printf( LOG, "ERROR: could not open %s\n", filename );
1441 // redirect stderr to log file
1443 output_streams[i].default_handle = dup(2);
1444 dup2( fileno(output_streams[i].f), 2 );
1448 // 4. traverse through the list of all registered tests.
1449 // Initialize the selected tests and put them into the separate sequence
1450 for( i = 0; i < all_tests.size(); i++ )
1452 test = (CvTest*)all_tests[i];
1453 if( !(test->get_support_testing_modes() & get_testing_mode()) )
1456 if( strcmp( test->get_func_list(), "" ) != 0 && filter(test) )
1458 if( test->init(this) >= 0 )
1460 selected_tests->push( test );
1462 ::printf( "%s\n", test->get_name() );
1465 printf( LOG, "WARNING: an error occured during test %s initialization\n", test->get_name() );
1475 // 5. setup all the neccessary handlers and print header
1476 set_handlers( !params.debug_mode );
1478 if( params.use_optimized == 0 )
1481 if( !params.skip_header )
1482 print_summary_header( SUMMARY + LOG + CONSOLE + CSV );
1483 rng = params.rng_seed;
1484 update_context( 0, -1, true );
1486 // 6. run all the tests
1487 for( i = 0; i < selected_tests->size(); i++ )
1489 CvTest* test = (CvTest*)selected_tests->at(i);
1493 if( memory_manager )
1494 memory_manager->start_tracking();
1495 update_context( test, -1, true );
1496 current_test_info.rng_seed0 = current_test_info.rng_seed;
1498 ostream_testname_mask = 0; // reset "test name was printed" flags
1500 if( output_streams[LOG_IDX].f )
1501 fflush( output_streams[LOG_IDX].f );
1503 temp = current_test_info;
1505 if( get_err_code() >= 0 )
1507 update_context( test, -1, false );
1508 current_test_info.rng_seed = temp.rng_seed;
1509 current_test_info.base_alloc_index = temp.base_alloc_index;
1512 if( memory_manager )
1513 memory_manager->stop_tracking_and_check();
1515 code = get_err_code();
1518 if( !params.print_only_failed )
1520 printf( SUMMARY + CONSOLE, "\t" );
1521 set_color( CV_TS_GREEN );
1522 printf( SUMMARY + CONSOLE, "Ok\n" );
1523 set_color( CV_TS_NORMAL );
1528 printf( SUMMARY + CONSOLE, "\t" );
1529 set_color( CV_TS_RED );
1530 printf( SUMMARY + CONSOLE, "FAIL(%s)\n", str_from_code(code) );
1531 set_color( CV_TS_NORMAL );
1532 printf( LOG, "context: test case = %d, seed = %08x%08x\n",
1533 current_test_info.test_case_idx,
1534 (unsigned)(current_test_info.rng_seed>>32),
1535 (unsigned)(current_test_info.rng_seed));
1538 logbuf[logbufpos] = '\0';
1539 printf( SUMMARY + CONSOLE, ">>>\n%s\n", logbuf);
1541 failed_tests->push(current_test_info);
1542 if( params.rerun_immediately )
1547 ostream_testname_mask = -1;
1548 print_summary_tailer( SUMMARY + CONSOLE + LOG );
1550 if( !params.debug_mode && (params.rerun_failed || params.rerun_immediately) )
1553 update_context( 0, -1, true );
1554 for( i = 0; i < failed_tests->size(); i++ )
1556 CvTestInfo info = failed_tests->at(i);
1557 if( (info.code == FAIL_MEMORY_CORRUPTION_BEGIN ||
1558 info.code == FAIL_MEMORY_CORRUPTION_END ||
1559 info.code == FAIL_MEMORY_LEAK) && memory_manager )
1560 memory_manager->start_tracking( info.alloc_index - info.base_alloc_index
1561 + memory_manager->get_alloc_index() );
1562 rng = info.rng_seed;
1563 test->safe_run( info.test_case_idx );
1566 int nfailed = failed_tests ? (int)failed_tests->size() : 0;
1573 void CvTS::print_help()
1576 "Usage: <test_executable> [{-h|--help}][-l] [-r] [-w] [-t] [-f <config_name>] [-d <data_path>] [-O{0|1}]\n\n"
1577 "-d - specify the test data path\n"
1578 "-f - use parameters from the provided XML/YAML config file\n"
1579 " instead of the default parameters\n"
1580 "-h or --help - print this help information\n"
1581 "-l - list all the registered tests or subset of the tests,\n"
1582 " selected in the config file, and exit\n"
1583 "-nc - do not use colors in the console output\n"
1584 "-O{0|1} - disable/enable on-fly detection of IPP and other\n"
1585 " supported optimized libs. It's enabled by default\n"
1586 "-r - continue running tests after OS/Hardware exception occured\n"
1587 "-t - switch to the performance testing mode instead of\n"
1588 " the default algorithmic/correctness testing mode\n"
1589 "-w - write default parameters of the algorithmic or\n"
1590 " performance (when -t is passed) tests to the specifed\n"
1591 " config file (see -f) and exit\n\n"
1592 //"Test data path and config file can also be specified by the environment variables 'config' and 'datapath'.\n\n"
1597 #if defined WIN32 || defined _WIN32
1598 const char* default_data_path = "../tests/cv/testdata/";
1600 const char* default_data_path = "../../../../tests/cv/testdata/";
1604 int CvTS::read_params( CvFileStorage* fs )
1606 CvFileNode* node = fs ? cvGetFileNodeByName( fs, 0, "common" ) : 0;
1607 if(params.debug_mode < 0)
1608 params.debug_mode = cvReadIntByName( fs, node, "debug_mode", 1 ) != 0;
1609 params.skip_header = cvReadIntByName( fs, node, "skip_header", 0 ) != 0;
1610 params.print_only_failed = cvReadIntByName( fs, node, "print_only_failed", 0 ) != 0;
1611 params.rerun_failed = cvReadIntByName( fs, node, "rerun_failed", 0 ) != 0;
1612 params.rerun_immediately = cvReadIntByName( fs, node, "rerun_immediately", 0 ) != 0;
1613 const char* str = cvReadStringByName( fs, node, "filter_mode", "tests" );
1614 params.test_filter_mode = strcmp( str, "functions" ) == 0 ? CHOOSE_FUNCTIONS : CHOOSE_TESTS;
1615 str = cvReadStringByName( fs, node, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
1616 params.test_mode = strcmp( str, "timing" ) == 0 || strcmp( str, "performance" ) == 0 ?
1617 TIMING_MODE : CORRECTNESS_CHECK_MODE;
1618 str = cvReadStringByName( fs, node, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
1619 params.timing_mode = strcmp( str, "average" ) == 0 || strcmp( str, "avg" ) == 0 ? AVG_TIME : MIN_TIME;
1620 params.test_filter_pattern = params.test_filter_pattern != 0 &&
1621 strlen(params.test_filter_pattern) > 0 ? params.test_filter_pattern :
1622 cvReadStringByName( fs, node, params.test_filter_mode == CHOOSE_FUNCTIONS ?
1623 "functions" : "tests", "" );
1624 params.resource_path = cvReadStringByName( fs, node, "." );
1625 if( params.use_optimized < 0 )
1626 params.use_optimized = cvReadIntByName( fs, node, "use_optimized", -1 );
1627 if( !params.data_path || !params.data_path[0] )
1629 const char* data_path =
1630 cvReadStringByName( fs, node, "data_path", default_data_path );
1631 set_data_path(data_path);
1633 params.test_case_count_scale = cvReadRealByName( fs, node, "test_case_count_scale", 1. );
1634 if( params.test_case_count_scale <= 0 )
1635 params.test_case_count_scale = 1.;
1636 str = cvReadStringByName( fs, node, "seed", 0 );
1637 params.rng_seed = 0;
1638 if( str && strlen(str) == 16 )
1640 params.rng_seed = 0;
1641 for( int i = 0; i < 16; i++ )
1643 int c = tolower(str[i]);
1646 params.rng_seed = 0;
1649 params.rng_seed = params.rng_seed * 16 +
1650 (str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10);
1654 if( params.rng_seed == 0 )
1655 params.rng_seed = cvGetTickCount();
1657 str = cvReadStringByName( fs, node, "output_file_base_name", 0 );
1659 make_output_stream_base_name( str );
1665 void CvTS::write_default_params( CvFileStorage* fs )
1667 read_params(0); // fill parameters with default values
1669 cvWriteInt( fs, "debug_mode", params.debug_mode );
1670 cvWriteInt( fs, "skip_header", params.skip_header );
1671 cvWriteInt( fs, "print_only_failed", params.print_only_failed );
1672 cvWriteInt( fs, "rerun_failed", params.rerun_failed );
1673 cvWriteInt( fs, "rerun_immediately", params.rerun_immediately );
1674 cvWriteString( fs, "filter_mode", params.test_filter_mode == CHOOSE_FUNCTIONS ? "functions" : "tests" );
1675 cvWriteString( fs, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
1676 cvWriteString( fs, "data_path", params.data_path ? params.data_path : default_data_path, 1 );
1677 if( params.test_mode == TIMING_MODE )
1678 cvWriteString( fs, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
1679 // test_filter, seed & output_file_base_name are not written
1683 void CvTS::enable_output_streams( int stream_mask, int value )
1685 for( int i = 0; i < MAX_IDX; i++ )
1686 if( stream_mask & (1 << i) )
1687 output_streams[i].enable = value != 0;
1691 void CvTS::update_context( CvTest* test, int test_case_idx, bool update_ts_context )
1693 current_test_info.test = test;
1694 current_test_info.test_case_idx = test_case_idx;
1695 current_test_info.alloc_index = 0;
1696 current_test_info.code = 0;
1697 cvSetErrStatus( CV_StsOk );
1698 if( update_ts_context )
1700 current_test_info.rng_seed = rng;
1701 current_test_info.base_alloc_index = memory_manager ?
1702 memory_manager->get_alloc_index() : 0;
1707 void CvTS::set_failed_test_info( int fail_code, int alloc_index )
1709 if( fail_code == FAIL_MEMORY_CORRUPTION_BEGIN ||
1710 fail_code == FAIL_MEMORY_CORRUPTION_END ||
1711 current_test_info.code >= 0 )
1713 current_test_info.code = fail_code;
1714 current_test_info.alloc_index = alloc_index;
1719 const char* CvTS::get_libs_info( const char** addon_modules )
1721 const char* all_info = 0;
1722 cvGetModuleInfo( 0, &all_info, addon_modules );
1727 void CvTS::print_summary_header( int streams )
1729 char csv_header[256], *ptr = csv_header;
1732 printf( streams, "Engine: %s\n", version );
1735 struct tm *t2 = localtime( &t1 );
1737 strftime( buf, sizeof(buf)-1, "%c", t2 );
1738 printf( streams, "Execution Date & Time: %s\n", buf );
1739 printf( streams, "Config File: %s\n", config_name );
1740 const char* plugins = 0;
1741 const char* lib_verinfo = get_libs_info( &plugins );
1742 printf( streams, "Tested Libraries: %s\n", lib_verinfo );
1743 printf( streams, "Optimized Low-level Plugin\'s: %s\n", plugins );
1744 printf( streams, "=================================================\n");
1746 sprintf( ptr, "funcName,dataType,channels,size," );
1749 for( i = 0; i < CvTest::TIMING_EXTRA_PARAMS; i++ )
1751 sprintf( ptr, "param%d,", i );
1755 sprintf( ptr, "CPE,Time(uSecs)" );
1756 printf( CSV, "%s\n", csv_header );
1760 void CvTS::print_summary_tailer( int streams )
1762 printf( streams, "=================================================\n");
1763 if( selected_tests && failed_tests )
1767 double total_time = difftime( end_time, start_time );
1768 printf( streams, "Summary: %d out of %d tests failed\n",
1769 failed_tests->size(), selected_tests->size() );
1770 int minutes = cvFloor(total_time/60.);
1771 int seconds = cvRound(total_time - minutes*60);
1772 int hours = minutes / 60;
1774 printf( streams, "Running time: %02d:%02d:%02d\n", hours, minutes, seconds );
1779 void CvTS::vprintf( int streams, const char* fmt, va_list l )
1784 vsprintf( str, fmt, l );
1786 for( int i = 0; i < MAX_IDX; i++ )
1788 if( (streams & (1 << i)) && output_streams[i].enable )
1790 FILE* f = i == CONSOLE_IDX ? stdout :
1791 i == LOG_IDX ? stderr : output_streams[i].f;
1794 if( i != CSV_IDX && !(ostream_testname_mask & (1 << i)) && current_test_info.test )
1796 fprintf( f, "-------------------------------------------------\n" );
1797 if( i == CONSOLE_IDX || i == SUMMARY_IDX )
1798 fprintf( f, "[%08x%08x]\n", (int)(current_test_info.rng_seed0 >> 32),
1799 (int)(current_test_info.rng_seed0));
1800 fprintf( f, "%s: ", current_test_info.test->get_name() );
1802 ostream_testname_mask |= 1 << i;
1809 size_t len = strlen(str);
1810 CV_Assert(logbufpos + len < logbufsize);
1811 strcpy(logbuf + logbufpos, str);
1814 if( i == CONSOLE_IDX )
1823 void CvTS::printf( int streams, const char* fmt, ... )
1829 vprintf( streams, fmt, l );
1834 void CvTS::set_color(int color)
1836 if( params.color_terminal )
1837 change_color(color);
1840 static char* cv_strnstr( const char* str, int len,
1841 const char* pattern,
1842 int pattern_len = -1,
1843 int whole_word = 1 )
1847 if( len < 0 && pattern_len < 0 )
1848 return (char*)strstr( str, pattern );
1851 len = (int)strlen( str );
1853 if( pattern_len < 0 )
1854 pattern_len = (int)strlen( pattern );
1856 for( i = 0; i < len - pattern_len + 1; i++ )
1858 int j = i + pattern_len;
1859 if( str[i] == pattern[0] &&
1860 memcmp( str + i, pattern, pattern_len ) == 0 &&
1862 ((i == 0 || (!isalnum(str[i-1]) && str[i-1] != '_')) &&
1863 (j == len || (!isalnum(str[j]) && str[j] != '_')))))
1864 return (char*)(str + i);
1871 int CvTS::filter( CvTest* test )
1873 const char* pattern = params.test_filter_pattern;
1876 if( pattern && pattern[0] == '!' )
1882 if( !pattern || strcmp( pattern, "" ) == 0 || strcmp( pattern, "*" ) == 0 )
1885 if( params.test_filter_mode == CHOOSE_TESTS )
1889 while( pattern && *pattern )
1891 char *ptr, *endptr = (char*)strchr( pattern, ',' );
1892 int len, have_wildcard;
1898 ptr = (char*)strchr( pattern, '*' );
1901 len = (int)(ptr - pattern);
1906 len = (int)strlen( pattern );
1910 t_name_len = (int)strlen( test->get_name() );
1911 found = (t_name_len == len || (have_wildcard && t_name_len > len)) &&
1912 (len == 0 || memcmp( test->get_name(), pattern, len ) == 0);
1916 pattern = endptr + 1;
1917 while( isspace(*pattern) )
1921 if( found || !endptr )
1925 return found ^ inverse;
1929 assert( params.test_filter_mode == CHOOSE_FUNCTIONS );
1930 int glob_len = (int)strlen( pattern );
1931 const char* ptr = test->get_func_list();
1932 const char *tmp_ptr;
1934 while( ptr && *ptr )
1936 const char* endptr = ptr - 1;
1937 const char* name_ptr;
1938 const char* name_first_match;
1943 while( isspace(c) );
1948 assert( isalpha(c) );
1952 while( isalnum(c) || c == '_' );
1954 if( c == ':' ) // class
1956 assert( endptr[1] == ':' );
1957 endptr = endptr + 2;
1958 name_len = (int)(endptr - name_ptr);
1960 // find the first occurence of the class name
1962 name_first_match = cv_strnstr( pattern,
1963 glob_len, name_ptr, name_len, 1 );
1965 if( *endptr == '*' )
1967 if( name_first_match )
1972 assert( *endptr == '{' ); // a list of methods
1974 if( !name_first_match )
1976 // skip all the methods, if there is no such a class name
1978 endptr = strchr( endptr, '}' );
1979 assert( endptr != 0 );
1985 const char* method_name_ptr;
1986 int method_name_len;
1989 while( isspace(c) );
1993 assert( isalpha(c) );
1995 method_name_ptr = endptr;
1998 while( isalnum(c) || c == '_' );
2000 method_name_len = (int)(endptr - method_name_ptr);
2002 // search for class_name::* or
2003 // class_name::{...method_name...}
2004 tmp_ptr = name_first_match;
2007 const char* tmp_ptr2;
2008 tmp_ptr += name_len;
2009 if( *tmp_ptr == '*' )
2011 assert( *tmp_ptr == '{' );
2012 tmp_ptr2 = strchr( tmp_ptr, '}' );
2015 if( cv_strnstr( tmp_ptr, (int)(tmp_ptr2 - tmp_ptr) + 1,
2016 method_name_ptr, method_name_len, 1 ))
2019 tmp_ptr = cv_strnstr( tmp_ptr2, glob_len -
2020 (int)(tmp_ptr2 - pattern),
2021 name_ptr, name_len, 1 );
2027 while( isspace(c) );
2036 assert( !c || isspace(c) || c == ',' );
2037 name_len = (int)(endptr - name_ptr);
2042 const char *tmp_ptr2, *tmp_ptr3;
2044 tmp_ptr = cv_strnstr( tmp_ptr, glob_len -
2045 (int)(tmp_ptr - pattern), name_ptr, name_len, 1 );
2050 // make sure it is not a method
2051 tmp_ptr2 = strchr( tmp_ptr, '}' );
2055 tmp_ptr3 = strchr( tmp_ptr, '{' );
2056 if( tmp_ptr3 < tmp_ptr2 )
2059 tmp_ptr = tmp_ptr2 + 1;
2066 while( isspace(c) );