]> git.donarmstrong.com Git - lilypond.git/blob - flower/include/yaffut.hh
Fix "make check" on gcc 4.3
[lilypond.git] / flower / include / yaffut.hh
1 // Copyright 2006 Rutger E.W. van Beusekom.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 #ifndef __YAFFUT_H__
7 #define __YAFFUT_H__
8
9 #include <cxxabi.h>
10
11 #include <cmath>
12 #include <cstring>
13 #include <iostream>
14 #include <limits>
15 #include <map>
16 #include <memory>
17 #include <sstream>
18 #include <stdexcept>
19
20 #define YAFFUT_STRINGIZE(x) YAFFUT_STRINGIZE_(x)
21 #define YAFFUT_STRINGIZE_(x) #x
22
23 #define __YAFFUT_AT__ __FILE__ ":" YAFFUT_STRINGIZE(__LINE__)": "
24 #ifndef __AT__
25 #define __AT__ __YAFFUT_AT__
26 #endif
27
28 #define YAFFUT_EQUAL(e,a) \
29   yaffut::equal (e ,a , __YAFFUT_AT__, "EQUAL(" #e " == " #a ") failed ")
30 #ifndef EQUAL
31 #define EQUAL YAFFUT_EQUAL
32 #endif
33
34 #define YAFFUT_UNEQUAL(e,a) \
35   yaffut::unequal (e, a, __YAFFUT_AT__, "UNEQUAL(" #e " != " #a ") failed ")
36 #ifndef UNEQUAL
37 #define UNEQUAL YAFFUT_UNEQUAL
38 #endif
39
40 #define YAFFUT_CHECK(e) \
41   yaffut::check (e, __YAFFUT_AT__, "CHECK(" #e ") failed ")
42 #ifndef CHECK
43 #define CHECK YAFFUT_CHECK
44 #endif
45
46 #define YAFFUT_FAIL(s) yaffut::fail (s, __YAFFUT_AT__);
47 #ifndef FAIL
48 #define FAIL YAFFUT_FAIL
49 #endif
50
51 #define YAFFUT_ASSERT_THROW(s, e) \
52   try \
53   { \
54     s; \
55     throw yaffut::failure (__YAFFUT_AT__,  #s " failed to throw"); \
56   } \
57   catch(const e&){}
58 #ifndef ASSERT_THROW
59 #define ASSERT_THROW YAFFUT_ASSERT_THROW
60 #endif
61
62 namespace yaffut {
63
64 template <typename T>
65 std::string demangle()
66 {
67   size_t sz;
68   int status;
69   char* ptr = abi::__cxa_demangle(typeid(T).name(), 0, &sz, &status);
70   std::string name(ptr ? ptr : "", ptr ? strlen(ptr) : 0);
71   if(ptr){ free(ptr); }
72   std::string::size_type pos = name.rfind("::");
73   if(pos != std::string::npos)
74   {
75     name = name.substr(pos + 2);
76   }  
77   return name;
78 }
79
80 struct ITest
81 {
82   virtual ~ITest(){}
83 };
84
85 class Factory
86 {
87 public:
88   typedef ITest* (*Create_t) ();
89 private:
90   typedef std::map<std::string, Create_t> Tests_t;
91   Tests_t m_Tests;
92   size_t m_fail;
93   size_t m_pass;
94 private:
95   Factory(){}
96   ~Factory(){}
97   static bool EqualsSuiteName (std::string const &name, std::string const& s)
98   {
99     return name.find (':') >= name.length () - 2
100       && s.substr (0, name.length ()) == name;
101   }
102 public:
103   static Factory& Instance()
104   {
105     static Factory instance;
106     return instance;
107   }
108   void Register(const std::string& name, Create_t create)
109   {
110     m_Tests[name] = create;
111   }
112   size_t Fail () { return m_fail; }
113   void List(const std::string& name)
114   {
115     for(Tests_t::const_iterator it = m_Tests.begin(); it != m_Tests.end(); ++it)
116     {
117       if(name.empty () || it->first == name
118          || EqualsSuiteName (name, it->first))
119         std::cout << it->first << std::endl;
120     }
121   }
122   void Run(const std::string& name)
123   {
124     for(Tests_t::const_iterator it = m_Tests.begin(); it != m_Tests.end(); ++it)
125     {
126       if("All" == name || it->first == name
127          || EqualsSuiteName (name, it->first))
128       {
129         try
130         {
131           std::cout << std::endl << it->first << ' ' << std::flush;
132           {
133             std::auto_ptr<ITest> test(it->second());
134           }
135           std::cout << "[OK]" << std::flush;
136           ++m_pass;
137         }
138         catch(const std::exception& e)
139         {
140           std::cout << "[FAIL]\n  " << e.what() << std::flush;
141           ++m_fail;
142         }
143         catch(...)
144         {
145           std::cout << "[FAIL]\n  unknown exception" << std::flush;
146           ++m_fail;
147         }
148       }
149     }
150   }
151   void Report ()
152   {
153     const size_t size = m_Tests.size();
154     std::cout << std::endl;
155     std::cout << "[TOTAL](" << m_pass + m_fail << '/' << size << ")" << std::endl;
156     std::cout << "[OK](" << m_pass << '/' << size << ")" << std::endl;
157     if (m_fail)
158       std::cout << "[FAIL](" << m_fail << '/' << size << ")" << std::endl;
159   }
160   int Main (int argc, const char* argv[])
161   {
162     if(argc > 1
163        && (std::string(argv[1]) == "-h" || std::string(argv[1]) == "--help"))
164     {
165       std::cout << "Yaffut - Yet Another Framework For Unit Testing.\n\n"
166         "Usage: yaffut [OPTION] [Suite:|Suite::Test]...\n\n"
167         "Options:\n"
168         "  -h, --help  show this help\n"
169         "  -l, --list  list test cases" << std::endl;
170       return 0;
171     }
172     if(argc > 1
173        && (std::string(argv[1]) == "-l" || std::string(argv[1]) == "--list"))
174     {
175       Factory::Instance().List(argc > 2 ? argv[2] : "");
176       return 0;
177     }
178
179     const char* all[] = {"All"};
180     const char** test = all;
181     int num = 1;
182     if(1 < argc)
183     {
184       test = argv;
185       num = argc;
186     }
187     
188     for(int i = 0; i < num; ++i)
189     {
190       try
191       {
192         Factory::Instance().Run(test[i]);
193       }
194       catch(const std::exception& e)
195       {
196         std::clog << e.what() << std::endl;
197       }
198     }
199
200     Factory::Instance().Report ();
201     return Factory::Instance().Fail ();
202   }
203 };
204
205 class failure: public std::exception
206 {
207   std::string failure_;
208 public:
209   template <typename Expected, typename Actual>
210   failure(const Expected& e, Actual& a, const char* at = "", const char* expr = "")
211   {
212     std::ostringstream os;
213     os << at << expr << "\nexpected: "
214        << "(" << demangle<Expected>() << ") " << e
215        << " != actual: " << "(" << demangle<Actual>() << ") " << a;
216     failure_ = os.str();
217   }
218   failure(const char* at = "", const char* expr = "")
219   {
220     std::ostringstream os;
221     os << at << expr;
222     failure_ = os.str();
223   }
224   virtual ~failure() throw() {}
225   virtual const char* what() const throw() { return failure_.c_str(); }
226 };
227
228 template <typename Suite, typename Case>
229 struct Registrator
230 {
231   Registrator()
232   {
233     Factory::Instance().Register(TestName(), Create);
234   }
235   const std::string& TestName()
236   {
237     static const std::string name(demangle<Suite>() + "::" + demangle<Case>());
238     return name;
239   }
240   static ITest* Create()
241   {
242     return new Case;
243   }
244 };
245
246 template <typename Case>
247 struct Registrator<Case, void>
248 {
249   Registrator()
250   {
251     Factory::Instance().Register(TestName(), Create);
252   }
253   const std::string& TestName()
254   {
255     static const std::string name ("::" + demangle<Case>());
256     return name;
257   }
258   static ITest* Create()
259   {
260     return new Case;
261   }
262 };
263
264
265 template <typename Suite, typename Case = void>
266 struct Test: public ITest, public virtual Suite
267 {
268   static Registrator<Suite, Case> s_Registrator;
269   Test(): Suite()
270   {
271     Registrator<Suite, Case>* r = &s_Registrator;
272     r = 0;
273   }
274   template <typename E, typename T>
275   void assert_throw(void(T::*mf)(), const char* at)
276   {
277     try
278     {
279       (dynamic_cast<T*> (this)->*mf)();
280       throw yaffut::failure (at, "statement failed to throw");
281     }
282     catch(const E&){}
283   }
284 };
285
286 template <typename Suite, typename Case>
287 Registrator<Suite, Case> Test<Suite, Case>::s_Registrator;
288
289
290 template <typename Case>
291 struct Test<Case, void>: public ITest
292 {
293   static Registrator<Case, void> s_Registrator;
294   Test()
295   {
296     Registrator<Case, void>* r = &s_Registrator;
297     r = 0;
298   }
299   template <typename E, typename T>
300   void assert_throw(void(T::*mf)(), const char* at)
301   {
302     try
303     {
304       (dynamic_cast<T*> (this)->*mf)();
305       throw yaffut::failure (at, "statement failed to throw");
306     }
307     catch(const E&){}
308   }
309 };
310
311 template <typename Case>
312 Registrator<Case, void> Test<Case, void>::s_Registrator;
313
314
315
316 template <typename Expected, typename Actual>
317 void equal(const Expected& e, const Actual& a, const char* at = "", const char* expr = "")
318 {
319   if(e != a)
320   {
321     throw failure(e, a, at, expr);
322   }
323 }
324 inline void equal(double e, double a, const char* at = "", const char* expr = "")
325 {
326   double max = std::abs(std::max(e, a));
327   max = max < 1.0 ? 1.0 : max;
328   if(std::abs(e - a) > std::numeric_limits<double>::epsilon() * max)
329   {
330     throw failure(e, a, at, expr);
331   }
332 }
333 inline void check(bool b, const char* at = "", const char* expr = "")
334
335   if(!b)
336   {
337     throw failure(at, expr);
338   }
339 }
340
341 template <typename Expected, typename Actual>
342 void unequal(const Expected& e, const Actual& a, const char* at = "", const char* expr = "")
343 {
344   if(e == a)
345   {
346     throw failure(e, a, at, expr);
347   }
348 }
349 inline void unequal(double e, double a, const char* at = "", const char* expr = "")
350 {
351   double max = std::abs(std::max(e, a));
352   max = max < 1.0 ? 1.0 : max;
353   if(std::abs(e - a) <= std::numeric_limits<double>::epsilon() * max)
354   {
355     throw failure(e, a, at, expr);
356   }
357 }
358
359 template <typename T>
360 void fail(const T& expr, const char* at = "")
361 {
362   std::ostringstream os;
363   os << expr;
364   throw failure(at, os.str().c_str());
365 }
366
367 template <typename E>
368 void assert_throw(void(*pf)(), const char* at = "")
369 {
370   try
371   {
372     (*pf)();
373     throw failure (at, " statement failed to throw");
374   }
375   catch(const E&){}
376 }
377
378 }
379
380 //and for those who prefer macro obscurity over typing
381 #define TEST(Suite, Case)\
382   namespace { struct Case: public yaffut::Test<Suite, Case>{ Case(); }; } \
383   template struct yaffut::Test<Suite, Case>; Case::Case()
384
385 #define FUNC(Case)\
386   namespace { struct Case: public yaffut::Test<Case>{ Case(); }; } \
387   template struct yaffut::Test<Case>; Case::Case()
388
389 #ifdef YAFFUT_MAIN
390
391 #include <iostream>
392
393 int main(int argc, const char* argv[])
394 {
395   std::cout << "pid(" << getpid() << ")" << std::endl;
396   return yaffut::Factory::Instance().Main (argc, argv);
397 };
398
399 #endif /* YAFFUT_MAIN */
400
401 #define yaffut_main(argc, argv) yaffut::Factory::Instance().Main (argc, argv)
402
403 #endif