From 0063534515c20ca50b4554442d159a992f32b241 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Fri, 12 Dec 2008 16:28:43 -0200 Subject: [PATCH] Add some C++ support 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 | 86 ++++++++++++++++++++++++++++++++++++--- sample/Makefile | 17 +++++++- sample/exception_test.cpp | 38 +++++++++++++++++ 3 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 sample/exception_test.cpp diff --git a/mutest.h b/mutest.h index 2fd2004..9afbac0 100644 --- 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; +#ifdef __cplusplus + +#include + +/* 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"); \ - 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 */ @@ -73,6 +104,49 @@ enum { */ #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 */ /* diff --git a/sample/Makefile b/sample/Makefile index 19bf4c3..a225aa0 100644 --- a/sample/Makefile +++ b/sample/Makefile @@ -11,9 +11,14 @@ # # 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 +CXXFLAGS = -Wall -std=c++98 +LD = $(CC) 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) +ifeq ($(CPP_SUITE), 1) +TEST_OBJS += exception_test.o +LD = $(CXX) +endif + 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) > $@ @@ -58,6 +68,9 @@ clean: .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 diff --git a/sample/exception_test.cpp b/sample/exception_test.cpp new file mode 100644 index 0000000..028a03b --- /dev/null +++ b/sample/exception_test.cpp @@ -0,0 +1,38 @@ +/* + * This file is part of mutest, a simple micro unit testing framework for C. + * + * mutest was written by Leandro Lucarella 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 // std::out_of_range +#include // std::vector + +#include "../mutest.h" + +extern "C" { + +void mu_test_exceptions() { + std::vector 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" + -- 2.43.0