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