]> git.llucax.com Git - software/mutest.git/commitdiff
Add some C++ support
authorLeandro Lucarella <llucarella@integratech.com.ar>
Fri, 12 Dec 2008 18:28:43 +0000 (16:28 -0200)
committerLeandro Lucarella <llucax@gmail.com>
Fri, 12 Dec 2008 21:08:27 +0000 (19:08 -0200)
This patch add some C++ support by catching exceptions in mu_check() and
mu_ensure() macros (when compiled with a C++ compiler, of course). In
addition to this, it adds 2 new macros for checking that some expression
throws a particular exception: mu_echeck() and mu_eensure().

A sample test suite for the new features is added too.

mutest.h
sample/Makefile
sample/exception_test.cpp [new file with mode: 0644]

index 2fd200458858536e3d4581f4d69b086230ce69d8..9afbac0c8d500c05a32a9240a5ed1593866fcf97 100644 (file)
--- a/mutest.h
+++ b/mutest.h
@@ -52,16 +52,47 @@ enum {
 /* modify the internal state so a success gets counted */
 #define mutest_count_suc ++mutest_passed_checks;
 
 /* 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"); \
 /* 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"); \
-               if (exp) mutest_count_suc \
-               else { \
-                       mutest_count_err \
-                       mu_printerr(name "(" #exp ")", action); \
-                       final; \
-               } \
+               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 */
        } while (0)
 
 /* check that an expression evaluates to true, continue if the check fails */
@@ -73,6 +104,49 @@ enum {
  */
 #define mu_ensure(exp) mu_check_base(exp, "mu_ensure", "aborting", return)
 
  */
 #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 */
 
 /*
 #ifndef MUTEST_PY /* we are using the C implementation */
 
 /*
index 19bf4c3d1367dd37813322c37f710c46dd117be8..a225aa09fbc0b28aebce2556ce8ff0c262d09b1e 100644 (file)
 #
 
 # Show the tests summary
 #
 
 # Show the tests summary
-V=-v
+V = -v
+
+# Set to 0 if you don't want to compile the C++ test suite
+CPP_SUITE = 1
 
 CFLAGS = -Wall -std=c89
 
 CFLAGS = -Wall -std=c89
+CXXFLAGS = -Wall -std=c++98
+LD = $(CC)
 
 TARGET = tester
 RUNNER_SRC = test_suite_runner.c
 
 TARGET = tester
 RUNNER_SRC = test_suite_runner.c
@@ -29,12 +34,17 @@ RUNNER_OBJ = $(RUNNER_SRC:.c=.o)
 ALL_OBJS = $(RUNNER_OBJ) $(OBJS) $(TEST_OBJS) $(MUTEST_OBJ)
 TEST_SOS = $(TEST_OBJS:.o=.so)
 
 ALL_OBJS = $(RUNNER_OBJ) $(OBJS) $(TEST_OBJS) $(MUTEST_OBJ)
 TEST_SOS = $(TEST_OBJS:.o=.so)
 
+ifeq ($(CPP_SUITE), 1)
+TEST_OBJS += exception_test.o
+LD = $(CXX)
+endif
+
 all: $(TARGET)
 
 py: $(TEST_SOS)
 
 $(TARGET): $(ALL_OBJS)
 all: $(TARGET)
 
 py: $(TEST_SOS)
 
 $(TARGET): $(ALL_OBJS)
-       $(CC) $(LDFLAGS) -o $@ $^
+       $(LD) $(LDFLAGS) -o $@ $^
 
 $(RUNNER_SRC): $(MKMUTEST_OBJ) $(MUTEST_H) $(TEST_OBJS)
        $(MKMUTEST) $(MUTEST_H) $(TEST_OBJS) > $@
 
 $(RUNNER_SRC): $(MKMUTEST_OBJ) $(MUTEST_H) $(TEST_OBJS)
        $(MKMUTEST) $(MUTEST_H) $(TEST_OBJS) > $@
@@ -58,6 +68,9 @@ clean:
 .c.so:
        $(CC) $(CFLAGS) $(LDFLAGS) -DMUTEST_PY -fPIC -shared -o $@ $^
 
 .c.so:
        $(CC) $(CFLAGS) $(LDFLAGS) -DMUTEST_PY -fPIC -shared -o $@ $^
 
+.cpp.so:
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) -DMUTEST_PY -fPIC -shared -o $@ $^
+
 .SUFFIXES: .so
 
 .PHONY: all test clean
 .SUFFIXES: .so
 
 .PHONY: all test clean
diff --git a/sample/exception_test.cpp b/sample/exception_test.cpp
new file mode 100644 (file)
index 0000000..028a03b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 is a C++ module test suite. It shows how to use checks involving
+ * exceptions.
+ *
+ * Please, read the README file for more details.
+ */
+
+#include <stdexcept> // std::out_of_range
+#include <vector> // std::vector
+
+#include "../mutest.h"
+
+extern "C" {
+
+void mu_test_exceptions() {
+       std::vector<int> v(1);
+       // ok
+       mu_check(v.at(0) == 0);
+       // throws! This fails
+       mu_check(v.at(1) == 0);
+       // ok, we expect the exception to be thrown, and it does
+       mu_echeck(std::out_of_range, v.at(1));
+       // fails! We expect this to throw, but it doesn't
+       mu_echeck(std::out_of_range, v.at(0));
+       // fails again, but this time the show is over (note the "ensure")
+       mu_eensure(std::out_of_range, v.at(0));
+       // this will never be executed (it should fail if it is)
+       mu_check(v.empty());
+}
+
+} // extern "C"
+