Issue #23: Added std::random_device to TestCase class
[libcds.git] / tests / cppunit / cppunit_mini.h
1 //$$CDS-header$$
2
3 /*
4  * Copyright (c) 2003, 2004
5  * Zdenek Nemec
6  *
7  * This material is provided "as is", with absolutely no warranty expressed
8  * or implied. Any use is at your own risk.
9  *
10  * Permission to use or copy this software for any purpose is hereby granted
11  * without fee, provided the above notices are retained on all copies.
12  * Permission to modify the code and to distribute modified code is granted,
13  * provided the above notices are retained, and a notice that the code was
14  * modified is included with the above copyright notice.
15  *
16  */
17
18 /*
19     Partially changed and expanded by Maxim Khiszinsky (cds), 2009
20 */
21
22 /* $Id$ */
23
24 #ifndef CDS_CPPUNIT_MPFR_H_
25 #define CDS_CPPUNIT_MPFR_H_
26
27 #include <string.h>
28 #include <sstream>
29 #include <iostream>
30 #include <vector>
31 #include <string>
32 #include <map>
33 #include <random>
34
35 #include <assert.h>
36
37 #include <boost/lexical_cast.hpp>
38
39 namespace CppUnitMini
40 {
41   class Reporter {
42   public:
43     virtual ~Reporter() {}
44     virtual void error(const char * /*macroName*/, const char * /*in_macro*/, const char * /*in_file*/, int /*in_line*/) {}
45     virtual void message( const char * /*msg*/ ) {}
46     virtual void progress( const char * /*in_className*/, const char * /*in_testName*/, bool /*ignored*/, bool /* explicit */) {}
47     virtual void end() {}
48     virtual void printSummary() {}
49   };
50
51   struct TestCfg
52   {
53       typedef std::map< std::string, std::string >  cfg_map;
54       cfg_map    m_Cfg ; // map param_name => value
55
56       template <typename T>
57       T get( const std::string& strParamName, T defVal ) const
58       {
59           cfg_map::const_iterator it = m_Cfg.find( strParamName );
60           if ( it == m_Cfg.end() )
61               return defVal ; // param not found -> returns default value
62           try {
63               return boost::lexical_cast< T >( it->second );
64           }
65           catch ( boost::bad_lexical_cast& ex )
66           {
67               std::cerr << "bad_lexical_cast encountered while getting parameter "
68                   << strParamName << "=" << it->second
69                   << ": " << ex.what()
70                   << std::endl
71 ;
72           }
73           return defVal;
74       }
75
76       template <typename T>
77       T get( const char * pszParamName, T defVal ) const
78       {
79           return get( std::string( pszParamName ), defVal );
80       }
81
82       int getInt( const char * pszParamName, int nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
83       unsigned int getUInt( const char * pszParamName, unsigned int nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
84       long getLong( const char * pszParamName, long nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
85       unsigned long getULong( const char * pszParamName, unsigned long nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
86       size_t getSizeT( const char * pszParamName, size_t nDefVal = 0 ) const 
87       {
88           return static_cast<size_t>( getULong( pszParamName, static_cast<unsigned long>(nDefVal)));
89       }
90
91       bool getBool( const char * pszParamName, bool bDefVal = false ) const
92       {
93           std::string strParamName( pszParamName );
94           cfg_map::const_iterator it = m_Cfg.find( strParamName );
95           if ( it == m_Cfg.end() )
96               return bDefVal ; // param not found -> returns default value
97           try {
98               return boost::lexical_cast< int >( it->second ) != 0;
99           }
100           catch ( boost::bad_lexical_cast& ex )
101           {
102               std::cerr << "bad_lexical_cast encountered while getting parameter "
103                   << strParamName << "=" << it->second
104                   << ": " << ex.what()
105                   << std::endl;
106           }
107           return bDefVal;
108       }
109
110   };
111
112   class Config {
113       std::map< std::string, TestCfg>  m_Cfg;
114
115   public:
116       Config() {}
117
118       void load( const char * fileName );
119
120       TestCfg& get( const std::string& strTestName )
121       {
122           return m_Cfg[ strTestName ];
123       }
124   };
125
126   class TestFixture {
127   public:
128     virtual ~TestFixture() {}
129
130     //! \brief Set up context before running a test.
131     virtual void setUp() {}
132
133     //! Clean up after the test run.
134     virtual void tearDown() {}
135   };
136
137   class TestCase : public TestFixture {
138   public:
139     TestCase() { registerTestCase(this); }
140
141     void setUp() { m_failed = false; }
142     static int run(Reporter *in_reporter = 0, const char *in_testName = "", bool invert = false);
143     int numErrors() { return m_numErrors; }
144     static void registerTestCase(TestCase *in_testCase);
145
146     static TestCase * current_test()
147     {
148         assert( m_pCurTestCase );
149         return m_pCurTestCase;
150     }
151
152     virtual void setUpParams( const TestCfg& /*cfg*/ ) {}
153     virtual void endTestCase() {}
154     virtual void myRun(const char * /*in_name*/, bool /*invert*/ = false) {}
155
156     virtual void error(const char *in_macroName, const char *in_macro, const char *in_file, int in_line) {
157       m_failed = true;
158       if (m_reporter) {
159         m_reporter->error(in_macroName, in_macro, in_file, in_line);
160       }
161     }
162
163     static void message(const char *msg) {
164       if (m_reporter) {
165         m_reporter->message(msg);
166       }
167     }
168
169     bool equalDoubles(double in_expected, double in_real, double in_maxErr) {
170       double diff = in_expected - in_real;
171       if (diff < 0.) {
172         diff = -diff;
173       }
174       return diff < in_maxErr;
175     }
176
177     virtual void progress(const char *in_className, const char *in_functionName, bool ignored, bool explicitTest) {
178       ++m_numTests;
179       if (m_reporter) {
180         m_reporter->progress(in_className, in_functionName, ignored, explicitTest);
181       }
182     }
183
184     bool shouldRunThis( const char *in_desiredTest, const char *in_className, const char *in_functionName,
185                         bool invert, bool explicit_test, bool &do_progress );
186
187     void tearDown() {
188       print_gc_state();
189       if (m_failed)
190         ++m_numErrors;
191       m_reporter->end();
192     }
193
194     static void print_gc_state();
195
196     static std::vector<std::string> const&    getTestStrings();
197
198     template <typename RandomIt>
199     void shuffle( RandomIt first, RandomIt last )
200     {
201         std::shuffle( first, last, m_RandomGen );
202     }
203
204   protected:
205     static std::vector<std::string>  m_arrStrings ;   // array of test strings
206
207   public:
208       static bool m_bPrintGCState   ;   // print GC state after each test
209       static Config m_Cfg;
210       static std::string m_strTestDataDir;
211       static bool m_bExactMatch;
212
213       // random shuffle support
214       static std::random_device m_RandomDevice;
215       static std::mt19937       m_RandomGen;
216
217   protected:
218     static int m_numErrors;
219     static int m_numTests;
220
221     static TestCase * m_pCurTestCase;
222
223   private:
224     static TestCase *m_root;
225     TestCase *m_next;
226     bool m_failed;
227
228     static Reporter *m_reporter;
229   };
230
231 }
232
233 #if !defined (CPPUNIT_MINI_HIDE_UNUSED_VARIABLE)
234 #  if defined (_MSC_VER)
235 #    define CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(v) (v);
236 #  else
237 #    define CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(v)
238 #  endif
239 #endif
240
241 #define CPPUNIT_TEST_SUITE_(X, cfgBranchName) \
242     typedef CppUnitMini::TestCase Base; \
243     virtual void myRun(const char *in_name, bool invert = false) { \
244     const char *className = #X; CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(className) \
245     bool ignoring = false; CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(ignoring) \
246     setUpParams( m_Cfg.get( cfgBranchName ));
247
248 #define CPPUNIT_TEST_SUITE_PART(X, func) \
249     void X::func(const char *in_name, bool invert /*= false*/) { \
250     const char *className = #X; CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(className) \
251     bool ignoring = false; CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(ignoring)
252
253 #define CPPUNIT_TEST_SUITE(X) CPPUNIT_TEST_SUITE_(X, #X)
254
255 #if defined CPPUNIT_MINI_USE_EXCEPTIONS
256 #  define CPPUNIT_TEST_BASE(X, Y) \
257   { \
258     bool do_progress; \
259     bool shouldRun = shouldRunThis(in_name, className, #X, invert, Y, do_progress); \
260     if (shouldRun || do_progress) { \
261       setUp(); \
262       progress(className, #X, ignoring || !shouldRun, !ignoring && Y); \
263       if (shouldRun && !ignoring) { \
264         try { \
265           X(); \
266         } \
267         catch(...) { \
268           Base::error("Test Failed: An exception was thrown.", #X, __FILE__, __LINE__); \
269         } \
270       } \
271       tearDown(); \
272     } \
273   }
274 #else
275 #  define CPPUNIT_TEST_BASE(X, Y) \
276   { \
277     bool do_progress; \
278     bool shouldRun = shouldRunThis(in_name, className, #X, invert, Y, do_progress); \
279     if (shouldRun || do_progress) { \
280       setUp(); \
281       progress(className, #X, ignoring || !shouldRun, !ignoring && Y); \
282       if (shouldRun && !ignoring) \
283         X(); \
284       tearDown(); \
285     } \
286   }
287 #endif
288
289 #define CPPUNIT_TEST(X) CPPUNIT_TEST_BASE(X, false)
290 #define CPPUNIT_EXPLICIT_TEST(X) CPPUNIT_TEST_BASE(X, true)
291
292 #define CDSUNIT_DECLARE_TEST(X) void X();
293
294 #define CPPUNIT_IGNORE \
295   ignoring = true
296
297 #define CPPUNIT_STOP_IGNORE \
298   ignoring = false
299
300 #define CPPUNIT_TEST_SUITE_END() endTestCase(); }
301 #define CPPUNIT_TEST_SUITE_END_PART() }
302
303 #define CPPUNIT_TEST_SUITE_REGISTRATION(X) static X local
304 #define CPPUNIT_TEST_SUITE_REGISTRATION_(X, NAME) static X NAME
305
306 #define CPPUNIT_CHECK(X) \
307   if (!(X)) { \
308     Base::error("CPPUNIT_CHECK", #X, __FILE__, __LINE__); \
309   }
310
311 #define CPPUNIT_CHECK_CURRENT(X) \
312   if (!(X)) { \
313     CppUnitMini::TestCase::current_test()->error("CPPUNIT_CHECK", #X, __FILE__, __LINE__); \
314   }
315
316 #define CPPUNIT_CHECK_EX(X, Y) \
317     if (!(X)) { \
318         std::stringstream st    ;   \
319         st << #X << ": " << Y   ;   \
320         Base::error("CPPUNIT_CHECK", st.str().c_str(), __FILE__, __LINE__); \
321     }
322
323 #define CPPUNIT_CHECK_CURRENT_EX(X, Y) \
324     if (!(X)) { \
325         std::stringstream st    ;   \
326         st << #X << ": " << Y   ;   \
327         CppUnitMini::TestCase::current_test()->error("CPPUNIT_CHECK", st.str().c_str(), __FILE__, __LINE__); \
328     }
329
330 #define CPPUNIT_ASSERT(X) \
331   if (!(X)) { \
332     Base::error("CPPUNIT_ASSERT", #X, __FILE__, __LINE__); \
333     return; \
334   }
335
336 #define CPPUNIT_ASSERT_CURRENT(X) \
337     if (!(X)) { \
338         CppUnitMini::TestCase::current_test()->error("CPPUNIT_ASSERT", #X, __FILE__, __LINE__); \
339         return; \
340     }
341
342
343 #define CPPUNIT_ASSERT_EX(A, X) \
344     if (!(A)) { \
345         std::stringstream st    ;   \
346         st << #A << ": " << X   ;   \
347         Base::error("CPPUNIT_ASSERT", st.str().c_str(), __FILE__, __LINE__); \
348         return; \
349     }
350
351 #define CPPUNIT_FAIL { \
352     Base::error("CPPUNIT_FAIL", "", __FILE__, __LINE__); \
353     return; \
354   }
355
356 #define CPPUNIT_ASSERT_EQUAL(X, Y) \
357   if ((X) != (Y)) { \
358     Base::error("CPPUNIT_ASSERT_EQUAL", #X","#Y, __FILE__, __LINE__); \
359     return; \
360   }
361
362 #define CPPUNIT_ASSERT_DOUBLES_EQUAL(X, Y, Z) \
363   if (!equalDoubles((X), (Y), (Z))) { \
364     Base::error("CPPUNIT_ASSERT_DOUBLES_EQUAL", #X","#Y","#Z, __FILE__, __LINE__); \
365     return; \
366   }
367
368 // added by cds
369 #define CPPUNIT_MSG( X ) \
370     {   \
371         std::stringstream st    ;   \
372         st << X ;   \
373         if ( !st.str().empty() ) \
374             CppUnitMini::TestCase::message( st.str().c_str() );   \
375     }
376
377 #define CPPUNIT_MESSAGE(m) CppUnitMini::TestCase::message(m)
378
379 #define CPPUNIT_ASSERT_MSG( A, X ) \
380     if ( !(A) ){   \
381         std::stringstream st    ;   \
382         st << #A << ": " << X ;   \
383         error( "CPPUNIT_ASSERT_MSG", st.str().c_str(), __FILE__, __LINE__ )     ;   \
384     }
385
386 #endif // #ifndef CDS_CPPUNIT_MPFR_H_