]> rtime.felk.cvut.cz Git - opencv.git/blobdiff - opencv/tests/cxts/cxts.cpp
fixed build on MSVC 2003
[opencv.git] / opencv / tests / cxts / cxts.cpp
index 6926036b19792a71e7d60d0d4f708500169cd196..37c38cb42568c028bac72000f6fe55bdc9474996 100644 (file)
@@ -44,7 +44,7 @@
 #include <stdarg.h>
 #include <fcntl.h>
 #include <time.h>
-#ifdef WIN32
+#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
 #include <io.h>
 #else
 #include <unistd.h>
@@ -65,13 +65,14 @@ int CvTest::test_count = 0;
 #define CV_TS_GREEN  2
 #define CV_TS_RED    4
 
-#ifdef WIN32
+#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
 #include <windows.h>
 
 #ifdef _MSC_VER
 #include <eh.h>
 #endif
 
+#ifdef _MSC_VER
 static void cv_seh_translator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp )
 {
     int code = CvTS::FAIL_EXCEPTION;
@@ -105,15 +106,7 @@ static void cv_seh_translator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp )
     }
     throw code;
 }
-
-
-#define CV_TS_TRY_BLOCK_BEGIN                   \
-    try {
-
-#define CV_TS_TRY_BLOCK_END                     \
-    } catch( int _code ) {                      \
-        ts->set_failed_test_info( _code );      \
-    }
+#endif
 
 static void change_color( int color )
 {
@@ -139,7 +132,7 @@ static void change_color( int color )
 
 #include <signal.h>
 
-static const int cv_ts_sig_id[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, -1 };
+static const int cv_ts_sig_id[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT, -1 };
 
 static jmp_buf cv_ts_jmp_mark;
 
@@ -162,18 +155,6 @@ void cv_signal_handler( int sig_code )
     longjmp( cv_ts_jmp_mark, code );
 }
 
-#define CV_TS_TRY_BLOCK_BEGIN                   \
-    {                                           \
-        int _code = setjmp( cv_ts_jmp_mark );   \
-        if( !_code ) {
-
-#define CV_TS_TRY_BLOCK_END                     \
-        }                                       \
-        else  {                                 \
-            ts->set_failed_test_info( _code );  \
-        }                                       \
-    }
-
 static void change_color( int color )
 {
     static const uchar ansi_tab[] = { 30, 34, 32, 36, 31, 35, 33, 37 };
@@ -183,12 +164,31 @@ static void change_color( int color )
     if( color != CV_TS_NORMAL )
         code = ansi_tab[color & (CV_TS_BLUE|CV_TS_GREEN|CV_TS_RED)];
     sprintf( buf, "\x1b[%dm", code );
-    printf( buf );
+    fputs( buf, stdout );
 }
 
 #endif
 
 
+// reads 16-digit hexadecimal number (i.e. 64-bit integer)
+static int64 read_seed( const char* str )
+{
+    int64 val = 0;
+    if( str && strlen(str) == 16 )
+    {
+        for( int i = 0; str[i]; i++ )
+        {
+            int c = tolower(str[i]);
+            if( !isxdigit(c) )
+                return 0;
+            val = val * 16 +
+            (str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10);
+        }
+    }
+    return val;
+}
+
+
 /***************************** memory manager *****************************/
 
 typedef struct CvTestAllocBlock
@@ -254,7 +254,7 @@ CvTestMemoryManager::CvTestMemoryManager( CvTS* _test_system )
 {
     ts = _test_system;
     guard_pattern = "THIS IS A GUARD PATTERN!";
-    guard_size = strlen(guard_pattern);
+    guard_size = (int)strlen(guard_pattern);
     block_align = CV_MALLOC_ALIGN;
     track_blocks = 0;
     marks_top = 0;
@@ -276,7 +276,7 @@ void CvTestMemoryManager::clear_and_check( int min_index )
     int alloc_index = -1;
     CvTestAllocBlock* block;
     int leak_size = 0, leak_block_count = 0, mem_size = 0;
-    void* mem_addr = 0; 
+    void* mem_addr = 0;
 
     while( marks_top > 0 && marks[marks_top - 1] >= min_index )
         marks_top--;
@@ -286,11 +286,11 @@ void CvTestMemoryManager::clear_and_check( int min_index )
         CvTestAllocBlock* prev = block->prev;
         if( block->index < min_index )
             break;
-        leak_size += block->size;
+        leak_size += (int)block->size;
         leak_block_count++;
         alloc_index = block->index;
         mem_addr = block->data;
-        mem_size = block->size;
+        mem_size = (int)block->size;
         free_block( block );
         block = prev;
     }
@@ -301,7 +301,7 @@ void CvTestMemoryManager::clear_and_check( int min_index )
         ts->printf( CvTS::LOG, "Memory leaks: %u blocks, %u bytes total\n"
                     "%s leaked block: %p, %u bytes\n",
                     leak_block_count, leak_size, leak_block_count > 1 ? "The first" : "The",
-                    mem_addr, mem_size ); 
+                    mem_addr, mem_size );
     }
 
     index = block ? block->index + 1 : 0;
@@ -332,10 +332,10 @@ int CvTestMemoryManager::free_block( CvTestAllocBlock* block )
 {
     int code = 0;
     char* data = block->data;
-    
+
     if( block->origin == 0 || ((size_t)block->origin & (sizeof(double)-1)) != 0 )
         code = CvTS::FAIL_MEMORY_CORRUPTION_BEGIN;
-        
+
     if( memcmp( data - guard_size, guard_pattern, guard_size ) != 0 )
         code = CvTS::FAIL_MEMORY_CORRUPTION_BEGIN;
     else if( memcmp( data + block->size, guard_pattern, guard_size ) != 0 )
@@ -397,7 +397,7 @@ void* CvTestMemoryManager::alloc( size_t size )
         {
             if( show_msg_box )
             {
-        #ifdef WIN32
+        #if defined WIN32 || defined _WIN32
                 MessageBox( NULL, "The block that is corrupted and/or not deallocated has been just allocated\n"
                             "Press Ok to start debugging", "Memory Manager", MB_ICONERROR|MB_OK|MB_SYSTEMMODAL );
         #endif
@@ -480,6 +480,10 @@ CvTest::~CvTest()
     clear();
 }
 
+CvTest* CvTest::get_first_test()
+{
+    return first;
+}
 
 void CvTest::clear()
 {
@@ -510,7 +514,7 @@ const char* CvTest::get_parent_name( const char* name, char* buffer )
     const char* dash_pos = strrchr( name ? name : "", '-' );
     if( !dash_pos )
         return 0;
-    
+
     if( name != (const char*)buffer )
         strncpy( buffer, name, dash_pos - name );
     buffer[dash_pos - name] = '\0';
@@ -639,6 +643,8 @@ int CvTest::read_params( CvFileStorage* fs )
 {
     int code = 0;
     
+    if(fs == NULL) return code; 
+
     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
     {
         timing_param_names = find_param( fs, "timing_params" );
@@ -691,7 +697,7 @@ int CvTest::read_params( CvFileStorage* fs )
             code = -1;
         }
     }
-    
+
     return code;
 }
 
@@ -700,7 +706,7 @@ int CvTest::get_next_timing_param_tuple()
 {
     bool increment;
     int i;
-    
+
     if( timing_param_count <= 0 || !timing_param_names || !timing_param_seqs )
         return -1;
 
@@ -788,11 +794,38 @@ int CvTest::get_support_testing_modes()
 
 void CvTest::safe_run( int start_from )
 {
-    CV_TS_TRY_BLOCK_BEGIN;
-
-    run( start_from );
-
-    CV_TS_TRY_BLOCK_END;
+    if(ts->is_debug_mode())
+        run( start_from );
+    else
+    {
+        try
+        {
+        #if !defined WIN32 && !defined _WIN32
+        int _code = setjmp( cv_ts_jmp_mark );
+        if( !_code )
+            run( start_from );
+        else
+            throw _code;
+        #else
+            run( start_from );
+        #endif
+        }
+        catch (const cv::Exception& exc)
+        {
+            const char* errorStr = cvErrorStr(exc.code);
+            char buf[1 << 16];
+            
+            sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d",
+                    errorStr, exc.err.c_str(), exc.func.size() > 0 ?
+                    exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line );
+            ts->printf(CvTS::LOG, "%s\n", buf);
+            ts->set_failed_test_info( CvTS::FAIL_ERROR_IN_CALLED_FUNC );
+        }
+        catch (...)
+        {
+            ts->set_failed_test_info( CvTS::FAIL_EXCEPTION );
+        }
+    }
 }
 
 
@@ -800,64 +833,65 @@ void CvTest::run( int start_from )
 {
     int i, test_case_idx, count = get_test_case_count();
     int64 t_start = cvGetTickCount();
-    double freq = cvGetTickFrequency();
+    double freq = cv::getTickFrequency();
     bool ff = can_do_fast_forward();
     int progress = 0, code;
-    
+    std::vector<double> v_cpe, v_time;
+    int64 t1 = t_start;
+
     for( test_case_idx = ff && start_from >= 0 ? start_from : 0;
          count < 0 || test_case_idx < count; test_case_idx++ )
     {
         ts->update_context( this, test_case_idx, ff );
-        int64 t00 = 0, t0, t1 = 0;
-        double t_acc = 0;
-
+        progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) );
+        
+        int64 t00 = 0, t0 = 0, t2 = 0, t3 = 0;
+        double t_acc = 0, t_cpu_acc = 0;
+        
         if( ts->get_testing_mode() == CvTS::TIMING_MODE )
         {
-            const int iterations = 15;
+            const int iterations = 20;
             code = prepare_test_case( test_case_idx );
-            
+
             if( code < 0 || ts->get_err_code() < 0 )
                 return;
 
             if( code == 0 )
                 continue;
+                
+            v_cpe.resize(0);
+            v_time.resize(0);
 
             for( i = 0; i < iterations; i++ )
             {
-                t0 = cvGetTickCount();
-                run_func();
-                t1 = cvGetTickCount();
-                if( ts->get_err_code() < 0 )
-                    return;
-
-                if( i == 0 )
-                {
-                    t_acc = (double)(t1 - t0);
-                    t00 = t0;
-                }
-                else
+                for(;;)
                 {
-                    t0 = t1 - t0;
-                
-                    if( ts->get_timing_mode() == CvTS::MIN_TIME )
-                    {
-                        if( (double)t0 < t_acc )
-                            t_acc = (double)t0;
-                    }
-                    else
-                    {
-                        assert( ts->get_timing_mode() == CvTS::AVG_TIME );
-                        t_acc += (double)t0;
-                    }
-                
-                    if( t1 - t00 > freq*2000000 )
-                        break;
-                }
+                                       t0 = cv::getTickCount();
+                                       t2 = cv::getCPUTickCount();
+                                       run_func();
+                                       t3 = cv::getCPUTickCount();
+                                       t1 = cv::getTickCount();
+                                       if( ts->get_err_code() < 0 )
+                                               return;
+
+                                       if( t3 - t2 > 0 && t1 - t0 > 1 )
+                                               break;
+                               }
+
+                               if( i == 0 )
+                                       t00 = t0;
+                               v_cpe.push_back((double)(t3 - t2));
+                               v_time.push_back((double)(t1 - t0));
+                if( i >= 5 && t1 - t00 > freq*5 )
+                    break;
             }
 
-            if( ts->get_timing_mode() == CvTS::AVG_TIME )
-                t_acc /= i;
-            print_time( test_case_idx, t_acc );
+                       sort(v_cpe.begin(), v_cpe.end());
+                       sort(v_time.begin(), v_time.end());
+                       
+            t_cpu_acc = v_cpe[i/2];
+            t_acc = v_time[i/2];
+            print_time( test_case_idx, t_acc, t_cpu_acc );
         }
         else
         {
@@ -875,8 +909,6 @@ void CvTest::run( int start_from )
             if( validate_test_results( test_case_idx ) < 0 || ts->get_err_code() < 0 )
                 return;
         }
-
-        progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) );
     }
 }
 
@@ -905,14 +937,14 @@ int CvTest::validate_test_results( int )
 }
 
 
-void CvTest::print_time( int /*test_case_idx*/, double /*time_usecs*/ )
+void CvTest::print_time( int /*test_case_idx*/, double /*time_usecs*/, double /*time_cpu_clocks*/ )
 {
 }
 
 
 int CvTest::update_progress( int progress, int test_case_idx, int count, double dt )
 {
-    int width = 60 - strlen(get_name());
+    int width = 60 - (int)strlen(get_name());
     if( count > 0 )
     {
         int t = cvRound( ((double)test_case_idx * width)/count );
@@ -922,15 +954,81 @@ int CvTest::update_progress( int progress, int test_case_idx, int count, double
             progress = t;
         }
     }
-    else if( cvRound(dt*0.001) > progress )
+    else if( cvRound(dt) > progress )
     {
         ts->printf( CvTS::CONSOLE, "." );
-        progress = cvRound(dt*0.001);
+        progress = cvRound(dt);
     }
 
     return progress;
 }
 
+
+CvBadArgTest::CvBadArgTest( const char* _test_name, const char* _test_funcs, const char* _test_descr )
+  : CvTest( _test_name, _test_funcs, _test_descr )
+{
+    progress = -1;
+    test_case_idx = -1;
+    freq = cv::getTickFrequency();
+}
+
+CvBadArgTest::~CvBadArgTest()
+{
+}
+
+int CvBadArgTest::run_test_case( int expected_code, const char* descr )
+{
+    double new_t = (double)cv::getTickCount(), dt;
+    if( test_case_idx < 0 )
+    {
+        test_case_idx = 0;
+        progress = 0;
+        dt = 0;
+    }
+    else
+    {
+        dt = (new_t - t)/(freq*1000);
+        t = new_t;
+    }
+    progress = update_progress(progress, test_case_idx, 0, dt);
+    
+    int errcount = 0;
+    bool thrown = false;
+    if(!descr)
+        descr = "";
+    
+    try
+    {
+        run_func();
+    }
+    catch(const cv::Exception& e)
+    {
+        thrown = true;
+        if( e.code != expected_code )
+        {
+            ts->printf(CvTS::LOG, "%s (test case #%d): the error code %d is different from the expected %d\n",
+                descr, test_case_idx, e.code, expected_code);
+            errcount = 1;
+        }
+    }
+    catch(...)
+    {
+        thrown = true;
+        ts->printf(CvTS::LOG, "%s  (test case #%d): unknown exception was thrown (the function has likely crashed)\n",
+                   descr, test_case_idx);
+        errcount = 1;
+    }
+    if(!thrown)
+    {
+        ts->printf(CvTS::LOG, "%s  (test case #%d): no expected exception was thrown\n",
+                   descr, test_case_idx);
+        errcount = 1;
+    }
+    test_case_idx++;
+    
+    return errcount;
+}
+
 /*****************************************************************************************\
 *                                 Base Class for Test System                              *
 \*****************************************************************************************/
@@ -982,7 +1080,7 @@ void CvTS::clear()
             fclose( output_streams[i].f );
             output_streams[i].f = 0;
         }
-        
+
         if( i == LOG_IDX && output_streams[i].default_handle > 0 )
         {
             dup2( output_streams[i].default_handle, 2 );
@@ -998,13 +1096,14 @@ void CvTS::clear()
         free( ostrm_base_name );
         ostrm_base_name = 0;
     }
-    params.rng_seed = (uint64)-1;
-    params.debug_mode = 1;
+    params.rng_seed = 0;
+    params.debug_mode = -1;
     params.print_only_failed = 0;
     params.skip_header = 0;
     params.test_mode = CORRECTNESS_CHECK_MODE;
     params.timing_mode = MIN_TIME;
     params.use_optimized = -1;
+    params.color_terminal = 1;
 
     if( memory_manager )
         memory_manager->clear_and_check();
@@ -1014,6 +1113,7 @@ void CvTS::clear()
 CvTS::~CvTS()
 {
     clear();
+    set_data_path(0);
 
     if( written_params )
     {
@@ -1024,7 +1124,6 @@ CvTS::~CvTS()
 
     delete selected_tests;
     delete failed_tests;
-    cvSetMemoryManager( 0, 0 );
 }
 
 
@@ -1035,6 +1134,7 @@ const char* CvTS::str_from_code( int code )
     case OK: return "Ok";
     case FAIL_GENERIC: return "Generic/Unknown";
     case FAIL_MISSING_TEST_DATA: return "No test data";
+    case FAIL_INVALID_TEST_DATA: return "Invalid test data";
     case FAIL_ERROR_IN_CALLED_FUNC: return "cvError invoked";
     case FAIL_EXCEPTION: return "Hardware/OS exception";
     case FAIL_MEMORY_EXCEPTION: return "Invalid memory access";
@@ -1055,7 +1155,7 @@ const char* CvTS::str_from_code( int code )
 
 void CvTS::make_output_stream_base_name( const char* config_name )
 {
-    int k, len = strlen( config_name );
+    int k, len = (int)strlen( config_name );
 
     if( ostrm_base_name )
         free( ostrm_base_name );
@@ -1069,7 +1169,7 @@ void CvTS::make_output_stream_base_name( const char* config_name )
 
     if( k > 0 && config_name[k] == '.' )
         len = k;
-    
+
     ostrm_base_name = (char*)malloc( len + 1 );
     memcpy( ostrm_base_name, config_name, len );
     ostrm_base_name[len] = '\0';
@@ -1082,7 +1182,7 @@ void CvTS::set_handlers( bool on )
     {
         cvSetErrMode( CV_ErrModeParent );
         cvRedirectError( cvStdErrReport );
-    #ifdef WIN32
+    #if defined WIN32 || defined _WIN32
         #ifdef _MSC_VER
         _set_se_translator( cv_seh_translator );
         #endif
@@ -1095,7 +1195,7 @@ void CvTS::set_handlers( bool on )
     {
         cvSetErrMode( CV_ErrModeLeaf );
         cvRedirectError( cvGuiBoxReport );
-    #ifdef WIN32
+    #if defined WIN32 || defined _WIN32
         #ifdef _MSC_VER
         _set_se_translator( 0 );
         #endif
@@ -1107,6 +1207,25 @@ void CvTS::set_handlers( bool on )
 }
 
 
+void CvTS::set_data_path( const char* data_path )
+{
+    if( data_path == params.data_path )
+        return;
+
+    if( params.data_path )
+        delete[] params.data_path;
+    if( data_path )
+    {
+        int size = (int)strlen(data_path)+1;
+        bool append_slash = data_path[size-1] != '/' && data_path[size-1] != '\\';
+        params.data_path = new char[size+1];
+        memcpy( params.data_path, data_path, size );
+        if( append_slash )
+            strcat( params.data_path, "/" );
+    }
+}
+
+
 typedef struct CvTsParamVal
 {
     const char* fullname;
@@ -1119,9 +1238,9 @@ int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype,
     const char* testname = test->get_name();
     bool add_to_list = test->get_func_list()[0] == '\0';
     char buffer[256];
-    int paramname_len = strlen(paramname);
-    int paramval_len = valtype == CV_NODE_INT ? sizeof(int) :
-        valtype == CV_NODE_REAL ? sizeof(double) : -1;
+    int paramname_len = (int)strlen(paramname);
+    int paramval_len = valtype == CV_NODE_INT ? (int)sizeof(int) :
+        valtype == CV_NODE_REAL ? (int)sizeof(double) : -1;
     const char* name = CvTest::get_parent_name( testname, buffer );
 
     if( !fs )
@@ -1135,7 +1254,7 @@ int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype,
 
     while( name )
     {
-        int i, len = strlen(buffer);
+        int i, len = (int)strlen(buffer);
         buffer[len] = '.';
         memcpy( buffer + len + 1, paramname, paramname_len + 1 );
         for( i = 0; i < written_params->size(); i++ )
@@ -1143,8 +1262,8 @@ int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype,
             CvTsParamVal* param = (CvTsParamVal*)written_params->at(i);
             if( strcmp( param->fullname, buffer ) == 0 )
             {
-                if( paramval_len > 0 && memcmp( param->val, val, paramval_len ) == 0 ||
-                    paramval_len < 0 && strcmp( (const char*)param->val, (const char*)val ) == 0 )
+                if( (paramval_len > 0 && memcmp( param->val, val, paramval_len ) == 0) ||
+                    (paramval_len < 0 && strcmp( (const char*)param->val, (const char*)val ) == 0) )
                     return 1;
                 break;
             }
@@ -1157,10 +1276,10 @@ int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype,
 
     if( add_to_list )
     {
-        int bufsize, fullname_len = strlen(testname) + paramname_len + 2;
+        int bufsize, fullname_len = (int)strlen(testname) + paramname_len + 2;
         CvTsParamVal* param;
         if( paramval_len < 0 )
-            paramval_len = strlen((const char*)val) + 1;
+            paramval_len = (int)strlen((const char*)val) + 1;
         bufsize = sizeof(*param) + fullname_len + paramval_len;
         param = (CvTsParamVal*)malloc(bufsize);
         param->fullname = (const char*)(param + 1);
@@ -1186,14 +1305,19 @@ static int CV_CDECL cmp_test_names( const void* a, const void* b )
 int CvTS::run( int argc, char** argv )
 {
     time( &start_time );
-    
+
     int i, write_params = 0;
+    int list_tests = 0;
     CvTestPtrVec all_tests;
     CvTest* test;
 
     // 0. reset all the parameters, reorder tests
     clear();
 
+/*#if defined WIN32 || defined _WIN32
+       cv::setBreakOnError(true);
+#endif*/
+
     for( test = get_first_test(), i = 0; test != 0; test = test->get_next(), i++ )
         all_tests.push(test);
 
@@ -1203,20 +1327,69 @@ int CvTS::run( int argc, char** argv )
     // 1. parse command line options
     for( i = 1; i < argc; i++ )
     {
-        if( argv[i] && argv[i][0] != '-' )
+        if( strcmp( argv[i], "-h" ) == 0 || strcmp( argv[i], "--help" ) == 0 )
         {
-            config_name = argv[i];
-            break;
+            print_help();
+            return 0;
         }
-        else
+        else if( strcmp( argv[i], "-f" ) == 0 )
+            config_name = argv[++i];
+        else if( strcmp( argv[i], "-w" ) == 0 )
+            write_params = 1;
+        else if( strcmp( argv[i], "-t" ) == 0 )
+            params.test_mode = TIMING_MODE;
+        else if( strcmp( argv[i], "-O0" ) == 0 || strcmp( argv[i], "-O1" ) == 0 )
+            params.use_optimized = argv[i][2] - '0';
+        else if( strcmp( argv[i], "-l" ) == 0 )
+            list_tests = 1;
+        else if( strcmp( argv[i], "-d" ) == 0 )
+            set_data_path(argv[++i]);
+        else if( strcmp( argv[i], "-nc" ) == 0 )
+            params.color_terminal = 0;
+        else if( strcmp( argv[i], "-r" ) == 0 )
+            params.debug_mode = 0;
+        else if( strcmp( argv[i], "-tn" ) == 0 )
         {
-            if( strcmp( argv[i], "-w" ) == 0 )
-                write_params = 1;
-            else if( strcmp( argv[i], "-t" ) == 0 )
-                params.test_mode = TIMING_MODE;
+            params.test_filter_pattern = argv[++i];
+            params.test_filter_mode = CHOOSE_TESTS;
+        }
+        else if( strcmp( argv[i], "-seed" ) == 0 )
+        {
+            params.rng_seed = read_seed(argv[++i]);
+            if( params.rng_seed == 0 )
+                fprintf(stderr, "Invalid or zero RNG seed. Will use the seed from the config file or default one\n");
         }
     }
 
+#if 0
+//#if !defined WIN32 && !defined _WIN32
+    if (! config_name )
+    {    
+      char * confname = getenv("configname");
+      if (confname)
+        config_name = confname;
+    }
+    
+    if( !params.data_path || !params.data_path[0] )
+    {
+        char* datapath = getenv("datapath");
+        if( datapath )
+            set_data_path(datapath);
+    }
+    
+    // this is the fallback for the current OpenCV autotools setup
+    if( !params.data_path || !params.data_path[0] )
+    {
+        char* srcdir = getenv("srcdir");
+        char buf[1024];
+        if( srcdir )
+        {
+            sprintf( buf, "%s/../../opencv_extra/testdata/", srcdir );
+            set_data_path(buf);
+        }
+    }
+#endif
+
     if( write_params )
     {
         if( !config_name )
@@ -1227,7 +1400,7 @@ int CvTS::run( int argc, char** argv )
         fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_WRITE );
         if( !fs )
         {
-            printf( LOG, "ERROR: could not open config file %s", config_name );
+            printf( LOG, "ERROR: could not open config file %s\n", config_name );
             return -1;
         }
         cvWriteComment( fs, CV_TS_VERSION " config file", 0 );
@@ -1260,8 +1433,13 @@ int CvTS::run( int argc, char** argv )
         }
     }
 
-    if( read_params(fs) < 0 )
-        return -1;
+    if( params.test_mode == CORRECTNESS_CHECK_MODE || fs )
+    {
+        // in the case of algorithmic tests we always run read_params,
+        // even if there is no config file
+        if( read_params(fs) < 0 )
+            return -1;
+    }
 
     if( !ostrm_base_name )
         make_output_stream_base_name( config_name ? config_name : argv[0] );
@@ -1300,24 +1478,27 @@ int CvTS::run( int argc, char** argv )
         if( strcmp( test->get_func_list(), "" ) != 0 && filter(test) )
         {
             if( test->init(this) >= 0 )
+            {
                 selected_tests->push( test );
+                if( list_tests )
+                    ::printf( "%s\n", test->get_name() );
+            }
             else
                 printf( LOG, "WARNING: an error occured during test %s initialization\n", test->get_name() );
         }
     }
 
+    if( list_tests )
+    {
+        clear();
+        return 0;
+    }
+
     // 5. setup all the neccessary handlers and print header
     set_handlers( !params.debug_mode );
 
-    if( params.use_optimized >= 0 )
-    {
-        printf( LOG, params.use_optimized ? "Loading optimized plugins..." : "Unloading optimized plugins..." );
-        if( params.use_optimized == 0 )
-            cvUseOptimized(0);
-        /*else
-            cvUseOptimized(1); // this is done anyway, so we comment it off
-        */
-    }
+    if( params.use_optimized == 0 )
+        cvUseOptimized(0);
 
     if( !params.skip_header )
         print_summary_header( SUMMARY + LOG + CONSOLE + CSV );
@@ -1334,7 +1515,10 @@ int CvTS::run( int argc, char** argv )
         if( memory_manager )
             memory_manager->start_tracking();
         update_context( test, -1, true );
+        current_test_info.rng_seed0 = current_test_info.rng_seed;
+        
         ostream_testname_mask = 0; // reset "test name was printed" flags
+        logbuf = std::string();
         if( output_streams[LOG_IDX].f )
             fflush( output_streams[LOG_IDX].f );
 
@@ -1356,21 +1540,25 @@ int CvTS::run( int argc, char** argv )
             if( !params.print_only_failed )
             {
                 printf( SUMMARY + CONSOLE, "\t" );
-                change_color( CV_TS_GREEN );
+                set_color( CV_TS_GREEN );
                 printf( SUMMARY + CONSOLE, "Ok\n" );
-                change_color( CV_TS_NORMAL );
+                set_color( CV_TS_NORMAL );
             }
         }
         else
         {
             printf( SUMMARY + CONSOLE, "\t" );
-            change_color( CV_TS_RED );
+            set_color( CV_TS_RED );
             printf( SUMMARY + CONSOLE, "FAIL(%s)\n", str_from_code(code) );
-            change_color( CV_TS_NORMAL );
+            set_color( CV_TS_NORMAL );
             printf( LOG, "context: test case = %d, seed = %08x%08x\n",
                     current_test_info.test_case_idx,
                     (unsigned)(current_test_info.rng_seed>>32),
                     (unsigned)(current_test_info.rng_seed));
+            if(logbuf.size() > 0)
+            {
+                printf( SUMMARY + CONSOLE, ">>>\n%s\n", logbuf.c_str());
+            }
             failed_tests->push(current_test_info);
             if( params.rerun_immediately )
                 break;
@@ -1396,50 +1584,81 @@ int CvTS::run( int argc, char** argv )
             test->safe_run( info.test_case_idx );
         }
     }
-
+    int nfailed = failed_tests ? (int)failed_tests->size() : 0;
     clear();
 
-    return 0;
+    return nfailed;
 }
 
 
+void CvTS::print_help()
+{
+    ::printf(
+        "Usage: <test_executable> [{-h|--help}][-l] [-r] [-w] [-t] [-f <config_name>] [-d <data_path>] [-O{0|1}] [-tn <test_name>]\n\n"
+        "-d - specify the test data path\n"
+        "-f - use parameters from the provided XML/YAML config file\n"
+        "     instead of the default parameters\n"
+        "-h or --help - print this help information\n"
+        "-l - list all the registered tests or subset of the tests,\n"
+        "     selected in the config file, and exit\n"
+        "-tn - only run a specific test\n"
+        "-nc - do not use colors in the console output\n"     
+        "-O{0|1} - disable/enable on-fly detection of IPP and other\n"
+        "          supported optimized libs. It's enabled by default\n"
+        "-r - continue running tests after OS/Hardware exception occured\n"
+        "-t - switch to the performance testing mode instead of\n"
+        "     the default algorithmic/correctness testing mode\n"
+        "-w - write default parameters of the algorithmic or\n"
+        "     performance (when -t is passed) tests to the specifed\n"
+        "     config file (see -f) and exit\n\n"
+        //"Test data path and config file can also be specified by the environment variables 'config' and 'datapath'.\n\n"
+        );
+}
+
+
+#if defined WIN32 || defined _WIN32
+const char* default_data_path = "../tests/cv/testdata/";
+#else
+const char* default_data_path = "../../../../tests/cv/testdata/";
+#endif
+
+
 int CvTS::read_params( CvFileStorage* fs )
 {
     CvFileNode* node = fs ? cvGetFileNodeByName( fs, 0, "common" ) : 0;
-    params.debug_mode = cvReadIntByName( fs, node, "debug_mode", 1 ) != 0;
+    if(params.debug_mode < 0)
+        params.debug_mode = cvReadIntByName( fs, node, "debug_mode", 1 ) != 0;
     params.skip_header = cvReadIntByName( fs, node, "skip_header", 0 ) != 0;
     params.print_only_failed = cvReadIntByName( fs, node, "print_only_failed", 0 ) != 0;
     params.rerun_failed = cvReadIntByName( fs, node, "rerun_failed", 0 ) != 0;
     params.rerun_immediately = cvReadIntByName( fs, node, "rerun_immediately", 0 ) != 0;
     const char* str = cvReadStringByName( fs, node, "filter_mode", "tests" );
     params.test_filter_mode = strcmp( str, "functions" ) == 0 ? CHOOSE_FUNCTIONS : CHOOSE_TESTS;
-    str = cvReadStringByName( fs, node, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" ); 
+    str = cvReadStringByName( fs, node, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
     params.test_mode = strcmp( str, "timing" ) == 0 || strcmp( str, "performance" ) == 0 ?
                         TIMING_MODE : CORRECTNESS_CHECK_MODE;
-    str = cvReadStringByName( fs, node, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" ); 
+    str = cvReadStringByName( fs, node, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
     params.timing_mode = strcmp( str, "average" ) == 0 || strcmp( str, "avg" ) == 0 ? AVG_TIME : MIN_TIME;
-    params.test_filter_pattern = cvReadStringByName( fs, node, params.test_filter_mode == CHOOSE_FUNCTIONS ?
+    params.test_filter_pattern = params.test_filter_pattern != 0 &&
+               strlen(params.test_filter_pattern) > 0 ? params.test_filter_pattern :
+               cvReadStringByName( fs, node, params.test_filter_mode == CHOOSE_FUNCTIONS ?
                                                      "functions" : "tests", "" );
     params.resource_path = cvReadStringByName( fs, node, "." );
-    params.use_optimized = cvReadIntByName( fs, node, "use_optimized", -1 );
-    str = cvReadStringByName( fs, node, "seed", 0 );
-    params.rng_seed = 0;
-    if( str && strlen(str) == 16 )
+    if( params.use_optimized < 0 )
+        params.use_optimized = cvReadIntByName( fs, node, "use_optimized", -1 );
+    if( !params.data_path || !params.data_path[0] )
     {
-        params.rng_seed = 0;
-        for( int i = 0; i < 16; i++ )
-        {
-            int c = tolower(str[i]);
-            if( !isxdigit(c) )
-            {
-                params.rng_seed = 0;
-                break;
-            }
-            params.rng_seed = params.rng_seed * 16 +
-                (str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10);
-        }
+        const char* data_path =
+            cvReadStringByName( fs, node, "data_path", default_data_path );
+        set_data_path(data_path);
     }
-    
+    params.test_case_count_scale = cvReadRealByName( fs, node, "test_case_count_scale", 1. );
+    if( params.test_case_count_scale <= 0 )
+        params.test_case_count_scale = 1.;
+    str = cvReadStringByName( fs, node, "seed", 0 );
+    if( str && params.rng_seed == 0 )
+        params.rng_seed = read_seed(str);
+
     if( params.rng_seed == 0 )
         params.rng_seed = cvGetTickCount();
 
@@ -1462,6 +1681,7 @@ void CvTS::write_default_params( CvFileStorage* fs )
     cvWriteInt( fs, "rerun_immediately", params.rerun_immediately );
     cvWriteString( fs, "filter_mode", params.test_filter_mode == CHOOSE_FUNCTIONS ? "functions" : "tests" );
     cvWriteString( fs, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
+    cvWriteString( fs, "data_path", params.data_path ? params.data_path : default_data_path, 1 );
     if( params.test_mode == TIMING_MODE )
         cvWriteString( fs, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
     // test_filter, seed & output_file_base_name are not written
@@ -1515,7 +1735,7 @@ const char* CvTS::get_libs_info( const char** addon_modules )
 void CvTS::print_summary_header( int streams )
 {
     char csv_header[256], *ptr = csv_header;
-    int i, len;
+    int i;
 
     printf( streams, "Engine: %s\n", version );
     time_t t1;
@@ -1531,22 +1751,20 @@ void CvTS::print_summary_header( int streams )
     printf( streams, "Optimized Low-level Plugin\'s: %s\n", plugins );
     printf( streams, "=================================================\n");
 
-    len = 0;
-    sprintf( ptr, "funcName,dataType,channels,size,%n", &len );
-    ptr += len;
+    sprintf( ptr, "funcName,dataType,channels,size," );
+    ptr += strlen(ptr);
 
     for( i = 0; i < CvTest::TIMING_EXTRA_PARAMS; i++ )
     {
-        len = 0;
-        sprintf( ptr, "param%d,%n", i, &len );
-        ptr += len;
+        sprintf( ptr, "param%d,", i );
+        ptr += strlen(ptr);
     }
 
     sprintf( ptr, "CPE,Time(uSecs)" );
     printf( CSV, "%s\n", csv_header );
 }
 
-    
+
 void CvTS::print_summary_tailer( int streams )
 {
     printf( streams, "=================================================\n");
@@ -1565,13 +1783,17 @@ void CvTS::print_summary_tailer( int streams )
     }
 }
 
+#if defined _MSC_VER && _MSC_VER < 1400
+#undef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
 
 void CvTS::vprintf( int streams, const char* fmt, va_list l )
 {
     if( streams )
     {
         char str[1 << 14];
-        vsprintf( str, fmt, l );
+        vsnprintf( str, sizeof(str)-1, fmt, l );
 
         for( int i = 0; i < MAX_IDX; i++ )
         {
@@ -1584,11 +1806,18 @@ void CvTS::vprintf( int streams, const char* fmt, va_list l )
                     if( i != CSV_IDX && !(ostream_testname_mask & (1 << i)) && current_test_info.test )
                     {
                         fprintf( f, "-------------------------------------------------\n" );
+                        if( i == CONSOLE_IDX || i == SUMMARY_IDX )
+                                                       fprintf( f, "[%08x%08x]\n", (int)(current_test_info.rng_seed0 >> 32),
+                                                           (int)(current_test_info.rng_seed0));
                         fprintf( f, "%s: ", current_test_info.test->get_name() );
                         fflush( f );
                         ostream_testname_mask |= 1 << i;
+                        if( i == LOG_IDX )
+                            logbuf = std::string();
                     }
                     fputs( str, f );
+                    if( i == LOG_IDX )
+                        logbuf += std::string(str);
                     if( i == CONSOLE_IDX )
                         fflush(f);
                 }
@@ -1609,6 +1838,11 @@ void CvTS::printf( int streams, const char* fmt, ... )
     }
 }
 
+void CvTS::set_color(int color)
+{
+    if( params.color_terminal )
+        change_color(color);
+}
 
 static char* cv_strnstr( const char* str, int len,
                          const char* pattern,
@@ -1621,10 +1855,10 @@ static char* cv_strnstr( const char* str, int len,
         return (char*)strstr( str, pattern );
 
     if( len < 0 )
-        len = strlen( str );
+        len = (int)strlen( str );
 
     if( pattern_len < 0 )
-        pattern_len = strlen( pattern );
+        pattern_len = (int)strlen( pattern );
 
     for( i = 0; i < len - pattern_len + 1; i++ )
     {
@@ -1632,8 +1866,8 @@ static char* cv_strnstr( const char* str, int len,
         if( str[i] == pattern[0] &&
             memcmp( str + i, pattern, pattern_len ) == 0 &&
             (!whole_word ||
-            ((i == 0 || !isalnum(str[i-1]) && str[i-1] != '_') &&
-             (j == len || !isalnum(str[j]) && str[j] != '_'))))
+            ((i == 0 || (!isalnum(str[i-1]) && str[i-1] != '_')) &&
+             (j == len || (!isalnum(str[j]) && str[j] != '_')))))
             return (char*)(str + i);
     }
 
@@ -1644,14 +1878,21 @@ static char* cv_strnstr( const char* str, int len,
 int CvTS::filter( CvTest* test )
 {
     const char* pattern = params.test_filter_pattern;
+    int inverse = 0;
+
+    if( pattern && pattern[0] == '!' )
+    {
+        inverse = 1;
+        pattern++;
+    }
 
     if( !pattern || strcmp( pattern, "" ) == 0 || strcmp( pattern, "*" ) == 0 )
-        return 1;
+        return 1 ^ inverse;
 
     if( params.test_filter_mode == CHOOSE_TESTS )
     {
         int found = 0;
-        
+
         while( pattern && *pattern )
         {
             char *ptr, *endptr = (char*)strchr( pattern, ',' );
@@ -1664,17 +1905,17 @@ int CvTS::filter( CvTest* test )
             ptr = (char*)strchr( pattern, '*' );
             if( ptr )
             {
-                len = ptr - pattern;
+                len = (int)(ptr - pattern);
                 have_wildcard = 1;
             }
             else
             {
-                len = strlen( pattern );
+                len = (int)strlen( pattern );
                 have_wildcard = 0;
             }
 
-            t_name_len = strlen( test->get_name() );
-            found = (t_name_len == len || have_wildcard && t_name_len > len) &&
+            t_name_len = (int)strlen( test->get_name() );
+            found = (t_name_len == len || (have_wildcard && t_name_len > len)) &&
                     (len == 0 || memcmp( test->get_name(), pattern, len ) == 0);
             if( endptr )
             {
@@ -1688,12 +1929,12 @@ int CvTS::filter( CvTest* test )
                 break;
         }
 
-        return found;
+        return found ^ inverse;
     }
     else
     {
         assert( params.test_filter_mode == CHOOSE_FUNCTIONS );
-        int glob_len = strlen( pattern );
+        int glob_len = (int)strlen( pattern );
         const char* ptr = test->get_func_list();
         const char *tmp_ptr;
 
@@ -1721,7 +1962,7 @@ int CvTS::filter( CvTest* test )
             {
                 assert( endptr[1] == ':' );
                 endptr = endptr + 2;
-                name_len = endptr - name_ptr;
+                name_len = (int)(endptr - name_ptr);
 
                 // find the first occurence of the class name
                 // in pattern
@@ -1731,7 +1972,7 @@ int CvTS::filter( CvTest* test )
                 if( *endptr == '*' )
                 {
                     if( name_first_match )
-                        return 1;
+                        return 1 ^ inverse;
                 }
                 else
                 {
@@ -1759,12 +2000,12 @@ int CvTS::filter( CvTest* test )
                         assert( isalpha(c) );
 
                         method_name_ptr = endptr;
-                    
+
                         do c = *++endptr;
                         while( isalnum(c) || c == '_' );
-                    
-                        method_name_len = endptr - method_name_ptr;
-                    
+
+                        method_name_len = (int)(endptr - method_name_ptr);
+
                         // search for class_name::* or
                         // class_name::{...method_name...}
                         tmp_ptr = name_first_match;
@@ -1778,12 +2019,12 @@ int CvTS::filter( CvTest* test )
                             tmp_ptr2 = strchr( tmp_ptr, '}' );
                             assert( tmp_ptr2 );
 
-                            if( cv_strnstr( tmp_ptr, tmp_ptr2 - tmp_ptr + 1,
+                            if( cv_strnstr( tmp_ptr, (int)(tmp_ptr2 - tmp_ptr) + 1,
                                              method_name_ptr, method_name_len, 1 ))
-                                return 1;
+                                return 1 ^ inverse;
 
                             tmp_ptr = cv_strnstr( tmp_ptr2, glob_len -
-                                                   (tmp_ptr2 - pattern),
+                                                   (int)(tmp_ptr2 - pattern),
                                                    name_ptr, name_len, 1 );
                         }
                         while( tmp_ptr );
@@ -1800,7 +2041,7 @@ int CvTS::filter( CvTest* test )
             else
             {
                 assert( !c || isspace(c) || c == ',' );
-                name_len = endptr - name_ptr;
+                name_len = (int)(endptr - name_ptr);
                 tmp_ptr = pattern;
 
                 for(;;)
@@ -1808,7 +2049,7 @@ int CvTS::filter( CvTest* test )
                     const char *tmp_ptr2, *tmp_ptr3;
 
                     tmp_ptr = cv_strnstr( tmp_ptr, glob_len -
-                        (tmp_ptr - pattern), name_ptr, name_len, 1 );
+                        (int)(tmp_ptr - pattern), name_ptr, name_len, 1 );
 
                     if( !tmp_ptr )
                         break;
@@ -1816,11 +2057,11 @@ int CvTS::filter( CvTest* test )
                     // make sure it is not a method
                     tmp_ptr2 = strchr( tmp_ptr, '}' );
                     if( !tmp_ptr2 )
-                        return 1;
+                        return 1 ^ inverse;
 
                     tmp_ptr3 = strchr( tmp_ptr, '{' );
                     if( tmp_ptr3 < tmp_ptr2 )
-                        return 1;
+                        return 1 ^ inverse;
 
                     tmp_ptr = tmp_ptr2 + 1;
                 }
@@ -1836,7 +2077,7 @@ int CvTS::filter( CvTest* test )
             ptr = endptr;
         }
 
-        return 0;
+        return 0 ^ inverse;
     }
 }