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