|
NCBI C++ ToolKit
|
00001 /* $Id: test_boost.cpp 53244 2012-03-05 14:23:25Z ivanovp $ 00002 * =========================================================================== 00003 * 00004 * PUBLIC DOMAIN NOTICE 00005 * National Center for Biotechnology Information 00006 * 00007 * This software/database is a "United States Government Work" under the 00008 * terms of the United States Copyright Act. It was written as part of 00009 * the author's official duties as a United States Government employee and 00010 * thus cannot be copyrighted. This software/database is freely available 00011 * to the public for use. The National Library of Medicine and the U.S. 00012 * Government have not placed any restriction on its use or reproduction. 00013 * 00014 * Although all reasonable efforts have been taken to ensure the accuracy 00015 * and reliability of the software and data, the NLM and the U.S. 00016 * Government do not and cannot warrant the performance or results that 00017 * may be obtained by using this software or data. The NLM and the U.S. 00018 * Government disclaim all warranties, express or implied, including 00019 * warranties of performance, merchantability or fitness for any particular 00020 * purpose. 00021 * 00022 * Please cite the author in any work or product based on this material. 00023 * 00024 * =========================================================================== 00025 * 00026 * Author: Pavel Ivanov 00027 * 00028 * File Description: 00029 * Implementation of special reporter for Boost.Test framework and utility 00030 * functions for embedding it into the Boost. 00031 * 00032 */ 00033 00034 #include <ncbi_pch.hpp> 00035 #include <corelib/ncbicfg.h> 00036 #include <corelib/error_codes.hpp> 00037 #include <corelib/ncbienv.hpp> 00038 #include <corelib/ncbimisc.hpp> 00039 #include <corelib/ncbiapp.hpp> 00040 #include <corelib/ncbi_system.hpp> 00041 00042 #ifndef BOOST_TEST_NO_LIB 00043 # define BOOST_TEST_NO_LIB 00044 #endif 00045 #define BOOST_TEST_NO_MAIN 00046 #include <corelib/test_boost.hpp> 00047 00048 #include <boost/preprocessor/cat.hpp> 00049 #include <boost/preprocessor/tuple/elem.hpp> 00050 #include <boost/preprocessor/tuple/eat.hpp> 00051 00052 // On Mac OS X, some corelib headers end up pulling in system headers 00053 // that #define nil as a macro that ultimately expands to __null, 00054 // breaking Boost's internal use of a struct nil. 00055 #ifdef nil 00056 # undef nil 00057 #endif 00058 #ifdef NCBI_COMPILER_MSVC 00059 # pragma warning(push) 00060 // 'class' : class has virtual functions, but destructor is not virtual 00061 # pragma warning(disable: 4265) 00062 // 'operator/operation' : unsafe conversion from 'type of expression' to 'type required' 00063 # pragma warning(disable: 4191) 00064 #endif 00065 00066 #include <boost/test/included/unit_test.hpp> 00067 #include <boost/test/results_collector.hpp> 00068 #include <boost/test/results_reporter.hpp> 00069 #include <boost/test/test_observer.hpp> 00070 #include <boost/test/unit_test_log.hpp> 00071 #include <boost/test/unit_test_log_formatter.hpp> 00072 #include <boost/test/output/plain_report_formatter.hpp> 00073 #include <boost/test/output/xml_report_formatter.hpp> 00074 #include <boost/test/output/compiler_log_formatter.hpp> 00075 #include <boost/test/output/xml_log_formatter.hpp> 00076 #include <boost/test/utils/xml_printer.hpp> 00077 #include <boost/test/detail/global_typedef.hpp> 00078 #include <boost/test/detail/unit_test_parameters.hpp> 00079 #include <boost/test/debug.hpp> 00080 00081 #ifdef NCBI_COMPILER_MSVC 00082 # pragma warning(pop) 00083 #endif 00084 00085 #include <list> 00086 #include <vector> 00087 #include <set> 00088 #include <map> 00089 #include <string> 00090 00091 00092 #define NCBI_USE_ERRCODE_X Corelib_TestBoost 00093 00094 00095 namespace but = boost::unit_test; 00096 00097 00098 BEGIN_NCBI_SCOPE 00099 00100 const char* kTestsDisableSectionName = "UNITTESTS_DISABLE"; 00101 const char* kTestsToFixSectionName = "UNITTESTS_TOFIX"; 00102 const char* kTestsTimeoutSectionName = "UNITTESTS_TIMEOUT_MULT"; 00103 const char* kTestConfigGlobalValue = "GLOBAL"; 00104 00105 #define DUMMY_TEST_FUNCTION_NAME DummyTestFunction 00106 const char* kDummyTestCaseName = BOOST_STRINGIZE(DUMMY_TEST_FUNCTION_NAME); 00107 00108 const char* kTestResultPassed = "passed"; 00109 const char* kTestResultFailed = "failed"; 00110 const char* kTestResultTimeout = "timeout"; 00111 const char* kTestResultAborted = "aborted"; 00112 const char* kTestResultSkipped = "skipped"; 00113 const char* kTestResultDisabled = "disabled"; 00114 const char* kTestResultToFix = "tofix"; 00115 00116 00117 typedef but::results_reporter::format TBoostRepFormatter; 00118 typedef but::unit_test_log_formatter TBoostLogFormatter; 00119 typedef set<but::test_unit*> TUnitsSet; 00120 typedef map<but::test_unit*, TUnitsSet> TUnitToManyMap; 00121 typedef map<string, but::test_unit*> TStringToUnitMap; 00122 00123 00124 /// Reporter for embedding in Boost framework and adding non-standard 00125 /// information to detailed report given by Boost. 00126 class CNcbiBoostReporter : public TBoostRepFormatter 00127 { 00128 public: 00129 CNcbiBoostReporter(void); 00130 virtual ~CNcbiBoostReporter(void) {} 00131 00132 /// Setup reporter tuned for printing report of specific format 00133 /// 00134 /// @param format 00135 /// Format of the report 00136 void SetOutputFormat(but::output_format format); 00137 00138 // TBoostRepFormatter interface 00139 virtual 00140 void results_report_start (ostream& ostr); 00141 virtual 00142 void results_report_finish (ostream& ostr); 00143 virtual 00144 void test_unit_report_start (but::test_unit const& tu, ostream& ostr); 00145 virtual 00146 void test_unit_report_finish(but::test_unit const& tu, ostream& ostr); 00147 virtual 00148 void do_confirmation_report (but::test_unit const& tu, ostream& ostr); 00149 00150 private: 00151 /// Standard reporter from Boost for particular report format 00152 AutoPtr<TBoostRepFormatter> m_Upper; 00153 /// If report is XML or not 00154 bool m_IsXML; 00155 /// Current indentation level in plain text report 00156 int m_Indent; 00157 }; 00158 00159 00160 /// Logger for embedding in Boost framework and adding non-standard 00161 /// information to logging given by Boost. 00162 class CNcbiBoostLogger : public TBoostLogFormatter 00163 { 00164 public: 00165 CNcbiBoostLogger(void); 00166 virtual ~CNcbiBoostLogger(void) {} 00167 00168 /// Setup logger tuned for printing log of specific format 00169 /// 00170 /// @param format 00171 /// Format of the report 00172 void SetOutputFormat(but::output_format format); 00173 00174 // TBoostLogFormatter interface 00175 virtual 00176 void log_start (ostream& ostr, but::counter_t test_cases_amount); 00177 virtual 00178 void log_finish (ostream& ostr); 00179 virtual 00180 void log_build_info (ostream& ostr); 00181 virtual 00182 void test_unit_start (ostream& ostr, but::test_unit const& tu); 00183 virtual 00184 void test_unit_finish (ostream& ostr, but::test_unit const& tu, 00185 unsigned long elapsed); 00186 virtual 00187 void test_unit_skipped(ostream& ostr, but::test_unit const& tu); 00188 #if BOOST_VERSION >= 104200 00189 virtual 00190 void log_exception (ostream& ostr, but::log_checkpoint_data const& lcd, 00191 boost::execution_exception const& ex); 00192 // Next line is necessary for compiling with ICC and Boost 1.41.0 and up 00193 using TBoostLogFormatter::log_exception; 00194 #else 00195 virtual 00196 void log_exception (ostream& ostr, but::log_checkpoint_data const& lcd, 00197 but::const_string explanation); 00198 #endif 00199 virtual 00200 void log_entry_start (ostream& ostr, but::log_entry_data const& led, 00201 log_entry_types let); 00202 virtual 00203 void log_entry_value (ostream& ostr, but::const_string value); 00204 // Next line is necessary for compiling with ICC and Boost 1.41.0 and up 00205 using TBoostLogFormatter::log_entry_value; 00206 virtual 00207 void log_entry_finish (ostream& ostr); 00208 00209 private: 00210 /// Standard logger from Boost for particular report format 00211 AutoPtr<TBoostLogFormatter> m_Upper; 00212 /// If report is XML or not 00213 bool m_IsXML; 00214 }; 00215 00216 00217 /// Special observer to embed in Boost.Test framework to initialize test 00218 /// dependencies before they started execution. 00219 class CNcbiTestsObserver : public but::test_observer 00220 { 00221 public: 00222 virtual ~CNcbiTestsObserver(void) {} 00223 00224 /// Method called before execution of all tests 00225 virtual void test_start(but::counter_t /* test_cases_amount */); 00226 00227 /// Method called after execution of all tests 00228 virtual void test_finish(void); 00229 00230 /// Method called before execution of each unit 00231 virtual void test_unit_start(but::test_unit const& tu); 00232 00233 /// Method called after execution of each unit 00234 virtual void test_unit_finish(but::test_unit const& tu, 00235 unsigned long elapsed); 00236 00237 /// Method called when some exception was caught during execution of unit 00238 virtual void exception_caught(boost::execution_exception const& ex); 00239 00240 virtual void test_unit_aborted(but::test_unit const& tu); 00241 virtual void assertion_result(bool passed); 00242 }; 00243 00244 00245 /// Class that can walk through all tree of tests and register them inside 00246 /// CNcbiTestApplication. 00247 class CNcbiTestsCollector : public but::test_tree_visitor 00248 { 00249 public: 00250 virtual ~CNcbiTestsCollector(void) {} 00251 00252 virtual void visit (but::test_case const& test ); 00253 virtual bool test_suite_start(but::test_suite const& suite); 00254 }; 00255 00256 00257 /// Element of tests tree. Used to make proper order between units to ensure 00258 /// that dependencies are executed earlier than dependents. 00259 class CNcbiTestTreeElement 00260 { 00261 public: 00262 /// Element represents one test unit 00263 CNcbiTestTreeElement(but::test_unit* tu); 00264 /// In destructor class destroys all its children 00265 ~CNcbiTestTreeElement(void); 00266 00267 /// Get unit represented by the element 00268 but::test_unit* GetTestUnit(void); 00269 00270 /// Add child element. Class acquires ownership on the child element and 00271 /// destroys it at the end of work. 00272 void AddChild(CNcbiTestTreeElement* element); 00273 00274 /// Get parent element in tests tree. If this element represents master 00275 /// test suite then return NULL. 00276 CNcbiTestTreeElement* GetParent(void); 00277 00278 /// Ensure good dependency of this element on "from" element. If 00279 /// dependency is not fulfilled well then ensure that "from" element will 00280 /// stand earlier in tests tree. Correct order is made in internal 00281 /// structures only. To make it in Boost tests tree you need to call 00282 /// FixUnitsOrder(). 00283 /// 00284 /// @sa FixUnitsOrder() 00285 void EnsureDep(CNcbiTestTreeElement* from); 00286 00287 /// Fix order of unit tests in the subtree rooted in this element. Any 00288 /// action is taken only if during calls to EnsureDep() some wrong order 00289 /// was found. 00290 /// 00291 /// @sa EnsureDep() 00292 void FixUnitsOrder(void); 00293 00294 private: 00295 /// Prohibit 00296 CNcbiTestTreeElement(const CNcbiTestTreeElement&); 00297 CNcbiTestTreeElement& operator= (const CNcbiTestTreeElement&); 00298 00299 typedef vector<CNcbiTestTreeElement*> TElemsList; 00300 typedef set <CNcbiTestTreeElement*> TElemsSet; 00301 00302 /// Ensure that leftElem and rightElem (or element pointed by it_right 00303 /// inside m_Children) are in that very order: leftElem first, rightElem 00304 /// after that. leftElem and rightElem should be children of this element. 00305 void x_EnsureChildOrder(CNcbiTestTreeElement* leftElem, 00306 CNcbiTestTreeElement* rightElem); 00307 void x_EnsureChildOrder(CNcbiTestTreeElement* leftElem, 00308 size_t idx_right); 00309 00310 /// Add leftElem (rightElem) in the list of elements that should be 00311 /// "lefter" ("righter") in the tests tree. 00312 void x_AddToMustLeft(CNcbiTestTreeElement* elem, 00313 CNcbiTestTreeElement* leftElem); 00314 void x_AddToMustRight(CNcbiTestTreeElement* elem, 00315 CNcbiTestTreeElement* rightElem); 00316 00317 00318 /// Parent element in tests tree 00319 CNcbiTestTreeElement* m_Parent; 00320 /// Unit represented by the element 00321 but::test_unit* m_TestUnit; 00322 /// If order of children was changed during checking dependencies 00323 bool m_OrderChanged; 00324 /// Children of the element in tests tree 00325 TElemsList m_Children; 00326 /// Elements that should be "on the left" from this element in tests tree 00327 /// (should have less index in the parent's list of children). 00328 TElemsSet m_MustLeft; 00329 /// Elements that should be "on the right" from this element in tests tree 00330 /// (should have greater index in the parent's list of children). 00331 TElemsSet m_MustRight; 00332 }; 00333 00334 00335 /// Class for traversing all Boost tests tree and building tree structure in 00336 /// our own accessible manner. 00337 class CNcbiTestsTreeBuilder : public but::test_tree_visitor 00338 { 00339 public: 00340 CNcbiTestsTreeBuilder(void); 00341 virtual ~CNcbiTestsTreeBuilder(void); 00342 00343 virtual void visit (but::test_case const& test ); 00344 virtual bool test_suite_start (but::test_suite const& suite); 00345 virtual void test_suite_finish(but::test_suite const& suite); 00346 00347 /// Ensure good dependency of the tu test unit on tu_from test unit. If 00348 /// dependency is not fulfilled well then ensure that tu_from element will 00349 /// stand earlier in tests tree. Correct order is made in internal 00350 /// structures only. To make it in Boost tests tree you need to call 00351 /// FixUnitsOrder(). 00352 /// 00353 /// @sa FixUnitsOrder() 00354 void EnsureDep(but::test_unit* tu, but::test_unit* tu_from); 00355 00356 /// Fix order of unit tests in the whole tree of tests. Any action is 00357 /// taken only if during calls to EnsureDep() some wrong order was found. 00358 /// 00359 /// @sa EnsureDep() 00360 void FixUnitsOrder(void); 00361 00362 private: 00363 typedef map<but::test_unit*, CNcbiTestTreeElement*> TUnitToElemMap; 00364 00365 /// Root element of the tests tree 00366 CNcbiTestTreeElement* m_RootElem; 00367 /// Element in tests tree representing started but not yet finished test 00368 /// suite, i.e. all test cases that will be visited now will for sure be 00369 /// from this test suite. 00370 CNcbiTestTreeElement* m_CurElem; 00371 /// Overall map of relations between test units and their representatives 00372 /// in elements tree. 00373 TUnitToElemMap m_AllUnits; 00374 }; 00375 00376 00377 /// Application for all unit tests 00378 class CNcbiTestApplication : public CNcbiApplication 00379 { 00380 public: 00381 CNcbiTestApplication(void); 00382 00383 virtual void Init (void); 00384 virtual int Run (void); 00385 virtual int DryRun(void); 00386 00387 /// Add user function 00388 void AddUserFunction(TNcbiTestUserFunction func, 00389 ETestUserFuncType func_type); 00390 /// Add dependency for test unit 00391 void AddTestDependsOn(but::test_unit* tu, but::test_unit* dep_tu); 00392 /// Set test as disabled by user 00393 void SetTestDisabled(but::test_unit* tu); 00394 /// Set flag that all tests globally disabled 00395 void SetGloballyDisabled(void); 00396 /// Set flag that all tests globally skipped 00397 void SetGloballySkipped(void); 00398 00399 /// Initialize this application, main test suite and all test framework 00400 but::test_suite* InitTestFramework(int argc, char* argv[]); 00401 /// Get object with argument descriptions. 00402 /// Return NULL if it is not right time to fill in descriptions. 00403 CArgDescriptions* GetArgDescrs(void); 00404 /// Get parser evaluating configuration conditions. 00405 /// Return NULL if it is not right time to deal with the parser. 00406 CExprParser* GetIniParser(void); 00407 00408 /// Save test unit in the collection of all tests. 00409 void CollectTestUnit(but::test_unit* tu); 00410 /// Get pointer to test case or test suite by its name. 00411 but::test_unit* GetTestUnit(CTempString test_name); 00412 /// Initialize already prepared test suite before running tests 00413 void InitTestsBeforeRun(void); 00414 /// Finalize test suite after running tests 00415 void FiniTestsAfterRun(void); 00416 /// Enable all necessary tests after execution but before printing report 00417 void ReEnableAllTests(void); 00418 /// Check the correct setting for unit timeout and check overall 00419 /// test timeout. 00420 void AdjustTestTimeout(but::test_unit* tu); 00421 /// Mark test case as failed due to hit of the timeout 00422 void SetTestTimedOut(but::test_case* tc); 00423 /// Register the fact of test failure 00424 void SetTestErrored(but::test_case* tc); 00425 /// Check if given test is marked as requiring fixing in the future 00426 bool IsTestToFix(const but::test_unit* tu); 00427 00428 /// Get number of actually executed tests 00429 int GetRanTestsCount(void); 00430 /// Get number of tests that were failed but are marked to be fixed 00431 int GetToFixTestsCount(void); 00432 /// Get string representation of result of test execution 00433 string GetTestResultString(but::test_unit* tu); 00434 /// Get pointer to empty test case added to Boost for internal purposes 00435 but::test_case* GetDummyTest(void); 00436 /// Check if user initialization functions failed 00437 bool IsInitFailed(void); 00438 00439 /// Check if there were any test errors 00440 bool HasTestErrors(void); 00441 /// Check if there were any timeouted tests 00442 bool HasTestTimeouts(void); 00443 00444 private: 00445 typedef list<TNcbiTestUserFunction> TUserFuncsList; 00446 00447 00448 /// Setup our own reporter for Boost.Test 00449 void x_SetupBoostReporters(void); 00450 /// Call all user functions. Return TRUE if functions execution is 00451 /// successful and FALSE if come function thrown exception. 00452 bool x_CallUserFuncs(ETestUserFuncType func_type); 00453 /// Ensure that all dependencies stand earlier in tests tree than their 00454 /// dependents. 00455 void x_EnsureAllDeps(void); 00456 /// Set up real Boost.Test dependencies based on ones made by 00457 /// AddTestDependsOn(). 00458 /// 00459 /// @sa AddTestDependsOn() 00460 void x_ActualizeDeps(void); 00461 /// Enable / disable tests based on application configuration file 00462 bool x_ReadConfiguration(void); 00463 /// Get number of tests which Boost will execute 00464 int x_GetEnabledTestsCount(void); 00465 /// Add empty test necesary for internal purposes 00466 void x_AddDummyTest(void); 00467 /// Initialize common for all tests parser variables 00468 /// (OS*, COMPILER* and DLL_BUILD) 00469 void x_InitCommonParserVars(void); 00470 /// Apply standard trimmings to test name and return resultant test name 00471 /// which will identify test inside the framework. 00472 string x_GetTrimmedTestName(const string& test_name); 00473 /// Enable / disable all tests known to application 00474 void x_EnableAllTests(bool enable); 00475 /// Collect names and pointers to all tests existing in master test suite 00476 void x_CollectAllTests(); 00477 /// Calculate the value from configuration file 00478 bool x_CalcConfigValue(const string& value); 00479 00480 00481 /// Mode of running testing application 00482 enum ERunMode { 00483 fTestList = 0x1, ///< Only tests list is requested 00484 fDisabled = 0x2, ///< All tests are disabled in configuration file 00485 fInitFailed = 0x4 ///< Initialization user functions failed 00486 }; 00487 typedef unsigned int TRunMode; 00488 00489 00490 /// If Run() was called or not 00491 /// 00492 /// @sa Run() 00493 bool m_RunCalled; 00494 /// Mode of running the application 00495 TRunMode m_RunMode; 00496 /// Lists of all user-defined functions 00497 TUserFuncsList m_UserFuncs[eTestUserFuncLast 00498 - eTestUserFuncFirst + 1]; 00499 /// Argument descriptions to be passed to SetArgDescriptions(). 00500 /// Value is not null only during NCBITEST_INIT_CMDLINE() function 00501 AutoPtr<CArgDescriptions> m_ArgDescrs; 00502 /// Parser to evaluate expressions in configuration file. 00503 /// Value is not null only during NCBITEST_INIT_VARIABLES() function 00504 AutoPtr<CExprParser> m_IniParser; 00505 /// List of all test units mapped to their names. 00506 TStringToUnitMap m_AllTests; 00507 /// List of all disabled tests 00508 TUnitsSet m_DisabledTests; 00509 /// List of all tests which result is a timeout 00510 TUnitsSet m_TimedOutTests; 00511 /// List of all tests marked as in need of fixing in the future 00512 TUnitsSet m_ToFixTests; 00513 /// List of all dependencies for each test having dependencies 00514 TUnitToManyMap m_TestDeps; 00515 /// Observer to make test dependencies and look for unit's timeouts 00516 CNcbiTestsObserver m_Observer; 00517 /// Boost reporter - must be pointer because Boost.Test calls free() on it 00518 CNcbiBoostReporter* m_Reporter; 00519 /// Boost logger - must be pointer because Boost.Test calls free() on it 00520 CNcbiBoostLogger* m_Logger; 00521 /// Output stream for Boost.Test report 00522 ofstream m_ReportOut; 00523 /// Builder of internal accessible from library tests tree 00524 CNcbiTestsTreeBuilder m_TreeBuilder; 00525 /// Empty test case added to Boost for internal perposes 00526 but::test_case* m_DummyTest; 00527 /// Timeout for the whole test 00528 double m_Timeout; 00529 /// String representation for whole test timeout (real value taken from 00530 /// CHECK_TIMEOUT in Makefile). 00531 string m_TimeoutStr; 00532 /// Multiplicator for timeouts 00533 double m_TimeMult; 00534 /// Timer measuring elapsed time for the whole test 00535 CStopWatch m_Timer; 00536 /// Timeout that was set in currently executing unit before adjustment 00537 /// 00538 /// @sa AdjustTestTimeout() 00539 unsigned int m_CurUnitTimeout; 00540 /// Flag showing if there were some test errors 00541 bool m_HasTestErrors; 00542 /// Flag showing if there were some timeouted tests 00543 bool m_HasTestTimeouts; 00544 }; 00545 00546 00547 inline 00548 CNcbiBoostReporter::CNcbiBoostReporter() 00549 : m_IsXML(false) 00550 {} 00551 00552 inline void 00553 CNcbiBoostReporter::SetOutputFormat(but::output_format format) 00554 { 00555 if (format == but::XML) { 00556 m_IsXML = true; 00557 m_Upper = new but::output::xml_report_formatter(); 00558 } 00559 else { 00560 m_IsXML = false; 00561 m_Upper = new but::output::plain_report_formatter(); 00562 } 00563 } 00564 00565 00566 inline 00567 CNcbiBoostLogger::CNcbiBoostLogger(void) 00568 : m_IsXML(false) 00569 {} 00570 00571 inline void 00572 CNcbiBoostLogger::SetOutputFormat(but::output_format format) 00573 { 00574 if (format == but::XML) { 00575 m_IsXML = true; 00576 m_Upper = new but::output::xml_log_formatter(); 00577 } 00578 else { 00579 m_IsXML = false; 00580 m_Upper = new but::output::compiler_log_formatter(); 00581 } 00582 } 00583 00584 00585 inline 00586 CNcbiTestTreeElement::CNcbiTestTreeElement(but::test_unit* tu) 00587 : m_Parent (NULL), 00588 m_TestUnit (tu), 00589 m_OrderChanged(false) 00590 {} 00591 00592 CNcbiTestTreeElement::~CNcbiTestTreeElement(void) 00593 { 00594 ITERATE(TElemsList, it, m_Children) { 00595 delete *it; 00596 } 00597 } 00598 00599 inline void 00600 CNcbiTestTreeElement::AddChild(CNcbiTestTreeElement* element) 00601 { 00602 m_Children.push_back(element); 00603 element->m_Parent = this; 00604 } 00605 00606 void 00607 CNcbiTestTreeElement::x_EnsureChildOrder(CNcbiTestTreeElement* leftElem, 00608 size_t idx_right) 00609 { 00610 size_t idx_left = 0; 00611 for (; idx_left < m_Children.size(); ++ idx_left) { 00612 if (m_Children[idx_left] == leftElem) 00613 break; 00614 } 00615 _ASSERT(idx_left < m_Children.size()); 00616 00617 if (idx_left < idx_right) 00618 return; 00619 00620 m_OrderChanged = true; 00621 m_Children.erase(m_Children.begin() + idx_left); 00622 m_Children.insert(m_Children.begin() + idx_right, leftElem); 00623 00624 ITERATE(TElemsSet, it, leftElem->m_MustLeft) { 00625 x_EnsureChildOrder(*it, idx_right); 00626 // If order is changed in the above call then leftElem will move to 00627 // the right and we need to change our index. 00628 while (m_Children[idx_right] != leftElem) 00629 ++idx_right; 00630 } 00631 } 00632 00633 void 00634 CNcbiTestTreeElement::x_AddToMustLeft(CNcbiTestTreeElement* elem, 00635 CNcbiTestTreeElement* leftElem) 00636 { 00637 if (elem == leftElem) { 00638 NCBI_THROW(CCoreException, eCore, 00639 FORMAT("Circular dependency found: '" 00640 << elem->m_TestUnit->p_name.get() 00641 << "' must depend on itself.")); 00642 } 00643 00644 elem->m_MustLeft.insert(leftElem); 00645 00646 ITERATE(TElemsSet, it, elem->m_MustRight) { 00647 x_AddToMustLeft(*it, leftElem); 00648 } 00649 } 00650 00651 void 00652 CNcbiTestTreeElement::x_AddToMustRight(CNcbiTestTreeElement* elem, 00653 CNcbiTestTreeElement* rightElem) 00654 { 00655 if (elem == rightElem) { 00656 NCBI_THROW(CCoreException, eCore, 00657 FORMAT("Circular dependency found: '" 00658 << elem->m_TestUnit->p_name.get() 00659 << "' must depend on itself.")); 00660 } 00661 00662 elem->m_MustRight.insert(rightElem); 00663 00664 ITERATE(TElemsSet, it, elem->m_MustLeft) { 00665 x_AddToMustRight(*it, rightElem); 00666 } 00667 } 00668 00669 inline void 00670 CNcbiTestTreeElement::x_EnsureChildOrder(CNcbiTestTreeElement* leftElem, 00671 CNcbiTestTreeElement* rightElem) 00672 { 00673 x_AddToMustLeft(rightElem, leftElem); 00674 x_AddToMustRight(leftElem, rightElem); 00675 00676 size_t idx_right = 0; 00677 for (; idx_right < m_Children.size(); ++idx_right) { 00678 if (m_Children[idx_right] == rightElem) 00679 break; 00680 } 00681 _ASSERT(idx_right < m_Children.size()); 00682 00683 x_EnsureChildOrder(leftElem, idx_right); 00684 } 00685 00686 void 00687 CNcbiTestTreeElement::EnsureDep(CNcbiTestTreeElement* from) 00688 { 00689 TElemsList parents; 00690 00691 CNcbiTestTreeElement* parElem = this; 00692 if (m_TestUnit->p_type != but::tut_suite) { 00693 parElem = m_Parent; 00694 } 00695 do { 00696 parents.push_back(parElem); 00697 parElem = parElem->m_Parent; 00698 } 00699 while (parElem != NULL); 00700 00701 parElem = from; 00702 CNcbiTestTreeElement* fromElem = from; 00703 do { 00704 TElemsList::iterator it = find(parents.begin(), parents.end(), parElem); 00705 if (it != parents.end()) { 00706 break; 00707 } 00708 fromElem = parElem; 00709 parElem = parElem->m_Parent; 00710 } 00711 while (parElem != NULL); 00712 _ASSERT(parElem); 00713 00714 if (parElem == this) { 00715 NCBI_THROW(CCoreException, eCore, 00716 FORMAT("Error in unit tests setup: dependency of '" 00717 << m_TestUnit->p_name.get() << "' from '" 00718 << from->m_TestUnit->p_name.get() 00719 << "' can never be implemented.")); 00720 } 00721 00722 CNcbiTestTreeElement* toElem = this; 00723 while (toElem->m_Parent != parElem) { 00724 toElem = toElem->m_Parent; 00725 } 00726 00727 parElem->x_EnsureChildOrder(fromElem, toElem); 00728 } 00729 00730 void 00731 CNcbiTestTreeElement::FixUnitsOrder(void) 00732 { 00733 if (m_OrderChanged) { 00734 but::test_suite* suite = static_cast<but::test_suite*>(m_TestUnit); 00735 ITERATE(TElemsList, it, m_Children) { 00736 suite->remove((*it)->m_TestUnit->p_id); 00737 } 00738 ITERATE(TElemsList, it, m_Children) { 00739 suite->add((*it)->m_TestUnit); 00740 } 00741 } 00742 00743 ITERATE(TElemsList, it, m_Children) { 00744 (*it)->FixUnitsOrder(); 00745 } 00746 } 00747 00748 inline but::test_unit* 00749 CNcbiTestTreeElement::GetTestUnit(void) 00750 { 00751 return m_TestUnit; 00752 } 00753 00754 inline CNcbiTestTreeElement* 00755 CNcbiTestTreeElement::GetParent(void) 00756 { 00757 return m_Parent; 00758 } 00759 00760 00761 CNcbiTestsTreeBuilder::CNcbiTestsTreeBuilder(void) 00762 : m_RootElem(NULL), 00763 m_CurElem (NULL) 00764 {} 00765 00766 CNcbiTestsTreeBuilder::~CNcbiTestsTreeBuilder(void) 00767 { 00768 delete m_RootElem; 00769 } 00770 00771 bool 00772 CNcbiTestsTreeBuilder::test_suite_start(but::test_suite const& suite) 00773 { 00774 but::test_suite* nc_suite = const_cast<but::test_suite*>(&suite); 00775 if (m_RootElem) { 00776 CNcbiTestTreeElement* next_elem = new CNcbiTestTreeElement(nc_suite); 00777 m_CurElem->AddChild(next_elem); 00778 m_CurElem = next_elem; 00779 } 00780 else { 00781 m_RootElem = new CNcbiTestTreeElement(nc_suite); 00782 m_CurElem = m_RootElem; 00783 } 00784 00785 m_AllUnits[nc_suite] = m_CurElem; 00786 00787 return true; 00788 } 00789 00790 void 00791 CNcbiTestsTreeBuilder::test_suite_finish(but::test_suite const& suite) 00792 { 00793 _ASSERT(m_CurElem->GetTestUnit() 00794 == &static_cast<const but::test_unit&>(suite)); 00795 m_CurElem = m_CurElem->GetParent(); 00796 } 00797 00798 void 00799 CNcbiTestsTreeBuilder::visit(but::test_case const& test) 00800 { 00801 but::test_case* nc_test = const_cast<but::test_case*>(&test); 00802 CNcbiTestTreeElement* elem = new CNcbiTestTreeElement(nc_test); 00803 m_CurElem->AddChild(elem); 00804 m_AllUnits[nc_test] = elem; 00805 } 00806 00807 inline void 00808 CNcbiTestsTreeBuilder::EnsureDep(but::test_unit* tu, but::test_unit* tu_from) 00809 { 00810 CNcbiTestTreeElement* elem = m_AllUnits[tu]; 00811 CNcbiTestTreeElement* elem_from = m_AllUnits[tu_from]; 00812 _ASSERT(elem && elem_from); 00813 00814 elem->EnsureDep(elem_from); 00815 } 00816 00817 inline void 00818 CNcbiTestsTreeBuilder::FixUnitsOrder(void) 00819 { 00820 m_RootElem->FixUnitsOrder(); 00821 } 00822 00823 00824 inline 00825 CNcbiTestApplication::CNcbiTestApplication(void) 00826 : m_RunCalled(false), 00827 m_RunMode (0), 00828 m_DummyTest(NULL), 00829 m_Timeout (0), 00830 m_TimeMult (1), 00831 m_Timer (CStopWatch::eStart), 00832 m_HasTestErrors(false), 00833 m_HasTestTimeouts(false) 00834 { 00835 m_Reporter = new CNcbiBoostReporter(); 00836 m_Logger = new CNcbiBoostLogger(); 00837 00838 // Do not show warning about inaccessible configuration file 00839 SetDiagFilter(eDiagFilter_Post, "!(106.11)"); 00840 } 00841 00842 /// Application for unit tests 00843 static CNcbiTestApplication& 00844 s_GetTestApp(void) 00845 { 00846 static CNcbiTestApplication s_TestApp; 00847 00848 return s_TestApp; 00849 } 00850 00851 void 00852 CNcbiTestApplication::Init(void) 00853 { 00854 m_ArgDescrs = new CArgDescriptions(); 00855 m_ArgDescrs->AddFlag("-help", 00856 "Print test framework related command line arguments"); 00857 #ifndef NCBI_COMPILER_WORKSHOP 00858 m_ArgDescrs->AddOptionalKey("-run_test", "Filter", 00859 "Allows to filter which test units to run", 00860 CArgDescriptions::eString, CArgDescriptions::fMandatorySeparator); 00861 #endif 00862 m_ArgDescrs->AddFlag("dryrun", 00863 "Do not actually run tests, " 00864 "just print list of all available tests."); 00865 m_ArgDescrs->SetUsageContext(GetArguments().GetProgramBasename(), 00866 "NCBI unit test"); 00867 if (!m_UserFuncs[eTestUserFuncCmdLine].empty()) 00868 x_CallUserFuncs(eTestUserFuncCmdLine); 00869 SetupArgDescriptions(m_ArgDescrs.release()); 00870 } 00871 00872 int 00873 CNcbiTestApplication::Run(void) 00874 { 00875 m_RunCalled = true; 00876 return 0; 00877 } 00878 00879 int 00880 CNcbiTestApplication::DryRun(void) 00881 { 00882 m_RunCalled = true; 00883 m_RunMode |= fTestList; 00884 but::results_reporter::set_level(but::DETAILED_REPORT); 00885 return 0; 00886 } 00887 00888 inline void 00889 CNcbiTestApplication::AddUserFunction(TNcbiTestUserFunction func, 00890 ETestUserFuncType func_type) 00891 { 00892 m_UserFuncs[func_type].push_back(func); 00893 } 00894 00895 inline void 00896 CNcbiTestApplication::AddTestDependsOn(but::test_unit* tu, 00897 but::test_unit* dep_tu) 00898 { 00899 m_TestDeps[tu].insert(dep_tu); 00900 } 00901 00902 inline void 00903 CNcbiTestApplication::SetTestDisabled(but::test_unit* tu) 00904 { 00905 if (but::runtime_config::test_to_run().empty()) { 00906 tu->p_enabled.set(false); 00907 m_DisabledTests.insert(tu); 00908 } 00909 } 00910 00911 inline CArgDescriptions* 00912 CNcbiTestApplication::GetArgDescrs(void) 00913 { 00914 return m_ArgDescrs.get(); 00915 } 00916 00917 inline CExprParser* 00918 CNcbiTestApplication::GetIniParser(void) 00919 { 00920 return m_IniParser.get(); 00921 } 00922 00923 inline but::test_case* 00924 CNcbiTestApplication::GetDummyTest(void) 00925 { 00926 return m_DummyTest; 00927 } 00928 00929 inline bool 00930 CNcbiTestApplication::IsInitFailed(void) 00931 { 00932 return (m_RunMode & fInitFailed) != 0; 00933 } 00934 00935 string 00936 CNcbiTestApplication::x_GetTrimmedTestName(const string& test_name) 00937 { 00938 string new_name = test_name; 00939 SIZE_TYPE pos = NStr::FindCase(new_name, "::", 0, new_name.size(), 00940 NStr::eLast); 00941 if (pos != NPOS) { 00942 new_name = new_name.substr(pos + 2); 00943 } 00944 00945 if(NStr::StartsWith(new_name, "test_", NStr::eNocase)) { 00946 new_name = new_name.substr(5); 00947 } 00948 else if(NStr::StartsWith(new_name, "test", NStr::eNocase)) { 00949 new_name = new_name.substr(4); 00950 } 00951 00952 return new_name; 00953 } 00954 00955 inline void 00956 CNcbiTestApplication::CollectTestUnit(but::test_unit* tu) 00957 { 00958 const string unit_name = x_GetTrimmedTestName(tu->p_name.get()); 00959 if (unit_name == kDummyTestCaseName) 00960 return; 00961 string test_name(unit_name); 00962 int index = 0; 00963 for (;;) { 00964 but::test_unit*& tu_val = m_AllTests[test_name]; 00965 if (!tu_val) { 00966 tu_val = tu; 00967 if (test_name != unit_name) { 00968 LOG_POST_X(3, Info << "Duplicate name found: '" << unit_name 00969 << "' - renamed to '" << test_name << "'"); 00970 tu->p_name.set(test_name); 00971 } 00972 break; 00973 } 00974 test_name = unit_name; 00975 test_name += "_"; 00976 test_name += NStr::IntToString(++index); 00977 } 00978 } 00979 00980 inline void 00981 CNcbiTestApplication::x_EnsureAllDeps(void) 00982 { 00983 ITERATE(TUnitToManyMap, it, m_TestDeps) { 00984 but::test_unit* test = it->first; 00985 ITERATE(TUnitsSet, dep_it, it->second) { 00986 but::test_unit* dep_test = *dep_it; 00987 m_TreeBuilder.EnsureDep(test, dep_test); 00988 } 00989 } 00990 00991 m_TreeBuilder.FixUnitsOrder(); 00992 } 00993 00994 inline void 00995 CNcbiTestApplication::x_ActualizeDeps(void) 00996 { 00997 ITERATE(TUnitToManyMap, it, m_TestDeps) { 00998 but::test_unit* test = it->first; 00999 if (!m_DisabledTests.count(test) && !test->p_enabled) { 01000 continue; 01001 } 01002 01003 ITERATE(TUnitsSet, dep_it, it->second) { 01004 but::test_unit* dep_test = *dep_it; 01005 if (!m_DisabledTests.count(dep_test) && !dep_test->p_enabled) { 01006 continue; 01007 } 01008 01009 test->depends_on(dep_test); 01010 } 01011 } 01012 } 01013 01014 /// Helper macro to check if NCBI preprocessor flag was defined empty or 01015 /// equal to 1. 01016 /// Macro expands to true if flag was defined empty or equal to 1 and to false 01017 /// if it was defined to something else or wasn't defined at all. 01018 #define IS_FLAG_DEFINED(flag) \ 01019 BOOST_PP_TUPLE_ELEM(2, 1, IS_FLAG_DEFINED_I(BOOST_PP_CAT(NCBI_, flag))) 01020 #define IS_VAR_DEFINED(var) \ 01021 BOOST_PP_TUPLE_ELEM(2, 1, IS_FLAG_DEFINED_I(var)) 01022 #define IS_FLAG_DEFINED_I(flag) \ 01023 (BOOST_PP_CAT(IS_FLAG_DEFINED_II_, flag) (), false) 01024 #define IS_FLAG_DEFINED_II_() \ 01025 BOOST_PP_NIL, true) BOOST_PP_TUPLE_EAT(2) (BOOST_PP_NIL 01026 #define IS_FLAG_DEFINED_II_1() \ 01027 BOOST_PP_NIL, true) BOOST_PP_TUPLE_EAT(2) (BOOST_PP_NIL 01028 01029 /// List of features that will be converted to unittest variables 01030 /// (checking testsuite environment variable $FEATURES). 01031 /// If you would like to add some new veriables here, please 01032 /// see Unix configure utility and Project Tree Builder for full 01033 /// list of supported values. 01034 /// @note 01035 /// All non alphanumeric charecters in the names replaced with "_" symbol. 01036 static const char* s_NcbiFeatures[] = { 01037 // Features 01038 "AIX", 01039 "BSD", 01040 "CompaqCompiler", 01041 "Cygwin", 01042 "CygwinMT", 01043 "DLL", 01044 "DLL_BUILD", 01045 "Darwin", 01046 "GCC", 01047 "ICC", 01048 "IRIX", 01049 "KCC", 01050 "Linux", 01051 "MIPSpro", 01052 "MSVC", 01053 "MSWin", 01054 "MT", 01055 "MacOS", 01056 "Ncbi_JNI", // Ncbi-JNI 01057 "OSF", 01058 "PubSeqOS", 01059 "SRAT_internal", // SRAT-internal 01060 "Solaris", 01061 "VisualAge", 01062 "WinMain", 01063 "WorkShop", 01064 "XCODE", 01065 "in_house_resources", // in-house-resources 01066 "unix", 01067 01068 // Packages 01069 "BZ2", 01070 "BerkeleyDB", 01071 "BerkeleyDB__", // BerkeleyDB++ 01072 "Boost_Regex", // Boost.Regex 01073 "Boost_Spirit", // Boost.Spirit 01074 "Boost_Test", // Boost.Test 01075 "Boost_Test_Included", // Boost.Test.Included 01076 "Boost_Threads", // Boost.Threads 01077 "C_Toolkit", // C-Toolkit 01078 "CPPUNIT", 01079 "C_ncbi", 01080 "DBLib", 01081 "EXPAT", 01082 "FLTK", 01083 "FUSE", 01084 "Fast_CGI", // Fast-CGI 01085 "FreeTDS", 01086 "FreeType", 01087 "GIF", 01088 "GLUT", 01089 "GNUTLS", 01090 "HDF5", 01091 "ICU", 01092 "JPEG", 01093 "LIBXML", 01094 "LIBXSLT", 01095 "LZO", 01096 "LocalBZ2", 01097 "LocalMSGMAIL2", 01098 "LocalNCBILS", 01099 "LocalPCRE", 01100 "LocalSSS", 01101 "LocalZ", 01102 "MAGIC", 01103 "MESA", 01104 "MUPARSER", 01105 "MySQL", 01106 "NCBILS2", 01107 "ODBC", 01108 "OECHEM", 01109 "OPENSSL", 01110 "ORBacus", 01111 "OpenGL", 01112 "PCRE", 01113 "PNG", 01114 "PYTHON", 01115 "PYTHON23", 01116 "PYTHON24", 01117 "PYTHON25", 01118 "SABLOT", 01119 "SGE", 01120 "SP", 01121 "SQLITE", 01122 "SQLITE3", 01123 "SQLITE3ASYNC", 01124 "SSSDB", 01125 "SSSUTILS", 01126 "Sybase", 01127 "SybaseCTLIB", 01128 "SybaseDBLIB", 01129 "TIFF", 01130 "UNGIF", 01131 "UUID", 01132 "XPM", 01133 "Xalan", 01134 "Xerces", 01135 "Z", 01136 "wx2_8", // wx2.8 01137 "wxWidgets", 01138 "wxWindows", 01139 01140 // Projects 01141 "algo", 01142 "app", 01143 "bdb", 01144 "cgi", 01145 "connext", 01146 "ctools", 01147 "dbapi", 01148 "gbench", 01149 "gui", 01150 "local_lbsm", 01151 "ncbi_crypt", 01152 "objects", 01153 "serial" 01154 }; 01155 01156 01157 inline void 01158 CNcbiTestApplication::x_InitCommonParserVars(void) 01159 { 01160 m_IniParser->AddSymbol("COMPILER_Compaq", IS_FLAG_DEFINED(COMPILER_COMPAQ)); 01161 m_IniParser->AddSymbol("COMPILER_GCC", IS_FLAG_DEFINED(COMPILER_GCC)); 01162 m_IniParser->AddSymbol("COMPILER_ICC", IS_FLAG_DEFINED(COMPILER_ICC)); 01163 m_IniParser->AddSymbol("COMPILER_KCC", IS_FLAG_DEFINED(COMPILER_KCC)); 01164 m_IniParser->AddSymbol("COMPILER_MipsPro", IS_FLAG_DEFINED(COMPILER_MIPSPRO)); 01165 m_IniParser->AddSymbol("COMPILER_MSVC", IS_FLAG_DEFINED(COMPILER_MSVC)); 01166 m_IniParser->AddSymbol("COMPILER_VisualAge", IS_FLAG_DEFINED(COMPILER_VISUALAGE)); 01167 m_IniParser->AddSymbol("COMPILER_WorkShop", IS_FLAG_DEFINED(COMPILER_WORKSHOP)); 01168 01169 m_IniParser->AddSymbol("OS_AIX", IS_FLAG_DEFINED(OS_AIX)); 01170 m_IniParser->AddSymbol("OS_BSD", IS_FLAG_DEFINED(OS_BSD)); 01171 m_IniParser->AddSymbol("OS_Cygwin", IS_FLAG_DEFINED(OS_CYGWIN)); 01172 m_IniParser->AddSymbol("OS_MacOSX", IS_FLAG_DEFINED(OS_DARWIN)); 01173 m_IniParser->AddSymbol("OS_Irix", IS_FLAG_DEFINED(OS_IRIX)); 01174 m_IniParser->AddSymbol("OS_Linux", IS_FLAG_DEFINED(OS_LINUX)); 01175 m_IniParser->AddSymbol("OS_MacOS", IS_FLAG_DEFINED(OS_MAC)); 01176 m_IniParser->AddSymbol("OS_Windows", IS_FLAG_DEFINED(OS_MSWIN)); 01177 m_IniParser->AddSymbol("OS_Tru64", IS_FLAG_DEFINED(OS_OSF1)); 01178 m_IniParser->AddSymbol("OS_Solaris", IS_FLAG_DEFINED(OS_SOLARIS)); 01179 m_IniParser->AddSymbol("OS_Unix", IS_FLAG_DEFINED(OS_UNIX)); 01180 01181 m_IniParser->AddSymbol("PLATFORM_Bits32", NCBI_PLATFORM_BITS == 32); 01182 m_IniParser->AddSymbol("PLATFORM_Bits64", NCBI_PLATFORM_BITS == 64); 01183 01184 m_IniParser->AddSymbol("PLATFORM_BigEndian", IS_VAR_DEFINED(WORDS_BIGENDIAN)); 01185 m_IniParser->AddSymbol("PLATFORM_LittleEndian", !IS_VAR_DEFINED(WORDS_BIGENDIAN)); 01186 01187 m_IniParser->AddSymbol("BUILD_Dll", IS_FLAG_DEFINED(DLL_BUILD)); 01188 m_IniParser->AddSymbol("BUILD_Static", !IS_FLAG_DEFINED(DLL_BUILD)); 01189 01190 m_IniParser->AddSymbol("BUILD_Debug", IS_VAR_DEFINED(_DEBUG)); 01191 m_IniParser->AddSymbol("BUILD_Release", !IS_VAR_DEFINED(_DEBUG)); 01192 01193 01194 // Add variables based on features available in the build 01195 01196 string features_str = NCBI_GetBuildFeatures(); 01197 if (features_str.empty()) { 01198 return; 01199 } 01200 // Split $FEATURES to tokens 01201 list<string> features_list; 01202 NStr::Split(features_str, " ", features_list); 01203 // Convert list<> to set<> to speed up a search 01204 typedef set<string> TFeatures; 01205 TFeatures features; 01206 // For all features 01207 ITERATE(list<string>, it, features_list) { 01208 // Replace all non alphanumeric characters in the names with "_". 01209 // Ignore negative features (with first "-" characters) 01210 string f = *it; 01211 if (f[0] != '-') { 01212 NON_CONST_ITERATE (string, fit, f) { 01213 if (!isalnum((unsigned char)(*fit))) { 01214 *fit = '_'; 01215 } 01216 } 01217 // Add feature name 01218 features.insert(f); 01219 } 01220 } 01221 // Add FEATURE_* variables 01222 for (size_t i = 0; i < sizeof(s_NcbiFeatures) / sizeof(s_NcbiFeatures[0]); i++) { 01223 string name("FEATURE_"); 01224 name += s_NcbiFeatures[i]; 01225 TFeatures::const_iterator it = features.find(s_NcbiFeatures[i]); 01226 bool found = (it != features.end()); 01227 m_IniParser->AddSymbol(name.c_str(), found); 01228 } 01229 } 01230 01231 inline bool 01232 CNcbiTestApplication::x_CalcConfigValue(const string& value) 01233 { 01234 m_IniParser->Parse(value.c_str()); 01235 const CExprValue& expr_res = m_IniParser->GetResult(); 01236 01237 if (expr_res.GetType() == CExprValue::eBOOL && !expr_res.GetBool()) 01238 return false; 01239 01240 return true; 01241 } 01242 01243 01244 void 01245 DUMMY_TEST_FUNCTION_NAME(void) 01246 { 01247 if (s_GetTestApp().IsInitFailed()) { 01248 but::results_collector.test_unit_aborted( 01249 *s_GetTestApp().GetDummyTest()); 01250 } 01251 } 01252 01253 01254 void 01255 CNcbiTestApplication::SetGloballyDisabled(void) 01256 { 01257 m_RunMode |= fDisabled; 01258 01259 // This should certainly go to the output. So we can use only printf, 01260 // nothing else. 01261 printf("All tests are disabled in current configuration.\n" 01262 " (for autobuild scripts: NCBI_UNITTEST_DISABLED)\n"); 01263 } 01264 01265 void 01266 CNcbiTestApplication::SetGloballySkipped(void) 01267 { 01268 m_RunMode |= fDisabled; 01269 01270 // This should certainly go to the output. So we can use only printf, 01271 // nothing else. 01272 printf("Tests cannot be executed in current configuration " 01273 "and will be skipped.\n" 01274 " (for autobuild scripts: NCBI_UNITTEST_SKIPPED)\n"); 01275 } 01276 01277 inline void 01278 CNcbiTestApplication::x_AddDummyTest(void) 01279 { 01280 if (!m_DummyTest) { 01281 m_DummyTest = BOOST_TEST_CASE(&DUMMY_TEST_FUNCTION_NAME); 01282 but::framework::master_test_suite().add(m_DummyTest); 01283 } 01284 } 01285 01286 inline bool 01287 CNcbiTestApplication::x_ReadConfiguration(void) 01288 { 01289 m_IniParser = new CExprParser(CExprParser::eDenyAutoVar); 01290 x_InitCommonParserVars(); 01291 if (!x_CallUserFuncs(eTestUserFuncVars)) 01292 return false; 01293 01294 const IRegistry& registry = s_GetTestApp().GetConfig(); 01295 list<string> reg_entries; 01296 registry.EnumerateEntries(kTestsDisableSectionName, ®_entries); 01297 01298 // Disable tests ... 01299 ITERATE(list<string>, it, reg_entries) { 01300 const string& test_name = *it; 01301 string reg_value = registry.Get(kTestsDisableSectionName, test_name); 01302 01303 if (test_name == kTestConfigGlobalValue) { 01304 if (x_CalcConfigValue(reg_value)) { 01305 SetGloballyDisabled(); 01306 } 01307 continue; 01308 } 01309 01310 but::test_unit* tu = GetTestUnit(test_name); 01311 if (tu) { 01312 if (x_CalcConfigValue(reg_value)) { 01313 SetTestDisabled(tu); 01314 } 01315 } 01316 else { 01317 ERR_POST_X(2, Warning << "Invalid test case name: '" 01318 << test_name << "'"); 01319 } 01320 } 01321 01322 reg_entries.clear(); 01323 registry.EnumerateEntries(kTestsToFixSectionName, ®_entries); 01324 // Put tests into "to-fix" list 01325 ITERATE(list<string>, it, reg_entries) { 01326 const string& test_name = *it; 01327 string reg_value = registry.Get(kTestsToFixSectionName, test_name); 01328 01329 but::test_unit* tu = GetTestUnit(test_name); 01330 if (tu) { 01331 if (x_CalcConfigValue(reg_value)) { 01332 m_ToFixTests.insert(tu); 01333 } 01334 } 01335 else { 01336 ERR_POST_X(4, Warning << "Invalid test case name: '" 01337 << test_name << "'"); 01338 } 01339 } 01340 01341 reg_entries.clear(); 01342 registry.EnumerateEntries(kTestsTimeoutSectionName, ®_entries); 01343 // Adjust timeouts of test units 01344 ITERATE(list<string>, it, reg_entries) { 01345 const string& test_name = *it; 01346 string reg_value = registry.Get(kTestsTimeoutSectionName, test_name); 01347 01348 but::test_unit* tu = GetTestUnit(test_name); 01349 if (tu) { 01350 list<CTempString> koef_lst; 01351 NStr::Split(reg_value, ";", koef_lst); 01352 ITERATE(list<CTempString>, it_koef, koef_lst) { 01353 CTempString koef_str, koef_cond; 01354 if (NStr::SplitInTwo(*it_koef, ":", koef_str, koef_cond)) { 01355 if (x_CalcConfigValue(koef_cond)) { 01356 double koef = NStr::StringToDouble(koef_str, 01357 NStr::fAllowLeadingSpaces 01358 | NStr::fAllowTrailingSpaces); 01359 tu->p_timeout.set(Uint4(tu->p_timeout.get() * koef)); 01360 break; 01361 } 01362 } 01363 else { 01364 ERR_POST_X(6, "Bad format of TIMEOUT_MULT string: '" 01365 << reg_value << "'"); 01366 break; 01367 } 01368 } 01369 } 01370 else { 01371 ERR_POST_X(5, Warning << "Invalid test case name: '" 01372 << test_name << "'"); 01373 } 01374 } 01375 01376 return true; 01377 } 01378 01379 void 01380 CNcbiTestApplication::x_EnableAllTests(bool enable) 01381 { 01382 ITERATE(TStringToUnitMap, it, m_AllTests) { 01383 but::test_unit* tu = it->second; 01384 if (tu->p_type == but::tut_case) { 01385 tu->p_enabled.set(enable); 01386 01387 /* 01388 For full correctness this functionality should exist but it 01389 can't be made now. So if test suite will be disabled by user 01390 then it will not be possible to get list of tests inside this 01391 suite to be included in the report. 01392 01393 if (enable && tu->p_type == but::tut_suite) { 01394 but::results_collector.results(tu->p_id).p_skipped = false; 01395 } 01396 */ 01397 } 01398 } 01399 } 01400 01401 inline void 01402 CNcbiTestApplication::InitTestsBeforeRun(void) 01403 { 01404 bool need_run = !(m_RunMode & (fTestList + fDisabled)); 01405 if (need_run && !x_CallUserFuncs(eTestUserFuncInit)) { 01406 m_RunMode |= fInitFailed; 01407 need_run = false; 01408 } 01409 // fDisabled property can be changed in initialization functions 01410 if (m_RunMode & fDisabled) 01411 need_run = false; 01412 01413 if (need_run) { 01414 x_EnsureAllDeps(); 01415 x_ActualizeDeps(); 01416 } 01417 else { 01418 x_EnableAllTests(false); 01419 01420 if (m_RunMode & fInitFailed) { 01421 x_AddDummyTest(); 01422 } 01423 } 01424 } 01425 01426 inline void 01427 CNcbiTestApplication::FiniTestsAfterRun(void) 01428 { 01429 x_CallUserFuncs(eTestUserFuncFini); 01430 } 01431 01432 inline void 01433 CNcbiTestApplication::ReEnableAllTests(void) 01434 { 01435 x_EnableAllTests(true); 01436 01437 // Disabled tests can accidentally become not included in full list if 01438 // they were disabled in initialization 01439 ITERATE(TUnitsSet, it, m_DisabledTests) { 01440 (*it)->p_enabled.set(true); 01441 } 01442 } 01443 01444 inline void 01445 CNcbiTestApplication::SetTestTimedOut(but::test_case* tc) 01446 { 01447 // If equal then it's real timeout, if not then it's just this unit hit 01448 // the whole test timeout. 01449 if (tc->p_timeout.get() == m_CurUnitTimeout) { 01450 m_TimedOutTests.insert(tc); 01451 } 01452 m_HasTestTimeouts = true; 01453 } 01454 01455 inline void 01456 CNcbiTestApplication::SetTestErrored(but::test_case* tc) 01457 { 01458 if (m_TimedOutTests.find(tc) == m_TimedOutTests.end()) 01459 m_HasTestErrors = true; 01460 } 01461 01462 void 01463 CNcbiTestApplication::AdjustTestTimeout(but::test_unit* tu) 01464 { 01465 m_CurUnitTimeout = tu->p_timeout.get(); 01466 unsigned int new_timeout = (unsigned int)(m_CurUnitTimeout * m_TimeMult); 01467 01468 if (m_Timeout != 0) { 01469 double elapsed = m_Timer.Elapsed(); 01470 if (m_Timeout <= elapsed) { 01471 CNcbiEnvironment env; 01472 printf("Maximum execution time of %s seconds is exceeded", 01473 m_TimeoutStr.c_str()); 01474 throw but::test_being_aborted(); 01475 } 01476 new_timeout = (unsigned int)(m_Timeout - elapsed); 01477 } 01478 if (m_CurUnitTimeout == 0 || m_CurUnitTimeout > new_timeout) { 01479 tu->p_timeout.set(new_timeout); 01480 } 01481 } 01482 01483 string 01484 CNcbiTestApplication::GetTestResultString(but::test_unit* tu) 01485 { 01486 string result; 01487 const but::test_results& tr = but::results_collector.results(tu->p_id); 01488 01489 if (m_DisabledTests.count(tu) != 0 || (m_RunMode & fDisabled)) 01490 result = kTestResultDisabled; 01491 else if (m_TimedOutTests.count(tu) != 0) 01492 result = kTestResultTimeout; 01493 else if (!tr.passed() && m_ToFixTests.find(tu) != m_ToFixTests.end()) 01494 result = kTestResultToFix; 01495 else if (tr.p_aborted) 01496 result = kTestResultAborted; 01497 else if (tr.p_assertions_failed.get() > tr.p_expected_failures.get() 01498 || tr.p_test_cases_failed.get() 01499 + tr.p_test_cases_aborted.get() > 0) 01500 { 01501 result = kTestResultFailed; 01502 } 01503 else if ((m_RunMode & fTestList) || tr.p_skipped) 01504 result = kTestResultSkipped; 01505 else if( tr.passed() ) 01506 result = kTestResultPassed; 01507 else 01508 result = kTestResultFailed; 01509 01510 return result; 01511 } 01512 01513 int 01514 CNcbiTestApplication::GetRanTestsCount(void) 01515 { 01516 int result = 0; 01517 ITERATE(TStringToUnitMap, it, m_AllTests) { 01518 but::test_unit* tu = it->second; 01519 if (tu->p_type.get() != but::tut_case) 01520 continue; 01521 01522 string str = GetTestResultString(tu); 01523 if (str != kTestResultDisabled && str != kTestResultSkipped) 01524 ++result; 01525 } 01526 return result; 01527 } 01528 01529 int 01530 CNcbiTestApplication::GetToFixTestsCount(void) 01531 { 01532 int result = 0; 01533 ITERATE(TUnitsSet, it, m_ToFixTests) { 01534 if (!but::results_collector.results((*it)->p_id).passed()) 01535 ++result; 01536 } 01537 return result; 01538 } 01539 01540 inline bool 01541 CNcbiTestApplication::IsTestToFix(const but::test_unit* tu) 01542 { 01543 return m_ToFixTests.find(const_cast<but::test_unit*>(tu)) 01544 != m_ToFixTests.end(); 01545 } 01546 01547 inline void 01548 CNcbiTestApplication::x_SetupBoostReporters(void) 01549 { 01550 but::output_format format = but::runtime_config::report_format(); 01551 01552 CNcbiEnvironment env; 01553 string is_autobuild = env.Get("NCBI_AUTOMATED_BUILD"); 01554 if (! is_autobuild.empty()) { 01555 // There shouldn't be any message box in the automated build mode 01556 SuppressSystemMessageBox(fSuppress_All); 01557 01558 format = but::XML; 01559 but::results_reporter::set_level(but::DETAILED_REPORT); 01560 01561 string boost_rep = env.Get("NCBI_BOOST_REPORT_FILE"); 01562 if (! boost_rep.empty()) { 01563 m_ReportOut.open(boost_rep.c_str()); 01564 if (m_ReportOut.good()) { 01565 but::results_reporter::set_stream(m_ReportOut); 01566 } 01567 else { 01568 ERR_POST("Error opening Boost.Test report file '" 01569 << boost_rep << "'"); 01570 } 01571 } 01572 } 01573 01574 m_Reporter->SetOutputFormat(format); 01575 but::results_reporter::set_format(m_Reporter); 01576 01577 m_Logger->SetOutputFormat(but::runtime_config::log_format()); 01578 but::unit_test_log.set_formatter(m_Logger); 01579 } 01580 01581 static const char* 01582 s_GetUserFuncName(ETestUserFuncType func_type) 01583 { 01584 switch (func_type) { 01585 case eTestUserFuncInit: 01586 return "NCBITEST_AUTO_INIT()"; 01587 case eTestUserFuncFini: 01588 return "NCBITEST_AUTO_FINI()"; 01589 case eTestUserFuncCmdLine: 01590 return "NCBITEST_INIT_CMDLINE()"; 01591 case eTestUserFuncVars: 01592 return "NCBITEST_INIT_VARIABLES()"; 01593 case eTestUserFuncDeps: 01594 return "NCBITEST_INIT_TREE()"; 01595 default: 01596 return NULL; 01597 } 01598 } 01599 01600 bool 01601 CNcbiTestApplication::x_CallUserFuncs(ETestUserFuncType func_type) 01602 { 01603 ITERATE(TUserFuncsList, it, m_UserFuncs[func_type]) { 01604 try { 01605 (*it)(); 01606 } 01607 catch (CException& e) { 01608 ERR_POST_X(1, "Exception in " << s_GetUserFuncName(func_type) << ": " << e); 01609 throw; 01610 //return false; 01611 } 01612 catch (exception& e) { 01613 ERR_POST_X(1, "Exception in " << s_GetUserFuncName(func_type) << ": " << e.what()); 01614 throw; 01615 //return false; 01616 } 01617 } 01618 01619 return true; 01620 } 01621 01622 inline but::test_unit* 01623 CNcbiTestApplication::GetTestUnit(CTempString test_name) 01624 { 01625 TStringToUnitMap::iterator it = m_AllTests.find( 01626 x_GetTrimmedTestName(test_name)); 01627 if (it == m_AllTests.end()) { 01628 NCBI_THROW(CCoreException, eInvalidArg, 01629 "Test unit '" + (string)test_name + "' not found."); 01630 } 01631 01632 return it->second; 01633 } 01634 01635 inline void 01636 CNcbiTestApplication::x_CollectAllTests(void) 01637 { 01638 m_AllTests.clear(); 01639 CNcbiTestsCollector collector; 01640 but::traverse_test_tree(but::framework::master_test_suite(), collector); 01641 } 01642 01643 inline int 01644 CNcbiTestApplication::x_GetEnabledTestsCount(void) 01645 { 01646 but::test_case_counter tcc; 01647 but::traverse_test_tree(but::framework::master_test_suite(), tcc); 01648 return tcc.p_count; 01649 } 01650 01651 but::test_suite* 01652 CNcbiTestApplication::InitTestFramework(int argc, char* argv[]) 01653 { 01654 // Do not detect memory leaks using msvcrt - this information is useless 01655 boost::debug::detect_memory_leaks(false); 01656 boost::debug::break_memory_alloc(0); 01657 01658 x_SetupBoostReporters(); 01659 but::framework::register_observer(m_Observer); 01660 01661 // TODO: change this functionality to use only -dryrun parameter 01662 for (int i = 1; i < argc; ++i) { 01663 if (NStr::CompareCase(argv[i], "--do_not_run") == 0) { 01664 m_RunMode |= fTestList; 01665 but::results_reporter::set_level(but::DETAILED_REPORT); 01666 01667 for (int j = i + 1; j < argc; ++j) { 01668 argv[j - 1] = argv[j]; 01669 } 01670 --argc; 01671 } 01672 } 01673 01674 CNcbiEnvironment env; 01675 m_TimeoutStr = env.Get("NCBI_CHECK_TIMEOUT"); 01676 if (!m_TimeoutStr.empty()) { 01677 m_Timeout = NStr::StringToDouble(m_TimeoutStr, NStr::fConvErr_NoThrow); 01678 } 01679 if (m_Timeout == 0) { 01680 m_Timer.Stop(); 01681 } 01682 else { 01683 m_Timeout = min(max(0.0, m_Timeout - 3), 0.9 * m_Timeout); 01684 } 01685 m_TimeMult = NCBI_GetCheckTimeoutMult(); 01686 01687 if (AppMain(argc, argv) == 0 && m_RunCalled) { 01688 x_CollectAllTests(); 01689 01690 but::traverse_test_tree(but::framework::master_test_suite(), 01691 m_TreeBuilder); 01692 01693 // We do not read configuration if particular tests were given in 01694 // command line 01695 if (x_CallUserFuncs(eTestUserFuncDeps) 01696 && (!but::runtime_config::test_to_run().empty() 01697 || x_ReadConfiguration())) 01698 { 01699 // Call should be doubled to support manual adding of 01700 // test cases inside NCBITEST_INIT_TREE(). 01701 x_CollectAllTests(); 01702 if (x_GetEnabledTestsCount() == 0) { 01703 SetGloballyDisabled(); 01704 x_AddDummyTest(); 01705 } 01706 #ifdef NCBI_COMPILER_WORKSHOP 01707 else if (!but::runtime_config::test_to_run().empty()) { 01708 printf("Parameter --run_test is not supported in current configuration\n"); 01709 x_EnableAllTests(false); 01710 x_AddDummyTest(); 01711 } 01712 #endif 01713 01714 return NULL; 01715 } 01716 } 01717 01718 // This path we'll be if something have gone wrong 01719 x_CollectAllTests(); 01720 x_EnableAllTests(false); 01721 01722 return NULL; 01723 } 01724 01725 inline bool 01726 CNcbiTestApplication::HasTestErrors(void) 01727 { 01728 return m_HasTestErrors; 01729 } 01730 01731 inline bool 01732 CNcbiTestApplication::HasTestTimeouts(void) 01733 { 01734 return m_HasTestTimeouts; 01735 } 01736 01737 void 01738 CNcbiTestsCollector::visit(but::test_case const& test) 01739 { 01740 s_GetTestApp().CollectTestUnit(const_cast<but::test_case*>(&test)); 01741 } 01742 01743 bool 01744 CNcbiTestsCollector::test_suite_start(but::test_suite const& suite) 01745 { 01746 s_GetTestApp().CollectTestUnit(const_cast<but::test_suite*>(&suite)); 01747 return true; 01748 } 01749 01750 01751 void 01752 CNcbiTestsObserver::test_start(but::counter_t /* test_cases_amount */) 01753 { 01754 s_GetTestApp().InitTestsBeforeRun(); 01755 } 01756 01757 void 01758 CNcbiTestsObserver::test_finish(void) 01759 { 01760 s_GetTestApp().FiniTestsAfterRun(); 01761 } 01762 01763 void 01764 CNcbiTestsObserver::test_unit_start(but::test_unit const& tu) 01765 { 01766 s_GetTestApp().AdjustTestTimeout(const_cast<but::test_unit*>(&tu)); 01767 } 01768 01769 void 01770 CNcbiTestsObserver::test_unit_finish(but::test_unit const& tu, 01771 unsigned long elapsed) 01772 { 01773 unsigned long timeout = tu.p_timeout.get(); 01774 // elapsed comes in microseconds 01775 if (timeout != 0 && timeout < elapsed / 1000000) { 01776 boost::execution_exception ex( 01777 boost::execution_exception::timeout_error, "Timeout exceeded" 01778 NCBI_BOOST_LOCATION()); 01779 but::framework::exception_caught(ex); 01780 } 01781 01782 but::test_results& tr = but::s_rc_impl().m_results_store[tu.p_id]; 01783 if (!tr.passed() && s_GetTestApp().IsTestToFix(&tu)) { 01784 static_cast<but::readwrite_property<bool>& >( 01785 static_cast<but::class_property<bool>& >( 01786 tr.p_skipped)).set(true); 01787 static_cast<but::readwrite_property<but::counter_t>& >( 01788 static_cast<but::class_property<but::counter_t>& >( 01789 tr.p_assertions_failed)).set(0); 01790 } 01791 } 01792 01793 void 01794 CNcbiTestsObserver::exception_caught(boost::execution_exception const& ex) 01795 { 01796 if (ex.code() == boost::execution_exception::timeout_error) { 01797 s_GetTestApp().SetTestTimedOut(const_cast<but::test_case*>( 01798 &but::framework::current_test_case())); 01799 } 01800 else { 01801 s_GetTestApp().SetTestErrored(const_cast<but::test_case*>( 01802 &but::framework::current_test_case())); 01803 } 01804 } 01805 01806 void 01807 CNcbiTestsObserver::test_unit_aborted(but::test_unit const& tu) 01808 { 01809 s_GetTestApp().SetTestErrored((but::test_case*)&tu); 01810 } 01811 01812 void 01813 CNcbiTestsObserver::assertion_result(bool passed) 01814 { 01815 if (!passed) { 01816 s_GetTestApp().SetTestErrored(const_cast<but::test_case*>( 01817 &but::framework::current_test_case())); 01818 } 01819 } 01820 01821 01822 void 01823 CNcbiBoostReporter::results_report_start(ostream& ostr) 01824 { 01825 m_Indent = 0; 01826 s_GetTestApp().ReEnableAllTests(); 01827 01828 m_Upper->results_report_start(ostr); 01829 } 01830 01831 void 01832 CNcbiBoostReporter::results_report_finish(ostream& ostr) 01833 { 01834 m_Upper->results_report_finish(ostr); 01835 if (m_IsXML) { 01836 ostr << endl; 01837 } 01838 } 01839 01840 void 01841 CNcbiBoostReporter::test_unit_report_start(but::test_unit const& tu, 01842 ostream& ostr) 01843 { 01844 if (tu.p_name.get() == kDummyTestCaseName) 01845 return; 01846 01847 string descr = s_GetTestApp().GetTestResultString( 01848 const_cast<but::test_unit*>(&tu)); 01849 01850 if (m_IsXML) { 01851 ostr << '<' << (tu.p_type == but::tut_case ? "TestCase" : "TestSuite") 01852 << " name" << but::attr_value() << tu.p_name.get() 01853 << " result" << but::attr_value() << descr; 01854 01855 ostr << '>'; 01856 } 01857 else { 01858 ostr << std::setw( m_Indent ) << "" 01859 << "Test " << (tu.p_type == but::tut_case ? "case " : "suite " ) 01860 << "\"" << tu.p_name << "\" " << descr; 01861 01862 ostr << '\n'; 01863 m_Indent += 2; 01864 } 01865 } 01866 01867 void 01868 CNcbiBoostReporter::test_unit_report_finish(but::test_unit const& tu, 01869 std::ostream& ostr) 01870 { 01871 if (tu.p_name.get() == kDummyTestCaseName) 01872 return; 01873 01874 m_Indent -= 2; 01875 m_Upper->test_unit_report_finish(tu, ostr); 01876 } 01877 01878 void 01879 CNcbiBoostReporter::do_confirmation_report(but::test_unit const& tu, 01880 std::ostream& ostr) 01881 { 01882 m_Upper->do_confirmation_report(tu, ostr); 01883 } 01884 01885 01886 void 01887 CNcbiBoostLogger::log_start(ostream& ostr, but::counter_t test_cases_amount) 01888 { 01889 m_Upper->log_start(ostr, test_cases_amount); 01890 } 01891 01892 void 01893 CNcbiBoostLogger::log_finish(ostream& ostr) 01894 { 01895 m_Upper->log_finish(ostr); 01896 if (!m_IsXML) { 01897 ostr << "Executed " << s_GetTestApp().GetRanTestsCount() 01898 << " test cases"; 01899 int to_fix = s_GetTestApp().GetToFixTestsCount(); 01900 if (to_fix != 0) { 01901 ostr << " (" << to_fix << " to fix)"; 01902 } 01903 ostr << "." << endl; 01904 } 01905 } 01906 01907 void 01908 CNcbiBoostLogger::log_build_info(ostream& ostr) 01909 { 01910 m_Upper->log_build_info(ostr); 01911 } 01912 01913 void 01914 CNcbiBoostLogger::test_unit_start(ostream& ostr, but::test_unit const& tu) 01915 { 01916 m_Upper->test_unit_start(ostr, tu); 01917 } 01918 01919 void 01920 CNcbiBoostLogger::test_unit_finish(ostream& ostr, but::test_unit const& tu, 01921 unsigned long elapsed) 01922 { 01923 m_Upper->test_unit_finish(ostr, tu, elapsed); 01924 } 01925 01926 void 01927 CNcbiBoostLogger::test_unit_skipped(ostream& ostr, but::test_unit const& tu) 01928 { 01929 m_Upper->test_unit_skipped(ostr, tu); 01930 } 01931 01932 #if BOOST_VERSION >= 104200 01933 void 01934 CNcbiBoostLogger::log_exception(ostream& ostr, but::log_checkpoint_data const& lcd, 01935 boost::execution_exception const& ex) 01936 { 01937 m_Upper->log_exception(ostr, lcd, ex); 01938 } 01939 #else 01940 void 01941 CNcbiBoostLogger::log_exception(ostream& ostr, but::log_checkpoint_data const& lcd, 01942 but::const_string explanation) 01943 { 01944 m_Upper->log_exception(ostr, lcd, explanation); 01945 } 01946 #endif 01947 01948 void 01949 CNcbiBoostLogger::log_entry_start(ostream& ostr, but::log_entry_data const& led, 01950 log_entry_types let) 01951 { 01952 m_Upper->log_entry_start(ostr, led, let); 01953 } 01954 01955 void 01956 CNcbiBoostLogger::log_entry_value(ostream& ostr, but::const_string value) 01957 { 01958 m_Upper->log_entry_value(ostr, value); 01959 } 01960 01961 void 01962 CNcbiBoostLogger::log_entry_finish(ostream& ostr) 01963 { 01964 m_Upper->log_entry_finish(ostr); 01965 } 01966 01967 01968 void 01969 RegisterNcbiTestUserFunc(TNcbiTestUserFunction func, 01970 ETestUserFuncType func_type) 01971 { 01972 s_GetTestApp().AddUserFunction(func, func_type); 01973 } 01974 01975 void 01976 NcbiTestDependsOn(but::test_unit* tu, but::test_unit* dep_tu) 01977 { 01978 s_GetTestApp().AddTestDependsOn(tu, dep_tu); 01979 } 01980 01981 void 01982 NcbiTestDisable(but::test_unit* tu) 01983 { 01984 s_GetTestApp().SetTestDisabled(tu); 01985 } 01986 01987 void 01988 NcbiTestSetGlobalDisabled(void) 01989 { 01990 s_GetTestApp().SetGloballyDisabled(); 01991 } 01992 01993 void 01994 NcbiTestSetGlobalSkipped(void) 01995 { 01996 s_GetTestApp().SetGloballySkipped(); 01997 } 01998 01999 CExprParser* 02000 NcbiTestGetIniParser(void) 02001 { 02002 return s_GetTestApp().GetIniParser(); 02003 } 02004 02005 CArgDescriptions* 02006 NcbiTestGetArgDescrs(void) 02007 { 02008 return s_GetTestApp().GetArgDescrs(); 02009 } 02010 02011 but::test_unit* 02012 NcbiTestGetUnit(CTempString test_name) 02013 { 02014 return s_GetTestApp().GetTestUnit(test_name); 02015 } 02016 02017 02018 END_NCBI_SCOPE 02019 02020 02021 using namespace but; 02022 02023 /// Global initialization function called from Boost framework 02024 test_suite* 02025 init_unit_test_suite(int argc, char* argv[]) 02026 { 02027 return NCBI_NS_NCBI::s_GetTestApp().InitTestFramework(argc, argv); 02028 } 02029 02030 // This main() is mostly a copy from Boost's unit_test_main.ipp 02031 int 02032 main(int argc, char* argv[]) 02033 { 02034 int result = boost::exit_success; 02035 02036 try { 02037 framework::init( &init_unit_test_suite, argc, argv ); 02038 02039 if( !runtime_config::test_to_run().is_empty() ) { 02040 test_case_filter filter( runtime_config::test_to_run() ); 02041 02042 traverse_test_tree( framework::master_test_suite().p_id, filter ); 02043 } 02044 02045 framework::run(); 02046 02047 // Let's try to make report in case of any error after all catches. 02048 //results_reporter::make_report(); 02049 02050 if (!runtime_config::no_result_code()) { 02051 result = results_collector.results( framework::master_test_suite().p_id ).result_code(); 02052 if (!NCBI_NS_NCBI::s_GetTestApp().HasTestErrors() 02053 && NCBI_NS_NCBI::s_GetTestApp().HasTestTimeouts()) 02054 { 02055 // This should certainly go to the output. So we can use only 02056 // printf, nothing else. 02057 printf("There were no test failures, only timeouts.\n" 02058 " (for autobuild scripts: NCBI_UNITTEST_TIMEOUTS_BUT_NO_ERRORS)\n"); 02059 } 02060 } 02061 } 02062 #if BOOST_VERSION >= 104200 02063 catch( framework::nothing_to_test const& ) { 02064 result = boost::exit_success; 02065 } 02066 #endif 02067 catch( framework::internal_error const& ex ) { 02068 results_reporter::get_stream() << "Boost.Test framework internal error: " << ex.what() << std::endl; 02069 02070 result = boost::exit_exception_failure; 02071 } 02072 catch( framework::setup_error const& ex ) { 02073 results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; 02074 02075 result = boost::exit_exception_failure; 02076 } 02077 catch( std::exception const& ex ) { 02078 results_reporter::get_stream() << "Test framework error: " << ex.what() << std::endl; 02079 02080 result = boost::exit_exception_failure; 02081 } 02082 catch( ... ) { 02083 results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl; 02084 02085 result = boost::exit_exception_failure; 02086 } 02087 02088 results_reporter::make_report(); 02089 02090 NCBI_NS_NCBI::GetDiagContext().SetExitCode(result); 02091 return result; 02092 }
1.7.5.1
Modified on Wed May 23 12:58:40 2012 by modify_doxy.py rev. 337098