]> git.llucax.com Git - software/mutest.git/commitdiff
Factor out most C code from mkmutest to mutest.c
authorLeandro Lucarella <llucarella@integratech.com.ar>
Wed, 10 Dec 2008 15:50:59 +0000 (13:50 -0200)
committerLeandro Lucarella <llucarella@integratech.com.ar>
Fri, 12 Dec 2008 12:54:34 +0000 (10:54 -0200)
This makes easier to improve the tester code, without having to code it as
a shell script embedded string. Now the only generated code is the one
that runs the test suites. You can also implement your own test suites
execution function; just write it in a separated C module and don't use
the mkmutest generator.

mkmutest
mutest.c [new file with mode: 0644]
mutest.h
sample/Makefile

index 82d71d1c55472450321f62f74f370e5d343db3b1..5e8db827ed26e98594aff3325540603d5fe229fe 100755 (executable)
--- a/mkmutest
+++ b/mkmutest
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 # This file is part of mutest, a micro testing framework for C.
 #
 #
 # Please, read the README file for more details.
 
-TESTER='
-#include <stdio.h> /* printf(), fprintf() */
-
-/* macro for running a single test case */
-#define run_case(name) \
-       do { \
-               if (mutest_verbose > 2) \
-                       printf("\\t- executing test case \"" #name "\"\\n"); \
-               void name(); \
-               mutest_case_name = #name; \
-               name(); \
-               if (mutest_case_failed) { \
-                       ++mutest_failed_cases; \
-                       mutest_suite_failed = 1; \
-               } else ++mutest_passed_cases; \
-               mutest_case_failed = 0; \
-       } while (0)
-
-/* globals for managing test suites */
-static const char* mutest_suite_name;
-static int mutest_failed_suites;
-static int mutest_passed_suites;
-static int mutest_suite_failed;
-
-/* globals for managing test cases */
-static const char* mutest_case_name;
-static int mutest_failed_cases;
-static int mutest_passed_cases;
-int mutest_case_failed;
-
-/* globals for managing checks */
-int mutest_failed_checks;
-int mutest_passed_checks;
-
-/*
- * verbosity level (each level shows all the previous levels too):
- *   0 shows only errors
- *   1 shows a summary
- *   2 shows test suites progress
- *   3 shows test cases progress
- */
-int mutest_verbose;
-
-static void run_suites();
-
-int main(int argc, char* argv[]) {
-
-       /*
-        * arguments checking, both -v -v and -vv are accepted for setting
-        * verbosity to 2.
-        */
-       while (*++argv)
-               if (strncmp(*argv, "-v", 2) == 0) {
-                       ++mutest_verbose;
-                       char* c = (*argv) + 1;
-                       while (*++c)
-                               if (*c == '"'v'"')
-                                       ++mutest_verbose;
-                               else
-                                       break;
-               }
-
-       run_suites();
-
-       if (mutest_verbose) {
-               printf("\\n");
-               printf("Tests done:\\n");
-               printf("\\t%d test suite(s) passed, %d failed.\\n",
-                               mutest_passed_suites,
-                               mutest_failed_suites);
-               printf("\\t%d test case(s) passed, %d failed.\\n",
-                               mutest_passed_cases,
-                               mutest_failed_cases);
-               printf("\\t%d check(s) passed, %d failed.\\n",
-                               mutest_passed_checks, mutest_failed_checks);
-       }
-
-       return mutest_failed_checks ? 1 : 0;
-}
-
-'
 
 # the trick here is getting all the test cases present in an object file using
 # nm. All the tests must take and return void, start with "mutest_" and, of
 # course, should not be static, which leads to a small limitation: all test
 # cases must have unique names, even across test suites.
-echo "$TESTER"
-echo "static void run_suites() {"
+
+# the first argument should be mutest.h
+mutest_h="$1"
+shift
+echo "#include \"$mutest_h\""
+echo "void mu_run_suites() {"
 echo
 for file in "$@"
 do
-       suite="`basename $file .o`"
-       echo "\tmutest_suite_name = \"$suite\";"
-       echo "\tif (mutest_verbose > 1)"
-       echo "\t\tprintf(\"\\\\nRunning suite \\\"$suite\\\"\\\\n\");"
+       suite="`basename "$file" .o | sed 's/\"/\\\\\"/g'`"
+       echo -e '\tmutest_suite_name = "'"$suite"'";'
+       echo -e '\tmu_print(MU_SUITE, "\\nRunning suite \"'"$suite"'\"\\n");'
        for symbol in `nm -p "$file" \
                        | egrep '^[[:xdigit:]]{8} T mu_test_\w+$' \
                        | cut -c12-`
        do
-               echo "\trun_case($symbol);"
+               echo -e "\tmu_run_case($symbol);"
        done
-       echo "\tif (mutest_suite_failed) ++mutest_failed_suites;"
-       echo "\telse                     ++mutest_passed_suites;"
-       echo "\tmutest_suite_failed = 0;"
+       echo -e "\tif (mutest_suite_failed) ++mutest_failed_suites;"
+       echo -e "\telse                     ++mutest_passed_suites;"
+       echo -e "\tmutest_suite_failed = 0;"
        echo
 done
 echo "}"
diff --git a/mutest.c b/mutest.c
new file mode 100644 (file)
index 0000000..2971480
--- /dev/null
+++ b/mutest.c
@@ -0,0 +1,73 @@
+
+#include "mutest.h" /* MU_* constants, mu_print() */
+#include <stdio.h> /* printf(), fprintf() */
+#include <string.h> /* strncmp() */
+
+/*
+ * note that all global variables are public because they need to be accessed
+ * from other modules, like the test suites or the module implementing
+ * mu_run_suites()
+ */
+
+/* globals for managing test suites */
+const char* mutest_suite_name;
+int mutest_failed_suites;
+int mutest_passed_suites;
+int mutest_suite_failed;
+
+
+/* globals for managing test cases */
+const char* mutest_case_name;
+int mutest_failed_cases;
+int mutest_passed_cases;
+int mutest_case_failed;
+
+
+/* globals for managing checks */
+int mutest_failed_checks;
+int mutest_passed_checks;
+
+
+/* verbosity level, see mutest.h */
+int mutest_verbose_level = 1; /* exported for use in test suites */
+
+
+
+/*
+ * only -v is supported right now, both "-v -v" and "-vv" are accepted for
+ * increasing the verbosity by 2.
+ */
+void parse_args(int argc, char* argv[]) {
+       while (*++argv) {
+               if (strncmp(*argv, "-v", 2) == 0) {
+                       ++mutest_verbose_level;
+                       char* c = (*argv) + 1;
+                       while (*++c) {
+                               if (*c != 'v')
+                                       break;
+                               ++mutest_verbose_level;
+                       }
+               }
+       }
+}
+
+
+int main(int argc, char* argv[]) {
+
+       parse_args(argc, argv);
+
+       mu_run_suites();
+
+       mu_print(MU_SUMMARY, "\n"
+                       "Tests done:\n"
+                       "\t%d test suite(s) passed, %d failed.\n"
+                       "\t%d test case(s) passed, %d failed.\n"
+                       "\t%d check(s) passed, %d failed.\n"
+                       "\n",
+                       mutest_passed_suites, mutest_failed_suites,
+                       mutest_passed_cases, mutest_failed_cases,
+                       mutest_passed_checks, mutest_failed_checks);
+
+       return mutest_failed_checks ? 1 : 0;
+}
+
index e0467e8849fbb67f10fc8e8b550cae22a1f08ce6..1f5561d745a22deef43776c04b37b9f7590200aa 100644 (file)
--- a/mutest.h
+++ b/mutest.h
 
-#include <stdio.h> // fprintf
+#include <stdio.h> /* fprintf() */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-extern int mutest_failed_checks;
-extern int mutest_passed_checks;
-extern int mutest_case_failed;
-
+/* 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; \
-                       fprintf(stderr, "%s:%d: mu_check(%s) failed, " \
+                       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; \
-                       fprintf(stderr, "%s:%d: mu_ensure(%s) failed, " \
+                       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 */
+       MU_ERROR,     /* shows errors only */
+       MU_SUMMARY,   /* shows a summary */
+       MU_SUITE,     /* shows test suites progress */
+       MU_CASE,      /* shows test cases progress */
+       MU_CHECK      /* shows the current running check */
+};
+
+/* print a message according to the verbosity level */
+#define mu_print(level, ...) \
+       do { \
+               if (mutest_verbose_level >= level) { \
+                       if (mutest_verbose_level == MU_ERROR) \
+                               fprintf(stderr, __VA_ARGS__); \
+                       else \
+                               fprintf(stdout, __VA_ARGS__); \
+               } \
+       } while (0)
+
+/*
+ * this function implements the test suites execution, you should generate
+ * a module with this function using mkmutest, or take a look to that script
+ * if you want to implement your own customized version */
+void mu_run_suites();
+
+/* macro for running a single test case */
+#ifndef mu_run_case
+#define mu_run_case(name) \
+       do { \
+               mu_print(MU_CASE, "\t- executing test case \"" #name "\"\n"); \
+               void name(); \
+               mutest_case_name = #name; \
+               name(); \
+               if (mutest_case_failed) { \
+                       ++mutest_failed_cases; \
+                       mutest_suite_failed = 1; \
+               } else ++mutest_passed_cases; \
+               mutest_case_failed = 0; \
+       } while (0)
+#endif /* mu_run_case */
+
+/*
+ * mutest exported variables for internal use, do not use directly unless you
+ *  know what you're doing.
+ */
+extern const char* mutest_suite_name;
+extern int mutest_failed_suites;
+extern int mutest_passed_suites;
+extern int mutest_suite_failed;
+/* test cases */
+extern const char* mutest_case_name;
+extern int mutest_failed_cases;
+extern int mutest_passed_cases;
+extern int mutest_case_failed;
+/* checks */
+extern int mutest_failed_checks;
+extern int mutest_passed_checks;
+/* verbosity */
+extern int mutest_verbose_level;
+
 #ifdef __cplusplus
 }
 #endif
index d3526549a05b87581af5f4da9a830368823cfa5e..e67a320033c789672ba526188706bbfb5509cfed 100644 (file)
@@ -2,13 +2,16 @@
 # Show the tests summary
 V=-v
 
+CFLAGS = -Wall -std=c89
+
 TARGET=tester
 
 OBJS = factorial.o sum.o
 TESTS = factorial_test.o sum_test.o
+MUTEST = mutest.o
 TESTER = tester.o
 SO = factorial.so sum.so
-ALL = $(TESTER) $(OBJS) $(TESTS)
+ALL = $(TESTER) $(OBJS) $(TESTS) $(MUTEST)
 
 all: $(TARGET)
 
@@ -16,13 +19,16 @@ py: $(SO)
 
 $(TARGET): $(ALL)
 
-$(TESTER): $(OBJS) $(TESTS)
-       ../mkmutest $(TESTS) | gcc -xc -o $(TESTER) -c -
+$(TESTER): $(OBJS) $(TESTS) $(MUTEST)
+       ../mkmutest ../mutest.h $(TESTS) | gcc -xc -o $(TESTER) -c -
 
 factorial.so: factorial_test.c
 
 sum.so: sum_test.c
 
+$(MUTEST): ../mutest.c
+       $(CC) $(CFLAGS) -c -o mutest.o $^
+
 test: $(TARGET)
        ./$(TARGET) $(V)