]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/tests/cxts/cxts.cpp
round scalars in the case of integer arrays in adds, subrs and absdiffs tests (will...
[opencv.git] / opencv / tests / cxts / cxts.cpp
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 "_cxts.h"
43 #include <ctype.h>
44 #include <stdarg.h>
45 #include <fcntl.h>
46 #include <time.h>
47 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
48 #include <io.h>
49 #else
50 #include <unistd.h>
51 #endif
52
53 CvTest* CvTest::first = 0;
54 CvTest* CvTest::last = 0;
55 int CvTest::test_count = 0;
56
57 /*****************************************************************************************\
58 *                                Exception and memory handlers                            *
59 \*****************************************************************************************/
60
61 // a few platform-dependent declarations
62
63 #define CV_TS_NORMAL 0
64 #define CV_TS_BLUE   1
65 #define CV_TS_GREEN  2
66 #define CV_TS_RED    4
67
68 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
69 #include <windows.h>
70
71 #ifdef _MSC_VER
72 #include <eh.h>
73 #endif
74
75 #ifdef _MSC_VER
76 static void cv_seh_translator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp )
77 {
78     int code = CvTS::FAIL_EXCEPTION;
79     switch( pExp->ExceptionRecord->ExceptionCode )
80     {
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;
88         break;
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;
98         break;
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;
106     }
107     throw code;
108 }
109 #endif
110
111 static void change_color( int color )
112 {
113     static int normal_attributes = -1;
114     HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
115     fflush(stdout);
116
117     if( normal_attributes < 0 )
118     {
119         CONSOLE_SCREEN_BUFFER_INFO info;
120         GetConsoleScreenBufferInfo( hstdout, &info );
121         normal_attributes = info.wAttributes;
122     }
123
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)) );
129 }
130
131 #else
132
133 #include <signal.h>
134
135 static const int cv_ts_sig_id[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT, -1 };
136
137 static jmp_buf cv_ts_jmp_mark;
138
139 void cv_signal_handler( int sig_code )
140 {
141     int code = CvTS::FAIL_EXCEPTION;
142     switch( sig_code )
143     {
144     case SIGFPE:
145         code = CvTS::FAIL_ARITHM_EXCEPTION;
146         break;
147     case SIGSEGV:
148     case SIGBUS:
149         code = CvTS::FAIL_ARITHM_EXCEPTION;
150         break;
151     case SIGILL:
152         code = CvTS::FAIL_EXCEPTION;
153     }
154
155     longjmp( cv_ts_jmp_mark, code );
156 }
157
158 static void change_color( int color )
159 {
160     static const uchar ansi_tab[] = { 30, 34, 32, 36, 31, 35, 33, 37 };
161     char buf[16];
162     int code = 0;
163     fflush( stdout );
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 );
168 }
169
170 #endif
171
172
173 // reads 16-digit hexadecimal number (i.e. 64-bit integer)
174 static int64 read_seed( const char* str )
175 {
176     int64 val = 0;
177     if( str && strlen(str) == 16 )
178     {
179         for( int i = 0; str[i]; i++ )
180         {
181             int c = tolower(str[i]);
182             if( !isxdigit(c) )
183                 return 0;
184             val = val * 16 +
185             (str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10);
186         }
187     }
188     return val;
189 }
190
191
192 /***************************** memory manager *****************************/
193
194 typedef struct CvTestAllocBlock
195 {
196     struct CvTestAllocBlock* prev;
197     struct CvTestAllocBlock* next;
198     char* origin;
199     char* data;
200     size_t size;
201     int index;
202 }
203 CvTestAllocBlock;
204
205
206 class CvTestMemoryManager
207 {
208 public:
209     CvTestMemoryManager( CvTS* ts );
210     virtual ~CvTestMemoryManager();
211
212     virtual void clear_and_check( int min_index = -1 );
213     virtual void start_tracking( int index_to_stop_at=-1 );
214     virtual void stop_tracking_and_check();
215     int get_alloc_index() { return index; }
216
217     static void* alloc_proxy( size_t size, void* userdata );
218     static int free_proxy( void* ptr, void* userdata );
219
220 protected:
221     virtual void* alloc( size_t size );
222     virtual int free( void* ptr );
223     virtual int free_block( CvTestAllocBlock* block );
224
225     int index;
226     int track_blocks;
227     int show_msg_box;
228     int index_to_stop_at;
229     const char* guard_pattern;
230     int guard_size;
231     int block_align;
232     enum { MAX_MARKS = 1024 };
233     int marks[MAX_MARKS];
234     int marks_top;
235     CvTS* ts;
236     CvTestAllocBlock* first;
237     CvTestAllocBlock* last;
238 };
239
240
241 void* CvTestMemoryManager::alloc_proxy( size_t size, void* userdata )
242 {
243     return ((CvTestMemoryManager*)userdata)->alloc( size );
244 }
245
246
247 int CvTestMemoryManager::free_proxy( void* ptr, void* userdata )
248 {
249     return ((CvTestMemoryManager*)userdata)->free( ptr );
250 }
251
252
253 CvTestMemoryManager::CvTestMemoryManager( CvTS* _test_system )
254 {
255     ts = _test_system;
256     guard_pattern = "THIS IS A GUARD PATTERN!";
257     guard_size = (int)strlen(guard_pattern);
258     block_align = CV_MALLOC_ALIGN;
259     track_blocks = 0;
260     marks_top = 0;
261     first = last = 0;
262     index = 0;
263     index_to_stop_at = -1;
264     show_msg_box = 1;
265 }
266
267
268 CvTestMemoryManager::~CvTestMemoryManager()
269 {
270     clear_and_check();
271 }
272
273
274 void CvTestMemoryManager::clear_and_check( int min_index )
275 {
276     int alloc_index = -1;
277     CvTestAllocBlock* block;
278     int leak_size = 0, leak_block_count = 0, mem_size = 0;
279     void* mem_addr = 0;
280
281     while( marks_top > 0 && marks[marks_top - 1] >= min_index )
282         marks_top--;
283
284     for( block = last; block != 0; )
285     {
286         CvTestAllocBlock* prev = block->prev;
287         if( block->index < min_index )
288             break;
289         leak_size += (int)block->size;
290         leak_block_count++;
291         alloc_index = block->index;
292         mem_addr = block->data;
293         mem_size = (int)block->size;
294         free_block( block );
295         block = prev;
296     }
297     track_blocks--;
298     if( leak_block_count > 0 )
299     {
300         ts->set_failed_test_info( CvTS::FAIL_MEMORY_LEAK, alloc_index );
301         ts->printf( CvTS::LOG, "Memory leaks: %u blocks, %u bytes total\n"
302                     "%s leaked block: %p, %u bytes\n",
303                     leak_block_count, leak_size, leak_block_count > 1 ? "The first" : "The",
304                     mem_addr, mem_size );
305     }
306
307     index = block ? block->index + 1 : 0;
308 }
309
310
311 void CvTestMemoryManager::start_tracking( int _index_to_stop_at )
312 {
313     track_blocks--;
314     marks[marks_top++] = index;
315     assert( marks_top <= MAX_MARKS );
316     track_blocks+=2;
317     index_to_stop_at = _index_to_stop_at >= index ? _index_to_stop_at : -1;
318 }
319
320
321 void CvTestMemoryManager::stop_tracking_and_check()
322 {
323     if( marks_top > 0 )
324     {
325         int min_index = marks[--marks_top];
326         clear_and_check( min_index );
327     }
328 }
329
330
331 int CvTestMemoryManager::free_block( CvTestAllocBlock* block )
332 {
333     int code = 0;
334     char* data = block->data;
335
336     if( block->origin == 0 || ((size_t)block->origin & (sizeof(double)-1)) != 0 )
337         code = CvTS::FAIL_MEMORY_CORRUPTION_BEGIN;
338
339     if( memcmp( data - guard_size, guard_pattern, guard_size ) != 0 )
340         code = CvTS::FAIL_MEMORY_CORRUPTION_BEGIN;
341     else if( memcmp( data + block->size, guard_pattern, guard_size ) != 0 )
342         code = CvTS::FAIL_MEMORY_CORRUPTION_END;
343
344     if( code >= 0 )
345     {
346         if( block->prev )
347             block->prev->next = block->next;
348         else if( first == block )
349             first = block->next;
350
351         if( block->next )
352             block->next->prev = block->prev;
353         else if( last == block )
354             last = block->prev;
355
356         free( block->origin );
357     }
358     else
359     {
360         ts->set_failed_test_info( code, block->index );
361         ts->printf( CvTS::LOG, "Corrupted block (%s): %p, %u bytes\n",
362                     code == CvTS::FAIL_MEMORY_CORRUPTION_BEGIN ? "beginning" : "end",
363                     block->data, block->size );
364     }
365
366     return code;
367 }
368
369
370 void* CvTestMemoryManager::alloc( size_t size )
371 {
372     char* data;
373     CvTestAllocBlock* block;
374     size_t new_size = sizeof(*block) + size + guard_size*2 + block_align + sizeof(size_t)*2;
375     char* ptr = (char*)malloc( new_size );
376
377     if( !ptr )
378         return 0;
379
380     data = (char*)cvAlignPtr( ptr + sizeof(size_t) + sizeof(*block) + guard_size, block_align );
381     block = (CvTestAllocBlock*)cvAlignPtr( data - guard_size -
382             sizeof(size_t) - sizeof(*block), sizeof(size_t) );
383     block->origin = ptr;
384     block->data = data;
385     block->size = 0;
386     block->index = -1;
387     block->next = block->prev = 0;
388     memcpy( data - guard_size, guard_pattern, guard_size );
389     memcpy( data + size, guard_pattern, guard_size );
390
391     if( track_blocks > 0 )
392     {
393         track_blocks--;
394         block->size = size;
395
396         if( index == index_to_stop_at )
397         {
398             if( show_msg_box )
399             {
400         #if defined WIN32 || defined _WIN32
401                 MessageBox( NULL, "The block that is corrupted and/or not deallocated has been just allocated\n"
402                             "Press Ok to start debugging", "Memory Manager", MB_ICONERROR|MB_OK|MB_SYSTEMMODAL );
403         #endif
404             }
405             CV_DBG_BREAK();
406         }
407
408         block->index = index++;
409
410         block->prev = last;
411         block->next = 0;
412         if( last )
413             last = last->next = block;
414         else
415             first = last = block;
416
417         track_blocks++;
418     }
419
420     return data;
421 }
422
423
424 int CvTestMemoryManager::free( void* ptr )
425 {
426     char* data = (char*)ptr;
427     CvTestAllocBlock* block = (CvTestAllocBlock*)
428         cvAlignPtr( data - guard_size - sizeof(size_t) - sizeof(*block), sizeof(size_t) );
429
430     int code = free_block( block );
431     if( code < 0 && ts->is_debug_mode() )
432         CV_DBG_BREAK();
433     return 0;
434 }
435
436
437 /***************************** error handler *****************************/
438
439 #if 0
440 static int cvTestErrorCallback( int status, const char* func_name, const char* err_msg,
441                          const char* file_name, int line, void* userdata )
442 {
443     if( status < 0 && status != CV_StsBackTrace && status != CV_StsAutoTrace )
444         ((CvTS*)userdata)->set_failed_test_info( CvTS::FAIL_ERROR_IN_CALLED_FUNC );
445
446     // print error message
447     return cvStdErrReport( status, func_name, err_msg, file_name, line, 0 );
448 }
449 #endif
450
451 /*****************************************************************************************\
452 *                                    Base Class for Tests                                 *
453 \*****************************************************************************************/
454
455 CvTest::CvTest( const char* _test_name, const char* _test_funcs, const char* _test_descr ) :
456     name(_test_name ? _test_name : ""), tested_functions(_test_funcs ? _test_funcs : ""),
457     description(_test_descr ? _test_descr : ""), ts(0)
458 {
459     if( last )
460         last->next = this;
461     else
462         first = this;
463     last = this;
464     test_count++;
465     ts = 0;
466     hdr_state = 0;
467
468     timing_param_names = 0;
469     timing_param_current = 0;
470     timing_param_seqs = 0;
471     timing_param_idxs = 0;
472     timing_param_count = -1;
473
474     test_case_count = -1;
475     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
476 }
477
478 CvTest::~CvTest()
479 {
480     clear();
481 }
482
483 CvTest* CvTest::get_first_test()
484 {
485     return first;
486 }
487
488 void CvTest::clear()
489 {
490     if( timing_param_current )
491         free( timing_param_current );
492     if( timing_param_seqs )
493         free( timing_param_seqs );
494     if( timing_param_idxs )
495         free( timing_param_idxs );
496
497     timing_param_current = 0;
498     timing_param_seqs = 0;
499     timing_param_idxs = 0;
500     timing_param_count = -1;
501 }
502
503
504 int CvTest::init( CvTS* _test_system )
505 {
506     clear();
507     ts = _test_system;
508     return read_params( ts->get_file_storage() );
509 }
510
511
512 const char* CvTest::get_parent_name( const char* name, char* buffer )
513 {
514     const char* dash_pos = strrchr( name ? name : "", '-' );
515     if( !dash_pos )
516         return 0;
517
518     if( name != (const char*)buffer )
519         strncpy( buffer, name, dash_pos - name );
520     buffer[dash_pos - name] = '\0';
521     return buffer;
522 }
523
524
525 const CvFileNode* CvTest::find_param( CvFileStorage* fs, const char* param_name )
526 {
527     char buffer[256];
528     const char* name = get_name();
529     CvFileNode* node = 0;
530
531     for(;;)
532     {
533         if( !name )
534             break;
535         node = cvGetFileNodeByName( fs, 0, name );
536         if( node )
537         {
538             node = cvGetFileNodeByName( fs, node, param_name );
539             if( node )
540                 break;
541         }
542         name = get_parent_name( name, buffer );
543     }
544
545     return node;
546 }
547
548
549 void CvTest::start_write_param( CvFileStorage* fs )
550 {
551     if( hdr_state == 0 )
552     {
553         cvStartWriteStruct( fs, get_name(), CV_NODE_MAP );
554         hdr_state = 1;
555     }
556 }
557
558
559 void CvTest::write_param( CvFileStorage* fs, const char* paramname, int val )
560 {
561     if( !ts->find_written_param( this, paramname, CV_NODE_INT, &val) )
562     {
563         start_write_param( fs );
564         cvWriteInt( fs, paramname, val );
565     }
566 }
567
568
569 void CvTest::write_param( CvFileStorage* fs, const char* paramname, double val )
570 {
571     if( !ts->find_written_param( this, paramname, CV_NODE_REAL, &val) )
572     {
573         start_write_param( fs );
574         cvWriteReal( fs, paramname, val );
575     }
576 }
577
578
579 void CvTest::write_param( CvFileStorage* fs, const char* paramname, const char* val )
580 {
581     if( !ts->find_written_param( this, paramname, CV_NODE_STRING, &val) )
582     {
583         start_write_param( fs );
584         cvWriteString( fs, paramname, val );
585     }
586 }
587
588
589 void CvTest::write_string_list( CvFileStorage* fs, const char* paramname, const char** val, int count )
590 {
591     if( val )
592     {
593         start_write_param( fs );
594         int i;
595         if( count < 0 )
596             count = INT_MAX;
597
598         cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
599         for( i = 0; i < count && val[i] != 0; i++ )
600             cvWriteString( fs, 0, val[i] );
601         cvEndWriteStruct( fs );
602     }
603 }
604
605
606 void CvTest::write_int_list( CvFileStorage* fs, const char* paramname,
607                              const int* val, int count, int stop_value )
608 {
609     if( val )
610     {
611         start_write_param( fs );
612         int i;
613         if( count < 0 )
614             count = INT_MAX;
615
616         cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
617         for( i = 0; i < count && val[i] != stop_value; i++ )
618             cvWriteInt( fs, 0, val[i] );
619         cvEndWriteStruct( fs );
620     }
621 }
622
623
624 void CvTest::write_real_list( CvFileStorage* fs, const char* paramname,
625                               const double* val, int count, double stop_value )
626 {
627     if( val )
628     {
629         start_write_param( fs );
630         int i;
631         if( count < 0 )
632             count = INT_MAX;
633
634         cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
635         for( i = 0; i < count && val[i] != stop_value; i++ )
636             cvWriteReal( fs, 0, val[i] );
637         cvEndWriteStruct( fs );
638     }
639 }
640
641
642 int CvTest::read_params( CvFileStorage* fs )
643 {
644     int code = 0;
645     
646     if(fs == NULL) return code; 
647
648     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
649     {
650         timing_param_names = find_param( fs, "timing_params" );
651         if( CV_NODE_IS_SEQ(timing_param_names->tag) )
652         {
653             CvSeq* seq = timing_param_names->data.seq;
654             CvSeqReader reader;
655             cvStartReadSeq( seq, &reader );
656             int i;
657
658             timing_param_count = seq->total;
659             timing_param_seqs = (const CvFileNode**)malloc( timing_param_count*sizeof(timing_param_seqs[0]));
660             timing_param_idxs = (int*)malloc( timing_param_count*sizeof(timing_param_idxs[0]));
661             timing_param_current = (const CvFileNode**)malloc( timing_param_count*sizeof(timing_param_current[0]));
662             test_case_count = 1;
663
664             for( i = 0; i < timing_param_count; i++ )
665             {
666                 CvFileNode* param_name = (CvFileNode*)(reader.ptr);
667
668                 if( !CV_NODE_IS_STRING(param_name->tag) )
669                 {
670                     ts->printf( CvTS::LOG, "ERROR: name of timing parameter #%d is not a string\n", i );
671                     code = -1;
672                     break;
673                 }
674
675                 timing_param_idxs[i] = 0;
676                 timing_param_current[i] = 0;
677                 timing_param_seqs[i] = find_param( fs, param_name->data.str.ptr );
678                 if( !timing_param_seqs[i] )
679                 {
680                     ts->printf( CvTS::LOG, "ERROR: timing parameter %s is not found\n", param_name->data.str.ptr );
681                     code = -1;
682                     break;
683                 }
684
685                 if( CV_NODE_IS_SEQ(timing_param_seqs[i]->tag) )
686                     test_case_count *= timing_param_seqs[i]->data.seq->total;
687
688                 CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
689             }
690
691             if( i < timing_param_count )
692                 timing_param_count = 0;
693         }
694         else
695         {
696             ts->printf( CvTS::LOG, "ERROR: \"timing_params\" is not found" );
697             code = -1;
698         }
699     }
700
701     return code;
702 }
703
704
705 int CvTest::get_next_timing_param_tuple()
706 {
707     bool increment;
708     int i;
709
710     if( timing_param_count <= 0 || !timing_param_names || !timing_param_seqs )
711         return -1;
712
713     increment = timing_param_current[0] != 0; // if already have some valid test tuple, move to the next
714     for( i = 0; i < timing_param_count; i++ )
715     {
716         const CvFileNode* node = timing_param_seqs[i];
717         int total = CV_NODE_IS_SEQ(node->tag) ? node->data.seq->total : 1;
718         int new_idx = timing_param_idxs[i];
719
720         if( !timing_param_current[i] )
721             timing_param_idxs[i] = new_idx = 0;
722         else if( increment )
723         {
724             new_idx++;
725             if( new_idx >= total )
726                 new_idx = 0;
727             else if( total > 1 )
728                 increment = false;
729         }
730
731         if( !timing_param_current[i] || new_idx != timing_param_idxs[i] )
732         {
733             if( CV_NODE_IS_SEQ(node->tag) )
734                 timing_param_current[i] = (CvFileNode*)cvGetSeqElem( node->data.seq, new_idx );
735             else
736                 timing_param_current[i] = node;
737             timing_param_idxs[i] = new_idx;
738         }
739     }
740
741     return !increment; // return 0 in case of overflow (i.e. if there is no more test cases)
742 }
743
744
745 const CvFileNode* CvTest::find_timing_param( const char* paramname )
746 {
747     if( timing_param_names )
748     {
749         int i;
750         CvSeqReader reader;
751         cvStartReadSeq( timing_param_names->data.seq, &reader, 0 );
752
753         for( i = 0; i < timing_param_count; i++ )
754         {
755             const char* ptr = ((const CvFileNode*)(reader.ptr))->data.str.ptr;
756             if( ptr[0] == paramname[0] && strcmp(ptr, paramname) == 0 )
757                 return timing_param_current[i];
758             CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
759         }
760     }
761     return 0;
762 }
763
764
765 int CvTest::write_defaults(CvTS* _ts)
766 {
767     ts = _ts;
768     hdr_state = 0;
769     write_default_params( ts->get_file_storage() );
770     if( hdr_state )
771         cvEndWriteStruct( ts->get_file_storage() );
772     return 0;
773 }
774
775
776 int CvTest::write_default_params( CvFileStorage* fs )
777 {
778     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
779         write_string_list( fs, "timing_params", default_timing_param_names, timing_param_count );
780     return 0;
781 }
782
783
784 bool CvTest::can_do_fast_forward()
785 {
786     return true;
787 }
788
789
790 int CvTest::get_support_testing_modes()
791 {
792     return support_testing_modes;
793 }
794
795 void CvTest::safe_run( int start_from )
796 {
797     if(ts->is_debug_mode())
798         run( start_from );
799     else
800     {
801         try
802         {
803         #if !defined WIN32 && !defined _WIN32
804         int _code = setjmp( cv_ts_jmp_mark );
805         if( !_code )
806             run( start_from );
807         else
808             throw _code;
809         #else
810             run( start_from );
811         #endif
812         }
813         catch (const cv::Exception& exc)
814         {
815             const char* errorStr = cvErrorStr(exc.code);
816             char buf[1 << 16];
817             
818             sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d",
819                     errorStr, exc.err.c_str(), exc.func.size() > 0 ?
820                     exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line );
821             ts->printf(CvTS::LOG, "%s\n", buf);
822             ts->set_failed_test_info( CvTS::FAIL_ERROR_IN_CALLED_FUNC );
823         }
824         catch (...)
825         {
826             ts->set_failed_test_info( CvTS::FAIL_EXCEPTION );
827         }
828     }
829 }
830
831
832 void CvTest::run( int start_from )
833 {
834     int i, test_case_idx, count = get_test_case_count();
835     int64 t_start = cvGetTickCount();
836     double freq = cv::getTickFrequency();
837     bool ff = can_do_fast_forward();
838     int progress = 0, code;
839     std::vector<double> v_cpe, v_time;
840     int64 t1 = t_start;
841
842     for( test_case_idx = ff && start_from >= 0 ? start_from : 0;
843          count < 0 || test_case_idx < count; test_case_idx++ )
844     {
845         ts->update_context( this, test_case_idx, ff );
846         progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) );
847         
848         int64 t00 = 0, t0 = 0, t2 = 0, t3 = 0;
849         double t_acc = 0, t_cpu_acc = 0;
850         
851         if( ts->get_testing_mode() == CvTS::TIMING_MODE )
852         {
853             const int iterations = 20;
854             code = prepare_test_case( test_case_idx );
855
856             if( code < 0 || ts->get_err_code() < 0 )
857                 return;
858
859             if( code == 0 )
860                 continue;
861                 
862             v_cpe.resize(0);
863             v_time.resize(0);
864
865             for( i = 0; i < iterations; i++ )
866             {
867                 for(;;)
868                 {
869                                         t0 = cv::getTickCount();
870                                         t2 = cv::getCPUTickCount();
871                                         run_func();
872                                         t3 = cv::getCPUTickCount();
873                                         t1 = cv::getTickCount();
874                                         if( ts->get_err_code() < 0 )
875                                                 return;
876
877                                         if( t3 - t2 > 0 && t1 - t0 > 1 )
878                                                 break;
879                                 }
880
881                                 if( i == 0 )
882                                         t00 = t0;
883                                 v_cpe.push_back((double)(t3 - t2));
884                                 v_time.push_back((double)(t1 - t0));
885                 if( i >= 5 && t1 - t00 > freq*5 )
886                     break;
887             }
888
889                         sort(v_cpe.begin(), v_cpe.end());
890                         sort(v_time.begin(), v_time.end());
891                         
892             t_cpu_acc = v_cpe[i/2];
893             t_acc = v_time[i/2];
894             print_time( test_case_idx, t_acc, t_cpu_acc );
895         }
896         else
897         {
898             code = prepare_test_case( test_case_idx );
899             if( code < 0 || ts->get_err_code() < 0 )
900                 return;
901
902             if( code == 0 )
903                 continue;
904
905             run_func();
906             if( ts->get_err_code() < 0 )
907                 return;
908
909             if( validate_test_results( test_case_idx ) < 0 || ts->get_err_code() < 0 )
910                 return;
911         }
912     }
913 }
914
915
916 void CvTest::run_func()
917 {
918     assert(0);
919 }
920
921
922 int CvTest::get_test_case_count()
923 {
924     return test_case_count;
925 }
926
927
928 int CvTest::prepare_test_case( int )
929 {
930     return 0;
931 }
932
933
934 int CvTest::validate_test_results( int )
935 {
936     return 0;
937 }
938
939
940 void CvTest::print_time( int /*test_case_idx*/, double /*time_usecs*/, double /*time_cpu_clocks*/ )
941 {
942 }
943
944
945 int CvTest::update_progress( int progress, int test_case_idx, int count, double dt )
946 {
947     int width = 60 - (int)strlen(get_name());
948     if( count > 0 )
949     {
950         int t = cvRound( ((double)test_case_idx * width)/count );
951         if( t > progress )
952         {
953             ts->printf( CvTS::CONSOLE, "." );
954             progress = t;
955         }
956     }
957     else if( cvRound(dt) > progress )
958     {
959         ts->printf( CvTS::CONSOLE, "." );
960         progress = cvRound(dt);
961     }
962
963     return progress;
964 }
965
966
967 CvBadArgTest::CvBadArgTest( const char* _test_name, const char* _test_funcs, const char* _test_descr )
968   : CvTest( _test_name, _test_funcs, _test_descr )
969 {
970     progress = -1;
971     test_case_idx = -1;
972     freq = cv::getTickFrequency();
973 }
974
975 CvBadArgTest::~CvBadArgTest()
976 {
977 }
978
979 int CvBadArgTest::run_test_case( int expected_code, const char* descr )
980 {
981     double new_t = (double)cv::getTickCount(), dt;
982     if( test_case_idx < 0 )
983     {
984         test_case_idx = 0;
985         progress = 0;
986         dt = 0;
987     }
988     else
989     {
990         dt = (new_t - t)/(freq*1000);
991         t = new_t;
992     }
993     progress = update_progress(progress, test_case_idx, 0, dt);
994     
995     int errcount = 0;
996     bool thrown = false;
997     if(!descr)
998         descr = "";
999     
1000     try
1001     {
1002         run_func();
1003     }
1004     catch(const cv::Exception& e)
1005     {
1006         thrown = true;
1007         if( e.code != expected_code )
1008         {
1009             ts->printf(CvTS::LOG, "%s (test case #%d): the error code %d is different from the expected %d\n",
1010                 descr, test_case_idx, e.code, expected_code);
1011             errcount = 1;
1012         }
1013     }
1014     catch(...)
1015     {
1016         thrown = true;
1017         ts->printf(CvTS::LOG, "%s  (test case #%d): unknown exception was thrown (the function has likely crashed)\n",
1018                    descr, test_case_idx);
1019         errcount = 1;
1020     }
1021     if(!thrown)
1022     {
1023         ts->printf(CvTS::LOG, "%s  (test case #%d): no expected exception was thrown\n",
1024                    descr, test_case_idx);
1025         errcount = 1;
1026     }
1027     test_case_idx++;
1028     
1029     return errcount;
1030 }
1031
1032 /*****************************************************************************************\
1033 *                                 Base Class for Test System                              *
1034 \*****************************************************************************************/
1035
1036 /******************************** Constructors/Destructors ******************************/
1037
1038 CvTS::CvTS()
1039 {
1040     start_time = 0;
1041     version = CV_TS_VERSION;
1042     memory_manager = 0;
1043     /*
1044     memory_manager = new CvTestMemoryManager(this);
1045     cvSetMemoryManager( CvTestMemoryManager::alloc_proxy,
1046                         CvTestMemoryManager::free_proxy,
1047                         memory_manager );*/
1048     ostrm_suffixes[SUMMARY_IDX] = ".sum";
1049     ostrm_suffixes[LOG_IDX] = ".log";
1050     ostrm_suffixes[CSV_IDX] = ".csv";
1051     ostrm_suffixes[CONSOLE_IDX] = 0;
1052     ostrm_base_name = 0;
1053     memset( output_streams, 0, sizeof(output_streams) );
1054     memset( &params, 0, sizeof(params) );
1055     selected_tests = new CvTestPtrVec();
1056     failed_tests = new CvTestInfoVec();
1057     written_params = new CvTestPtrVec();
1058
1059     clear();
1060 }
1061
1062
1063 void CvTS::clear()
1064 {
1065     int i;
1066     CvTest* test;
1067
1068     for( test = get_first_test(); test != 0; test = test->get_next() )
1069         test->clear();
1070
1071     for( i = 0; i <= CONSOLE_IDX; i++ )
1072     {
1073         if( i == LOG_IDX )
1074             fflush( stderr );
1075         else if( i == CONSOLE_IDX )
1076             fflush( stdout );
1077
1078         if( i < CONSOLE_IDX && output_streams[i].f )
1079         {
1080             fclose( output_streams[i].f );
1081             output_streams[i].f = 0;
1082         }
1083
1084         if( i == LOG_IDX && output_streams[i].default_handle > 0 )
1085         {
1086             dup2( output_streams[i].default_handle, 2 );
1087             output_streams[i].default_handle = 0;
1088         }
1089         output_streams[i].enable = 1;
1090     }
1091     cvReleaseFileStorage( &fs );
1092     selected_tests->clear();
1093     failed_tests->clear();
1094     if( ostrm_base_name )
1095     {
1096         free( ostrm_base_name );
1097         ostrm_base_name = 0;
1098     }
1099     params.rng_seed = 0;
1100     params.debug_mode = -1;
1101     params.print_only_failed = 0;
1102     params.skip_header = 0;
1103     params.test_mode = CORRECTNESS_CHECK_MODE;
1104     params.timing_mode = MIN_TIME;
1105     params.use_optimized = -1;
1106     params.color_terminal = 1;
1107
1108     if( memory_manager )
1109         memory_manager->clear_and_check();
1110 }
1111
1112
1113 CvTS::~CvTS()
1114 {
1115     clear();
1116     set_data_path(0);
1117
1118     if( written_params )
1119     {
1120         for( int i = 0; i < written_params->size(); i++ )
1121             free( written_params->at(i) );
1122         delete written_params;
1123     }
1124
1125     delete selected_tests;
1126     delete failed_tests;
1127 }
1128
1129
1130 const char* CvTS::str_from_code( int code )
1131 {
1132     switch( code )
1133     {
1134     case OK: return "Ok";
1135     case FAIL_GENERIC: return "Generic/Unknown";
1136     case FAIL_MISSING_TEST_DATA: return "No test data";
1137     case FAIL_INVALID_TEST_DATA: return "Invalid test data";
1138     case FAIL_ERROR_IN_CALLED_FUNC: return "cvError invoked";
1139     case FAIL_EXCEPTION: return "Hardware/OS exception";
1140     case FAIL_MEMORY_EXCEPTION: return "Invalid memory access";
1141     case FAIL_ARITHM_EXCEPTION: return "Arithmetic exception";
1142     case FAIL_MEMORY_CORRUPTION_BEGIN: return "Corrupted memblock (beginning)";
1143     case FAIL_MEMORY_CORRUPTION_END: return "Corrupted memblock (end)";
1144     case FAIL_MEMORY_LEAK: return "Memory leak";
1145     case FAIL_INVALID_OUTPUT: return "Invalid function output";
1146     case FAIL_MISMATCH: return "Unexpected output";
1147     case FAIL_BAD_ACCURACY: return "Bad accuracy";
1148     case FAIL_HANG: return "Infinite loop(?)";
1149     case FAIL_BAD_ARG_CHECK: return "Incorrect handling of bad arguments";
1150     default: return "Generic/Unknown";
1151     }
1152 }
1153
1154 /************************************** Running tests **********************************/
1155
1156 void CvTS::make_output_stream_base_name( const char* config_name )
1157 {
1158     int k, len = (int)strlen( config_name );
1159
1160     if( ostrm_base_name )
1161         free( ostrm_base_name );
1162
1163     for( k = len-1; k >= 0; k-- )
1164     {
1165         char c = config_name[k];
1166         if( c == '.' || c == '/' || c == '\\' || c == ':' )
1167             break;
1168     }
1169
1170     if( k > 0 && config_name[k] == '.' )
1171         len = k;
1172
1173     ostrm_base_name = (char*)malloc( len + 1 );
1174     memcpy( ostrm_base_name, config_name, len );
1175     ostrm_base_name[len] = '\0';
1176 }
1177
1178
1179 void CvTS::set_handlers( bool on )
1180 {
1181     if( on )
1182     {
1183         cvSetErrMode( CV_ErrModeParent );
1184         cvRedirectError( cvStdErrReport );
1185     #if defined WIN32 || defined _WIN32
1186         #ifdef _MSC_VER
1187         _set_se_translator( cv_seh_translator );
1188         #endif
1189     #else
1190         for( int i = 0; cv_ts_sig_id[i] >= 0; i++ )
1191             signal( cv_ts_sig_id[i], cv_signal_handler );
1192     #endif
1193     }
1194     else
1195     {
1196         cvSetErrMode( CV_ErrModeLeaf );
1197         cvRedirectError( cvGuiBoxReport );
1198     #if defined WIN32 || defined _WIN32
1199         #ifdef _MSC_VER
1200         _set_se_translator( 0 );
1201         #endif
1202     #else
1203         for( int i = 0; cv_ts_sig_id[i] >= 0; i++ )
1204             signal( cv_ts_sig_id[i], SIG_DFL );
1205     #endif
1206     }
1207 }
1208
1209
1210 void CvTS::set_data_path( const char* data_path )
1211 {
1212     if( data_path == params.data_path )
1213         return;
1214
1215     if( params.data_path )
1216         delete[] params.data_path;
1217     if( data_path )
1218     {
1219         int size = (int)strlen(data_path)+1;
1220         bool append_slash = data_path[size-1] != '/' && data_path[size-1] != '\\';
1221         params.data_path = new char[size+1];
1222         memcpy( params.data_path, data_path, size );
1223         if( append_slash )
1224             strcat( params.data_path, "/" );
1225     }
1226 }
1227
1228
1229 typedef struct CvTsParamVal
1230 {
1231     const char* fullname;
1232     const void* val;
1233 }
1234 CvTsParamVal;
1235
1236 int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype, const void* val )
1237 {
1238     const char* testname = test->get_name();
1239     bool add_to_list = test->get_func_list()[0] == '\0';
1240     char buffer[256];
1241     int paramname_len = (int)strlen(paramname);
1242     int paramval_len = valtype == CV_NODE_INT ? (int)sizeof(int) :
1243         valtype == CV_NODE_REAL ? (int)sizeof(double) : -1;
1244     const char* name = CvTest::get_parent_name( testname, buffer );
1245
1246     if( !fs )
1247         return -1;
1248
1249     if( paramval_len < 0 )
1250     {
1251         assert(0); // unsupported parameter type
1252         return -1;
1253     }
1254
1255     while( name )
1256     {
1257         int i, len = (int)strlen(buffer);
1258         buffer[len] = '.';
1259         memcpy( buffer + len + 1, paramname, paramname_len + 1 );
1260         for( i = 0; i < written_params->size(); i++ )
1261         {
1262             CvTsParamVal* param = (CvTsParamVal*)written_params->at(i);
1263             if( strcmp( param->fullname, buffer ) == 0 )
1264             {
1265                 if( (paramval_len > 0 && memcmp( param->val, val, paramval_len ) == 0) ||
1266                     (paramval_len < 0 && strcmp( (const char*)param->val, (const char*)val ) == 0) )
1267                     return 1;
1268                 break;
1269             }
1270         }
1271         if( i < written_params->size() )
1272             break;
1273         buffer[len] = '\0';
1274         name = CvTest::get_parent_name( buffer, buffer );
1275     }
1276
1277     if( add_to_list )
1278     {
1279         int bufsize, fullname_len = (int)strlen(testname) + paramname_len + 2;
1280         CvTsParamVal* param;
1281         if( paramval_len < 0 )
1282             paramval_len = (int)strlen((const char*)val) + 1;
1283         bufsize = sizeof(*param) + fullname_len + paramval_len;
1284         param = (CvTsParamVal*)malloc(bufsize);
1285         param->fullname = (const char*)(param + 1);
1286         param->val = param->fullname + fullname_len;
1287         sprintf( (char*)param->fullname, "%s.%s", testname, paramname );
1288         memcpy( (void*)param->val, val, paramval_len );
1289         written_params->push( param );
1290     }
1291
1292     return 0;
1293 }
1294
1295
1296 #ifndef MAX_PATH
1297 #define MAX_PATH 1024
1298 #endif
1299
1300 static int CV_CDECL cmp_test_names( const void* a, const void* b )
1301 {
1302     return strcmp( (*(const CvTest**)a)->get_name(), (*(const CvTest**)b)->get_name() );
1303 }
1304
1305 int CvTS::run( int argc, char** argv )
1306 {
1307     time( &start_time );
1308
1309     int i, write_params = 0;
1310     int list_tests = 0;
1311     CvTestPtrVec all_tests;
1312     CvTest* test;
1313
1314     // 0. reset all the parameters, reorder tests
1315     clear();
1316
1317 /*#if defined WIN32 || defined _WIN32
1318         cv::setBreakOnError(true);
1319 #endif*/
1320
1321     for( test = get_first_test(), i = 0; test != 0; test = test->get_next(), i++ )
1322         all_tests.push(test);
1323
1324     if( all_tests.size() > 0 && all_tests.data() )
1325         qsort( all_tests.data(), all_tests.size(), sizeof(CvTest*), cmp_test_names );
1326
1327     // 1. parse command line options
1328     for( i = 1; i < argc; i++ )
1329     {
1330         if( strcmp( argv[i], "-h" ) == 0 || strcmp( argv[i], "--help" ) == 0 )
1331         {
1332             print_help();
1333             return 0;
1334         }
1335         else if( strcmp( argv[i], "-f" ) == 0 )
1336             config_name = argv[++i];
1337         else if( strcmp( argv[i], "-w" ) == 0 )
1338             write_params = 1;
1339         else if( strcmp( argv[i], "-t" ) == 0 )
1340             params.test_mode = TIMING_MODE;
1341         else if( strcmp( argv[i], "-O0" ) == 0 || strcmp( argv[i], "-O1" ) == 0 )
1342             params.use_optimized = argv[i][2] - '0';
1343         else if( strcmp( argv[i], "-l" ) == 0 )
1344             list_tests = 1;
1345         else if( strcmp( argv[i], "-d" ) == 0 )
1346             set_data_path(argv[++i]);
1347         else if( strcmp( argv[i], "-nc" ) == 0 )
1348             params.color_terminal = 0;
1349         else if( strcmp( argv[i], "-r" ) == 0 )
1350             params.debug_mode = 0;
1351         else if( strcmp( argv[i], "-tn" ) == 0 )
1352         {
1353             params.test_filter_pattern = argv[++i];
1354             params.test_filter_mode = CHOOSE_TESTS;
1355         }
1356         else if( strcmp( argv[i], "-seed" ) == 0 )
1357         {
1358             params.rng_seed = read_seed(argv[++i]);
1359             if( params.rng_seed == 0 )
1360                 fprintf(stderr, "Invalid or zero RNG seed. Will use the seed from the config file or default one\n");
1361         }
1362     }
1363
1364 #if 0
1365 //#if !defined WIN32 && !defined _WIN32
1366     if (! config_name )
1367     {    
1368       char * confname = getenv("configname");
1369       if (confname)
1370         config_name = confname;
1371     }
1372     
1373     if( !params.data_path || !params.data_path[0] )
1374     {
1375         char* datapath = getenv("datapath");
1376         if( datapath )
1377             set_data_path(datapath);
1378     }
1379     
1380     // this is the fallback for the current OpenCV autotools setup
1381     if( !params.data_path || !params.data_path[0] )
1382     {
1383         char* srcdir = getenv("srcdir");
1384         char buf[1024];
1385         if( srcdir )
1386         {
1387             sprintf( buf, "%s/../../opencv_extra/testdata/", srcdir );
1388             set_data_path(buf);
1389         }
1390     }
1391 #endif
1392
1393     if( write_params )
1394     {
1395         if( !config_name )
1396         {
1397             printf( LOG, "ERROR: output config name is not specified\n" );
1398             return -1;
1399         }
1400         fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_WRITE );
1401         if( !fs )
1402         {
1403             printf( LOG, "ERROR: could not open config file %s\n", config_name );
1404             return -1;
1405         }
1406         cvWriteComment( fs, CV_TS_VERSION " config file", 0 );
1407         cvStartWriteStruct( fs, "common", CV_NODE_MAP );
1408         write_default_params( fs );
1409         cvEndWriteStruct( fs );
1410
1411         for( i = 0; i < all_tests.size(); i++ )
1412         {
1413             test = (CvTest*)all_tests[i];
1414             if( !(test->get_support_testing_modes() & get_testing_mode()) )
1415                 continue;
1416             test->write_defaults( this );
1417             test->clear();
1418         }
1419         cvReleaseFileStorage( &fs );
1420         return 0;
1421     }
1422
1423     if( !config_name )
1424         printf( LOG, "WARNING: config name is not specified, using default parameters\n" );
1425     else
1426     {
1427         // 2. read common parameters of test system
1428         fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_READ );
1429         if( !fs )
1430         {
1431             printf( LOG, "ERROR: could not open config file %s", config_name );
1432             return -1;
1433         }
1434     }
1435
1436     if( params.test_mode == CORRECTNESS_CHECK_MODE || fs )
1437     {
1438         // in the case of algorithmic tests we always run read_params,
1439         // even if there is no config file
1440         if( read_params(fs) < 0 )
1441             return -1;
1442     }
1443
1444     if( !ostrm_base_name )
1445         make_output_stream_base_name( config_name ? config_name : argv[0] );
1446
1447     ostream_testname_mask = -1; // disable printing test names at initial stage
1448
1449     // 3. open file streams
1450     for( i = 0; i < CONSOLE_IDX; i++ )
1451     {
1452         char filename[MAX_PATH];
1453         sprintf( filename, "%s%s", ostrm_base_name, ostrm_suffixes[i] );
1454         output_streams[i].f = fopen( filename, "wt" );
1455         if( !output_streams[i].f )
1456         {
1457             printf( LOG, "ERROR: could not open %s\n", filename );
1458             return -1;
1459         }
1460
1461         if( i == LOG_IDX )
1462         {
1463             // redirect stderr to log file
1464             fflush( stderr );
1465             output_streams[i].default_handle = dup(2);
1466             dup2( fileno(output_streams[i].f), 2 );
1467         }
1468     }
1469
1470     // 4. traverse through the list of all registered tests.
1471     // Initialize the selected tests and put them into the separate sequence
1472     for( i = 0; i < all_tests.size(); i++ )
1473     {
1474         test = (CvTest*)all_tests[i];
1475         if( !(test->get_support_testing_modes() & get_testing_mode()) )
1476             continue;
1477
1478         if( strcmp( test->get_func_list(), "" ) != 0 && filter(test) )
1479         {
1480             if( test->init(this) >= 0 )
1481             {
1482                 selected_tests->push( test );
1483                 if( list_tests )
1484                     ::printf( "%s\n", test->get_name() );
1485             }
1486             else
1487                 printf( LOG, "WARNING: an error occured during test %s initialization\n", test->get_name() );
1488         }
1489     }
1490
1491     if( list_tests )
1492     {
1493         clear();
1494         return 0;
1495     }
1496
1497     // 5. setup all the neccessary handlers and print header
1498     set_handlers( !params.debug_mode );
1499
1500     if( params.use_optimized == 0 )
1501         cvUseOptimized(0);
1502
1503     if( !params.skip_header )
1504         print_summary_header( SUMMARY + LOG + CONSOLE + CSV );
1505     rng = params.rng_seed;
1506     update_context( 0, -1, true );
1507
1508     // 6. run all the tests
1509     for( i = 0; i < selected_tests->size(); i++ )
1510     {
1511         CvTest* test = (CvTest*)selected_tests->at(i);
1512         int code;
1513         CvTestInfo temp;
1514
1515         if( memory_manager )
1516             memory_manager->start_tracking();
1517         update_context( test, -1, true );
1518         current_test_info.rng_seed0 = current_test_info.rng_seed;
1519         
1520         ostream_testname_mask = 0; // reset "test name was printed" flags
1521         logbuf = std::string();
1522         if( output_streams[LOG_IDX].f )
1523             fflush( output_streams[LOG_IDX].f );
1524
1525         temp = current_test_info;
1526         test->safe_run(0);
1527         if( get_err_code() >= 0 )
1528         {
1529             update_context( test, -1, false );
1530             current_test_info.rng_seed = temp.rng_seed;
1531             current_test_info.base_alloc_index = temp.base_alloc_index;
1532         }
1533         test->clear();
1534         if( memory_manager )
1535             memory_manager->stop_tracking_and_check();
1536
1537         code = get_err_code();
1538         if( code >= 0 )
1539         {
1540             if( !params.print_only_failed )
1541             {
1542                 printf( SUMMARY + CONSOLE, "\t" );
1543                 set_color( CV_TS_GREEN );
1544                 printf( SUMMARY + CONSOLE, "Ok\n" );
1545                 set_color( CV_TS_NORMAL );
1546             }
1547         }
1548         else
1549         {
1550             printf( SUMMARY + CONSOLE, "\t" );
1551             set_color( CV_TS_RED );
1552             printf( SUMMARY + CONSOLE, "FAIL(%s)\n", str_from_code(code) );
1553             set_color( CV_TS_NORMAL );
1554             printf( LOG, "context: test case = %d, seed = %08x%08x\n",
1555                     current_test_info.test_case_idx,
1556                     (unsigned)(current_test_info.rng_seed>>32),
1557                     (unsigned)(current_test_info.rng_seed));
1558             if(logbuf.size() > 0)
1559             {
1560                 printf( SUMMARY + CONSOLE, ">>>\n%s\n", logbuf.c_str());
1561             }
1562             failed_tests->push(current_test_info);
1563             if( params.rerun_immediately )
1564                 break;
1565         }
1566     }
1567
1568     ostream_testname_mask = -1;
1569     print_summary_tailer( SUMMARY + CONSOLE + LOG );
1570
1571     if( !params.debug_mode && (params.rerun_failed || params.rerun_immediately) )
1572     {
1573         set_handlers(0);
1574         update_context( 0, -1, true );
1575         for( i = 0; i < failed_tests->size(); i++ )
1576         {
1577             CvTestInfo info = failed_tests->at(i);
1578             if( (info.code == FAIL_MEMORY_CORRUPTION_BEGIN ||
1579                 info.code == FAIL_MEMORY_CORRUPTION_END ||
1580                 info.code == FAIL_MEMORY_LEAK) && memory_manager )
1581                 memory_manager->start_tracking( info.alloc_index - info.base_alloc_index
1582                                                 + memory_manager->get_alloc_index() );
1583             rng = info.rng_seed;
1584             test->safe_run( info.test_case_idx );
1585         }
1586     }
1587     int nfailed = failed_tests ? (int)failed_tests->size() : 0;
1588     clear();
1589
1590     return nfailed;
1591 }
1592
1593
1594 void CvTS::print_help()
1595 {
1596     ::printf(
1597         "Usage: <test_executable> [{-h|--help}][-l] [-r] [-w] [-t] [-f <config_name>] [-d <data_path>] [-O{0|1}] [-tn <test_name>]\n\n"
1598         "-d - specify the test data path\n"
1599         "-f - use parameters from the provided XML/YAML config file\n"
1600         "     instead of the default parameters\n"
1601         "-h or --help - print this help information\n"
1602         "-l - list all the registered tests or subset of the tests,\n"
1603         "     selected in the config file, and exit\n"
1604         "-tn - only run a specific test\n"
1605         "-nc - do not use colors in the console output\n"     
1606         "-O{0|1} - disable/enable on-fly detection of IPP and other\n"
1607         "          supported optimized libs. It's enabled by default\n"
1608         "-r - continue running tests after OS/Hardware exception occured\n"
1609         "-t - switch to the performance testing mode instead of\n"
1610         "     the default algorithmic/correctness testing mode\n"
1611         "-w - write default parameters of the algorithmic or\n"
1612         "     performance (when -t is passed) tests to the specifed\n"
1613         "     config file (see -f) and exit\n\n"
1614         //"Test data path and config file can also be specified by the environment variables 'config' and 'datapath'.\n\n"
1615         );
1616 }
1617
1618
1619 #if defined WIN32 || defined _WIN32
1620 const char* default_data_path = "../tests/cv/testdata/";
1621 #else
1622 const char* default_data_path = "../../../../tests/cv/testdata/";
1623 #endif
1624
1625
1626 int CvTS::read_params( CvFileStorage* fs )
1627 {
1628     CvFileNode* node = fs ? cvGetFileNodeByName( fs, 0, "common" ) : 0;
1629     if(params.debug_mode < 0)
1630         params.debug_mode = cvReadIntByName( fs, node, "debug_mode", 1 ) != 0;
1631     params.skip_header = cvReadIntByName( fs, node, "skip_header", 0 ) != 0;
1632     params.print_only_failed = cvReadIntByName( fs, node, "print_only_failed", 0 ) != 0;
1633     params.rerun_failed = cvReadIntByName( fs, node, "rerun_failed", 0 ) != 0;
1634     params.rerun_immediately = cvReadIntByName( fs, node, "rerun_immediately", 0 ) != 0;
1635     const char* str = cvReadStringByName( fs, node, "filter_mode", "tests" );
1636     params.test_filter_mode = strcmp( str, "functions" ) == 0 ? CHOOSE_FUNCTIONS : CHOOSE_TESTS;
1637     str = cvReadStringByName( fs, node, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
1638     params.test_mode = strcmp( str, "timing" ) == 0 || strcmp( str, "performance" ) == 0 ?
1639                         TIMING_MODE : CORRECTNESS_CHECK_MODE;
1640     str = cvReadStringByName( fs, node, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
1641     params.timing_mode = strcmp( str, "average" ) == 0 || strcmp( str, "avg" ) == 0 ? AVG_TIME : MIN_TIME;
1642     params.test_filter_pattern = params.test_filter_pattern != 0 &&
1643                 strlen(params.test_filter_pattern) > 0 ? params.test_filter_pattern :
1644                 cvReadStringByName( fs, node, params.test_filter_mode == CHOOSE_FUNCTIONS ?
1645                                                      "functions" : "tests", "" );
1646     params.resource_path = cvReadStringByName( fs, node, "." );
1647     if( params.use_optimized < 0 )
1648         params.use_optimized = cvReadIntByName( fs, node, "use_optimized", -1 );
1649     if( !params.data_path || !params.data_path[0] )
1650     {
1651         const char* data_path =
1652             cvReadStringByName( fs, node, "data_path", default_data_path );
1653         set_data_path(data_path);
1654     }
1655     params.test_case_count_scale = cvReadRealByName( fs, node, "test_case_count_scale", 1. );
1656     if( params.test_case_count_scale <= 0 )
1657         params.test_case_count_scale = 1.;
1658     str = cvReadStringByName( fs, node, "seed", 0 );
1659     if( str && params.rng_seed == 0 )
1660         params.rng_seed = read_seed(str);
1661
1662     if( params.rng_seed == 0 )
1663         params.rng_seed = cvGetTickCount();
1664
1665     str = cvReadStringByName( fs, node, "output_file_base_name", 0 );
1666     if( str )
1667         make_output_stream_base_name( str );
1668
1669     return 0;
1670 }
1671
1672
1673 void CvTS::write_default_params( CvFileStorage* fs )
1674 {
1675     read_params(0); // fill parameters with default values
1676
1677     cvWriteInt( fs, "debug_mode", params.debug_mode );
1678     cvWriteInt( fs, "skip_header", params.skip_header );
1679     cvWriteInt( fs, "print_only_failed", params.print_only_failed );
1680     cvWriteInt( fs, "rerun_failed", params.rerun_failed );
1681     cvWriteInt( fs, "rerun_immediately", params.rerun_immediately );
1682     cvWriteString( fs, "filter_mode", params.test_filter_mode == CHOOSE_FUNCTIONS ? "functions" : "tests" );
1683     cvWriteString( fs, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
1684     cvWriteString( fs, "data_path", params.data_path ? params.data_path : default_data_path, 1 );
1685     if( params.test_mode == TIMING_MODE )
1686         cvWriteString( fs, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
1687     // test_filter, seed & output_file_base_name are not written
1688 }
1689
1690
1691 void CvTS::enable_output_streams( int stream_mask, int value )
1692 {
1693     for( int i = 0; i < MAX_IDX; i++ )
1694         if( stream_mask & (1 << i) )
1695             output_streams[i].enable = value != 0;
1696 }
1697
1698
1699 void CvTS::update_context( CvTest* test, int test_case_idx, bool update_ts_context )
1700 {
1701     current_test_info.test = test;
1702     current_test_info.test_case_idx = test_case_idx;
1703     current_test_info.alloc_index = 0;
1704     current_test_info.code = 0;
1705     cvSetErrStatus( CV_StsOk );
1706     if( update_ts_context )
1707     {
1708         current_test_info.rng_seed = rng;
1709         current_test_info.base_alloc_index = memory_manager ?
1710             memory_manager->get_alloc_index() : 0;
1711     }
1712 }
1713
1714
1715 void CvTS::set_failed_test_info( int fail_code, int alloc_index )
1716 {
1717     if( fail_code == FAIL_MEMORY_CORRUPTION_BEGIN ||
1718         fail_code == FAIL_MEMORY_CORRUPTION_END ||
1719         current_test_info.code >= 0 )
1720     {
1721         current_test_info.code = fail_code;
1722         current_test_info.alloc_index = alloc_index;
1723     }
1724 }
1725
1726
1727 const char* CvTS::get_libs_info( const char** addon_modules )
1728 {
1729     const char* all_info = 0;
1730     cvGetModuleInfo( 0, &all_info, addon_modules );
1731     return all_info;
1732 }
1733
1734
1735 void CvTS::print_summary_header( int streams )
1736 {
1737     char csv_header[256], *ptr = csv_header;
1738     int i;
1739
1740     printf( streams, "Engine: %s\n", version );
1741     time_t t1;
1742     time( &t1 );
1743     struct tm *t2 = localtime( &t1 );
1744     char buf[1024];
1745     strftime( buf, sizeof(buf)-1, "%c", t2 );
1746     printf( streams, "Execution Date & Time: %s\n", buf );
1747     printf( streams, "Config File: %s\n", config_name );
1748     const char* plugins = 0;
1749     const char* lib_verinfo = get_libs_info( &plugins );
1750     printf( streams, "Tested Libraries: %s\n", lib_verinfo );
1751     printf( streams, "Optimized Low-level Plugin\'s: %s\n", plugins );
1752     printf( streams, "=================================================\n");
1753
1754     sprintf( ptr, "funcName,dataType,channels,size," );
1755     ptr += strlen(ptr);
1756
1757     for( i = 0; i < CvTest::TIMING_EXTRA_PARAMS; i++ )
1758     {
1759         sprintf( ptr, "param%d,", i );
1760         ptr += strlen(ptr);
1761     }
1762
1763     sprintf( ptr, "CPE,Time(uSecs)" );
1764     printf( CSV, "%s\n", csv_header );
1765 }
1766
1767
1768 void CvTS::print_summary_tailer( int streams )
1769 {
1770     printf( streams, "=================================================\n");
1771     if( selected_tests && failed_tests )
1772     {
1773         time_t end_time;
1774         time( &end_time );
1775         double total_time = difftime( end_time, start_time );
1776         printf( streams, "Summary: %d out of %d tests failed\n",
1777             failed_tests->size(), selected_tests->size() );
1778         int minutes = cvFloor(total_time/60.);
1779         int seconds = cvRound(total_time - minutes*60);
1780         int hours = minutes / 60;
1781         minutes %= 60;
1782         printf( streams, "Running time: %02d:%02d:%02d\n", hours, minutes, seconds );
1783     }
1784 }
1785
1786
1787 void CvTS::vprintf( int streams, const char* fmt, va_list l )
1788 {
1789     if( streams )
1790     {
1791         char str[1 << 14];
1792         vsnprintf( str, sizeof(str)-1, fmt, l );
1793
1794         for( int i = 0; i < MAX_IDX; i++ )
1795         {
1796             if( (streams & (1 << i)) && output_streams[i].enable )
1797             {
1798                 FILE* f = i == CONSOLE_IDX ? stdout :
1799                           i == LOG_IDX ? stderr : output_streams[i].f;
1800                 if( f )
1801                 {
1802                     if( i != CSV_IDX && !(ostream_testname_mask & (1 << i)) && current_test_info.test )
1803                     {
1804                         fprintf( f, "-------------------------------------------------\n" );
1805                         if( i == CONSOLE_IDX || i == SUMMARY_IDX )
1806                                                         fprintf( f, "[%08x%08x]\n", (int)(current_test_info.rng_seed0 >> 32),
1807                                                             (int)(current_test_info.rng_seed0));
1808                         fprintf( f, "%s: ", current_test_info.test->get_name() );
1809                         fflush( f );
1810                         ostream_testname_mask |= 1 << i;
1811                         if( i == LOG_IDX )
1812                             logbuf = std::string();
1813                     }
1814                     fputs( str, f );
1815                     if( i == LOG_IDX )
1816                         logbuf += std::string(str);
1817                     if( i == CONSOLE_IDX )
1818                         fflush(f);
1819                 }
1820             }
1821         }
1822     }
1823 }
1824
1825
1826 void CvTS::printf( int streams, const char* fmt, ... )
1827 {
1828     if( streams )
1829     {
1830         va_list l;
1831         va_start( l, fmt );
1832         vprintf( streams, fmt, l );
1833         va_end( l );
1834     }
1835 }
1836
1837 void CvTS::set_color(int color)
1838 {
1839     if( params.color_terminal )
1840         change_color(color);
1841 }
1842
1843 static char* cv_strnstr( const char* str, int len,
1844                          const char* pattern,
1845                          int pattern_len = -1,
1846                          int whole_word = 1 )
1847 {
1848     int i;
1849
1850     if( len < 0 && pattern_len < 0 )
1851         return (char*)strstr( str, pattern );
1852
1853     if( len < 0 )
1854         len = (int)strlen( str );
1855
1856     if( pattern_len < 0 )
1857         pattern_len = (int)strlen( pattern );
1858
1859     for( i = 0; i < len - pattern_len + 1; i++ )
1860     {
1861         int j = i + pattern_len;
1862         if( str[i] == pattern[0] &&
1863             memcmp( str + i, pattern, pattern_len ) == 0 &&
1864             (!whole_word ||
1865             ((i == 0 || (!isalnum(str[i-1]) && str[i-1] != '_')) &&
1866              (j == len || (!isalnum(str[j]) && str[j] != '_')))))
1867             return (char*)(str + i);
1868     }
1869
1870     return 0;
1871 }
1872
1873
1874 int CvTS::filter( CvTest* test )
1875 {
1876     const char* pattern = params.test_filter_pattern;
1877     int inverse = 0;
1878
1879     if( pattern && pattern[0] == '!' )
1880     {
1881         inverse = 1;
1882         pattern++;
1883     }
1884
1885     if( !pattern || strcmp( pattern, "" ) == 0 || strcmp( pattern, "*" ) == 0 )
1886         return 1 ^ inverse;
1887
1888     if( params.test_filter_mode == CHOOSE_TESTS )
1889     {
1890         int found = 0;
1891
1892         while( pattern && *pattern )
1893         {
1894             char *ptr, *endptr = (char*)strchr( pattern, ',' );
1895             int len, have_wildcard;
1896             int t_name_len;
1897
1898             if( endptr )
1899                 *endptr = '\0';
1900
1901             ptr = (char*)strchr( pattern, '*' );
1902             if( ptr )
1903             {
1904                 len = (int)(ptr - pattern);
1905                 have_wildcard = 1;
1906             }
1907             else
1908             {
1909                 len = (int)strlen( pattern );
1910                 have_wildcard = 0;
1911             }
1912
1913             t_name_len = (int)strlen( test->get_name() );
1914             found = (t_name_len == len || (have_wildcard && t_name_len > len)) &&
1915                     (len == 0 || memcmp( test->get_name(), pattern, len ) == 0);
1916             if( endptr )
1917             {
1918                 *endptr = ',';
1919                 pattern = endptr + 1;
1920                 while( isspace(*pattern) )
1921                     pattern++;
1922             }
1923
1924             if( found || !endptr )
1925                 break;
1926         }
1927
1928         return found ^ inverse;
1929     }
1930     else
1931     {
1932         assert( params.test_filter_mode == CHOOSE_FUNCTIONS );
1933         int glob_len = (int)strlen( pattern );
1934         const char* ptr = test->get_func_list();
1935         const char *tmp_ptr;
1936
1937         while( ptr && *ptr )
1938         {
1939             const char* endptr = ptr - 1;
1940             const char* name_ptr;
1941             const char* name_first_match;
1942             int name_len;
1943             char c;
1944
1945             do c = *++endptr;
1946             while( isspace(c) );
1947
1948             if( !c )
1949                 break;
1950
1951             assert( isalpha(c) );
1952             name_ptr = endptr;
1953
1954             do c = *++endptr;
1955             while( isalnum(c) || c == '_' );
1956
1957             if( c == ':' ) // class
1958             {
1959                 assert( endptr[1] == ':' );
1960                 endptr = endptr + 2;
1961                 name_len = (int)(endptr - name_ptr);
1962
1963                 // find the first occurence of the class name
1964                 // in pattern
1965                 name_first_match = cv_strnstr( pattern,
1966                                       glob_len, name_ptr, name_len, 1 );
1967
1968                 if( *endptr == '*' )
1969                 {
1970                     if( name_first_match )
1971                         return 1 ^ inverse;
1972                 }
1973                 else
1974                 {
1975                     assert( *endptr == '{' ); // a list of methods
1976
1977                     if( !name_first_match )
1978                     {
1979                         // skip all the methods, if there is no such a class name
1980                         // in pattern
1981                         endptr = strchr( endptr, '}' );
1982                         assert( endptr != 0 );
1983                         endptr--;
1984                     }
1985
1986                     for( ;; )
1987                     {
1988                         const char* method_name_ptr;
1989                         int method_name_len;
1990
1991                         do c = *++endptr;
1992                         while( isspace(c) );
1993
1994                         if( c == '}' )
1995                             break;
1996                         assert( isalpha(c) );
1997
1998                         method_name_ptr = endptr;
1999
2000                         do c = *++endptr;
2001                         while( isalnum(c) || c == '_' );
2002
2003                         method_name_len = (int)(endptr - method_name_ptr);
2004
2005                         // search for class_name::* or
2006                         // class_name::{...method_name...}
2007                         tmp_ptr = name_first_match;
2008                         do
2009                         {
2010                             const char* tmp_ptr2;
2011                             tmp_ptr += name_len;
2012                             if( *tmp_ptr == '*' )
2013                                 return 1;
2014                             assert( *tmp_ptr == '{' );
2015                             tmp_ptr2 = strchr( tmp_ptr, '}' );
2016                             assert( tmp_ptr2 );
2017
2018                             if( cv_strnstr( tmp_ptr, (int)(tmp_ptr2 - tmp_ptr) + 1,
2019                                              method_name_ptr, method_name_len, 1 ))
2020                                 return 1 ^ inverse;
2021
2022                             tmp_ptr = cv_strnstr( tmp_ptr2, glob_len -
2023                                                    (int)(tmp_ptr2 - pattern),
2024                                                    name_ptr, name_len, 1 );
2025                         }
2026                         while( tmp_ptr );
2027
2028                         endptr--;
2029                         do c = *++endptr;
2030                         while( isspace(c) );
2031
2032                         if( c != ',' )
2033                             endptr--;
2034                     }
2035                 }
2036             }
2037             else
2038             {
2039                 assert( !c || isspace(c) || c == ',' );
2040                 name_len = (int)(endptr - name_ptr);
2041                 tmp_ptr = pattern;
2042
2043                 for(;;)
2044                 {
2045                     const char *tmp_ptr2, *tmp_ptr3;
2046
2047                     tmp_ptr = cv_strnstr( tmp_ptr, glob_len -
2048                         (int)(tmp_ptr - pattern), name_ptr, name_len, 1 );
2049
2050                     if( !tmp_ptr )
2051                         break;
2052
2053                     // make sure it is not a method
2054                     tmp_ptr2 = strchr( tmp_ptr, '}' );
2055                     if( !tmp_ptr2 )
2056                         return 1 ^ inverse;
2057
2058                     tmp_ptr3 = strchr( tmp_ptr, '{' );
2059                     if( tmp_ptr3 < tmp_ptr2 )
2060                         return 1 ^ inverse;
2061
2062                     tmp_ptr = tmp_ptr2 + 1;
2063                 }
2064
2065                 endptr--;
2066             }
2067
2068             do c = *++endptr;
2069             while( isspace(c) );
2070
2071             if( c == ',' )
2072                 endptr++;
2073             ptr = endptr;
2074         }
2075
2076         return 0 ^ inverse;
2077     }
2078 }
2079
2080 /* End of file. */