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