* New upstream release, compatible with GCC 4.3 (closes: #417434).
[debian/mimetic.git] / test / cutee.h
1 /***************************************************************************
2     copyright            : (C) 2003-2005 by Stefano Barbato
3     email                : stefano@codesink.org
4
5     $Id: cutee.h,v 1.12 2007/04/03 08:13:22 tat Exp $
6  ***************************************************************************/
7
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16
17 #ifndef _CUTEE_CUTEE_H_
18 #define _CUTEE_CUTEE_H_
19 #include <cstdlib>
20 #include <iostream>
21 #include <sstream>
22 #include <iomanip>
23 #include <stdarg.h>
24
25 typedef unsigned int uint;
26
27 #define CUTEE_VERSION "0.4.2"
28
29 #define MAX_TEST_COUNT 1000
30
31
32 #define TEST_CLASS( name ) \
33     dummy_##name: public cutee::CuteeTest { \
34     public: \
35         dummy_##name() \
36         { \
37             className(#name); \
38             classFileName(__FILE__); \
39             classLineNo(__LINE__); \
40         } \
41     }; \
42     struct name: public dummy_##name
43 #define TEST_FUNCTION_EX( funcname, filename, lineno ) \
44     run_##funcname() \
45     { \
46         functionName(#funcname); \
47         functionLineNo(lineno); \
48         mEvt->enterFunction(*this); \
49         mFuncExitCode = 0; \
50         funcname(); \
51         if(mFuncExitCode) mFailed++; \
52         mEvt->leaveFunction(*this, mFuncExitCode == 0); \
53     } \
54     void funcname()
55
56
57 #define TEST_FUNCTION( funcname ) \
58     TEST_FUNCTION_EX( funcname, __FILE__, __LINE__)
59
60 #define PRINT_VALUE( a ) \
61     "\t[" << #a << ": " << a << "]" << std::endl
62
63 #define PRINT_ON_FAILURE_1( a ) \
64     PRINT_VALUE( a ) 
65 #define PRINT_ON_FAILURE_2( a, b ) \
66     PRINT_VALUE( a ) << PRINT_VALUE( b )
67 #define PRINT_ON_FAILURE_3( a, b, c ) \
68     PRINT_VALUE( a ) << PRINT_VALUE( b ) << PRINT_VALUE( c )
69 #define PRINT_ON_FAILURE_4( a, b, c, d ) \
70     PRINT_VALUE( a ) << PRINT_VALUE( b ) << \
71     PRINT_VALUE( c ) << PRINT_VALUE( d )
72
73 #define TEST_ASSERT_EX( e, file, line ) \
74     do { expr(#e); exprFileName(file); exprLineNo(line); \
75     testAssert(e); } while(0)
76
77 #define TEST_ASSERT_EX_M( e, p, file, line ) \
78     do { expr(#e); exprFileName(file); exprLineNo(line); \
79     std::stringstream _l_ss; _l_ss << p << std::endl; \
80     testAssertM(e, _l_ss ); } while(0) 
81
82
83
84 #define TEST_ASSERT( expr ) TEST_ASSERT_EX( expr, __FILE__, __LINE__ ) 
85 #define TEST_ASSERT_EQUALS( a, b ) TEST_ASSERT_EX( (a == b), __FILE__,__LINE__ )
86 #define TEST_ASSERT_DIFFERS( a, b ) TEST_ASSERT_EX( (a != b),__FILE__,__LINE__ )
87
88 // print p on test fail
89 #define TEST_ASSERT_M( expr , p) TEST_ASSERT_EX_M( expr, p, __FILE__,__LINE__ ) 
90 #define TEST_ASSERT_EQUALS_M( a, b, p ) TEST_ASSERT_EX_M( (a == b), p,__FILE__,__LINE__ )
91 #define TEST_ASSERT_DIFFERS_M( a, b, p ) TEST_ASSERT_EX_M( (a != b), p,__FILE__,__LINE__)
92
93 // print a and b on error
94 #define TEST_ASSERT_P( expr ) TEST_ASSERT_EX_M( expr, PRINT_ON_FAILURE_1( expr ), __FILE__,__LINE__ ) 
95 #define TEST_ASSERT_EQUALS_P( a, b ) TEST_ASSERT_EX_M( (a == b), PRINT_ON_FAILURE_2( a, b ), __FILE__,__LINE__ )
96 #define TEST_ASSERT_DIFFERS_P( a, b ) TEST_ASSERT_EX_M( (a != b), PRINT_ON_FAILURE_2( a, b ), __FILE__,__LINE__)
97
98 #define TEST_ASSERT_PM( expr, m ) TEST_ASSERT_EX_M( expr, PRINT_ON_FAILURE_2( expr, m ), __FILE__,__LINE__ ) 
99 #define TEST_ASSERT_EQUALS_PM( a, b, m ) TEST_ASSERT_EX_M( (a == b), PRINT_ON_FAILURE_3( a, b, m ), __FILE__,__LINE__ )
100 #define TEST_ASSERT_DIFFERS_PM( a, b, m ) TEST_ASSERT_EX_M( (a != b), PRINT_ON_FAILURE_3( a, b, m ), __FILE__,__LINE__)
101
102 namespace cutee // c++ unit testing environment 
103 {
104
105 struct CuteeTest;
106
107 // store runtime context (class name, function name, line numbers, etc.)
108 struct Context
109 {
110     typedef std::string string;
111     Context()
112     : mClassLineNo(0), mFunctionLineNo(0), mExprLineNo(0) 
113     {}
114     // class info
115     const string& className() const    { return mClassName; }
116     uint classLineNo() const { return mClassLineNo; }
117     const string& classFileName() const { return mClassFileName; }
118     // filename
119     const string& fileName() const { return mFileName; }
120     // function info
121     const string& functionName() const { return mFunctionName; }
122     uint functionLineNo() const { return mFunctionLineNo; }
123     // assertion info
124     const string& expr() const { return mExpr; }
125     const string& exprFileName() const { return mExprFileName; }
126     uint exprLineNo() const { return mExprLineNo; }
127
128     void className(const string& s) { mClassName = s; }
129     void classFileName(const string& s) { mClassFileName = s; }
130     void classLineNo(uint i) { mClassLineNo = i; }
131
132     void filename(const string& s) { mFileName = s; }
133
134     void functionName(const string& s) { mFunctionName = s; }
135     void functionLineNo(uint i) { mFunctionLineNo = i; }
136
137     void expr(const string& s) { mExpr = s; }
138     void exprFileName(const string& s) { mExprFileName = s; }
139     void exprLineNo(uint i) { mExprLineNo = i; }
140 private:
141     std::string mClassName, mClassFileName, mFunctionName, 
142         mFileName, mExpr, mExprFileName;
143     uint mClassLineNo, mFunctionLineNo, mExprLineNo;
144 };
145
146
147 // execution monitor interface
148 struct TestRunMonitor
149 {
150     virtual ~TestRunMonitor() {}
151     
152     virtual void beginTesting() {}
153     virtual void endTesting() {}
154
155     // virtual void enterSuite(const CuteeTest&) {}
156     // virtual void leaveSuite(const CuteeTest&, int b) {}
157
158     virtual void enterClass(const CuteeTest&) {}
159     virtual void leaveClass(const CuteeTest&, int) {}
160
161     virtual void enterFunction(const CuteeTest&) {}
162     virtual void leaveFunction(const CuteeTest&, int ) {}
163
164     virtual void assertion(const CuteeTest&, int, 
165         const std::string& u = "") {}
166 };
167
168 // statically store pointers to test classes
169 struct TestList
170 {
171     virtual ~TestList() {}
172     // FIXME add dynamic array alloc to avoid fixed limit
173     static CuteeTest* list[MAX_TEST_COUNT];
174     static int list_idx;
175 };
176
177
178
179 // this is the base class of all cutee test classes
180 struct CuteeTest: public cutee::Context 
181 {
182     CuteeTest()
183     : mEvt(&mNullMonitor), mFuncExitCode(0), mFailed(0)
184     {
185     }
186     virtual ~CuteeTest() {}
187     virtual void setUp() {}
188     virtual void tearDown()    {}
189     void testRunMonitor(TestRunMonitor *evt) { mEvt = evt; }
190     int passed() const  { return mFailed == 0; }
191     virtual void run() = 0;
192     virtual uint count() = 0;
193 protected:
194     void testAssert(int b)
195     {
196         if( b == 0 ) // assertion failed 
197             mFuncExitCode++; 
198         mEvt->assertion(*this, b);
199     }
200     void testAssertM(int b, std::stringstream& os)
201     {
202         if( b == 0 ) // assertion failed 
203             mFuncExitCode++; 
204         mEvt->assertion(*this, b, os.str());
205     }
206 protected:
207     TestRunMonitor *mEvt, mNullMonitor;
208     uint mFuncExitCode, mFailed;
209 };
210
211
212
213 // monitors execution and keep statistics on classes/functions/tests
214 struct StatsMonitor: public TestRunMonitor
215 {
216     StatsMonitor()
217     : mAssertPassed(0), mAssertFailed(0), mAssertCount(0),
218       mFuncPassed(0),  mFuncFailed(0), mFuncCount(0),
219       mClassPassed(0),  mClassFailed(0), mClassCount(0)
220     {
221     }
222     // void enterSuite(const CuteeTest& t)    {}
223     // void leaveSuite(const CuteeTest& t, int b) {}
224     void enterClass(const CuteeTest& t) 
225     {
226         mClassCount++;
227     }
228     void leaveClass(const CuteeTest& t, int b) 
229     {
230         if(b) 
231             mClassPassed++;
232         else 
233             mClassFailed++;
234     }
235     void enterFunction(const CuteeTest&)
236     {
237         mFuncCount++;
238     }
239     void leaveFunction(const CuteeTest&, int b) 
240     {
241         if(b) 
242             mFuncPassed++;
243         else 
244             mFuncFailed++;
245     }
246     void assertion(const CuteeTest& t, int b, const std::string& userMsg) 
247     {
248         mAssertCount++;
249         if(b) 
250             mAssertPassed++;
251         else 
252             mAssertFailed++;
253     }
254 protected:
255     uint mAssertPassed, mAssertFailed, mAssertCount, mFuncPassed,
256          mFuncFailed, mFuncCount, mClassPassed, mClassFailed, mClassCount;
257 };
258
259 // keep stats and print results on exit
260 struct ConsoleRunMonitor: public StatsMonitor
261 {
262     void assertion(const CuteeTest& t, int b, const std::string& userMsg) 
263     {
264         using namespace std;
265         StatsMonitor::assertion(t, b, userMsg);
266         if(!b) 
267         {
268             cout << endl << " [" 
269                 << t.exprFileName() << ":" 
270                 << t.exprLineNo()<< "] "
271                 << t.className() << "::" 
272                 << t.functionName() << "(): "
273                 << t.expr() << " assertion failed" 
274                 << endl;
275             if(!userMsg.empty())
276                 cout << userMsg << endl;
277         }
278     }
279     void endTesting()
280     {
281         using namespace std;
282         cout << endl << endl;
283         cout << "    ======================================" << endl;
284         cout << "          Tests Statistics           " << endl;
285         cout << "    --------------------------------------" << endl;
286         cout << "                Functions       Checks   " << endl;
287         cout << "      Success   "<< setw(8) << mFuncPassed << 
288             "      " << setw(8) << mAssertPassed << endl;
289         cout << "       Failed   "<< setw(8) << mFuncFailed << 
290             "      " << setw(8) << mAssertFailed << endl;
291         cout << "    --------------------------------------" << endl;
292         cout << "        Total   "<< setw(8) << mFuncCount << 
293             "      " <<  setw(8) << mAssertCount << endl;
294         cout << "    ======================================" << endl;
295     }
296 };
297
298 // keep stats and print skimmer xml output on exit
299 struct SkimmerRunMonitor: public StatsMonitor
300 {
301     void beginTesting() 
302     {
303         using namespace std;
304         cout << "<?xml version=\"1.0\"?>" << endl;
305         cout << "<tests>" << endl;
306     }
307     void endTesting() 
308     {
309         using namespace std;
310         cout << "</tests>" << endl;
311     }
312     void enterClass(const CuteeTest&)
313     {
314     }
315     void leaveClass(const CuteeTest&, int) 
316     {
317     }
318     void enterFunction(const CuteeTest& t) 
319     {
320         using namespace std;
321         cout << "<test>" << endl;
322         cout << "<name>"; 
323         cout << t.className() << "::" << t.functionName() << "()";
324         cout << "</name>" << endl;
325     }
326     void leaveFunction(const CuteeTest& t, int b) 
327     {
328         using namespace std;
329         cout << "<type>" << (b ? "pass" : "fail") << "</type>" << endl;
330         cout << "</test>" << endl << endl << endl;
331     }
332     void assertion(const CuteeTest& t, int b, const std::string& u = "") 
333     {
334         using namespace std;
335         if(b)
336             return;
337         cout << "  <info>" << endl;
338         cout << "  <type>" << (b ? "pass" : "fail") << "</type>" << endl;
339         cout << "  <data>" << endl;
340         cout << "  <file>" << t.exprFileName() << "</file>" << endl;
341         cout << "  <line>" << t.exprLineNo() << "</line>" << endl;
342         cout << "  <expression>" << t.expr() << "</expression>" <<endl;
343         if(!u.empty())
344             cout << "  <output>" << u << endl << "  </output>" << endl;
345         cout << "  </expression>" << endl;
346         cout << "  </data>" << endl;
347         cout << "  </info>" << endl << endl;
348     }
349 };
350
351 // create the appropriate TestRunMonitor based on environment variables
352 // or command line parameters and run tests
353 struct Runner
354 {
355     Runner(int argc, char** argv)
356     : mEvt(0)
357     {
358         if(getenv("SKIMMER_MODE"))
359             mEvt = new SkimmerRunMonitor;
360         else
361             mEvt = new ConsoleRunMonitor;
362     }
363     void run()
364     {
365         mEvt->beginTesting();
366         for(int i =0; i < TestList::list_idx; i++)
367         {
368             CuteeTest *ct = TestList::list[i];
369             ct->testRunMonitor(mEvt);
370             mEvt->enterClass(*ct);
371             ct->run();
372             mEvt->leaveClass(*ct, ct->passed());
373         }
374         mEvt->endTesting();
375     }
376 private:
377     TestRunMonitor *mEvt;
378 };
379
380 }
381
382
383 #endif