]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/tests/cxts/cxts.cpp
make the code compile and run on EM64T(~AMD64)
[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 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 WIN64
69 #include <windows.h>
70
71 #ifdef _MSC_VER
72 #include <eh.h>
73 #endif
74
75 static void cv_seh_translator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp )
76 {
77     int code = CvTS::FAIL_EXCEPTION;
78     switch( pExp->ExceptionRecord->ExceptionCode )
79     {
80     case EXCEPTION_ACCESS_VIOLATION:
81     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
82     case EXCEPTION_DATATYPE_MISALIGNMENT:
83     case EXCEPTION_FLT_STACK_CHECK:
84     case EXCEPTION_STACK_OVERFLOW:
85     case EXCEPTION_IN_PAGE_ERROR:
86         code = CvTS::FAIL_MEMORY_EXCEPTION;
87         break;
88     case EXCEPTION_FLT_DENORMAL_OPERAND:
89     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
90     case EXCEPTION_FLT_INEXACT_RESULT:
91     case EXCEPTION_FLT_INVALID_OPERATION:
92     case EXCEPTION_FLT_OVERFLOW:
93     case EXCEPTION_FLT_UNDERFLOW:
94     case EXCEPTION_INT_DIVIDE_BY_ZERO:
95     case EXCEPTION_INT_OVERFLOW:
96         code = CvTS::FAIL_ARITHM_EXCEPTION;
97         break;
98     case EXCEPTION_BREAKPOINT:
99     case EXCEPTION_ILLEGAL_INSTRUCTION:
100     case EXCEPTION_INVALID_DISPOSITION:
101     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
102     case EXCEPTION_PRIV_INSTRUCTION:
103     case EXCEPTION_SINGLE_STEP:
104         code = CvTS::FAIL_EXCEPTION;
105     }
106     throw code;
107 }
108
109
110 #define CV_TS_TRY_BLOCK_BEGIN                   \
111     try {
112
113 #define CV_TS_TRY_BLOCK_END                     \
114     } catch( int _code ) {                      \
115         ts->set_failed_test_info( _code );      \
116     }
117
118 static void change_color( int color )
119 {
120     static int normal_attributes = -1;
121     HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
122     fflush(stdout);
123
124     if( normal_attributes < 0 )
125     {
126         CONSOLE_SCREEN_BUFFER_INFO info;
127         GetConsoleScreenBufferInfo( hstdout, &info );
128         normal_attributes = info.wAttributes;
129     }
130
131     SetConsoleTextAttribute( hstdout,
132         (WORD)(color == CV_TS_NORMAL ? normal_attributes :
133         ((color & CV_TS_BLUE ? FOREGROUND_BLUE : 0)|
134         (color & CV_TS_GREEN ? FOREGROUND_GREEN : 0)|
135         (color & CV_TS_RED ? FOREGROUND_RED : 0)|FOREGROUND_INTENSITY)) );
136 }
137
138 #else
139
140 #include <signal.h>
141
142 static const int cv_ts_sig_id[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, -1 };
143
144 static jmp_buf cv_ts_jmp_mark;
145
146 void cv_signal_handler( int sig_code )
147 {
148     int code = CvTS::FAIL_EXCEPTION;
149     switch( sig_code )
150     {
151     case SIGFPE:
152         code = CvTS::FAIL_ARITHM_EXCEPTION;
153         break;
154     case SIGSEGV:
155     case SIGBUS:
156         code = CvTS::FAIL_ARITHM_EXCEPTION;
157         break;
158     case SIGILL:
159         code = CvTS::FAIL_EXCEPTION;
160     }
161
162     longjmp( cv_ts_jmp_mark, code );
163 }
164
165 #define CV_TS_TRY_BLOCK_BEGIN                   \
166     {                                           \
167         int _code = setjmp( cv_ts_jmp_mark );   \
168         if( !_code ) {
169
170 #define CV_TS_TRY_BLOCK_END                     \
171         }                                       \
172         else  {                                 \
173             ts->set_failed_test_info( _code );  \
174         }                                       \
175     }
176
177 static void change_color( int color )
178 {
179     static const uchar ansi_tab[] = { 30, 34, 32, 36, 31, 35, 33, 37 };
180     char buf[16];
181     int code = 0;
182     fflush( stdout );
183     if( color != CV_TS_NORMAL )
184         code = ansi_tab[color & (CV_TS_BLUE|CV_TS_GREEN|CV_TS_RED)];
185     sprintf( buf, "\x1b[%dm", code );
186     printf( buf );
187 }
188
189 #endif
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         #ifdef 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
484 void CvTest::clear()
485 {
486     if( timing_param_current )
487         free( timing_param_current );
488     if( timing_param_seqs )
489         free( timing_param_seqs );
490     if( timing_param_idxs )
491         free( timing_param_idxs );
492
493     timing_param_current = 0;
494     timing_param_seqs = 0;
495     timing_param_idxs = 0;
496     timing_param_count = -1;
497 }
498
499
500 int CvTest::init( CvTS* _test_system )
501 {
502     clear();
503     ts = _test_system;
504     return read_params( ts->get_file_storage() );
505 }
506
507
508 const char* CvTest::get_parent_name( const char* name, char* buffer )
509 {
510     const char* dash_pos = strrchr( name ? name : "", '-' );
511     if( !dash_pos )
512         return 0;
513     
514     if( name != (const char*)buffer )
515         strncpy( buffer, name, dash_pos - name );
516     buffer[dash_pos - name] = '\0';
517     return buffer;
518 }
519
520
521 const CvFileNode* CvTest::find_param( CvFileStorage* fs, const char* param_name )
522 {
523     char buffer[256];
524     const char* name = get_name();
525     CvFileNode* node = 0;
526
527     for(;;)
528     {
529         if( !name )
530             break;
531         node = cvGetFileNodeByName( fs, 0, name );
532         if( node )
533         {
534             node = cvGetFileNodeByName( fs, node, param_name );
535             if( node )
536                 break;
537         }
538         name = get_parent_name( name, buffer );
539     }
540
541     return node;
542 }
543
544
545 void CvTest::start_write_param( CvFileStorage* fs )
546 {
547     if( hdr_state == 0 )
548     {
549         cvStartWriteStruct( fs, get_name(), CV_NODE_MAP );
550         hdr_state = 1;
551     }
552 }
553
554
555 void CvTest::write_param( CvFileStorage* fs, const char* paramname, int val )
556 {
557     if( !ts->find_written_param( this, paramname, CV_NODE_INT, &val) )
558     {
559         start_write_param( fs );
560         cvWriteInt( fs, paramname, val );
561     }
562 }
563
564
565 void CvTest::write_param( CvFileStorage* fs, const char* paramname, double val )
566 {
567     if( !ts->find_written_param( this, paramname, CV_NODE_REAL, &val) )
568     {
569         start_write_param( fs );
570         cvWriteReal( fs, paramname, val );
571     }
572 }
573
574
575 void CvTest::write_param( CvFileStorage* fs, const char* paramname, const char* val )
576 {
577     if( !ts->find_written_param( this, paramname, CV_NODE_STRING, &val) )
578     {
579         start_write_param( fs );
580         cvWriteString( fs, paramname, val );
581     }
582 }
583
584
585 void CvTest::write_string_list( CvFileStorage* fs, const char* paramname, const char** val, int count )
586 {
587     if( val )
588     {
589         start_write_param( fs );
590         int i;
591         if( count < 0 )
592             count = INT_MAX;
593
594         cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
595         for( i = 0; i < count && val[i] != 0; i++ )
596             cvWriteString( fs, 0, val[i] );
597         cvEndWriteStruct( fs );
598     }
599 }
600
601
602 void CvTest::write_int_list( CvFileStorage* fs, const char* paramname,
603                              const int* val, int count, int stop_value )
604 {
605     if( val )
606     {
607         start_write_param( fs );
608         int i;
609         if( count < 0 )
610             count = INT_MAX;
611
612         cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
613         for( i = 0; i < count && val[i] != stop_value; i++ )
614             cvWriteInt( fs, 0, val[i] );
615         cvEndWriteStruct( fs );
616     }
617 }
618
619
620 void CvTest::write_real_list( CvFileStorage* fs, const char* paramname,
621                               const double* val, int count, double stop_value )
622 {
623     if( val )
624     {
625         start_write_param( fs );
626         int i;
627         if( count < 0 )
628             count = INT_MAX;
629
630         cvStartWriteStruct( fs, paramname, CV_NODE_SEQ + CV_NODE_FLOW );
631         for( i = 0; i < count && val[i] != stop_value; i++ )
632             cvWriteReal( fs, 0, val[i] );
633         cvEndWriteStruct( fs );
634     }
635 }
636
637
638 int CvTest::read_params( CvFileStorage* fs )
639 {
640     int code = 0;
641     
642     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
643     {
644         timing_param_names = find_param( fs, "timing_params" );
645         if( CV_NODE_IS_SEQ(timing_param_names->tag) )
646         {
647             CvSeq* seq = timing_param_names->data.seq;
648             CvSeqReader reader;
649             cvStartReadSeq( seq, &reader );
650             int i;
651
652             timing_param_count = seq->total;
653             timing_param_seqs = (const CvFileNode**)malloc( timing_param_count*sizeof(timing_param_seqs[0]));
654             timing_param_idxs = (int*)malloc( timing_param_count*sizeof(timing_param_idxs[0]));
655             timing_param_current = (const CvFileNode**)malloc( timing_param_count*sizeof(timing_param_current[0]));
656             test_case_count = 1;
657
658             for( i = 0; i < timing_param_count; i++ )
659             {
660                 CvFileNode* param_name = (CvFileNode*)(reader.ptr);
661
662                 if( !CV_NODE_IS_STRING(param_name->tag) )
663                 {
664                     ts->printf( CvTS::LOG, "ERROR: name of timing parameter #%d is not a string\n", i );
665                     code = -1;
666                     break;
667                 }
668
669                 timing_param_idxs[i] = 0;
670                 timing_param_current[i] = 0;
671                 timing_param_seqs[i] = find_param( fs, param_name->data.str.ptr );
672                 if( !timing_param_seqs[i] )
673                 {
674                     ts->printf( CvTS::LOG, "ERROR: timing parameter %s is not found\n", param_name->data.str.ptr );
675                     code = -1;
676                     break;
677                 }
678
679                 if( CV_NODE_IS_SEQ(timing_param_seqs[i]->tag) )
680                     test_case_count *= timing_param_seqs[i]->data.seq->total;
681
682                 CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
683             }
684
685             if( i < timing_param_count )
686                 timing_param_count = 0;
687         }
688         else
689         {
690             ts->printf( CvTS::LOG, "ERROR: \"timing_params\" is not found" );
691             code = -1;
692         }
693     }
694     
695     return code;
696 }
697
698
699 int CvTest::get_next_timing_param_tuple()
700 {
701     bool increment;
702     int i;
703     
704     if( timing_param_count <= 0 || !timing_param_names || !timing_param_seqs )
705         return -1;
706
707     increment = timing_param_current[0] != 0; // if already have some valid test tuple, move to the next
708     for( i = 0; i < timing_param_count; i++ )
709     {
710         const CvFileNode* node = timing_param_seqs[i];
711         int total = CV_NODE_IS_SEQ(node->tag) ? node->data.seq->total : 1;
712         int new_idx = timing_param_idxs[i];
713
714         if( !timing_param_current[i] )
715             timing_param_idxs[i] = new_idx = 0;
716         else if( increment )
717         {
718             new_idx++;
719             if( new_idx >= total )
720                 new_idx = 0;
721             else if( total > 1 )
722                 increment = false;
723         }
724
725         if( !timing_param_current[i] || new_idx != timing_param_idxs[i] )
726         {
727             if( CV_NODE_IS_SEQ(node->tag) )
728                 timing_param_current[i] = (CvFileNode*)cvGetSeqElem( node->data.seq, new_idx );
729             else
730                 timing_param_current[i] = node;
731             timing_param_idxs[i] = new_idx;
732         }
733     }
734
735     return !increment; // return 0 in case of overflow (i.e. if there is no more test cases)
736 }
737
738
739 const CvFileNode* CvTest::find_timing_param( const char* paramname )
740 {
741     if( timing_param_names )
742     {
743         int i;
744         CvSeqReader reader;
745         cvStartReadSeq( timing_param_names->data.seq, &reader, 0 );
746
747         for( i = 0; i < timing_param_count; i++ )
748         {
749             const char* ptr = ((const CvFileNode*)(reader.ptr))->data.str.ptr;
750             if( ptr[0] == paramname[0] && strcmp(ptr, paramname) == 0 )
751                 return timing_param_current[i];
752             CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
753         }
754     }
755     return 0;
756 }
757
758
759 int CvTest::write_defaults(CvTS* _ts)
760 {
761     ts = _ts;
762     hdr_state = 0;
763     write_default_params( ts->get_file_storage() );
764     if( hdr_state )
765         cvEndWriteStruct( ts->get_file_storage() );
766     return 0;
767 }
768
769
770 int CvTest::write_default_params( CvFileStorage* fs )
771 {
772     if( ts->get_testing_mode() == CvTS::TIMING_MODE )
773         write_string_list( fs, "timing_params", default_timing_param_names, timing_param_count );
774     return 0;
775 }
776
777
778 bool CvTest::can_do_fast_forward()
779 {
780     return true;
781 }
782
783
784 int CvTest::get_support_testing_modes()
785 {
786     return support_testing_modes;
787 }
788
789 void CvTest::safe_run( int start_from )
790 {
791     CV_TS_TRY_BLOCK_BEGIN;
792
793     run( start_from );
794
795     CV_TS_TRY_BLOCK_END;
796 }
797
798
799 void CvTest::run( int start_from )
800 {
801     int i, test_case_idx, count = get_test_case_count();
802     int64 t_start = cvGetTickCount();
803     double freq = cvGetTickFrequency();
804     bool ff = can_do_fast_forward();
805     int progress = 0, code;
806     
807     for( test_case_idx = ff && start_from >= 0 ? start_from : 0;
808          count < 0 || test_case_idx < count; test_case_idx++ )
809     {
810         ts->update_context( this, test_case_idx, ff );
811         int64 t00 = 0, t0, t1 = 0;
812         double t_acc = 0;
813
814         if( ts->get_testing_mode() == CvTS::TIMING_MODE )
815         {
816             const int iterations = 15;
817             code = prepare_test_case( test_case_idx );
818             
819             if( code < 0 || ts->get_err_code() < 0 )
820                 return;
821
822             if( code == 0 )
823                 continue;
824
825             for( i = 0; i < iterations; i++ )
826             {
827                 t0 = cvGetTickCount();
828                 run_func();
829                 t1 = cvGetTickCount();
830                 if( ts->get_err_code() < 0 )
831                     return;
832
833                 if( i == 0 )
834                 {
835                     t_acc = (double)(t1 - t0);
836                     t00 = t0;
837                 }
838                 else
839                 {
840                     t0 = t1 - t0;
841                 
842                     if( ts->get_timing_mode() == CvTS::MIN_TIME )
843                     {
844                         if( (double)t0 < t_acc )
845                             t_acc = (double)t0;
846                     }
847                     else
848                     {
849                         assert( ts->get_timing_mode() == CvTS::AVG_TIME );
850                         t_acc += (double)t0;
851                     }
852                 
853                     if( t1 - t00 > freq*2000000 )
854                         break;
855                 }
856             }
857
858             if( ts->get_timing_mode() == CvTS::AVG_TIME )
859                 t_acc /= i;
860             print_time( test_case_idx, t_acc );
861         }
862         else
863         {
864             code = prepare_test_case( test_case_idx );
865             if( code < 0 || ts->get_err_code() < 0 )
866                 return;
867
868             if( code == 0 )
869                 continue;
870
871             run_func();
872             if( ts->get_err_code() < 0 )
873                 return;
874
875             if( validate_test_results( test_case_idx ) < 0 || ts->get_err_code() < 0 )
876                 return;
877         }
878
879         progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) );
880     }
881 }
882
883
884 void CvTest::run_func()
885 {
886     assert(0);
887 }
888
889
890 int CvTest::get_test_case_count()
891 {
892     return test_case_count;
893 }
894
895
896 int CvTest::prepare_test_case( int )
897 {
898     return 0;
899 }
900
901
902 int CvTest::validate_test_results( int )
903 {
904     return 0;
905 }
906
907
908 void CvTest::print_time( int /*test_case_idx*/, double /*time_usecs*/ )
909 {
910 }
911
912
913 int CvTest::update_progress( int progress, int test_case_idx, int count, double dt )
914 {
915     int width = 60 - (int)strlen(get_name());
916     if( count > 0 )
917     {
918         int t = cvRound( ((double)test_case_idx * width)/count );
919         if( t > progress )
920         {
921             ts->printf( CvTS::CONSOLE, "." );
922             progress = t;
923         }
924     }
925     else if( cvRound(dt*0.001) > progress )
926     {
927         ts->printf( CvTS::CONSOLE, "." );
928         progress = cvRound(dt*0.001);
929     }
930
931     return progress;
932 }
933
934 /*****************************************************************************************\
935 *                                 Base Class for Test System                              *
936 \*****************************************************************************************/
937
938 /******************************** Constructors/Destructors ******************************/
939
940 CvTS::CvTS()
941 {
942     start_time = 0;
943     version = CV_TS_VERSION;
944     memory_manager = 0;
945     /*
946     memory_manager = new CvTestMemoryManager(this);
947     cvSetMemoryManager( CvTestMemoryManager::alloc_proxy,
948                         CvTestMemoryManager::free_proxy,
949                         memory_manager );*/
950     ostrm_suffixes[SUMMARY_IDX] = ".sum";
951     ostrm_suffixes[LOG_IDX] = ".log";
952     ostrm_suffixes[CSV_IDX] = ".csv";
953     ostrm_suffixes[CONSOLE_IDX] = 0;
954     ostrm_base_name = 0;
955     memset( output_streams, 0, sizeof(output_streams) );
956     memset( &params, 0, sizeof(params) );
957     selected_tests = new CvTestPtrVec();
958     failed_tests = new CvTestInfoVec();
959     written_params = new CvTestPtrVec();
960
961     clear();
962 }
963
964
965 void CvTS::clear()
966 {
967     int i;
968     CvTest* test;
969
970     for( test = get_first_test(); test != 0; test = test->get_next() )
971         test->clear();
972
973     for( i = 0; i <= CONSOLE_IDX; i++ )
974     {
975         if( i == LOG_IDX )
976             fflush( stderr );
977         else if( i == CONSOLE_IDX )
978             fflush( stdout );
979
980         if( i < CONSOLE_IDX && output_streams[i].f )
981         {
982             fclose( output_streams[i].f );
983             output_streams[i].f = 0;
984         }
985         
986         if( i == LOG_IDX && output_streams[i].default_handle > 0 )
987         {
988             dup2( output_streams[i].default_handle, 2 );
989             output_streams[i].default_handle = 0;
990         }
991         output_streams[i].enable = 1;
992     }
993     cvReleaseFileStorage( &fs );
994     selected_tests->clear();
995     failed_tests->clear();
996     if( ostrm_base_name )
997     {
998         free( ostrm_base_name );
999         ostrm_base_name = 0;
1000     }
1001     params.rng_seed = (uint64)-1;
1002     params.debug_mode = 1;
1003     params.print_only_failed = 0;
1004     params.skip_header = 0;
1005     params.test_mode = CORRECTNESS_CHECK_MODE;
1006     params.timing_mode = MIN_TIME;
1007     params.use_optimized = -1;
1008
1009     if( memory_manager )
1010         memory_manager->clear_and_check();
1011 }
1012
1013
1014 CvTS::~CvTS()
1015 {
1016     clear();
1017
1018     if( written_params )
1019     {
1020         for( int i = 0; i < written_params->size(); i++ )
1021             free( written_params->at(i) );
1022         delete written_params;
1023     }
1024
1025     delete selected_tests;
1026     delete failed_tests;
1027     cvSetMemoryManager( 0, 0 );
1028 }
1029
1030
1031 const char* CvTS::str_from_code( int code )
1032 {
1033     switch( code )
1034     {
1035     case OK: return "Ok";
1036     case FAIL_GENERIC: return "Generic/Unknown";
1037     case FAIL_MISSING_TEST_DATA: return "No test data";
1038     case FAIL_ERROR_IN_CALLED_FUNC: return "cvError invoked";
1039     case FAIL_EXCEPTION: return "Hardware/OS exception";
1040     case FAIL_MEMORY_EXCEPTION: return "Invalid memory access";
1041     case FAIL_ARITHM_EXCEPTION: return "Arithmetic exception";
1042     case FAIL_MEMORY_CORRUPTION_BEGIN: return "Corrupted memblock (beginning)";
1043     case FAIL_MEMORY_CORRUPTION_END: return "Corrupted memblock (end)";
1044     case FAIL_MEMORY_LEAK: return "Memory leak";
1045     case FAIL_INVALID_OUTPUT: return "Invalid function output";
1046     case FAIL_MISMATCH: return "Unexpected output";
1047     case FAIL_BAD_ACCURACY: return "Bad accuracy";
1048     case FAIL_HANG: return "Infinite loop(?)";
1049     case FAIL_BAD_ARG_CHECK: return "Incorrect handling of bad arguments";
1050     default: return "Generic/Unknown";
1051     }
1052 }
1053
1054 /************************************** Running tests **********************************/
1055
1056 void CvTS::make_output_stream_base_name( const char* config_name )
1057 {
1058     int k, len = (int)strlen( config_name );
1059
1060     if( ostrm_base_name )
1061         free( ostrm_base_name );
1062
1063     for( k = len-1; k >= 0; k-- )
1064     {
1065         char c = config_name[k];
1066         if( c == '.' || c == '/' || c == '\\' || c == ':' )
1067             break;
1068     }
1069
1070     if( k > 0 && config_name[k] == '.' )
1071         len = k;
1072     
1073     ostrm_base_name = (char*)malloc( len + 1 );
1074     memcpy( ostrm_base_name, config_name, len );
1075     ostrm_base_name[len] = '\0';
1076 }
1077
1078
1079 void CvTS::set_handlers( bool on )
1080 {
1081     if( on )
1082     {
1083         cvSetErrMode( CV_ErrModeParent );
1084         cvRedirectError( cvStdErrReport );
1085     #ifdef WIN32
1086         #ifdef _MSC_VER
1087         _set_se_translator( cv_seh_translator );
1088         #endif
1089     #else
1090         for( int i = 0; cv_ts_sig_id[i] >= 0; i++ )
1091             signal( cv_ts_sig_id[i], cv_signal_handler );
1092     #endif
1093     }
1094     else
1095     {
1096         cvSetErrMode( CV_ErrModeLeaf );
1097         cvRedirectError( cvGuiBoxReport );
1098     #ifdef WIN32
1099         #ifdef _MSC_VER
1100         _set_se_translator( 0 );
1101         #endif
1102     #else
1103         for( int i = 0; cv_ts_sig_id[i] >= 0; i++ )
1104             signal( cv_ts_sig_id[i], SIG_DFL );
1105     #endif
1106     }
1107 }
1108
1109
1110 typedef struct CvTsParamVal
1111 {
1112     const char* fullname;
1113     const void* val;
1114 }
1115 CvTsParamVal;
1116
1117 int CvTS::find_written_param( CvTest* test, const char* paramname, int valtype, const void* val )
1118 {
1119     const char* testname = test->get_name();
1120     bool add_to_list = test->get_func_list()[0] == '\0';
1121     char buffer[256];
1122     int paramname_len = (int)strlen(paramname);
1123     int paramval_len = valtype == CV_NODE_INT ? sizeof(int) :
1124         valtype == CV_NODE_REAL ? sizeof(double) : -1;
1125     const char* name = CvTest::get_parent_name( testname, buffer );
1126
1127     if( !fs )
1128         return -1;
1129
1130     if( paramval_len < 0 )
1131     {
1132         assert(0); // unsupported parameter type
1133         return -1;
1134     }
1135
1136     while( name )
1137     {
1138         int i, len = (int)strlen(buffer);
1139         buffer[len] = '.';
1140         memcpy( buffer + len + 1, paramname, paramname_len + 1 );
1141         for( i = 0; i < written_params->size(); i++ )
1142         {
1143             CvTsParamVal* param = (CvTsParamVal*)written_params->at(i);
1144             if( strcmp( param->fullname, buffer ) == 0 )
1145             {
1146                 if( paramval_len > 0 && memcmp( param->val, val, paramval_len ) == 0 ||
1147                     paramval_len < 0 && strcmp( (const char*)param->val, (const char*)val ) == 0 )
1148                     return 1;
1149                 break;
1150             }
1151         }
1152         if( i < written_params->size() )
1153             break;
1154         buffer[len] = '\0';
1155         name = CvTest::get_parent_name( buffer, buffer );
1156     }
1157
1158     if( add_to_list )
1159     {
1160         int bufsize, fullname_len = (int)strlen(testname) + paramname_len + 2;
1161         CvTsParamVal* param;
1162         if( paramval_len < 0 )
1163             paramval_len = (int)strlen((const char*)val) + 1;
1164         bufsize = sizeof(*param) + fullname_len + paramval_len;
1165         param = (CvTsParamVal*)malloc(bufsize);
1166         param->fullname = (const char*)(param + 1);
1167         param->val = param->fullname + fullname_len;
1168         sprintf( (char*)param->fullname, "%s.%s", testname, paramname );
1169         memcpy( (void*)param->val, val, paramval_len );
1170         written_params->push( param );
1171     }
1172
1173     return 0;
1174 }
1175
1176
1177 #ifndef MAX_PATH
1178 #define MAX_PATH 1024
1179 #endif
1180
1181 static int CV_CDECL cmp_test_names( const void* a, const void* b )
1182 {
1183     return strcmp( (*(const CvTest**)a)->get_name(), (*(const CvTest**)b)->get_name() );
1184 }
1185
1186 int CvTS::run( int argc, char** argv )
1187 {
1188     time( &start_time );
1189     
1190     int i, write_params = 0;
1191     int list_tests = 0;
1192     CvTestPtrVec all_tests;
1193     CvTest* test;
1194
1195     // 0. reset all the parameters, reorder tests
1196     clear();
1197
1198     for( test = get_first_test(), i = 0; test != 0; test = test->get_next(), i++ )
1199         all_tests.push(test);
1200
1201     if( all_tests.size() > 0 && all_tests.data() )
1202         qsort( all_tests.data(), all_tests.size(), sizeof(CvTest*), cmp_test_names );
1203
1204     // 1. parse command line options
1205     for( i = 1; i < argc; i++ )
1206     {
1207         if( argv[i] && argv[i][0] != '-' )
1208         {
1209             config_name = argv[i];
1210             break;
1211         }
1212         else
1213         {
1214             if( strcmp( argv[i], "-w" ) == 0 )
1215                 write_params = 1;
1216             else if( strcmp( argv[i], "-t" ) == 0 )
1217                 params.test_mode = TIMING_MODE;
1218             else if( strcmp( argv[i], "-l" ) == 0 )
1219                 list_tests = 1;
1220         }
1221     }
1222
1223     if( write_params )
1224     {
1225         if( !config_name )
1226         {
1227             printf( LOG, "ERROR: output config name is not specified\n" );
1228             return -1;
1229         }
1230         fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_WRITE );
1231         if( !fs )
1232         {
1233             printf( LOG, "ERROR: could not open config file %s", config_name );
1234             return -1;
1235         }
1236         cvWriteComment( fs, CV_TS_VERSION " config file", 0 );
1237         cvStartWriteStruct( fs, "common", CV_NODE_MAP );
1238         write_default_params( fs );
1239         cvEndWriteStruct( fs );
1240
1241         for( i = 0; i < all_tests.size(); i++ )
1242         {
1243             test = (CvTest*)all_tests[i];
1244             if( !(test->get_support_testing_modes() & get_testing_mode()) )
1245                 continue;
1246             test->write_defaults( this );
1247             test->clear();
1248         }
1249         cvReleaseFileStorage( &fs );
1250         return 0;
1251     }
1252
1253     if( !config_name )
1254         printf( LOG, "WARNING: config name is not specified, using default parameters\n" );
1255     else
1256     {
1257         // 2. read common parameters of test system
1258         fs = cvOpenFileStorage( config_name, 0, CV_STORAGE_READ );
1259         if( !fs )
1260         {
1261             printf( LOG, "ERROR: could not open config file %s", config_name );
1262             return -1;
1263         }
1264     }
1265
1266     if( read_params(fs) < 0 )
1267         return -1;
1268
1269     if( !ostrm_base_name )
1270         make_output_stream_base_name( config_name ? config_name : argv[0] );
1271
1272     ostream_testname_mask = -1; // disable printing test names at initial stage
1273
1274     // 3. open file streams
1275     for( i = 0; i < CONSOLE_IDX; i++ )
1276     {
1277         char filename[MAX_PATH];
1278         sprintf( filename, "%s%s", ostrm_base_name, ostrm_suffixes[i] );
1279         output_streams[i].f = fopen( filename, "wt" );
1280         if( !output_streams[i].f )
1281         {
1282             printf( LOG, "ERROR: could not open %s\n", filename );
1283             return -1;
1284         }
1285
1286         if( i == LOG_IDX )
1287         {
1288             // redirect stderr to log file
1289             fflush( stderr );
1290             output_streams[i].default_handle = dup(2);
1291             dup2( fileno(output_streams[i].f), 2 );
1292         }
1293     }
1294
1295     // 4. traverse through the list of all registered tests.
1296     // Initialize the selected tests and put them into the separate sequence
1297     for( i = 0; i < all_tests.size(); i++ )
1298     {
1299         test = (CvTest*)all_tests[i];
1300         if( !(test->get_support_testing_modes() & get_testing_mode()) )
1301             continue;
1302
1303         if( strcmp( test->get_func_list(), "" ) != 0 && filter(test) )
1304         {
1305             if( test->init(this) >= 0 )
1306             {
1307                 selected_tests->push( test );
1308                 if( list_tests )
1309                     ::printf( "%s\n", test->get_name() );
1310             }
1311             else
1312                 printf( LOG, "WARNING: an error occured during test %s initialization\n", test->get_name() );
1313         }
1314     }
1315
1316     if( list_tests )
1317         goto _exit_;
1318
1319     // 5. setup all the neccessary handlers and print header
1320     set_handlers( !params.debug_mode );
1321
1322     if( params.use_optimized >= 0 )
1323     {
1324         printf( LOG, params.use_optimized ? "Loading optimized plugins..." : "Unloading optimized plugins..." );
1325         if( params.use_optimized == 0 )
1326             cvUseOptimized(0);
1327         /*else
1328             cvUseOptimized(1); // this is done anyway, so we comment it off
1329         */
1330     }
1331
1332     if( !params.skip_header )
1333         print_summary_header( SUMMARY + LOG + CONSOLE + CSV );
1334     rng = params.rng_seed;
1335     update_context( 0, -1, true );
1336
1337     // 6. run all the tests
1338     for( i = 0; i < selected_tests->size(); i++ )
1339     {
1340         CvTest* test = (CvTest*)selected_tests->at(i);
1341         int code;
1342         CvTestInfo temp;
1343
1344         if( memory_manager )
1345             memory_manager->start_tracking();
1346         update_context( test, -1, true );
1347         ostream_testname_mask = 0; // reset "test name was printed" flags
1348         if( output_streams[LOG_IDX].f )
1349             fflush( output_streams[LOG_IDX].f );
1350
1351         temp = current_test_info;
1352         test->safe_run(0);
1353         if( get_err_code() >= 0 )
1354         {
1355             update_context( test, -1, false );
1356             current_test_info.rng_seed = temp.rng_seed;
1357             current_test_info.base_alloc_index = temp.base_alloc_index;
1358         }
1359         test->clear();
1360         if( memory_manager )
1361             memory_manager->stop_tracking_and_check();
1362
1363         code = get_err_code();
1364         if( code >= 0 )
1365         {
1366             if( !params.print_only_failed )
1367             {
1368                 printf( SUMMARY + CONSOLE, "\t" );
1369                 change_color( CV_TS_GREEN );
1370                 printf( SUMMARY + CONSOLE, "Ok\n" );
1371                 change_color( CV_TS_NORMAL );
1372             }
1373         }
1374         else
1375         {
1376             printf( SUMMARY + CONSOLE, "\t" );
1377             change_color( CV_TS_RED );
1378             printf( SUMMARY + CONSOLE, "FAIL(%s)\n", str_from_code(code) );
1379             change_color( CV_TS_NORMAL );
1380             printf( LOG, "context: test case = %d, seed = %08x%08x\n",
1381                     current_test_info.test_case_idx,
1382                     (unsigned)(current_test_info.rng_seed>>32),
1383                     (unsigned)(current_test_info.rng_seed));
1384             failed_tests->push(current_test_info);
1385             if( params.rerun_immediately )
1386                 break;
1387         }
1388     }
1389
1390     ostream_testname_mask = -1;
1391     print_summary_tailer( SUMMARY + CONSOLE + LOG );
1392
1393     if( !params.debug_mode && (params.rerun_failed || params.rerun_immediately) )
1394     {
1395         set_handlers(0);
1396         update_context( 0, -1, true );
1397         for( i = 0; i < failed_tests->size(); i++ )
1398         {
1399             CvTestInfo info = failed_tests->at(i);
1400             if( (info.code == FAIL_MEMORY_CORRUPTION_BEGIN ||
1401                 info.code == FAIL_MEMORY_CORRUPTION_END ||
1402                 info.code == FAIL_MEMORY_LEAK) && memory_manager )
1403                 memory_manager->start_tracking( info.alloc_index - info.base_alloc_index
1404                                                 + memory_manager->get_alloc_index() );
1405             rng = info.rng_seed;
1406             test->safe_run( info.test_case_idx );
1407         }
1408     }
1409 _exit_:
1410     clear();
1411
1412     return 0;
1413 }
1414
1415
1416 int CvTS::read_params( CvFileStorage* fs )
1417 {
1418     CvFileNode* node = fs ? cvGetFileNodeByName( fs, 0, "common" ) : 0;
1419     params.debug_mode = cvReadIntByName( fs, node, "debug_mode", 1 ) != 0;
1420     params.skip_header = cvReadIntByName( fs, node, "skip_header", 0 ) != 0;
1421     params.print_only_failed = cvReadIntByName( fs, node, "print_only_failed", 0 ) != 0;
1422     params.rerun_failed = cvReadIntByName( fs, node, "rerun_failed", 0 ) != 0;
1423     params.rerun_immediately = cvReadIntByName( fs, node, "rerun_immediately", 0 ) != 0;
1424     const char* str = cvReadStringByName( fs, node, "filter_mode", "tests" );
1425     params.test_filter_mode = strcmp( str, "functions" ) == 0 ? CHOOSE_FUNCTIONS : CHOOSE_TESTS;
1426     str = cvReadStringByName( fs, node, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" ); 
1427     params.test_mode = strcmp( str, "timing" ) == 0 || strcmp( str, "performance" ) == 0 ?
1428                         TIMING_MODE : CORRECTNESS_CHECK_MODE;
1429     str = cvReadStringByName( fs, node, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" ); 
1430     params.timing_mode = strcmp( str, "average" ) == 0 || strcmp( str, "avg" ) == 0 ? AVG_TIME : MIN_TIME;
1431     params.test_filter_pattern = cvReadStringByName( fs, node, params.test_filter_mode == CHOOSE_FUNCTIONS ?
1432                                                      "functions" : "tests", "" );
1433     params.resource_path = cvReadStringByName( fs, node, "." );
1434     params.use_optimized = cvReadIntByName( fs, node, "use_optimized", -1 );
1435     str = cvReadStringByName( fs, node, "seed", 0 );
1436     params.rng_seed = 0;
1437     if( str && strlen(str) == 16 )
1438     {
1439         params.rng_seed = 0;
1440         for( int i = 0; i < 16; i++ )
1441         {
1442             int c = tolower(str[i]);
1443             if( !isxdigit(c) )
1444             {
1445                 params.rng_seed = 0;
1446                 break;
1447             }
1448             params.rng_seed = params.rng_seed * 16 +
1449                 (str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10);
1450         }
1451     }
1452     
1453     if( params.rng_seed == 0 )
1454         params.rng_seed = cvGetTickCount();
1455
1456     str = cvReadStringByName( fs, node, "output_file_base_name", 0 );
1457     if( str )
1458         make_output_stream_base_name( str );
1459
1460     return 0;
1461 }
1462
1463
1464 void CvTS::write_default_params( CvFileStorage* fs )
1465 {
1466     read_params(0); // fill parameters with default values
1467
1468     cvWriteInt( fs, "debug_mode", params.debug_mode );
1469     cvWriteInt( fs, "skip_header", params.skip_header );
1470     cvWriteInt( fs, "print_only_failed", params.print_only_failed );
1471     cvWriteInt( fs, "rerun_failed", params.rerun_failed );
1472     cvWriteInt( fs, "rerun_immediately", params.rerun_immediately );
1473     cvWriteString( fs, "filter_mode", params.test_filter_mode == CHOOSE_FUNCTIONS ? "functions" : "tests" );
1474     cvWriteString( fs, "test_mode", params.test_mode == TIMING_MODE ? "timing" : "correctness" );
1475     if( params.test_mode == TIMING_MODE )
1476         cvWriteString( fs, "timing_mode", params.timing_mode == AVG_TIME ? "avg" : "min" );
1477     // test_filter, seed & output_file_base_name are not written
1478 }
1479
1480
1481 void CvTS::enable_output_streams( int stream_mask, int value )
1482 {
1483     for( int i = 0; i < MAX_IDX; i++ )
1484         if( stream_mask & (1 << i) )
1485             output_streams[i].enable = value != 0;
1486 }
1487
1488
1489 void CvTS::update_context( CvTest* test, int test_case_idx, bool update_ts_context )
1490 {
1491     current_test_info.test = test;
1492     current_test_info.test_case_idx = test_case_idx;
1493     current_test_info.alloc_index = 0;
1494     current_test_info.code = 0;
1495     cvSetErrStatus( CV_StsOk );
1496     if( update_ts_context )
1497     {
1498         current_test_info.rng_seed = rng;
1499         current_test_info.base_alloc_index = memory_manager ?
1500             memory_manager->get_alloc_index() : 0;
1501     }
1502 }
1503
1504
1505 void CvTS::set_failed_test_info( int fail_code, int alloc_index )
1506 {
1507     if( fail_code == FAIL_MEMORY_CORRUPTION_BEGIN ||
1508         fail_code == FAIL_MEMORY_CORRUPTION_END ||
1509         current_test_info.code >= 0 )
1510     {
1511         current_test_info.code = fail_code;
1512         current_test_info.alloc_index = alloc_index;
1513     }
1514 }
1515
1516
1517 const char* CvTS::get_libs_info( const char** addon_modules )
1518 {
1519     const char* all_info = 0;
1520     cvGetModuleInfo( 0, &all_info, addon_modules );
1521     return all_info;
1522 }
1523
1524
1525 void CvTS::print_summary_header( int streams )
1526 {
1527     char csv_header[256], *ptr = csv_header;
1528     int i, len;
1529
1530     printf( streams, "Engine: %s\n", version );
1531     time_t t1;
1532     time( &t1 );
1533     struct tm *t2 = localtime( &t1 );
1534     char buf[1024];
1535     strftime( buf, sizeof(buf)-1, "%c", t2 );
1536     printf( streams, "Execution Date & Time: %s\n", buf );
1537     printf( streams, "Config File: %s\n", config_name );
1538     const char* plugins = 0;
1539     const char* lib_verinfo = get_libs_info( &plugins );
1540     printf( streams, "Tested Libraries: %s\n", lib_verinfo );
1541     printf( streams, "Optimized Low-level Plugin\'s: %s\n", plugins );
1542     printf( streams, "=================================================\n");
1543
1544     len = 0;
1545     sprintf( ptr, "funcName,dataType,channels,size,%n", &len );
1546     ptr += len;
1547
1548     for( i = 0; i < CvTest::TIMING_EXTRA_PARAMS; i++ )
1549     {
1550         len = 0;
1551         sprintf( ptr, "param%d,%n", i, &len );
1552         ptr += len;
1553     }
1554
1555     sprintf( ptr, "CPE,Time(uSecs)" );
1556     printf( CSV, "%s\n", csv_header );
1557 }
1558
1559     
1560 void CvTS::print_summary_tailer( int streams )
1561 {
1562     printf( streams, "=================================================\n");
1563     if( selected_tests && failed_tests )
1564     {
1565         time_t end_time;
1566         time( &end_time );
1567         double total_time = difftime( end_time, start_time );
1568         printf( streams, "Summary: %d out of %d tests failed\n",
1569             failed_tests->size(), selected_tests->size() );
1570         int minutes = cvFloor(total_time/60.);
1571         int seconds = cvRound(total_time - minutes*60);
1572         int hours = minutes / 60;
1573         minutes %= 60;
1574         printf( streams, "Running time: %02d:%02d:%02d\n", hours, minutes, seconds );
1575     }
1576 }
1577
1578
1579 void CvTS::vprintf( int streams, const char* fmt, va_list l )
1580 {
1581     if( streams )
1582     {
1583         char str[1 << 14];
1584         vsprintf( str, fmt, l );
1585
1586         for( int i = 0; i < MAX_IDX; i++ )
1587         {
1588             if( (streams & (1 << i)) && output_streams[i].enable )
1589             {
1590                 FILE* f = i == CONSOLE_IDX ? stdout :
1591                           i == LOG_IDX ? stderr : output_streams[i].f;
1592                 if( f )
1593                 {
1594                     if( i != CSV_IDX && !(ostream_testname_mask & (1 << i)) && current_test_info.test )
1595                     {
1596                         fprintf( f, "-------------------------------------------------\n" );
1597                         fprintf( f, "%s: ", current_test_info.test->get_name() );
1598                         fflush( f );
1599                         ostream_testname_mask |= 1 << i;
1600                     }
1601                     fputs( str, f );
1602                     if( i == CONSOLE_IDX )
1603                         fflush(f);
1604                 }
1605             }
1606         }
1607     }
1608 }
1609
1610
1611 void CvTS::printf( int streams, const char* fmt, ... )
1612 {
1613     if( streams )
1614     {
1615         va_list l;
1616         va_start( l, fmt );
1617         vprintf( streams, fmt, l );
1618         va_end( l );
1619     }
1620 }
1621
1622
1623 static char* cv_strnstr( const char* str, int len,
1624                          const char* pattern,
1625                          int pattern_len = -1,
1626                          int whole_word = 1 )
1627 {
1628     int i;
1629
1630     if( len < 0 && pattern_len < 0 )
1631         return (char*)strstr( str, pattern );
1632
1633     if( len < 0 )
1634         len = (int)strlen( str );
1635
1636     if( pattern_len < 0 )
1637         pattern_len = (int)strlen( pattern );
1638
1639     for( i = 0; i < len - pattern_len + 1; i++ )
1640     {
1641         int j = i + pattern_len;
1642         if( str[i] == pattern[0] &&
1643             memcmp( str + i, pattern, pattern_len ) == 0 &&
1644             (!whole_word ||
1645             ((i == 0 || !isalnum(str[i-1]) && str[i-1] != '_') &&
1646              (j == len || !isalnum(str[j]) && str[j] != '_'))))
1647             return (char*)(str + i);
1648     }
1649
1650     return 0;
1651 }
1652
1653
1654 int CvTS::filter( CvTest* test )
1655 {
1656     const char* pattern = params.test_filter_pattern;
1657
1658     if( !pattern || strcmp( pattern, "" ) == 0 || strcmp( pattern, "*" ) == 0 )
1659         return 1;
1660
1661     if( params.test_filter_mode == CHOOSE_TESTS )
1662     {
1663         int found = 0;
1664         
1665         while( pattern && *pattern )
1666         {
1667             char *ptr, *endptr = (char*)strchr( pattern, ',' );
1668             int len, have_wildcard;
1669             int t_name_len;
1670
1671             if( endptr )
1672                 *endptr = '\0';
1673
1674             ptr = (char*)strchr( pattern, '*' );
1675             if( ptr )
1676             {
1677                 len = (int)(ptr - pattern);
1678                 have_wildcard = 1;
1679             }
1680             else
1681             {
1682                 len = (int)strlen( pattern );
1683                 have_wildcard = 0;
1684             }
1685
1686             t_name_len = (int)strlen( test->get_name() );
1687             found = (t_name_len == len || have_wildcard && t_name_len > len) &&
1688                     (len == 0 || memcmp( test->get_name(), pattern, len ) == 0);
1689             if( endptr )
1690             {
1691                 *endptr = ',';
1692                 pattern = endptr + 1;
1693                 while( isspace(*pattern) )
1694                     pattern++;
1695             }
1696
1697             if( found || !endptr )
1698                 break;
1699         }
1700
1701         return found;
1702     }
1703     else
1704     {
1705         assert( params.test_filter_mode == CHOOSE_FUNCTIONS );
1706         int glob_len = (int)strlen( pattern );
1707         const char* ptr = test->get_func_list();
1708         const char *tmp_ptr;
1709
1710         while( ptr && *ptr )
1711         {
1712             const char* endptr = ptr - 1;
1713             const char* name_ptr;
1714             const char* name_first_match;
1715             int name_len;
1716             char c;
1717
1718             do c = *++endptr;
1719             while( isspace(c) );
1720
1721             if( !c )
1722                 break;
1723
1724             assert( isalpha(c) );
1725             name_ptr = endptr;
1726
1727             do c = *++endptr;
1728             while( isalnum(c) || c == '_' );
1729
1730             if( c == ':' ) // class
1731             {
1732                 assert( endptr[1] == ':' );
1733                 endptr = endptr + 2;
1734                 name_len = (int)(endptr - name_ptr);
1735
1736                 // find the first occurence of the class name
1737                 // in pattern
1738                 name_first_match = cv_strnstr( pattern,
1739                                       glob_len, name_ptr, name_len, 1 );
1740
1741                 if( *endptr == '*' )
1742                 {
1743                     if( name_first_match )
1744                         return 1;
1745                 }
1746                 else
1747                 {
1748                     assert( *endptr == '{' ); // a list of methods
1749
1750                     if( !name_first_match )
1751                     {
1752                         // skip all the methods, if there is no such a class name
1753                         // in pattern
1754                         endptr = strchr( endptr, '}' );
1755                         assert( endptr != 0 );
1756                         endptr--;
1757                     }
1758
1759                     for( ;; )
1760                     {
1761                         const char* method_name_ptr;
1762                         int method_name_len;
1763
1764                         do c = *++endptr;
1765                         while( isspace(c) );
1766
1767                         if( c == '}' )
1768                             break;
1769                         assert( isalpha(c) );
1770
1771                         method_name_ptr = endptr;
1772                     
1773                         do c = *++endptr;
1774                         while( isalnum(c) || c == '_' );
1775                     
1776                         method_name_len = (int)(endptr - method_name_ptr);
1777                     
1778                         // search for class_name::* or
1779                         // class_name::{...method_name...}
1780                         tmp_ptr = name_first_match;
1781                         do
1782                         {
1783                             const char* tmp_ptr2;
1784                             tmp_ptr += name_len;
1785                             if( *tmp_ptr == '*' )
1786                                 return 1;
1787                             assert( *tmp_ptr == '{' );
1788                             tmp_ptr2 = strchr( tmp_ptr, '}' );
1789                             assert( tmp_ptr2 );
1790
1791                             if( cv_strnstr( tmp_ptr, (int)(tmp_ptr2 - tmp_ptr) + 1,
1792                                              method_name_ptr, method_name_len, 1 ))
1793                                 return 1;
1794
1795                             tmp_ptr = cv_strnstr( tmp_ptr2, glob_len -
1796                                                    (int)(tmp_ptr2 - pattern),
1797                                                    name_ptr, name_len, 1 );
1798                         }
1799                         while( tmp_ptr );
1800
1801                         endptr--;
1802                         do c = *++endptr;
1803                         while( isspace(c) );
1804
1805                         if( c != ',' )
1806                             endptr--;
1807                     }
1808                 }
1809             }
1810             else
1811             {
1812                 assert( !c || isspace(c) || c == ',' );
1813                 name_len = (int)(endptr - name_ptr);
1814                 tmp_ptr = pattern;
1815
1816                 for(;;)
1817                 {
1818                     const char *tmp_ptr2, *tmp_ptr3;
1819
1820                     tmp_ptr = cv_strnstr( tmp_ptr, glob_len -
1821                         (int)(tmp_ptr - pattern), name_ptr, name_len, 1 );
1822
1823                     if( !tmp_ptr )
1824                         break;
1825
1826                     // make sure it is not a method
1827                     tmp_ptr2 = strchr( tmp_ptr, '}' );
1828                     if( !tmp_ptr2 )
1829                         return 1;
1830
1831                     tmp_ptr3 = strchr( tmp_ptr, '{' );
1832                     if( tmp_ptr3 < tmp_ptr2 )
1833                         return 1;
1834
1835                     tmp_ptr = tmp_ptr2 + 1;
1836                 }
1837
1838                 endptr--;
1839             }
1840
1841             do c = *++endptr;
1842             while( isspace(c) );
1843
1844             if( c == ',' )
1845                 endptr++;
1846             ptr = endptr;
1847         }
1848
1849         return 0;
1850     }
1851 }
1852
1853 /* End of file. */