--- /dev/null
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#define TEST
+#include "test_suite.h"
+
+static struct options_ {
+ unsigned int verbosity;
+} options_ = {
+ .verbosity = 0,
+};
+
+void test_verbose(const char *fmt, ...) {
+ va_list ap;
+
+ if (options_.verbosity < 1)
+ return;
+
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+}
+
+void test_info(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+}
+
+void test_error(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static
+int run_test_(test_t *t) {
+ int r = t->test_fn(t->test_data, test_suite_data);
+ test_info("-- test '%s': %s --\n", t->test_name, r ? "FAILED" : "OK");
+ return r;
+}
+
+int main(int argc, char **argv) {
+ test_t *t;
+ int c;
+
+ while ( (c = getopt(argc, argv, "vl")) != EOF ) {
+ switch (c) {
+ case 'v':
+ options_.verbosity++;
+ break;
+ case 'l':
+ test_info("available test suites:\n");
+ for (t = test_suite; t->test_name; t++) {
+ test_info("\t%s\n", t->test_name);
+ }
+ exit(EXIT_SUCCESS);
+ default:
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (test_suite_pre(test_suite_data)) {
+ test_error("%s: %s", "test_suite_pre", "FAILED");
+ exit(EXIT_FAILURE);
+ }
+
+ if (argc - optind) {
+ while (argc - optind) {
+ for (t = test_suite; t->test_name && strcmp(argv[optind], t->test_name); t++) {}
+ if (t->test_name == NULL) {
+ test_error("unknown suite '%s'\n", argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ if (run_test_(t))
+ exit(EXIT_FAILURE);
+ optind++;
+ }
+ } else {
+ for (t = test_suite; t->test_name; t++) {
+ if (run_test_(t))
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (test_suite_post(test_suite_data)) {
+ test_error("%s: %s\n", "test_suite_post", "FAILED");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
\ No newline at end of file