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