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