]> git.llucax.com Git - software/mutest.git/blobdiff - mutest.h
Add some C++ support
[software/mutest.git] / mutest.h
index 938918f6449cae707d472b09154cf7f1212d3315..9afbac0c8d500c05a32a9240a5ed1593866fcf97 100644 (file)
--- a/mutest.h
+++ b/mutest.h
@@ -1,3 +1,18 @@
+/*
+ * This file is part of mutest, a simple micro unit testing framework for C.
+ *
+ * mutest was written by Leandro Lucarella <llucax@gmail.com> and is released
+ * under the BOLA license, please see the LICENSE file or visit:
+ * http://blitiri.com.ar/p/bola/
+ *
+ * This header file should be included in the source files that will make up
+ * a test suite. It's used for both C and Python implementation, but when
+ * using the Python implementation you should define the MUTEST_PY macro.
+ * If you implement your mu_run_suites() function yourself, you probably will
+ * need to include this header too (see mkmutest).
+ *
+ * Please, read the README file for more details.
+ */
 
 #include <stdio.h> /* fprintf() */
 
 
 #include <stdio.h> /* fprintf() */
 
@@ -5,44 +20,6 @@
 extern "C" {
 #endif
 
 extern "C" {
 #endif
 
-/* check that an expression evaluates to true, continue if the check fails */
-#define mu_check(exp) \
-       do { \
-               mu_print(MU_CHECK, "\t\t* Checking mu_check(%s)...\n", #exp); \
-               if (exp) ++mutest_passed_checks; \
-               else { \
-                       ++mutest_failed_checks; \
-                       mutest_case_failed = 1; \
-                       mu_print(MU_ERROR, "%s:%d: mu_check(%s) failed, " \
-                                       "resuming test case\n", __FILE__, \
-                                       __LINE__, #exp); \
-               } \
-       } while (0)
-
-/*
- * ensure that an expression evaluates to true, abort the current test
- * case if the check fails
- */
-#define mu_ensure(exp) \
-       do { \
-               mu_print(MU_CHECK, "\t\t* Checking mu_ensure(%s)...\n", #exp);\
-               if (exp) ++mutest_passed_checks; \
-               else { \
-                       ++mutest_failed_checks; \
-                       mutest_case_failed = 1; \
-                       mu_print(MU_ERROR, "%s:%d: mu_ensure(%s) failed, " \
-                                       "aborting test case\n", __FILE__, \
-                                       __LINE__, #exp); \
-                       return; \
-               } \
-       } while (0)
-
-/*
- * you don't need to pay any attention to what's next, unless you want to do
- * some customization, of course, in which case, you're encouraged to take
- * a look an play =)
- */
-
 /* verbosity level (each level shows all the previous levels too) */
 enum {
        MU_QUIET = 0, /* be completely quiet */
 /* verbosity level (each level shows all the previous levels too) */
 enum {
        MU_QUIET = 0, /* be completely quiet */
@@ -64,6 +41,114 @@ enum {
                } \
        } while (0)
 
                } \
        } while (0)
 
+/* print an error message */
+#define mu_printerr(name, action) \
+               mu_print(MU_ERROR, __FILE__ ":%d: " name " failed, "\
+                               action " test case\n", __LINE__);
+
+/* modify the internal state so a failure gets counted */
+#define mutest_count_err ++mutest_failed_checks; mutest_case_failed = 1;
+
+/* modify the internal state so a success gets counted */
+#define mutest_count_suc ++mutest_passed_checks;
+
+#ifdef __cplusplus
+
+#include <exception>
+
+/* print an error message triggered by a C++ exception */
+#define mu_printex(name, action, ex) \
+               mu_print(MU_ERROR, __FILE__ ":%d: " name " failed, " \
+                               "exception thrown (%s), " action \
+                               " test case\n", __LINE__, ex);
+
+#define mutest_try try {
+#define mutest_catch(name, action, final) \
+               } catch (const std::exception& e) { \
+                       mutest_count_err \
+                       mu_printex(name, action, e.what()); \
+                       final; \
+               } catch (...) { \
+                       mutest_count_err \
+                       mu_printex(name, action, "[unknown]"); \
+                       final; \
+               }
+
+#else /* !__cplusplus */
+
+#define mutest_try
+#define mutest_catch(name, action, exp)
+
+#endif /* __cplusplus */
+
+/* check that an expression evaluates to true, continue if the check fails */
+#define mu_check_base(exp, name, action, final) \
+       do { \
+               mu_print(MU_CHECK, "\t\t* Checking " name "(" #exp ")...\n"); \
+               mutest_try \
+                       if (exp) mutest_count_suc \
+                       else { \
+                               mutest_count_err \
+                               mu_printerr(name "(" #exp ")", action); \
+                               final; \
+                       } \
+               mutest_catch(name, action, final) \
+       } while (0)
+
+/* check that an expression evaluates to true, continue if the check fails */
+#define mu_check(exp) mu_check_base(exp, "mu_check", "resuming", continue)
+
+/*
+ * ensure that an expression evaluates to true, abort the current test
+ * case if the check fails
+ */
+#define mu_ensure(exp) mu_check_base(exp, "mu_ensure", "aborting", return)
+
+#ifdef __cplusplus
+
+#define mu_echeck_base(ex, exp, name, action, final) \
+       do { \
+               mu_print(MU_CHECK, "\t\t* Checking " name "(" #ex ", " #exp \
+                               ")...\n"); \
+               try { \
+                       exp; \
+                       mutest_count_err \
+                       mu_printerr(name "(" #ex ", " #exp ")", \
+                                       "no exception thrown, " action); \
+                       final; \
+               } catch (const ex& e) { \
+                       mutest_count_suc \
+               } catch (const std::exception& e) { \
+                       mutest_count_err \
+                       mu_printex(name "(" #ex ", " #exp ")", action, \
+                                       e.what()); \
+                       final; \
+               } catch (...) { \
+                       mutest_count_err \
+                       mu_printex(name "(" #ex ", " #exp ")", action, \
+                                       "[unknown]"); \
+                       final; \
+               } \
+       } while (0)
+
+/*
+ * check that an expression throws a particular exception, continue if the
+ * check fails
+ */
+#define mu_echeck(ex, exp) \
+       mu_echeck_base(ex, exp, "mu_echeck", "resuming", continue)
+
+/*
+ * ensure that an expression throws a particular exception, abort the current
+ * test case if the check fails
+ */
+#define mu_eensure(ex, exp) \
+       mu_echeck_base(ex, exp, "mu_eensure", "aborting", return)
+
+#endif /* __cplusplus */
+
+#ifndef MUTEST_PY /* we are using the C implementation */
+
 /*
  * this function implements the test suites execution, you should generate
  * a module with this function using mkmutest, or take a look to that script
 /*
  * this function implements the test suites execution, you should generate
  * a module with this function using mkmutest, or take a look to that script
@@ -136,6 +221,27 @@ extern int mutest_passed_checks;
 /* verbosity */
 extern int mutest_verbose_level;
 
 /* verbosity */
 extern int mutest_verbose_level;
 
+#else /* MUTEST_PY is defined, using the Python implementation */
+
+/* this increments when the "API" changes, it's just for sanity check */
+int mutest_api_version = 1;
+
+int mutest_case_failed; /* unused, for C implementation compatibility */
+
+int mutest_passed_checks;
+int mutest_failed_checks;
+void mutest_reset_counters() {
+       mutest_passed_checks = 0;
+       mutest_failed_checks = 0;
+}
+
+int mutest_verbose_level = MU_ERROR;
+void mutest_set_verbose_level(int val) {
+       mutest_verbose_level = val;
+}
+
+#endif /* MUTEST_PY */
+
 #ifdef __cplusplus
 }
 #endif
 #ifdef __cplusplus
 }
 #endif