Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / test / impl / test_tools.ipp
1 //  (C) Copyright Gennadiy Rozental 2005-2008.
2 //  Distributed under the Boost Software License, Version 1.0.
3 //  (See accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt)
5
6 //  See http://www.boost.org/libs/test for the library home page.
7 //
8 //  File        : $RCSfile$
9 //
10 //  Version     : $Revision$
11 //
12 //  Description : supplies offline implementation for the Test Tools
13 // ***************************************************************************
14
15 #ifndef BOOST_TEST_TEST_TOOLS_IPP_012205GER
16 #define BOOST_TEST_TEST_TOOLS_IPP_012205GER
17
18 // Boost.Test
19 #include <boost/test/test_tools.hpp>
20 #include <boost/test/unit_test_log.hpp>
21 #include <boost/test/output_test_stream.hpp>
22 #include <boost/test/framework.hpp>
23 #include <boost/test/execution_monitor.hpp> // execution_aborted
24 #include <boost/test/unit_test_suite_impl.hpp>
25
26 // Boost
27 #include <boost/config.hpp>
28
29 // STL
30 #include <fstream>
31 #include <string>
32 #include <cstring>
33 #include <cctype>
34 #include <cwchar>
35 #include <stdexcept>
36 #include <ios>
37
38 // !! should we use #include <cstdarg>
39 #include <stdarg.h>
40
41 #include <boost/test/detail/suppress_warnings.hpp>
42
43 //____________________________________________________________________________//
44
45 # ifdef BOOST_NO_STDC_NAMESPACE
46 namespace std { using ::strcmp; using ::strlen; using ::isprint; }
47 #if !defined( BOOST_NO_CWCHAR )
48 namespace std { using ::wcscmp; }
49 #endif
50 # endif
51
52 namespace boost {
53
54 namespace test_tools {
55
56 // ************************************************************************** //
57 // **************                print_log_value               ************** //
58 // ************************************************************************** //
59
60 void
61 print_log_value<char>::operator()( std::ostream& ostr, char t )
62 {
63     if( (std::isprint)( static_cast<unsigned char>(t) ) )
64         ostr << '\'' << t << '\'';
65     else
66         ostr << std::hex
67 #if BOOST_TEST_USE_STD_LOCALE
68         << std::showbase
69 #else
70         << "0x"
71 #endif
72         << static_cast<int>(t);
73 }
74
75 //____________________________________________________________________________//
76
77 void
78 print_log_value<unsigned char>::operator()( std::ostream& ostr, unsigned char t )
79 {
80     ostr << std::hex
81         // showbase is only available for new style streams:
82 #if BOOST_TEST_USE_STD_LOCALE
83         << std::showbase
84 #else
85         << "0x"
86 #endif
87         << static_cast<int>(t);
88 }
89
90 //____________________________________________________________________________//
91
92 void
93 print_log_value<char const*>::operator()( std::ostream& ostr, char const* t )
94 {
95     ostr << ( t ? t : "null string" );
96 }
97
98 //____________________________________________________________________________//
99
100 void
101 print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const* t )
102 {
103     ostr << ( t ? t : L"null string" );
104 }
105
106 //____________________________________________________________________________//
107
108 namespace tt_detail {
109
110 // ************************************************************************** //
111 // **************            TOOL BOX Implementation           ************** //
112 // ************************************************************************** //
113
114 using ::boost::unit_test::lazy_ostream;
115
116 bool
117 check_impl( predicate_result const& pr, lazy_ostream const& check_descr,
118             const_string file_name, std::size_t line_num,
119             tool_level tl, check_type ct,
120             std::size_t num_of_args, ... )
121 {
122     using namespace unit_test;
123
124     if( !framework::is_initialized() )
125         throw std::runtime_error( "can't use testing tools before framework is initialized" );
126
127     if( !!pr )
128         tl = PASS;
129
130     log_level    ll;
131     char const*  prefix;
132     char const*  suffix;
133        
134     switch( tl ) {
135     case PASS:
136         ll      = log_successful_tests;
137         prefix  = "check ";
138         suffix  = " passed";
139         break;
140     case WARN:
141         ll      = log_warnings;
142         prefix  = "condition ";
143         suffix  = " is not satisfied";
144         break;
145     case CHECK:
146         ll      = log_all_errors;
147         prefix  = "check ";
148         suffix  = " failed";
149         break;
150     case REQUIRE:
151         ll      = log_fatal_errors;
152         prefix  = "critical check ";
153         suffix  = " failed";
154         break;
155     default:
156         return true;
157     }
158
159     switch( ct ) {
160     case CHECK_PRED:
161         unit_test_log << unit_test::log::begin( file_name, line_num ) 
162                       << ll << prefix << check_descr << suffix;
163         
164         if( !pr.has_empty_message() )
165             unit_test_log << ". " << pr.message();
166         
167         unit_test_log << unit_test::log::end();
168         break;
169
170     case CHECK_MSG:
171         unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
172         
173         if( tl == PASS )
174             unit_test_log << prefix << "'" << check_descr << "'" << suffix;
175         else
176             unit_test_log << check_descr;
177         
178         if( !pr.has_empty_message() )
179             unit_test_log << ". " << pr.message();
180
181         unit_test_log << unit_test::log::end();
182         break;
183
184     case CHECK_EQUAL: 
185     case CHECK_NE: 
186     case CHECK_LT: 
187     case CHECK_LE: 
188     case CHECK_GT: 
189     case CHECK_GE: {
190         static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " };
191         static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < "  };
192
193         va_list args;
194
195         va_start( args, num_of_args );
196         char const*         arg1_descr  = va_arg( args, char const* );
197         lazy_ostream const* arg1_val    = va_arg( args, lazy_ostream const* );
198         char const*         arg2_descr  = va_arg( args, char const* );
199         lazy_ostream const* arg2_val    = va_arg( args, lazy_ostream const* );
200
201         unit_test_log << unit_test::log::begin( file_name, line_num ) 
202                       << ll << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix;
203
204         if( tl != PASS )
205             unit_test_log << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ;
206
207         va_end( args );
208         
209         if( !pr.has_empty_message() )
210             unit_test_log << ". " << pr.message();
211
212         unit_test_log << unit_test::log::end();
213         break;
214     }
215
216     case CHECK_CLOSE:
217     case CHECK_CLOSE_FRACTION: {
218         va_list args;
219
220         va_start( args, num_of_args );
221         char const*         arg1_descr  = va_arg( args, char const* );
222         lazy_ostream const* arg1_val    = va_arg( args, lazy_ostream const* );
223         char const*         arg2_descr  = va_arg( args, char const* );
224         lazy_ostream const* arg2_val    = va_arg( args, lazy_ostream const* );
225         /* toler_descr = */               va_arg( args, char const* );
226         lazy_ostream const* toler_val   = va_arg( args, lazy_ostream const* );
227
228         unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
229
230         unit_test_log << "difference{" << pr.message() << (ct == CHECK_CLOSE ? "%" : "")
231                       << "} between " << arg1_descr << "{" << *arg1_val
232                       << "} and "               << arg2_descr << "{" << *arg2_val
233                       << ( tl == PASS ? "} doesn't exceed " : "} exceeds " )
234                       << *toler_val;
235         if( ct == CHECK_CLOSE )
236             unit_test_log << "%";
237
238         va_end( args );
239         
240         unit_test_log << unit_test::log::end();
241         break;
242     }
243     case CHECK_SMALL: {
244         va_list args;
245
246         va_start( args, num_of_args );
247         char const*         arg1_descr  = va_arg( args, char const* );
248         lazy_ostream const* arg1_val    = va_arg( args, lazy_ostream const* );
249         /* toler_descr = */               va_arg( args, char const* );
250         lazy_ostream const* toler_val   = va_arg( args, lazy_ostream const* );
251
252         unit_test_log << unit_test::log::begin( file_name, line_num ) << ll;
253
254         unit_test_log << "absolute value of " << arg1_descr << "{" << *arg1_val << "}" 
255                       << ( tl == PASS ? " doesn't exceed " : " exceeds " )
256                       << *toler_val;
257
258         va_end( args );
259         
260         if( !pr.has_empty_message() )
261             unit_test_log << ". " << pr.message();
262
263         unit_test_log << unit_test::log::end();
264         break;
265     }
266
267     case CHECK_PRED_WITH_ARGS: {
268         unit_test_log << unit_test::log::begin( file_name, line_num ) 
269                       << ll << prefix << check_descr;
270
271         // print predicate call description
272         {
273             va_list args;
274             va_start( args, num_of_args );
275
276             unit_test_log << "( ";
277             for( std::size_t i = 0; i < num_of_args; ++i ) {
278                 unit_test_log << va_arg( args, char const* );
279                 va_arg( args, lazy_ostream const* ); // skip argument value;
280                 
281                 if( i != num_of_args-1 )
282                     unit_test_log << ", ";
283             }
284             unit_test_log << " )" << suffix;
285             va_end( args );
286         }
287                         
288         if( tl != PASS ) {
289             va_list args;
290             va_start( args, num_of_args );
291
292             unit_test_log << " for ( ";
293             for( std::size_t i = 0; i < num_of_args; ++i ) {
294                 va_arg( args, char const* ); // skip argument description;            
295                 unit_test_log << *va_arg( args, lazy_ostream const* );
296                 
297                 if( i != num_of_args-1 )
298                     unit_test_log << ", ";
299             }
300             unit_test_log << " )";
301             va_end( args );
302         }
303        
304         if( !pr.has_empty_message() )
305             unit_test_log << ". " << pr.message();
306
307         unit_test_log << unit_test::log::end();
308         break;
309     }
310
311     case CHECK_EQUAL_COLL: {
312         va_list args;
313
314         va_start( args, num_of_args );
315         char const* left_begin_descr    = va_arg( args, char const* );
316         char const* left_end_descr      = va_arg( args, char const* );
317         char const* right_begin_descr   = va_arg( args, char const* );
318         char const* right_end_descr     = va_arg( args, char const* );
319
320         unit_test_log << unit_test::log::begin( file_name, line_num ) 
321                       << ll << prefix 
322                       << "{ " << left_begin_descr  << ", " << left_end_descr  << " } == { " 
323                               << right_begin_descr << ", " << right_end_descr << " }"
324                       << suffix;
325
326         va_end( args );
327         
328         if( !pr.has_empty_message() )
329             unit_test_log << ". " << pr.message();
330
331         unit_test_log << unit_test::log::end();
332         break;
333     }
334
335     case CHECK_BITWISE_EQUAL: {
336         va_list args;
337
338         va_start( args, num_of_args );
339         char const* left_descr    = va_arg( args, char const* );
340         char const* right_descr   = va_arg( args, char const* );
341
342         unit_test_log << unit_test::log::begin( file_name, line_num )
343                       << ll << prefix << left_descr  << " =.= " << right_descr << suffix;
344
345         va_end( args );
346         
347         if( !pr.has_empty_message() )
348             unit_test_log << ". " << pr.message();
349
350         unit_test_log << unit_test::log::end();
351         break;
352     }
353     }
354
355     switch( tl ) {
356     case PASS:
357         framework::assertion_result( true );
358         return true;
359
360     case WARN:
361         return false;
362
363     case CHECK:
364         framework::assertion_result( false );
365         return false;
366         
367     case REQUIRE:
368         framework::assertion_result( false );
369
370         framework::test_unit_aborted( framework::current_test_case() );
371
372         throw execution_aborted();
373     }
374
375     return true;
376 }
377
378 //____________________________________________________________________________//
379
380 predicate_result
381 equal_impl( char const* left, char const* right )
382 {
383     return (left && right) ? std::strcmp( left, right ) == 0 : (left == right);
384 }
385
386 //____________________________________________________________________________//
387
388 #if !defined( BOOST_NO_CWCHAR )
389
390 predicate_result
391 equal_impl( wchar_t const* left, wchar_t const* right )
392 {
393     return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right);
394 }
395
396 #endif // !defined( BOOST_NO_CWCHAR )
397
398 //____________________________________________________________________________//
399
400 bool
401 is_defined_impl( const_string symbol_name, const_string symbol_value )
402 {
403     symbol_value.trim_left( 2 );
404     return symbol_name != symbol_value;
405 }
406
407 //____________________________________________________________________________//
408
409 } // namespace tt_detail
410
411 // ************************************************************************** //
412 // **************               output_test_stream             ************** //
413 // ************************************************************************** //
414
415 struct output_test_stream::Impl
416 {
417     std::fstream    m_pattern;
418     bool            m_match_or_save;
419     bool            m_text_or_binary;
420     std::string     m_synced_string;
421
422     char            get_char()
423     {
424         char res;
425         do {
426             m_pattern.get( res );
427         } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() );
428
429         return res;
430     }
431
432     void            check_and_fill( predicate_result& res )
433     {
434         if( !res.p_predicate_value )
435             res.message() << "Output content: \"" << m_synced_string << '\"';
436     }
437 };
438
439 //____________________________________________________________________________//
440
441 output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary )
442 : m_pimpl( new Impl )
443 {
444     if( !pattern_file_name.is_empty() ) {
445         std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out;
446         if( !text_or_binary )
447             m |= std::ios::binary;
448
449         m_pimpl->m_pattern.open( pattern_file_name.begin(), m );
450
451         BOOST_WARN_MESSAGE( m_pimpl->m_pattern.is_open(),
452                              "Can't open pattern file " << pattern_file_name
453                                 << " for " << (match_or_save ? "reading" : "writing") );
454     }
455
456     m_pimpl->m_match_or_save    = match_or_save;
457     m_pimpl->m_text_or_binary   = text_or_binary;
458 }
459
460 //____________________________________________________________________________//
461
462 output_test_stream::~output_test_stream()
463 {
464     delete m_pimpl;
465 }
466
467 //____________________________________________________________________________//
468
469 predicate_result
470 output_test_stream::is_empty( bool flush_stream )
471 {
472     sync();
473
474     result_type res( m_pimpl->m_synced_string.empty() );
475
476     m_pimpl->check_and_fill( res );
477
478     if( flush_stream )
479         flush();
480
481     return res;
482 }
483
484 //____________________________________________________________________________//
485
486 predicate_result
487 output_test_stream::check_length( std::size_t length_, bool flush_stream )
488 {
489     sync();
490
491     result_type res( m_pimpl->m_synced_string.length() == length_ );
492
493     m_pimpl->check_and_fill( res );
494
495     if( flush_stream )
496         flush();
497
498     return res;
499 }
500
501 //____________________________________________________________________________//
502
503 predicate_result
504 output_test_stream::is_equal( const_string arg, bool flush_stream )
505 {
506     sync();
507
508     result_type res( const_string( m_pimpl->m_synced_string ) == arg );
509
510     m_pimpl->check_and_fill( res );
511
512     if( flush_stream )
513         flush();
514
515     return res;
516 }
517
518 //____________________________________________________________________________//
519
520 predicate_result
521 output_test_stream::match_pattern( bool flush_stream )
522 {
523     sync();
524
525     result_type result( true );
526
527     if( !m_pimpl->m_pattern.is_open() ) {
528         result = false;
529         result.message() << "Pattern file can't be opened!";
530     }
531     else {
532         if( m_pimpl->m_match_or_save ) {
533             for ( std::string::size_type i = 0; i < m_pimpl->m_synced_string.length(); ++i ) {
534                 char c = m_pimpl->get_char();
535
536                 result = !m_pimpl->m_pattern.fail() &&
537                          !m_pimpl->m_pattern.eof()  &&
538                          (m_pimpl->m_synced_string[i] == c);
539
540                 if( !result ) {
541                     std::string::size_type suffix_size  = (std::min)( m_pimpl->m_synced_string.length() - i,
542                                                                     static_cast<std::string::size_type>(5) );
543
544                     // try to log area around the mismatch
545                     result.message() << "Mismatch at position " << i << '\n'
546                         << "..." << m_pimpl->m_synced_string.substr( i, suffix_size ) << "..." << '\n'
547                         << "..." << c;
548
549                     std::string::size_type counter = suffix_size;
550                     while( --counter ) {
551                         char c = m_pimpl->get_char();
552
553                         if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() )
554                             break;
555
556                         result.message() << c;
557                     }
558
559                     result.message() << "...";
560
561                     // skip rest of the bytes. May help for further matching
562                     m_pimpl->m_pattern.ignore( 
563                         static_cast<std::streamsize>( m_pimpl->m_synced_string.length() - i - suffix_size) );
564                     break;
565                 }
566             }
567         }
568         else {
569             m_pimpl->m_pattern.write( m_pimpl->m_synced_string.c_str(),
570                                       static_cast<std::streamsize>( m_pimpl->m_synced_string.length() ) );
571             m_pimpl->m_pattern.flush();
572         }
573     }
574
575     if( flush_stream )
576         flush();
577
578     return result;
579 }
580
581 //____________________________________________________________________________//
582
583 void
584 output_test_stream::flush()
585 {
586     m_pimpl->m_synced_string.erase();
587
588 #ifndef BOOST_NO_STRINGSTREAM
589     str( std::string() );
590 #else
591     seekp( 0, std::ios::beg );
592 #endif
593 }
594
595 //____________________________________________________________________________//
596
597 std::size_t
598 output_test_stream::length()
599 {
600     sync();
601
602     return m_pimpl->m_synced_string.length();
603 }
604
605 //____________________________________________________________________________//
606
607 void
608 output_test_stream::sync()
609 {
610 #ifdef BOOST_NO_STRINGSTREAM
611     m_pimpl->m_synced_string.assign( str(), pcount() );
612     freeze( false );
613 #else
614     m_pimpl->m_synced_string = str();
615 #endif
616 }
617
618 //____________________________________________________________________________//
619
620 } // namespace test_tools
621
622 } // namespace boost
623
624 //____________________________________________________________________________//
625
626 #include <boost/test/detail/enable_warnings.hpp>
627
628 #endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER