blob: b47ef814a5bdfbc67cbaf18f1b9e581861c214d6 [file] [log] [blame]
Jeff Thompsonef2d5a42013-08-22 19:09:24 -07001// (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: 54633 $
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 <ndnboost/test/test_tools.hpp>
20#include <ndnboost/test/unit_test_log.hpp>
21#include <ndnboost/test/output_test_stream.hpp>
22#include <ndnboost/test/framework.hpp>
23#include <ndnboost/test/execution_monitor.hpp> // execution_aborted
24#include <ndnboost/test/unit_test_suite_impl.hpp>
25
26// Boost
27#include <ndnboost/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 <ndnboost/test/detail/suppress_warnings.hpp>
42
43//____________________________________________________________________________//
44
45# ifdef BOOST_NO_STDC_NAMESPACE
46namespace std { using ::strcmp; using ::strlen; using ::isprint; }
47#if !defined( BOOST_NO_CWCHAR )
48namespace std { using ::wcscmp; }
49#endif
50# endif
51
52namespace ndnboost {
53
54namespace test_tools {
55
56// ************************************************************************** //
57// ************** print_log_value ************** //
58// ************************************************************************** //
59
60void
61print_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
77void
78print_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
92void
93print_log_value<char const*>::operator()( std::ostream& ostr, char const* t )
94{
95 ostr << ( t ? t : "null string" );
96}
97
98//____________________________________________________________________________//
99
100void
101print_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
108namespace tt_detail {
109
110// ************************************************************************** //
111// ************** TOOL BOX Implementation ************** //
112// ************************************************************************** //
113
114using ::ndnboost::unit_test::lazy_ostream;
115
116bool
117check_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
380predicate_result
381equal_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
390predicate_result
391equal_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
400bool
401is_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
415struct 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
441output_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
462output_test_stream::~output_test_stream()
463{
464 delete m_pimpl;
465}
466
467//____________________________________________________________________________//
468
469predicate_result
470output_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
486predicate_result
487output_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
503predicate_result
504output_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
520predicate_result
521output_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
583void
584output_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
597std::size_t
598output_test_stream::length()
599{
600 sync();
601
602 return m_pimpl->m_synced_string.length();
603}
604
605//____________________________________________________________________________//
606
607void
608output_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 ndnboost
623
624//____________________________________________________________________________//
625
626#include <ndnboost/test/detail/enable_warnings.hpp>
627
628#endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER