1 #ifndef CORELIB___TEST_BOOST__HPP
2 #define CORELIB___TEST_BOOST__HPP
3
4 /* $Id: test_boost.hpp 631032 2021-05-12 14:09:52Z ivanov $
5 * ===========================================================================
6 *
7 * PUBLIC DOMAIN NOTICE
8 * National Center for Biotechnology Information
9 *
10 * This software/database is a "United States Government Work" under the
11 * terms of the United States Copyright Act. It was written as part of
12 * the author's official duties as a United States Government employee and
13 * thus cannot be copyrighted. This software/database is freely available
14 * to the public for use. The National Library of Medicine and the U.S.
15 * Government have not placed any restriction on its use or reproduction.
16 *
17 * Although all reasonable efforts have been taken to ensure the accuracy
18 * and reliability of the software and data, the NLM and the U.S.
19 * Government do not and cannot warrant the performance or results that
20 * may be obtained by using this software or data. The NLM and the U.S.
21 * Government disclaim all warranties, express or implied, including
22 * warranties of performance, merchantability or fitness for any particular
23 * purpose.
24 *
25 * Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author: Pavel Ivanov
30 *
31 */
32
33 /// @file test_boost.hpp
34 /// Utility stuff for more convenient using of Boost.Test library.
35 ///
36 /// This header must be included before any Boost.Test header
37 /// (if you have any).
38
39 #ifdef BOOST_CHECK
40 # error "test_boost.hpp should be included before any Boost.Test header"
41 #endif
42
43
44 #include <corelib/expr.hpp>
45 #include <corelib/ncbiapp.hpp>
46 #include <corelib/request_ctx.hpp>
47 #include <corelib/ncbisys.hpp>
48 #include <corelib/ncbimtx.hpp>
49
50
51 // Keep Boost's inclusion of <limits> from breaking under old WorkShop versions.
52 #if defined(numeric_limits) && defined(NCBI_NUMERIC_LIMITS)
53 # undef numeric_limits
54 #endif
55
56 // BOOST_AUTO_TEST_MAIN should not be defined - it is in test_boost library
57 #ifdef BOOST_AUTO_TEST_MAIN
58 # undef BOOST_AUTO_TEST_MAIN
59 #endif
60
61 #ifdef NCBI_COMPILER_MSVC
62 # pragma warning(push)
63 // 'class' : class has virtual functions, but destructor is not virtual
64 # pragma warning(disable: 4265)
65 #endif
66
67 #include <boost/version.hpp>
68 #include <boost/test/unit_test.hpp>
69 #if BOOST_VERSION >= 105900
70 # include <boost/test/tools/floating_point_comparison.hpp>
71 #else
72 # include <boost/test/floating_point_comparison.hpp>
73 #endif
74 #include <boost/test/framework.hpp>
75 #include <boost/test/execution_monitor.hpp>
76 #include <boost/test/parameterized_test.hpp>
77 #include <boost/test/results_collector.hpp>
78
79 #if BOOST_VERSION >= 105600
80 # include <boost/core/ignore_unused.hpp>
81 #endif
82
83 #include <boost/preprocessor/tuple/rem.hpp>
84 #include <boost/preprocessor/repeat.hpp>
85 #include <boost/preprocessor/array/elem.hpp>
86 #include <boost/preprocessor/arithmetic/inc.hpp>
87
88 #include <common/boost_skew_guard.hpp>
89
90 #ifdef NCBI_COMPILER_MSVC
91 # pragma warning(pop)
92 #endif
93
94
95 // Redefine some Boost macros to make them more comfortable and fit them into
96 // the framework.
97 #undef BOOST_CHECK_THROW_IMPL
98 #undef BOOST_CHECK_NO_THROW_IMPL
99 #ifdef BOOST_FIXTURE_TEST_CASE_WITH_DECOR
100 # undef BOOST_FIXTURE_TEST_CASE_WITH_DECOR
101 #else
102 # undef BOOST_FIXTURE_TEST_CASE
103 #endif
104 #undef BOOST_PARAM_TEST_CASE
105
106
107 /// Check that current boost test case passed (no exceptions or assertions)
108 /// on the moment of calling this method.
109 /// This can be useful to ignore some unit code if (any) previos checks fails.
BOOST_CURRENT_TEST_PASSED()110 inline bool BOOST_CURRENT_TEST_PASSED()
111 {
112 ::boost::unit_test::test_case::id_t id = ::boost::unit_test::framework::current_test_case().p_id;
113 ::boost::unit_test::test_results rc = ::boost::unit_test::results_collector.results(id);
114 return rc.passed();
115 }
116
117
118 #if BOOST_VERSION >= 105900
119 # if BOOST_VERSION >= 106000
120 # define BOOST_CHECK_THROW_IMPL_EX( S, E, P, postfix, TL, guard ) \
121 do { \
122 try { \
123 BOOST_TEST_PASSPOINT(); \
124 S; \
125 guard; \
126 BOOST_TEST_TOOL_IMPL( 2, false, "exception " BOOST_STRINGIZE(E) \
127 " expected but not raised", \
128 TL, CHECK_MSG, _ ); \
129 } catch( E const& ex ) { \
130 ::boost::ignore_unused( ex ); \
131 guard; \
132 BOOST_TEST_TOOL_IMPL( 2, P, \
133 "exception \"" BOOST_STRINGIZE( E ) \
134 "\" raised as expected" postfix, \
135 TL, CHECK_MSG, _ ); \
136 } catch (...) { \
137 guard; \
138 BOOST_TEST_TOOL_IMPL( 2, false, \
139 "an unexpected exception was thrown by " \
140 BOOST_STRINGIZE( S ), \
141 TL, CHECK_MSG, _ ); \
142 } \
143 } while( ::boost::test_tools::tt_detail::dummy_cond() ) \
144 /**/
145
146 # define BOOST_THROW_AFFIX ""
147 # define BOOST_EXCEPTION_AFFIX(P) \
148 ": validation on the raised exception through predicate \"" \
149 BOOST_STRINGIZE(P) "\""
150
151 # else
152 # define BOOST_CHECK_THROW_IMPL_EX( S, E, P, prefix, TL, guard ) \
153 do { \
154 try { \
155 BOOST_TEST_PASSPOINT(); \
156 S; \
157 guard; \
158 BOOST_TEST_TOOL_IMPL( 2, false, "exception " BOOST_STRINGIZE(E) \
159 " is expected", \
160 TL, CHECK_MSG, _ ); \
161 } catch( E const& ex ) { \
162 ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \
163 guard; \
164 BOOST_TEST_TOOL_IMPL( 2, P, prefix BOOST_STRINGIZE( E ) " is caught", \
165 TL, CHECK_MSG, _ ); \
166 } catch (...) { \
167 guard; \
168 BOOST_TEST_TOOL_IMPL( 2, false, \
169 "an unexpected exception was thrown by " \
170 BOOST_STRINGIZE( S ), \
171 TL, CHECK_MSG, _ ); \
172 } \
173 } while( ::boost::test_tools::tt_detail::dummy_cond() ) \
174 /**/
175 # endif
176
177 # define BOOST_CHECK_NO_THROW_IMPL_EX( S, TL, guard ) \
178 do { \
179 try { \
180 S; \
181 guard; \
182 BOOST_TEST_TOOL_IMPL( 2, true, "no exceptions thrown by " \
183 BOOST_STRINGIZE( S ), \
184 TL, CHECK_MSG, _ ); \
185 } catch (std::exception& ex) { \
186 guard; \
187 BOOST_TEST_TOOL_IMPL( 2, false, "an std::exception was thrown by " \
188 BOOST_STRINGIZE( S ) " : " << ex.what(), \
189 TL, CHECK_MSG, _ ); \
190 } catch( ... ) { \
191 guard; \
192 BOOST_TEST_TOOL_IMPL( 2, false, "a nonstandard exception thrown by " \
193 BOOST_STRINGIZE( S ), \
194 TL, CHECK_MSG, _ ); \
195 } \
196 } while( ::boost::test_tools::tt_detail::dummy_cond() ) \
197 /**/
198 #else
199 # define BOOST_CHECK_THROW_IMPL_EX( S, E, P, prefix, TL, guard ) \
200 try { \
201 BOOST_TEST_PASSPOINT(); \
202 S; \
203 guard; \
204 BOOST_CHECK_IMPL( false, "exception " BOOST_STRINGIZE( E ) \
205 " is expected", TL, CHECK_MSG ); } \
206 catch( E const& ex ) { \
207 boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \
208 guard; \
209 BOOST_CHECK_IMPL( P, prefix BOOST_STRINGIZE( E ) " is caught", \
210 TL, CHECK_MSG ); \
211 } \
212 catch (...) { \
213 guard; \
214 BOOST_CHECK_IMPL(false, "an unexpected exception was thrown by " \
215 BOOST_STRINGIZE( S ), \
216 TL, CHECK_MSG); \
217 } \
218 /**/
219
220 # define BOOST_CHECK_NO_THROW_IMPL_EX( S, TL, guard ) \
221 try { \
222 S; \
223 guard; \
224 BOOST_CHECK_IMPL( true, "no exceptions thrown by " BOOST_STRINGIZE( S ), \
225 TL, CHECK_MSG ); \
226 } \
227 catch (std::exception& ex) { \
228 guard; \
229 BOOST_CHECK_IMPL( false, "an std::exception was thrown by " \
230 BOOST_STRINGIZE( S ) " : " << ex.what(), \
231 TL, CHECK_MSG); \
232 } \
233 catch( ... ) { \
234 guard; \
235 BOOST_CHECK_IMPL( false, "a nonstandard exception thrown by " \
236 BOOST_STRINGIZE( S ), \
237 TL, CHECK_MSG ); \
238 } \
239 /**/
240 #endif
241
242 #ifndef BOOST_THROW_AFFIX // 1.59 or older
243 # define BOOST_THROW_AFFIX "exception "
244 # define BOOST_EXCEPTION_AFFIX(P) "incorrect exception "
245 #endif
246
247 # define BOOST_CHECK_THROW_IMPL( S, E, P, affix, TL ) \
248 BOOST_CHECK_THROW_IMPL_EX( S, E, P, affix, TL, )
249 # define BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, P, affix, TL ) \
250 BOOST_CHECK_THROW_IMPL_EX( S, E, P, affix, TL, \
251 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard( \
252 NCBI_NS_NCBI::g_NcbiTestMutex) )
253
254 #define BOOST_WARN_THROW_MT_SAFE( S, E ) \
255 BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, true, BOOST_THROW_AFFIX, WARN )
256 #define BOOST_CHECK_THROW_MT_SAFE( S, E ) \
257 BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, true, BOOST_THROW_AFFIX, CHECK )
258 #define BOOST_REQUIRE_THROW_MT_SAFE( S, E ) \
259 BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, true, BOOST_THROW_AFFIX, REQUIRE )
260
261 #define BOOST_WARN_EXCEPTION_MT_SAFE( S, E, P ) \
262 BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, P( ex ), BOOST_EXCEPTION_AFFIX(P), \
263 WARN )
264 #define BOOST_CHECK_EXCEPTION_MT_SAFE( S, E, P ) \
265 BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, P( ex ), BOOST_EXCEPTION_AFFIX(P), \
266 CHECK )
267 #define BOOST_REQUIRE_EXCEPTION_MT_SAFE( S, E, P ) \
268 BOOST_CHECK_THROW_IMPL_MT_SAFE( S, E, P( ex ), BOOST_EXCEPTION_AFFIX(P), \
269 REQUIRE )
270
271 #define BOOST_CHECK_NO_THROW_IMPL( S, TL ) \
272 BOOST_CHECK_NO_THROW_IMPL_EX( S, TL, )
273 #define BOOST_CHECK_NO_THROW_IMPL_MT_SAFE( S, TL ) \
274 BOOST_CHECK_NO_THROW_IMPL_EX( S, TL, \
275 NCBI_NS_NCBI::CFastMutexGuard \
276 _ncbitest_guard( \
277 NCBI_NS_NCBI::g_NcbiTestMutex) )
278
279 #define BOOST_WARN_NO_THROW_MT_SAFE( S ) \
280 BOOST_CHECK_NO_THROW_IMPL_MT_SAFE( S, WARN )
281 #define BOOST_CHECK_NO_THROW_MT_SAFE( S ) \
282 BOOST_CHECK_NO_THROW_IMPL_MT_SAFE( S, CHECK )
283 #define BOOST_REQUIRE_NO_THROW_MT_SAFE( S ) \
284 BOOST_CHECK_NO_THROW_IMPL_MT_SAFE( S, REQUIRE )
285
286
287 #if BOOST_VERSION >= 104200
288 # define NCBI_BOOST_LOCATION() , boost::execution_exception::location()
289 #else
290 # define NCBI_BOOST_LOCATION()
291 #endif
292
293 #ifdef BOOST_FIXTURE_TEST_CASE_NO_DECOR
294 # if BOOST_VERSION < 106900
295 BEGIN_SCOPE(boost)
296 BEGIN_SCOPE(unit_test)
297 BEGIN_SCOPE(decorator)
298 typedef collector collector_t;
299 END_SCOPE(decorator)
300 END_SCOPE(unit_test)
301 END_SCOPE(boost)
302 # endif
303 # define NCBI_BOOST_DECORATOR_ARG \
304 , boost::unit_test::decorator::collector_t::instance()
305 #else
306 # define NCBI_BOOST_DECORATOR_ARG
307 #endif
308
309 #ifdef BOOST_FIXTURE_TEST_CASE_NO_DECOR
310 # define BOOST_FIXTURE_TEST_CASE_WITH_DECOR( test_name, F, decorators ) \
311 struct test_name : public F { void test_method(); }; \
312 \
313 static void BOOST_AUTO_TC_INVOKER( test_name )() \
314 { \
315 NCBI_NS_NCBI::CDiagContext& dctx = NCBI_NS_NCBI::GetDiagContext(); \
316 NCBI_NS_NCBI::CRequestContext& rctx = dctx.GetRequestContext(); \
317 rctx.SetRequestID(); \
318 NCBI_NS_NCBI::CRequestContextGuard_Base rg(&rctx); \
319 dctx.PrintRequestStart().Print("test_name", #test_name); \
320 BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture entry."); \
321 test_name t; \
322 BOOST_TEST_CHECKPOINT('"' << #test_name << "\" entry."); \
323 try { \
324 t.test_method(); \
325 } \
326 catch (NCBI_NS_NCBI::CException& ex) { \
327 ERR_POST("Uncaught exception in \"" \
328 << boost::unit_test \
329 ::framework::current_test_case().p_name \
330 << "\"" << ex); \
331 char* msg = NcbiSysChar_strdup(ex.what()); \
332 NCBI_NS_NCBI::CNcbiTestMemoryCleanupList::GetInstance()->Add(msg); \
333 throw boost::execution_exception( \
334 boost::execution_exception::cpp_exception_error, \
335 msg \
336 NCBI_BOOST_LOCATION() ); \
337 } \
338 BOOST_TEST_CHECKPOINT('"' << #test_name << "\" exit."); \
339 } \
340 \
341 struct BOOST_AUTO_TC_UNIQUE_ID( test_name ) {}; \
342 \
343 static ::NCBI_NS_NCBI::SNcbiTestRegistrar \
344 BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) ( \
345 boost::unit_test::make_test_case( \
346 &BOOST_AUTO_TC_INVOKER( test_name ), #test_name, \
347 __FILE__, __LINE__ ), \
348 ::NCBI_NS_NCBI::SNcbiTestTCTimeout< \
349 BOOST_AUTO_TC_UNIQUE_ID( test_name )>::instance()->value(), \
350 decorators ); \
351 \
352 void test_name::test_method() \
353 /**/
354 #else
355 # define BOOST_FIXTURE_TEST_CASE( test_name, F ) \
356 struct test_name : public F { void test_method(); }; \
357 \
358 static void BOOST_AUTO_TC_INVOKER( test_name )() \
359 { \
360 NCBI_NS_NCBI::CDiagContext& dctx = NCBI_NS_NCBI::GetDiagContext(); \
361 NCBI_NS_NCBI::CRequestContext& rctx = dctx.GetRequestContext(); \
362 rctx.SetRequestID(); \
363 NCBI_NS_NCBI::CRequestContextGuard_Base rg(&rctx); \
364 dctx.PrintRequestStart().Print("test_name", #test_name); \
365 test_name t; \
366 try { \
367 t.test_method(); \
368 } \
369 catch (NCBI_NS_NCBI::CException& ex) { \
370 ERR_POST("Uncaught exception in \"" \
371 << boost::unit_test \
372 ::framework::current_test_case().p_name \
373 << "\"" << ex); \
374 char* msg = NcbiSysChar_strdup(ex.what()); \
375 NCBI_NS_NCBI::CNcbiTestMemoryCleanupList::GetInstance()->Add(msg); \
376 throw boost::execution_exception( \
377 boost::execution_exception::cpp_exception_error, \
378 msg \
379 NCBI_BOOST_LOCATION() ); \
380 } \
381 } \
382 \
383 struct BOOST_AUTO_TC_UNIQUE_ID( test_name ) {}; \
384 \
385 static ::NCBI_NS_NCBI::SNcbiTestRegistrar \
386 BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) ( \
387 boost::unit_test::make_test_case( \
388 &BOOST_AUTO_TC_INVOKER( test_name ), #test_name ), \
389 boost::unit_test::ut_detail::auto_tc_exp_fail< \
390 BOOST_AUTO_TC_UNIQUE_ID( test_name )>::instance()->value(), \
391 ::NCBI_NS_NCBI::SNcbiTestTCTimeout< \
392 BOOST_AUTO_TC_UNIQUE_ID( test_name )>::instance()->value() ); \
393 \
394 void test_name::test_method() \
395 /**/
396 #endif
397
398 #define BOOST_PARAM_TEST_CASE( function, begin, end ) \
399 ::NCBI_NS_NCBI::NcbiTestGenTestCases( function, \
400 BOOST_TEST_STRINGIZE( function ), \
401 (begin), (end) ) \
402 /**/
403
404 /// Set timeout value for the test case created using auto-registration
405 /// facility.
406 #define BOOST_AUTO_TEST_CASE_TIMEOUT(test_name, n) \
407 struct BOOST_AUTO_TC_UNIQUE_ID( test_name ); \
408 \
409 static struct BOOST_JOIN( test_name, _timeout_spec ) \
410 : ::NCBI_NS_NCBI:: \
411 SNcbiTestTCTimeout<BOOST_AUTO_TC_UNIQUE_ID( test_name ) > \
412 { \
413 BOOST_JOIN( test_name, _timeout_spec )() \
414 : ::NCBI_NS_NCBI:: \
415 SNcbiTestTCTimeout<BOOST_AUTO_TC_UNIQUE_ID( test_name ) >( n ) \
416 {} \
417 } BOOST_JOIN( test_name, _timeout_spec_inst ); \
418 /**/
419
420 /// Automatic registration of the set of test cases based on some function
421 /// accepting one parameter. Set of parameters used to call that function is
422 /// taken from iterator 'begin' which is incremented until it reaches 'end'.
423 ///
424 /// @sa BOOST_PARAM_TEST_CASE
425 #define BOOST_AUTO_PARAM_TEST_CASE( function, begin, end ) \
426 BOOST_AUTO_TU_REGISTRAR(function) ( \
427 BOOST_PARAM_TEST_CASE(function, begin, end) \
428 NCBI_BOOST_DECORATOR_ARG) \
429 /**/
430
431 #define BOOST_TIMEOUT(M) \
432 do { \
433 throw boost::execution_exception( \
434 boost::execution_exception::timeout_error, M \
435 NCBI_BOOST_LOCATION()); \
436 } while (0) \
437 /**/
438
439
440 # define BOOST_TEST_TOOL_PASS_ARG_ONLY( r, _, arg ) , arg
441
442 #if BOOST_VERSION >= 105900
443
444 # define NCBITEST_CHECK_IMPL_EX(frwd_type, P, check_descr, TL, CT, ARGS) \
445 BOOST_CHECK_NO_THROW_IMPL( \
446 BOOST_TEST_TOOL_IMPL(frwd_type, P, check_descr, TL, CT, ARGS), TL)
447
448 # define NCBITEST_CHECK_IMPL(P, check_descr, TL, CT) \
449 NCBITEST_CHECK_IMPL_EX(2, P, check_descr, TL, CT, _)
450
451 # define NCBITEST_CHECK_WITH_ARGS_IMPL(P, check_descr, TL, CT, ARGS) \
452 NCBITEST_CHECK_IMPL_EX(0, ::boost::test_tools::tt_detail::P(), \
453 check_descr, TL, CT, ARGS)
454
455 # define NCBITEST_CHECK_IMPL_MT_SAFE(P, check_descr, TL, CT) \
456 do { \
457 bool _ncbitest_value; \
458 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
459 (NCBI_NS_NCBI::eEmptyGuard); \
460 BOOST_CHECK_NO_THROW_IMPL_EX(_ncbitest_value = (P);, TL, \
461 _ncbitest_guard.Guard(NCBI_NS_NCBI::g_NcbiTestMutex)); \
462 BOOST_TEST_TOOL_IMPL(2, _ncbitest_value, check_descr, TL, CT, _); \
463 } while( ::boost::test_tools::tt_detail::dummy_cond() )
464
465 # define BOOST_PP_BOOL_00 0
466
467 # define BOOST_TEST_TOOL_PASS_PRED00( P, ARGS ) P
468
469 # define BOOST_TEST_TOOL_PASS_ARGS00( ARGS ) \
470 BOOST_PP_SEQ_FOR_EACH( BOOST_TEST_TOOL_PASS_ARG_ONLY, _, ARGS )
471
472 # define NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE(P, descr, TL, CT, A1, A2) \
473 do { \
474 std::decay<decltype(A1)>::type _ncbitest_value1; \
475 std::decay<decltype(A2)>::type _ncbitest_value2; \
476 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
477 (NCBI_NS_NCBI::eEmptyGuard); \
478 BOOST_CHECK_NO_THROW_IMPL_EX( \
479 _ncbitest_value1 = (A1); _ncbitest_value2 = (A2);, TL, \
480 _ncbitest_guard.Guard(NCBI_NS_NCBI::g_NcbiTestMutex)); \
481 BOOST_TEST_TOOL_IMPL(00, ::boost::test_tools::tt_detail::P(), \
482 descr, TL, CT, \
483 (_ncbitest_value1)(BOOST_STRINGIZE(A1)) \
484 (_ncbitest_value2)(BOOST_STRINGIZE(A2))); \
485 } while( ::boost::test_tools::tt_detail::dummy_cond() )
486
487 # define BOOST_CHECK_IMPL_MT_SAFE( P, check_descr, TL, CT ) \
488 do { \
489 bool _ncbitest_value = (P); \
490 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
491 (NCBI_NS_NCBI::g_NcbiTestMutex); \
492 BOOST_TEST_TOOL_IMPL( 2, _ncbitest_value, check_descr, TL, CT, _ ); \
493 } while( ::boost::test_tools::tt_detail::dummy_cond() )
494
495 # define BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE(P, descr, TL, CT, A1, A2) \
496 do { \
497 auto _ncbitest_value1 = A1; \
498 auto _ncbitest_value2 = A2; \
499 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
500 (NCBI_NS_NCBI::g_NcbiTestMutex); \
501 BOOST_TEST_TOOL_IMPL(00, ::boost::test_tools::tt_detail::P(), \
502 descr, TL, CT, \
503 (_ncbitest_value1)(BOOST_STRINGIZE(A1)) \
504 (_ncbitest_value2)(BOOST_STRINGIZE(A2))); \
505 } while( ::boost::test_tools::tt_detail::dummy_cond() )
506
507 # define BOOST_CLOSE_IMPL_MT_SAFE( L, R, T, TL ) \
508 do { \
509 auto _ncbitest_l = L; \
510 auto _ncbitest_r = R; \
511 auto _ncbitest_t = ::boost::math::fpc::percent_tolerance(T); \
512 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
513 (NCBI_NS_NCBI::g_NcbiTestMutex); \
514 BOOST_TEST_TOOL_IMPL( \
515 00, ::boost::test_tools::check_is_close_t(), "", TL, CHECK_CLOSE, \
516 (_ncbitest_l)(BOOST_STRINGIZE(L))(_ncbitest_r)(BOOST_STRINGIZE(R))\
517 (_ncbitest_t)("")); \
518 } while ( ::boost::test_tools::tt_detail::dummy_cond() )
519
520 # define BOOST_EQUAL_COLLECTIONS_IMPL_MT_SAFE( LB, LE, RB, RE, TL ) \
521 do { \
522 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
523 (NCBI_NS_NCBI::g_NcbiTestMutex); \
524 BOOST_TEST_TOOL_IMPL( \
525 1, ::boost::test_tools::tt_detail::equal_coll_impl(), \
526 "", TL, CHECK_EQUAL_COLL, (LB)(LE)(RB)(RE) ); \
527 } while( ::boost::test_tools::tt_detail::dummy_cond() )
528
529 #else
530
531 # define NCBITEST_CHECK_IMPL(P, check_descr, TL, CT) \
532 BOOST_CHECK_NO_THROW_IMPL(BOOST_CHECK_IMPL(P, check_descr, TL, CT), TL)
533
534 # define NCBITEST_CHECK_WITH_ARGS_IMPL(P, check_descr, TL, CT, ARGS) \
535 BOOST_CHECK_NO_THROW_IMPL(BOOST_CHECK_WITH_ARGS_IMPL( \
536 ::boost::test_tools::tt_detail::P(), check_descr, TL, CT, ARGS), TL)
537
538 # define NCBITEST_CHECK_IMPL_MT_SAFE(P, check_descr, TL, CT) \
539 do { \
540 bool _ncbitest_value; \
541 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
542 (NCBI_NS_NCBI::eEmptyGuard); \
543 BOOST_CHECK_NO_THROW_IMPL_EX(_ncbitest_value = (P), TL, \
544 _ncbitest_guard.Guard(NCBI_NS_NCBI::g_NcbiTestMutex)); \
545 BOOST_CHECK_IMPL(_ncbitest_value, check_descr, TL, CT); \
546 } while ( ::boost::test_tools::dummy_cond )
547
548 # define NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE(P, descr, TL, CT, A1, A2) \
549 do { \
550 std::decay<decltype(A1)>::type _ncbitest_value1; \
551 std::decay<decltype(A2)>::type _ncbitest_value2; \
552 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
553 (NCBI_NS_NCBI::eEmptyGuard); \
554 BOOST_CHECK_NO_THROW_IMPL_EX( \
555 _ncbitest_value1 = (A1); _ncbitest_value2 = (A2);, TL, \
556 _ncbitest_guard.Guard(NCBI_NS_NCBI::g_NcbiTestMutex)); \
557 /* BOOST_TEST_PASSPOINT(); */ /* redundant */ \
558 BOOST_TEST_TOOL_IMPL( check_frwd, \
559 ::boost::test_tools::tt_detail::P(), \
560 descr, TL, CT ) \
561 BOOST_PP_SEQ_FOR_EACH( BOOST_TEST_TOOL_PASS_ARG_ONLY, '_', \
562 (_ncbitest_value1)(BOOST_STRINGIZE(A1)) \
563 (_ncbitest_value2)(BOOST_STRINGIZE(A2)))); \
564 } while ( ::boost::test_tools::dummy_cond )
565
566 # define BOOST_CHECK_IMPL_MT_SAFE( P, check_descr, TL, CT ) \
567 do { \
568 bool _ncbitest_value = (P); \
569 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
570 (NCBI_NS_NCBI::g_NcbiTestMutex); \
571 BOOST_CHECK_IMPL( _ncbitest_value, check_descr, TL, CT ); \
572 } while ( ::boost::test_tools::dummy_cond )
573
574 # define BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE(P, descr, TL, CT, A1, A2) \
575 do { \
576 auto _ncbitest_value1 = A1; \
577 auto _ncbitest_value2 = A2; \
578 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
579 (NCBI_NS_NCBI::g_NcbiTestMutex); \
580 BOOST_TEST_PASSPOINT(); \
581 BOOST_TEST_TOOL_IMPL( check_frwd, \
582 ::boost::test_tools::tt_detail::P(), \
583 descr, TL, CT ) \
584 BOOST_PP_SEQ_FOR_EACH( BOOST_TEST_TOOL_PASS_ARG_ONLY, '_', \
585 (_ncbitest_value1)(BOOST_STRINGIZE(A1)) \
586 (_ncbitest_value2)(BOOST_STRINGIZE(A2)))); \
587 } while ( ::boost::test_tools::dummy_cond )
588
589 # define BOOST_CLOSE_IMPL_MT_SAFE( L, R, T, TL ) \
590 do { \
591 auto _ncbitest_l = L; \
592 auto _ncbitest_r = R; \
593 auto _ncbitest_t = ::boost::test_tools::percent_tolerance(T); \
594 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
595 (NCBI_NS_NCBI::g_NcbiTestMutex); \
596 BOOST_TEST_PASSPOINT(); \
597 BOOST_TEST_TOOL_IMPL(check_frwd, ::boost::test_tools::check_is_close, \
598 "", TL, CHECK_CLOSE) \
599 BOOST_PP_SEQ_FOR_EACH(BOOST_TEST_TOOL_PASS_ARG_ONLY, '_', \
600 (_ncbitest_l)(BOOST_STRINGIZE(L)) \
601 (_ncbitest_r)(BOOST_STRINGIZE(R)) \
602 (_ncbitest_t)(""))); \
603 } while ( ::boost::test_tools::dummy_cond )
604
605 # define BOOST_EQUAL_COLLECTIONS_IMPL_MT_SAFE( LB, LE, RB, RE, TL ) \
606 do { \
607 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
608 (NCBI_NS_NCBI::g_NcbiTestMutex); \
609 BOOST_EQUAL_COLLECTIONS_IMPL( LB, LE, RB, RE, TL ); \
610 } while( ::boost::test_tools::dummy_cond )
611
612 #endif
613
614 // Several analogs to BOOST_* macros that make simultaneous checking of
615 // NO_THROW and some other condition
616 #define NCBITEST_WARN(P) NCBITEST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), WARN, CHECK_PRED )
617 #define NCBITEST_CHECK(P) NCBITEST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), CHECK, CHECK_PRED )
618 #define NCBITEST_REQUIRE(P) NCBITEST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), REQUIRE, CHECK_PRED )
619
620 #define NCBITEST_WARN_MT_SAFE(P) \
621 NCBITEST_CHECK_IMPL_MT_SAFE( (P), BOOST_TEST_STRINGIZE( P ), WARN, \
622 CHECK_PRED )
623 #define NCBITEST_CHECK_MT_SAFE(P) \
624 NCBITEST_CHECK_IMPL_MT_SAFE( (P), BOOST_TEST_STRINGIZE( P ), CHECK, \
625 CHECK_PRED )
626 #define NCBITEST_REQUIRE_MT_SAFE(P) \
627 NCBITEST_CHECK_IMPL_MT_SAFE( (P), BOOST_TEST_STRINGIZE( P ), REQUIRE, \
628 CHECK_PRED )
629
630
631 #define NCBITEST_WARN_MESSAGE( P, M ) NCBITEST_CHECK_IMPL( (P), M, WARN, CHECK_MSG )
632 #define NCBITEST_CHECK_MESSAGE( P, M ) NCBITEST_CHECK_IMPL( (P), M, CHECK, CHECK_MSG )
633 #define NCBITEST_REQUIRE_MESSAGE( P, M ) NCBITEST_CHECK_IMPL( (P), M, REQUIRE, CHECK_MSG )
634
635 #define NCBITEST_WARN_MESSAGE_MT_SAFE( P, M ) \
636 NCBITEST_CHECK_IMPL_MT_SAFE( (P), M, WARN, CHECK_MSG )
637 #define NCBITEST_CHECK_MESSAGE_MT_SAFE( P, M ) \
638 NCBITEST_CHECK_IMPL_MT_SAFE( (P), M, CHECK, CHECK_MSG )
639 #define NCBITEST_REQUIRE_MESSAGE_MT_SAFE( P, M ) \
640 NCBITEST_CHECK_IMPL_MT_SAFE( (P), M, REQUIRE, CHECK_MSG )
641
642
643 #define NCBITEST_WARN_EQUAL( L, R ) \
644 NCBITEST_CHECK_WITH_ARGS_IMPL( equal_impl_frwd, "", WARN, CHECK_EQUAL, (L)(R) )
645 #define NCBITEST_CHECK_EQUAL( L, R ) \
646 NCBITEST_CHECK_WITH_ARGS_IMPL( equal_impl_frwd, "", CHECK, CHECK_EQUAL, (L)(R) )
647 #define NCBITEST_REQUIRE_EQUAL( L, R ) \
648 NCBITEST_CHECK_WITH_ARGS_IMPL( equal_impl_frwd, "", REQUIRE, CHECK_EQUAL, (L)(R) )
649
650 #define NCBITEST_WARN_EQUAL_MT_SAFE( L, R ) \
651 NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( equal_impl_frwd, "", WARN, \
652 CHECK_EQUAL, L, R )
653 #define NCBITEST_CHECK_EQUAL_MT_SAFE( L, R ) \
654 NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( equal_impl_frwd, "", CHECK, \
655 CHECK_EQUAL, L, R )
656 #define NCBITEST_REQUIRE_EQUAL_MT_SAFE( L, R ) \
657 NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( equal_impl_frwd, "", REQUIRE, \
658 CHECK_EQUAL, L, R )
659
660
661 #define NCBITEST_WARN_NE( L, R ) \
662 NCBITEST_CHECK_WITH_ARGS_IMPL( ne_impl, "", WARN, CHECK_NE, (L)(R) )
663 #define NCBITEST_CHECK_NE( L, R ) \
664 NCBITEST_CHECK_WITH_ARGS_IMPL( ne_impl, "", CHECK, CHECK_NE, (L)(R) )
665 #define NCBITEST_REQUIRE_NE( L, R ) \
666 NCBITEST_CHECK_WITH_ARGS_IMPL( ne_impl, "", REQUIRE, CHECK_NE, (L)(R) )
667
668 #define NCBITEST_WARN_NE_MT_SAFE( L, R ) \
669 NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( ne_impl, "", WARN, \
670 CHECK_NE, L, R )
671 #define NCBITEST_CHECK_NE_MT_SAFE( L, R ) \
672 NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( ne_impl, "", CHECK, \
673 CHECK_NE, L, R )
674 #define NCBITEST_REQUIRE_NE_MT_SAFE( L, R ) \
675 NCBITEST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( ne_impl, "", REQUIRE, \
676 CHECK_NE, L, R )
677
678 // MT-safe variants of commonly used standard Boost macros
679 #define BOOST_WARN_MT_SAFE( P ) \
680 BOOST_CHECK_IMPL_MT_SAFE( (P), BOOST_TEST_STRINGIZE(P), WARN, CHECK_PRED )
681 #define BOOST_CHECK_MT_SAFE( P ) \
682 BOOST_CHECK_IMPL_MT_SAFE( (P), BOOST_TEST_STRINGIZE(P), CHECK, CHECK_PRED )
683 #define BOOST_REQUIRE_MT_SAFE( P ) \
684 BOOST_CHECK_IMPL_MT_SAFE( (P), BOOST_TEST_STRINGIZE(P), REQUIRE, \
685 CHECK_PRED )
686
687 #define BOOST_WARN_MESSAGE_MT_SAFE( P, M ) \
688 BOOST_CHECK_IMPL_MT_SAFE( (P), M, WARN, CHECK_MSG )
689 #define BOOST_CHECK_MESSAGE_MT_SAFE( P, M ) \
690 BOOST_CHECK_IMPL_MT_SAFE( (P), M, CHECK, CHECK_MSG )
691 #define BOOST_REQUIRE_MESSAGE_MT_SAFE( P, M ) \
692 BOOST_CHECK_IMPL_MT_SAFE( (P), M, REQUIRE, CHECK_MSG )
693
694 #define BOOST_WARN_EQUAL_MT_SAFE( L, R ) \
695 BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( equal_impl_frwd, "", WARN, \
696 CHECK_EQUAL, L, R )
697 #define BOOST_CHECK_EQUAL_MT_SAFE( L, R ) \
698 BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( equal_impl_frwd, "", CHECK, \
699 CHECK_EQUAL, L, R )
700 #define BOOST_REQUIRE_EQUAL_MT_SAFE( L, R ) \
701 BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( equal_impl_frwd, "", REQUIRE, \
702 CHECK_EQUAL, L, R )
703
704 #define BOOST_WARN_NE_MT_SAFE( L, R ) \
705 BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( ne_impl, "", WARN, CHECK_NE, L, R )
706 #define BOOST_CHECK_NE_MT_SAFE( L, R ) \
707 BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE( ne_impl, "", CHECK, CHECK_NE, L, R )
708 #define BOOST_REQUIRE_NE_MT_SAFE( L, R ) \
709 BOOST_CHECK_WITH_2_ARGS_IMPL_MT_SAFE(ne_impl, "", REQUIRE, CHECK_NE, L, R )
710
711 #define BOOST_ERROR_MT_SAFE( M ) BOOST_CHECK_MESSAGE_MT_SAFE( false, M )
712 #define BOOST_FAIL_MT_SAFE( M ) BOOST_REQUIRE_MESSAGE_MT_SAFE( false, M )
713
714 #define BOOST_TEST_MESSAGE_MT_SAFE( M ) \
715 do { \
716 NCBI_NS_NCBI::CFastMutexGuard _ncbitest_guard \
717 (NCBI_NS_NCBI::g_NcbiTestMutex); \
718 BOOST_TEST_MESSAGE( M ); \
719 } while (false)
720
721 #define BOOST_WARN_CLOSE_MT_SAFE( L, R, T ) \
722 BOOST_CLOSE_IMPL_MT_SAFE( L, R, T, WARN )
723 #define BOOST_CHECK_CLOSE_MT_SAFE( L, R, T ) \
724 BOOST_CLOSE_IMPL_MT_SAFE( L, R, T, CHECK )
725 #define BOOST_REQUIRE_CLOSE_MT_SAFE( L, R, T ) \
726 BOOST_CLOSE_IMPL_MT_SAFE( L, R, T, REQUIRE )
727
728 #define BOOST_WARN_EQUAL_COLLECTIONS_MT_SAFE( LB, LE, RB, RE ) \
729 BOOST_EQUAL_COLLECTIONS_IMPL_MT_SAFE( LB, LE, RB, RE, WARN )
730 #define BOOST_CHECK_EQUAL_COLLECTIONS_MT_SAFE( LB, LE, RB, RE ) \
731 BOOST_EQUAL_COLLECTIONS_IMPL_MT_SAFE( LB, LE, RB, RE, CHECK )
732 #define BOOST_REQUIRE_EQUAL_COLLECTIONS_MT_SAFE( LB, LE, RB, RE ) \
733 BOOST_EQUAL_COLLECTIONS_IMPL_MT_SAFE( LB, LE, RB, RE, REQUIRE )
734
735 // Ensure Clang analysis tools (notably scan-build) recognize that a failed
736 // {BOOST,NCBITEST}_REQUIRE* call will bail.
737 #ifdef __clang_analyzer__
738 # undef BOOST_REQUIRE
739 # define BOOST_REQUIRE(P) _ALWAYS_ASSERT(P)
740 # undef BOOST_REQUIRE_MT_SAFE
741 # define BOOST_REQUIRE_MT_SAFE(P) BOOST_REQUIRE(P)
742 # undef BOOST_REQUIRE_MESSAGE
743 # define BOOST_REQUIRE_MESSAGE(P, M) _ALWAYS_ASSERT((FORMAT(M), (P)))
744 # undef BOOST_REQUIRE_MESSAGE_MT_SAFE
745 # define BOOST_REQUIRE_MESSAGE_MT_SAFE(P, M) BOOST_REQUIRE_MESSAGE(P, M)
746 # undef BOOST_REQUIRE_EQUAL
747 # define BOOST_REQUIRE_EQUAL(L, R) _ALWAYS_ASSERT((L) == (R))
748 # undef BOOST_REQUIRE_EQUAL_MT_SAFE
749 # define BOOST_REQUIRE_EQUAL_MT_SAFE(L, R) BOOST_REQUIRE_EQUAL(L, R)
750 # undef BOOST_REQUIRE_NE
751 # define BOOST_REQUIRE_NE(L, R) _ALWAYS_ASSERT((L) != (R))
752 # undef BOOST_REQUIRE_NE_MT_SAFE
753 # define BOOST_REQUIRE_NE_MT_SAFE(L, R) BOOST_REQUIRE_NE(L, R)
754 # undef BOOST_REQUIRE_NO_THROW
755 # define BOOST_REQUIRE_NO_THROW(S) try { S; } catch (...) { _ALWAYS_TROUBLE; }
756 # undef BOOST_REQUIRE_NO_THROW_MT_SAFE
757 # define BOOST_REQUIRE_NO_THROW_MT_SAFE(S) BOOST_REQUIRE_NO_THROW(S)
758 # undef BOOST_REQUIRE_THROW
759 # define BOOST_REQUIRE_THROW(S, E) \
760 do { try { S; } catch (E const&) { break; } _ALWAYS_TROUBLE; } while(false)
761 # undef BOOST_REQUIRE_THROW_MT_SAFE
762 # define BOOST_REQUIRE_THROW_MT_SAFE(S, E) BOOST_REQUIRE_THROW(S, E)
763 # undef NCBITEST_REQUIRE
764 # define NCBITEST_REQUIRE(P) BOOST_REQUIRE_NO_THROW(_ALWAYS_ASSERT(P))
765 # undef NCBITEST_REQUIRE_MT_SAFE
766 # define NCBITEST_REQUIRE_MT_SAFE(P) NCBITEST_REQUIRE(P)
767 # undef NCBITEST_REQUIRE_MESSAGE
768 # define NCBITEST_REQUIRE_MESSAGE(P, M) NCBITEST_REQUIRE((FORMAT(M), (P)))
769 # undef NCBITEST_REQUIRE_MESSAGE_MT_SAFE
770 # define NCBITEST_REQUIRE_MESSAGE_MT_SAFE(P, M) NCBITEST_REQUIRE_MESSAGE(P, M)
771 # undef NCBITEST_REQUIRE_EQUAL
772 # define NCBITEST_REQUIRE_EQUAL(L, R) NCBITEST_REQUIRE((L) == (R))
773 # undef NCBITEST_REQUIRE_EQUAL_MT_SAFE
774 # define NCBITEST_REQUIRE_EQUAL_MT_SAFE(L, R) NCBITEST_REQUIRE_EQUAL(L, R)
775 # undef NCBITEST_REQUIRE_NE
776 # define NCBITEST_REQUIRE_NE(L, R) NCBITEST_REQUIRE((L) != (R))
777 # undef NCBITEST_REQUIRE_NE_MT_SAFE
778 # define NCBITEST_REQUIRE_NE_MT_SAFE(L, R) NCBITEST_REQUIRE_NE(L, R)
779 // Used but left as is: BOOST_REQUIRE_CLOSE, BOOST_REQUIRE_EQUAL_COLLECTIONS.
780 // Irrelevant: BOOST_REQUIRE_CTX (custom, based on BOOST_REQUIRE),
781 // BOOST_REQUIRE_CUTPOINT (custom, based on throw).
782 // Used only in BOOST_CHECK_... form: GE, GT, LT, SMALL.
783 #endif
784
785
786 /** @addtogroup Tests
787 *
788 * @{
789 */
790
791
792 BEGIN_NCBI_SCOPE
793
794
795 /// Macro for introducing function initializing argument descriptions for
796 /// tests. This function will be called before CNcbiApplication will parse
797 /// command line arguments. So it will parse command line using descriptions
798 /// set by this function. Also test framework will react correctly on such
799 /// arguments as -h, -help or -dryrun (the last will just print list of unit
800 /// tests without actually executing them). The parameter var_name is a name
801 /// for variable of type CArgDescriptions* that can be used inside function
802 /// to set up argument descriptions. Usage of this macro is like this:<pre>
803 /// NCBITEST_INIT_CMDLINE(my_args)
804 /// {
805 /// my_args->SetUsageContext(...);
806 /// my_args->AddPositional(...);
807 /// }
808 /// </pre>
809 ///
810 #define NCBITEST_INIT_CMDLINE(var_name) \
811 NCBITEST_AUTOREG_PARAMFUNC(eTestUserFuncCmdLine, \
812 CArgDescriptions* var_name, \
813 NcbiTestGetArgDescrs)
814
815
816 /// Macro for introducing initialization function which will be called before
817 /// tests execution and only if tests will be executed (if there's no command
818 /// line parameter -dryrun or --do_not_test) even if only select number of
819 /// tests will be executed (if command line parameter --run_test=... were
820 /// given). If any of these initialization functions will throw an exception
821 /// then tests will not be executed. The usage of this macro:<pre>
822 /// NCBITEST_AUTO_INIT()
823 /// {
824 /// // initialization function body
825 /// }
826 /// </pre>
827 /// Arbitrary number of initialization functions can be defined. They all will
828 /// be called before tests but the order of these callings is not defined.
829 ///
830 /// @sa NCBITEST_AUTO_FINI
831 ///
832 #define NCBITEST_AUTO_INIT() NCBITEST_AUTOREG_FUNCTION(eTestUserFuncInit)
833
834
835 /// Macro for introducing finalization function which will be called after
836 /// actual tests execution even if only select number of tests will be
837 /// executed (if command line parameter --run_test=... were given). The usage
838 /// of this macro:<pre>
839 /// NCBITEST_AUTO_FINI()
840 /// {
841 /// // finalization function body
842 /// }
843 /// </pre>
844 /// Arbitrary number of finalization functions can be defined. They all will
845 /// be called after tests are executed but the order of these callings is not
846 /// defined.
847 ///
848 /// @sa NCBITEST_AUTO_INIT
849 ///
850 #define NCBITEST_AUTO_FINI() NCBITEST_AUTOREG_FUNCTION(eTestUserFuncFini)
851
852
853 /// Macro for introducing function which should initialize configuration
854 /// conditions parser. This parser will be used to evaluate conditions for
855 /// running tests written in configuration file. So you should set values for
856 /// all variables that you want to participate in those expressions. Test
857 /// framework automatically adds all OS*, COMPILER* and DLL_BUILD variables
858 /// with the values of analogous NCBI_OS*, NCBI_COMPILER* and NCBI_DLL_BUILD
859 /// macros. The usage of this macro:<pre>
860 /// NCBITEST_INIT_VARIABLES(my_parser)
861 /// {
862 /// my_parser->AddSymbol("var_name1", value_expr1);
863 /// my_parser->AddSymbol("var_name2", value_expr2);
864 /// }
865 /// </pre>
866 /// Arbitrary number of such functions can be defined.
867 ///
868 #define NCBITEST_INIT_VARIABLES(var_name) \
869 NCBITEST_AUTOREG_PARAMFUNC(eTestUserFuncVars, \
870 CExprParser* var_name, \
871 NcbiTestGetIniParser)
872
873
874 /// Macro for introducing function which should initialize dependencies
875 /// between test units and some hard coded (not taken from configuration file)
876 /// tests disablings. All function job can be done by using NCBITEST_DISABLE,
877 /// NCBITEST_DEPENDS_ON and NCBITEST_DEPENDS_ON_N macros in conjunction with
878 /// some conditional statements maybe. The usage of this macro:<pre>
879 /// NCBITEST_INIT_TREE()
880 /// {
881 /// NCBITEST_DISABLE(test_name11);
882 ///
883 /// NCBITEST_DEPENDS_ON(test_name22, test_name1);
884 /// NCBITEST_DEPENDS_ON_N(test_name33, N, (test_name1, ..., test_nameN));
885 /// }
886 /// </pre>
887 /// Arbitrary number of such functions can be defined.
888 ///
889 /// @sa NCBITEST_DISABLE, NCBITEST_DEPENDS_ON, NCBITEST_DEPENDS_ON_N
890 ///
891 #define NCBITEST_INIT_TREE() NCBITEST_AUTOREG_FUNCTION(eTestUserFuncDeps)
892
893
894 /// Unconditionally disable test case. To be used inside function introduced
895 /// by NCBITEST_INIT_TREE.
896 ///
897 /// @param test_name
898 /// Name of the test as a bare text without quotes. Name can exclude test_
899 /// prefix if function name includes one and class prefix if it is class
900 /// member test case.
901 ///
902 /// @sa NCBITEST_INIT_TREE
903 ///
904 #define NCBITEST_DISABLE(test_name) \
905 NcbiTestDisable(NcbiTestGetUnit(BOOST_STRINGIZE(test_name)))
906
907
908 /// Add dependency between test test_name and dep_name. This dependency means
909 /// if test dep_name is failed during execution or was disabled by any reason
910 /// then test test_name will not be executed (will be skipped).
911 /// To be used inside function introduced by NCBITEST_INIT_TREE.
912 ///
913 /// @param test_name
914 /// Name of the test as a bare text without quotes. Name can exclude test_
915 /// prefix if function name includes one and class prefix if it is class
916 /// member test case.
917 /// @param dep_name
918 /// Name of the test to depend on. Name can be given with the same
919 /// assumptions as test_name.
920 ///
921 /// @sa NCBITEST_INIT_TREE, NCBI_TEST_DEPENDS_ON_N
922 ///
923 #define NCBITEST_DEPENDS_ON(test_name, dep_name) \
924 NcbiTestDependsOn(NcbiTestGetUnit(BOOST_STRINGIZE(test_name)), \
925 NcbiTestGetUnit(BOOST_STRINGIZE(dep_name)))
926
927
928 /// Add dependency between test test_name and several other tests which names
929 /// given in the list dep_names_array. This dependency means if any of the
930 /// tests in list dep_names_array is failed during execution or was disabled
931 /// by any reason then test test_name will not be executed (will be skipped).
932 /// To be used inside function introduced by NCBITEST_INIT_TREE. Macro is
933 /// equivalent to use NCBI_TEST_DEPENDS_ON several times for each test in
934 /// dep_names_array.
935 ///
936 /// @param test_name
937 /// Name of the test as a bare text without quotes. Name can exclude test_
938 /// prefix if function name includes one and class prefix if it is class
939 /// member test case.
940 /// @param N
941 /// Number of tests in dep_names_array
942 /// @param dep_names_array
943 /// Names of tests to depend on. Every name can be given with the same
944 /// assumptions as test_name. Array should be given enclosed in parenthesis
945 /// like (test_name1, ..., test_nameN) and should include exactly N elements
946 /// or preprocessor error will occur during compilation.
947 ///
948 /// @sa NCBITEST_INIT_TREE, NCBI_TEST_DEPENDS_ON
949 ///
950 #define NCBITEST_DEPENDS_ON_N(test_name, N, dep_names_array) \
951 BOOST_PP_REPEAT(N, NCBITEST_DEPENDS_ON_N_IMPL, \
952 (BOOST_PP_INC(N), (test_name, \
953 BOOST_PP_TUPLE_REM(N) dep_names_array))) \
954 (void)0
955
956
957 /// Set of macros to manually add test cases that cannot be created using
958 /// BOOST_AUTO_TEST_CASE. To create such test cases you should have a function
959 /// (that can accept up to 3 parameters) and use one of macros below inside
960 /// NCBITEST_INIT_TREE() function. All function parameters are passed by value.
961 ///
962 /// @sa NCBITEST_INIT_TREE, BOOST_AUTO_PARAM_TEST_CASE
963 #define NCBITEST_ADD_TEST_CASE(function) \
964 boost::unit_test::framework::master_test_suite().add( \
965 boost::unit_test::make_test_case( \
966 boost::bind(function), \
967 BOOST_TEST_STRINGIZE(function) \
968 ) )
969 #define NCBITEST_ADD_TEST_CASE1(function, param1) \
970 boost::unit_test::framework::master_test_suite().add( \
971 boost::unit_test::make_test_case( \
972 boost::bind(function, (param1)), \
973 BOOST_TEST_STRINGIZE(function) \
974 ) )
975 #define NCBITEST_ADD_TEST_CASE2(function, param1, param2) \
976 boost::unit_test::framework::master_test_suite().add( \
977 boost::unit_test::make_test_case( \
978 boost::bind(function, (param1), (param2)), \
979 BOOST_TEST_STRINGIZE(function) \
980 ) )
981 #define NCBITEST_ADD_TEST_CASE3(function, param1, param2, param3) \
982 boost::unit_test::framework::master_test_suite().add( \
983 boost::unit_test::make_test_case( \
984 boost::bind(function, (param1), (param2), (param3)), \
985 BOOST_TEST_STRINGIZE(function) \
986 ) )
987
988
989 /// Disable execution of all tests in current configuration. Call to the
990 /// function is equivalent to setting GLOBAL = true in ini file.
991 /// Globally disabled tests are shown as DIS by check scripts
992 /// (called via make check).
993 /// Function should be called only from NCBITEST_AUTO_INIT() or
994 /// NCBITEST_INIT_TREE() functions.
995 ///
996 /// @sa NCBITEST_AUTO_INIT, NCBITEST_INIT_TREE
997 ///
998 void NcbiTestSetGlobalDisabled(void);
999
1000
1001 /// Skip execution of all tests in current configuration.
1002 /// Globally skipped tests are shown as SKP by check scripts
1003 /// (called via make check).
1004 /// Function should be called only from NCBITEST_AUTO_INIT() or
1005 /// NCBITEST_INIT_TREE() functions.
1006 ///
1007 /// @sa NCBITEST_AUTO_INIT, NCBITEST_INIT_TREE
1008 ///
1009 void NcbiTestSetGlobalSkipped(void);
1010
1011
1012 /// Return current application instance. Similar to CNcbiApplication::Instance().
1013 ///
1014 CNcbiApplication* NcbiTestGetAppInstance(void);
1015
1016
1017 /// Wrapper to get the application's configuration parameters, accessible to read-write.
1018 /// We cannot use CNcbiApplication::GetConfig(), because it return read-only registry,
1019 /// and protected CNcbiApplication::GetRWConfig() is not accessible for unit tests directly.
1020 ///
1021 CNcbiRegistry& NcbiTestGetRWConfig(void);
1022
1023
1024
1025 //////////////////////////////////////////////////////////////////////////
1026 // All API from this line below is for internal use only and is not
1027 // intended for use by any users. All this stuff is used by end-user
1028 // macros defined above.
1029 //////////////////////////////////////////////////////////////////////////
1030
1031 #ifdef SYSTEM_MUTEX_INITIALIZER
1032 extern SSystemFastMutex g_NcbiTestMutex;
1033 #else
1034 extern CAutoInitializeStaticFastMutex g_NcbiTestMutex;
1035 #endif
1036
1037 /// Helper macro to implement NCBI_TEST_DEPENDS_ON_N.
1038 #define NCBITEST_DEPENDS_ON_N_IMPL(z, n, names_array) \
1039 NCBITEST_DEPENDS_ON(BOOST_PP_ARRAY_ELEM(0, names_array), \
1040 BOOST_PP_ARRAY_ELEM(BOOST_PP_INC(n), names_array));
1041
1042
1043 /// Mark test case/suite as dependent on another test case/suite.
1044 /// If dependency test case didn't executed successfully for any reason then
1045 /// dependent test will not be executed. This rule has one exception: if test
1046 /// is requested to execute in command line via parameter "--run_test" and
1047 /// dependency was not requested to execute, requested test will be executed
1048 /// anyways.
1049 ///
1050 /// @param tu
1051 /// Test case/suite that should be marked as dependent
1052 /// @param dep_tu
1053 /// Test case/suite that will be "parent" for tu
1054 void NcbiTestDependsOn(boost::unit_test::test_unit* tu,
1055 boost::unit_test::test_unit* dep_tu);
1056
1057 /// Disable test unit.
1058 /// Disabled test unit will not be executed (as if p_enabled is set to false)
1059 /// but it will be reported in final Boost.Test report as disabled (as opposed
1060 /// to setting p_enabled to false when test does not appear in final
1061 /// Boost.Test report).
1062 void NcbiTestDisable(boost::unit_test::test_unit* tu);
1063
1064
1065 /// Type of user-defined function which will be automatically registered
1066 /// in test framework
1067 typedef void (*TNcbiTestUserFunction)(void);
1068
1069 /// Types of functions that user can define
1070 enum ETestUserFuncType {
1071 eTestUserFuncInit,
1072 eTestUserFuncFini,
1073 eTestUserFuncCmdLine,
1074 eTestUserFuncVars,
1075 eTestUserFuncDeps,
1076 eTestUserFuncFirst = eTestUserFuncInit,
1077 eTestUserFuncLast = eTestUserFuncDeps
1078 };
1079
1080 /// Registrar of all user-defined functions
1081 void RegisterNcbiTestUserFunc(TNcbiTestUserFunction func,
1082 ETestUserFuncType func_type);
1083
1084 /// Class for implementing automatic registration of user functions
1085 struct SNcbiTestUserFuncReg
1086 {
SNcbiTestUserFuncRegSNcbiTestUserFuncReg1087 SNcbiTestUserFuncReg(TNcbiTestUserFunction func,
1088 ETestUserFuncType func_type)
1089 {
1090 RegisterNcbiTestUserFunc(func, func_type);
1091 }
1092 };
1093
1094 /// Get pointer to parser which will be used for evaluating conditions written
1095 /// in configuration file
1096 CExprParser* NcbiTestGetIniParser(void);
1097
1098 /// Get ArgDescriptions object which will be passed to application for parsing
1099 /// command line arguments.
1100 CArgDescriptions* NcbiTestGetArgDescrs(void);
1101
1102 /// Get pointer to test unit by its name which can be partial, i.e. without
1103 /// class prefix and/or test_ prefix if any. Throws an exception in case of
1104 /// name of non-existent test
1105 boost::unit_test::test_unit* NcbiTestGetUnit(CTempString test_name);
1106
1107
1108 /// Helper macros for unique identifiers
1109 #define NCBITEST_AUTOREG_FUNC(type) \
1110 BOOST_JOIN(BOOST_JOIN(Ncbi_, type), __LINE__)
1111 #define NCBITEST_AUTOREG_OBJ BOOST_JOIN(NcbiTestAutoObj, __LINE__)
1112 #define NCBITEST_AUTOREG_HELPER BOOST_JOIN(NcbiTestAutoHelper, __LINE__)
1113
1114 #define NCBITEST_AUTOREG_FUNCTION(type) \
1115 static void NCBITEST_AUTOREG_FUNC(type)(void); \
1116 static ::NCBI_NS_NCBI::SNcbiTestUserFuncReg \
1117 NCBITEST_AUTOREG_OBJ(&NCBITEST_AUTOREG_FUNC(type), ::NCBI_NS_NCBI::type); \
1118 static void NCBITEST_AUTOREG_FUNC(type)(void)
1119
1120 #define NCBITEST_AUTOREG_PARAMFUNC(type, param_decl, param_func) \
1121 static void NCBITEST_AUTOREG_FUNC(type)(::NCBI_NS_NCBI::param_decl); \
1122 static void NCBITEST_AUTOREG_HELPER(void) \
1123 { \
1124 NCBITEST_AUTOREG_FUNC(type)(::NCBI_NS_NCBI::param_func()); \
1125 } \
1126 static ::NCBI_NS_NCBI::SNcbiTestUserFuncReg \
1127 NCBITEST_AUTOREG_OBJ(&NCBITEST_AUTOREG_HELPER, ::NCBI_NS_NCBI::type); \
1128 static void NCBITEST_AUTOREG_FUNC(type)(::NCBI_NS_NCBI::param_decl)
1129
1130 /// Extension auto-registrar from Boost.Test that can automatically set the
1131 /// timeout for unit.
1132 struct SNcbiTestRegistrar
1133 : public boost::unit_test::ut_detail::auto_test_unit_registrar
1134 {
1135 typedef boost::unit_test::ut_detail::auto_test_unit_registrar TParent;
1136
SNcbiTestRegistrarSNcbiTestRegistrar1137 SNcbiTestRegistrar(boost::unit_test::test_case* tc,
1138 boost::unit_test::counter_t exp_fail,
1139 unsigned int timeout)
1140 : TParent(tc NCBI_BOOST_DECORATOR_ARG, exp_fail)
1141 {
1142 tc->p_timeout.set(timeout);
1143 }
1144
1145 #ifdef BOOST_FIXTURE_TEST_CASE_WITH_DECOR
SNcbiTestRegistrarSNcbiTestRegistrar1146 SNcbiTestRegistrar(boost::unit_test::test_case* tc,
1147 unsigned int timeout,
1148 boost::unit_test::decorator::collector_t& decorator)
1149 : TParent(tc, decorator)
1150 {
1151 tc->p_timeout.set(timeout);
1152 }
1153 #endif
1154
SNcbiTestRegistrarSNcbiTestRegistrar1155 SNcbiTestRegistrar(boost::unit_test::test_case* tc,
1156 boost::unit_test::counter_t exp_fail)
1157 : TParent(tc NCBI_BOOST_DECORATOR_ARG, exp_fail)
1158 {}
1159
1160 #ifndef BOOST_FIXTURE_TEST_CASE_WITH_DECOR
1161 explicit
SNcbiTestRegistrarSNcbiTestRegistrar1162 SNcbiTestRegistrar(boost::unit_test::const_string ts_name)
1163 : TParent(ts_name)
1164 {}
1165 #endif
1166
1167 explicit
SNcbiTestRegistrarSNcbiTestRegistrar1168 SNcbiTestRegistrar(boost::unit_test::test_unit_generator const& tc_gen)
1169 : TParent(tc_gen NCBI_BOOST_DECORATOR_ARG)
1170 {}
1171
1172 explicit
SNcbiTestRegistrarSNcbiTestRegistrar1173 SNcbiTestRegistrar(int n)
1174 : TParent(n)
1175 {}
1176 };
1177
1178
1179 /// Copy of auto_tc_exp_fail from Boost.Test to store the value of timeout
1180 /// for each test.
1181 template<typename T>
1182 struct SNcbiTestTCTimeout
1183 {
SNcbiTestTCTimeoutSNcbiTestTCTimeout1184 SNcbiTestTCTimeout() : m_value(0) {}
1185
SNcbiTestTCTimeoutSNcbiTestTCTimeout1186 explicit SNcbiTestTCTimeout(unsigned int v)
1187 : m_value( v )
1188 {
1189 instance() = this;
1190 }
1191
instanceSNcbiTestTCTimeout1192 static SNcbiTestTCTimeout*& instance()
1193 {
1194 static SNcbiTestTCTimeout inst;
1195 static SNcbiTestTCTimeout* inst_ptr = &inst;
1196
1197 return inst_ptr;
1198 }
1199
valueSNcbiTestTCTimeout1200 unsigned int value() const { return m_value; }
1201
1202 private:
1203 // Data members
1204 unsigned m_value;
1205 };
1206
1207
1208 /// Special generator of test cases for function accepting one parameter.
1209 /// Generator differs from the one provided in Boost.Test in names assigned to
1210 /// generated test cases. NCBI.Test library requires all test names to be
1211 /// unique.
1212 template<typename ParamType, typename ParamIter>
1213 class CNcbiTestParamTestCaseGenerator
1214 : public boost::unit_test::test_unit_generator
1215 {
1216 public:
1217 #if BOOST_VERSION >= 105900
1218 typedef boost::function<void (ParamType)> TTestFunc;
1219 #else
1220 typedef boost::unit_test::callback1<ParamType> TTestFunc;
1221 #endif
1222
CNcbiTestParamTestCaseGenerator(TTestFunc const & test_func,boost::unit_test::const_string name,ParamIter par_begin,ParamIter par_end)1223 CNcbiTestParamTestCaseGenerator(TTestFunc const& test_func,
1224 boost::unit_test::const_string name,
1225 ParamIter par_begin,
1226 ParamIter par_end)
1227 : m_TestFunc(test_func),
1228 m_Name(boost::unit_test::ut_detail::normalize_test_case_name(name)),
1229 m_ParBegin(par_begin),
1230 m_ParEnd(par_end),
1231 m_CaseIndex(0)
1232 {
1233 m_Name += "_";
1234 }
1235
~CNcbiTestParamTestCaseGenerator()1236 virtual ~CNcbiTestParamTestCaseGenerator() {}
1237
next() const1238 virtual boost::unit_test::test_unit* next() const
1239 {
1240 if( m_ParBegin == m_ParEnd )
1241 return NULL;
1242
1243 string this_name(m_Name);
1244 this_name += NStr::IntToString(++m_CaseIndex);
1245 #if BOOST_VERSION >= 105900
1246 boost::unit_test::test_unit* res
1247 = new boost::unit_test::test_case
1248 (this_name, boost::bind(m_TestFunc, *m_ParBegin));
1249 #else
1250 boost::unit_test::ut_detail::test_func_with_bound_param<ParamType>
1251 bound_test_func( m_TestFunc, *m_ParBegin );
1252 boost::unit_test::test_unit* res
1253 = new boost::unit_test::test_case(this_name, bound_test_func);
1254 #endif
1255 ++m_ParBegin;
1256
1257 return res;
1258 }
1259
1260 private:
1261 // Data members
1262 TTestFunc m_TestFunc;
1263 string m_Name;
1264 mutable ParamIter m_ParBegin;
1265 ParamIter m_ParEnd;
1266 mutable int m_CaseIndex;
1267 };
1268
1269
1270 /// Helper functions to be used in BOOST_PARAM_TEST_CASE macro to create
1271 /// special test case generator.
1272 template<typename ParamType, typename ParamIter>
1273 inline CNcbiTestParamTestCaseGenerator<ParamType, ParamIter>
NcbiTestGenTestCases(typename CNcbiTestParamTestCaseGenerator<ParamType,ParamIter>::TTestFunc const & test_func,boost::unit_test::const_string name,ParamIter par_begin,ParamIter par_end)1274 NcbiTestGenTestCases(typename CNcbiTestParamTestCaseGenerator<ParamType, ParamIter>::TTestFunc const& test_func,
1275 boost::unit_test::const_string name,
1276 ParamIter par_begin,
1277 ParamIter par_end)
1278 {
1279 return CNcbiTestParamTestCaseGenerator<ParamType, ParamIter>(
1280 test_func, name, par_begin, par_end);
1281 }
1282
1283 template<typename ParamType, typename ParamIter>
1284 inline CNcbiTestParamTestCaseGenerator<
1285 typename boost::remove_const<
1286 typename boost::remove_reference<ParamType>::type
1287 >::type, ParamIter>
NcbiTestGenTestCases(void (* test_func)(ParamType),boost::unit_test::const_string name,ParamIter par_begin,ParamIter par_end)1288 NcbiTestGenTestCases(void (*test_func)(ParamType),
1289 boost::unit_test::const_string name,
1290 ParamIter par_begin,
1291 ParamIter par_end )
1292 {
1293 typedef typename boost::remove_const<
1294 typename boost::remove_reference<ParamType>::type
1295 >::type param_value_type;
1296 return CNcbiTestParamTestCaseGenerator<param_value_type, ParamIter>(
1297 test_func, name, par_begin, par_end);
1298 }
1299
1300
1301 /////////////////////////////////////////////////////////////////////////////
1302 ///
1303 /// CNcbiTestMemoryCleanupList -- Define a list of pointers to free at exit.
1304 ///
1305 /// Not really necessary for tests, but used to avoid memory leaks and
1306 /// corresponding reports by memory checkers like Valgrind.
1307
1308 class CNcbiTestMemoryCleanupList
1309 {
1310 public:
1311 static CNcbiTestMemoryCleanupList* GetInstance();
1312 ~CNcbiTestMemoryCleanupList();
1313 void Add(void* ptr);
1314 private:
1315 std::list<void*> m_List;
1316 };
1317
1318
1319 END_NCBI_SCOPE
1320
1321
1322 /* @} */
1323
1324 #endif /* CORELIB___TEST_BOOST__HPP */
1325