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