--- /dev/null
+I don't like licenses, because I don't like having to worry about all this
+legal stuff just for a simple piece of software I don't really mind anyone
+using. But I also believe that it's important that people share and give back;
+so I'm placing this work under the following license.
+
+
+BOLA - Buena Onda License Agreement (v1.0)
+------------------------------------------
+
+This work is provided 'as-is', without any express or implied warranty. In no
+event will the authors be held liable for any damages arising from the use of
+this work.
+
+To all effects and purposes, this work is to be considered Public Domain.
+
+
+However, if you want to be "Buena onda", you should:
+
+1. Not take credit for it, and give proper recognition to the authors.
+2. Share your modifications, so everybody benefits from them.
+4. Do something nice for the authors.
+5. Help someone who needs it: sign up for some volunteer work or help your
+ neighbour paint the house.
+6. Don't waste. Anything, but specially energy that comes from natural
+ non-renewable resources. Extra points if you discover or invent something
+ to replace them.
+7. Be tolerant. Everything that's good in nature comes from cooperation.
+
+The order is important, and the further you go the more "Buena onda" you are.
+Make the world a better place: be "Buena onda".
--- /dev/null
+#!/bin/sh
+
+# This file is part of mutest, a micro testing framework for C.
+#
+# mutest is under the BOLA license, please see the LICENSE file or visit
+# http://blitiri.com.ar/p/bola/
+#
+# This is a simple script to generate a C file that runs all the test cases
+# present in .o files passed as arguments.
+#
+# 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() {"
+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\");"
+ for symbol in `nm -p "$file" \
+ | egrep '^[[:xdigit:]]{8} T mu_test_\w+$' \
+ | cut -c12-`
+ do
+ echo "\trun_case($symbol);"
+ done
+ echo "\tif (mutest_suite_failed) ++mutest_failed_suites;"
+ echo "\telse ++mutest_passed_suites;"
+ echo "\tmutest_suite_failed = 0;"
+ echo
+done
+echo "}"
+
--- /dev/null
+
+#include <stdio.h> // fprintf
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int mutest_failed_checks;
+extern int mutest_passed_checks;
+extern int mutest_case_failed;
+
+#define mu_check(exp) \
+ do { \
+ if (exp) ++mutest_passed_checks; \
+ else { \
+ ++mutest_failed_checks; \
+ mutest_case_failed = 1; \
+ fprintf(stderr, "%s:%d: mu_check(%s) failed, " \
+ "resuming test case\n", __FILE__, \
+ __LINE__, #exp); \
+ } \
+ } while (0)
+
+#define mu_ensure(exp) \
+ do { \
+ if (exp) ++mutest_passed_checks; \
+ else { \
+ ++mutest_failed_checks; \
+ mutest_case_failed = 1; \
+ fprintf(stderr, "%s:%d: mu_ensure(%s) failed, " \
+ "aborting test case\n", __FILE__, \
+ __LINE__, #exp); \
+ return; \
+ } \
+ } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null
+*.o
+tester
--- /dev/null
+
+# Show the tests summary
+V=-v
+
+TARGET=tester
+
+OBJS = factorial.o sum.o
+TESTS = factorial_test.o sum_test.o
+TESTER = tester.o
+ALL = $(TESTER) $(OBJS) $(TESTS)
+
+all: $(TARGET)
+
+$(TARGET): $(ALL)
+
+$(TESTER): $(OBJS) $(TESTS)
+ ../mkmutest $(TESTS) | gcc -xc -o $(TESTER) -c -
+
+test: $(TARGET)
+ ./$(TARGET) $(V)
+
+clean:
+ $(RM) $(TARGET) $(ALL)
+
+.PHONY: all test clean
+
--- /dev/null
+
+Just take a look to all the files and find out. To try it out, you can type:
+make test
+
+If you want extra verbosity, try:
+make test V=-vvv
+
+
--- /dev/null
+
+unsigned factorial(unsigned x) {
+ if (x <= 1)
+ return 1;
+ return x * factorial(x-1);
+}
+
--- /dev/null
+
+int factorial(int);
+
--- /dev/null
+
+#include "../mutest.h"
+#include "factorial.h"
+
+void mu_test_factorial_zero() {
+ unsigned x = factorial(0);
+ mu_check(x == 1);
+}
+
+void mu_test_factorial_one() {
+ unsigned x = factorial(1);
+ /* this test is wrong on purpose, to see how it fails */
+ mu_check(x == 2);
+}
+
+void mu_test_factorial_positive() {
+ unsigned x = factorial(2);
+ /* this test is wrong on purpose, to see how it fails */
+ mu_check(x == 3);
+
+ x = factorial(3);
+ /* we don't want to continue if this fails, because the next result
+ * depends on this one. This one will succeed. */
+ mu_ensure(x == 6);
+
+ x = factorial(x);
+ mu_check(x == 720);
+
+ x = factorial(4);
+ mu_ensure(x == 6); /* same as before, but this one will fail. */
+
+ x = factorial(x-15); /* and this will never be executed */
+ mu_check(x == 362881); /* but if excecuted, will fail */
+}
+
--- /dev/null
+
+int sum(int x, int y) {
+ return x + y;
+}
+
--- /dev/null
+
+int sum(int, int);
+
--- /dev/null
+
+/* see factorial_test.c for more complete examples, this file is mostly to show
+ * how to have multiple test suites, and a test suite that succeed. */
+
+#include "../mutest.h"
+#include "sum.h"
+
+void mu_test_sum() {
+ mu_check(sum(4, 5) == 9);
+ mu_check(sum(-4, -5) == -9);
+ mu_check(sum(0, 0) == 0);
+ mu_check(sum(1, -1) == 0);
+}
+