TestBase.h

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/test/TestBase.h#17 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 #ifndef Fennel_TestBase_Included
00025 #define Fennel_TestBase_Included
00026 
00027 #include "fennel/common/ConfigMap.h"
00028 #include "fennel/synch/SynchObj.h"
00029 #include "fennel/common/TraceTarget.h"
00030 #include "fennel/common/FileStatsTarget.h"
00031 #include "fennel/synch/StatsTimer.h"
00032 
00033 #define BOOST_TEST_DYN_LINK
00034 
00035 #include <boost/shared_ptr.hpp>
00036 #include <boost/test/unit_test.hpp>
00037 #include <boost/test/unit_test_suite.hpp>
00038 #include <boost/test/parameterized_test.hpp>
00039 #include <boost/enable_shared_from_this.hpp>
00040 #include <fstream>
00041 #include <vector>
00042 
00043 typedef boost::unit_test_framework::test_suite TestSuite;
00044 
00045 FENNEL_BEGIN_NAMESPACE
00046 
00050 class FENNEL_TEST_EXPORT TestBase
00051     : public TraceTarget,
00052         public boost::enable_shared_from_this<TestBase>
00053 
00054 {
00055 protected:
00059     TestSuite *pTestSuite;
00060 
00061     boost::shared_ptr<TestBase> pTestObj;
00062 
00066     std::ofstream traceStream;
00067 
00071     StrictMutex traceMutex;
00072 
00076     std::string testName;
00077 
00081     TraceLevel traceLevel;
00082 
00086     FileStatsTarget statsTarget;
00087 
00091     StatsTimer statsTimer;
00092 
00093     // TODO:  move to SynchObj
00094     void snooze(uint nSeconds);
00095 
00099     bool traceStdout;
00100 
00104     bool traceFile;
00105 
00110     static bool runAll;
00111 
00116     static std::string runSingle;
00117 
00122     class FENNEL_TEST_EXPORT TestCaseGroup
00123     {
00124         struct Item
00125         {
00126             std::string name;
00127             boost::unit_test::test_unit * tu;
00128             Item(std::string name, boost::unit_test::test_unit* tu)
00129                 : name(name), tu(tu) {}
00130         };
00132         std::vector<Item> items;
00133     public:
00134         void addTest(std::string name, boost::unit_test::test_unit *tu);
00135         boost::unit_test::test_unit* findTest(std::string name) const;
00136         void addAllToTestSuite(TestSuite *) const;
00137     };
00138 
00139     TestCaseGroup defaultTests;
00140     TestCaseGroup extraTests;
00141 
00142 public:
00143     static ParamName paramTestSuiteName;
00144     static ParamName paramTraceFileName;
00145     static ParamName paramDictionaryFileName;
00146     static ParamName paramTraceLevel;
00147     static ParamName paramStatsFileName;
00148     static ParamName paramTraceStdout;
00149     static ParamName paramDegreeOfParallelism;
00150 
00155     static ConfigMap configMap;
00156 
00157     explicit TestBase();
00158     virtual ~TestBase();
00159 
00160     // helpers for FENNEL_UNIT_TEST_SUITE etc. below
00161     static void readParams(int argc,char **argv);
00162     TestSuite *releaseTestSuite();
00163     void beforeTestCase(std::string testCaseName);
00164     void afterTestCase(std::string testCaseName);
00165 
00170     virtual void testCaseSetUp();
00171 
00176     virtual void testCaseTearDown();
00177 
00178     // implement TraceTarget
00179     virtual void notifyTrace(
00180         std::string source,TraceLevel level,std::string message);
00181     virtual TraceLevel getSourceTraceLevel(std::string source);
00182 };
00183 
00188 template<class UserTestClass>
00189 class TestWrapperTemplate
00190 {
00191 public:
00192     typedef void (UserTestClass::*FunctionType)();
00193 
00194 private:
00195     std::string name;
00196     boost::shared_ptr<UserTestClass> pUserTestCase;
00197 
00198 public:
00199     // Constructor
00200     TestWrapperTemplate(
00201         std::string nameInit,
00202         boost::shared_ptr<UserTestClass>& pUserTestCaseInit)
00203         : pUserTestCase(pUserTestCaseInit)
00204     {
00205         name = nameInit;
00206     }
00207 
00208     void runTest(FunctionType pFunction)
00209     {
00210         pUserTestCase->beforeTestCase(name);
00211         pUserTestCase->testCaseSetUp();
00212         try {
00213             try {
00214                 ((*pUserTestCase).*pFunction)();
00215             } catch (std::exception &ex) {
00216                 pUserTestCase->notifyTrace(name, TRACE_SEVERE, ex.what());
00217                 throw ex;
00218             }
00219         } catch (...) {
00220             try {
00221                 pUserTestCase->testCaseTearDown();
00222             } catch (...) {
00223                 // ignore teardown errors after failure
00224             }
00225             throw;
00226         }
00227         try {
00228             pUserTestCase->testCaseTearDown();
00229         } catch (...) {
00230             pUserTestCase->afterTestCase(name);
00231             throw;
00232         }
00233         pUserTestCase->afterTestCase(name);
00234     }
00235 };
00236 
00237 // FENNEL_UNIT_TEST_SUITE should be invoked at top scope within the .cpp file
00238 // defining a test class derived from TestBase, with UserTestClass equal to the
00239 // derived class name.
00240 
00241 #define FENNEL_UNIT_TEST_SUITE(UserTestClass) \
00242 bool init_unit_test() \
00243 { \
00244     TestBase::readParams( \
00245         boost::unit_test::framework::master_test_suite().argc, \
00246         boost::unit_test::framework::master_test_suite().argv); \
00247     std::string paramKey(TestBase::paramTestSuiteName); \
00248     std::string paramVal(#UserTestClass); \
00249     TestBase::configMap.setStringParam(paramKey,paramVal); \
00250     UserTestClass *pTestObj = new UserTestClass(); \
00251     TestBase::configMap.disableTracing(); \
00252     boost::unit_test::framework::master_test_suite().add( \
00253         pTestObj->releaseTestSuite()); \
00254     return true; \
00255 } \
00256 \
00257 int main(int argc, char **argv) \
00258 { \
00259     return ::boost::unit_test::unit_test_main(&init_unit_test, argc, argv); \
00260 }
00261 
00262 
00263 
00264 // In the test class constructor, invoke either FENNEL_UNIT_TEST_CASE or
00265 // FENNEL_EXTRA_UNIT_TEST_CASE for each test case method. Call
00266 // FENNEL_UNIT_TEST_CASE to define a test case that is run by default. Call
00267 // FENNEL_EXTRA_UNIT_TEST_CASE to define an extra test case that is run only
00268 // when selected from the command line, either by "-t TESTNAME" or by "-all".
00269 
00270 #define FENNEL_UNIT_TEST_CASE(UserTestClass,testMethodName) \
00271   FENNEL_DEFINE_UNIT_TEST_CASE(defaultTests,UserTestClass,testMethodName)
00272 
00273 #define FENNEL_EXTRA_UNIT_TEST_CASE(UserTestClass,testMethodName) \
00274   FENNEL_DEFINE_UNIT_TEST_CASE(extraTests,UserTestClass,testMethodName)
00275 
00276 // This macro is based on BOOST_PARAM_CLASS_TEST_CASE():
00277 // make_test_case() below actually returns a test_unit_generator, not a
00278 // test_case. The generator emits one test.
00279 #define FENNEL_DEFINE_UNIT_TEST_CASE(group,UserTestClass,testMethodName) \
00280 do { \
00281     typedef TestWrapperTemplate<UserTestClass> TestWrapper; \
00282     boost::shared_ptr<UserTestClass> pDerivedTestObj = \
00283         boost::dynamic_pointer_cast<UserTestClass>(pTestObj); \
00284     TestWrapper::FunctionType params [] = \
00285         { &UserTestClass::testMethodName }; \
00286     boost::unit_test::test_unit *tu = \
00287         boost::unit_test::make_test_case<TestWrapper>(\
00288             &TestWrapper::runTest, \
00289             #testMethodName, \
00290             boost::shared_ptr<TestWrapper>(new TestWrapper(\
00291                 #testMethodName, \
00292                 pDerivedTestObj)), \
00293             params, \
00294             params + 1).next(); \
00295     group.addTest(#testMethodName, tu); \
00296 } while (0)
00297 
00298 FENNEL_END_NAMESPACE
00299 
00300 #endif
00301 
00302 // End TestBase.h

Generated on Mon Jun 22 04:00:21 2009 for Fennel by  doxygen 1.5.1