Added some unit tests for some of the utility functions.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Tue, 15 Jun 2010 23:31:01 +0000 (00:31 +0100)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Tue, 15 Jun 2010 23:31:01 +0000 (00:31 +0100)
Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
makefile
src/ag_test.c [new file with mode: 0644]
src/unittest.h [new file with mode: 0644]

index 82cf0771ec3ad95d732debcf412a418f5e26232f..66f4e651302762d065179b16e375800181d81d7e 100755 (executable)
--- a/makefile
+++ b/makefile
@@ -1,27 +1,33 @@
-LFLAGS=-Wall -funroll-loops -fomit-frame-pointer -pipe -O9
-CFLAGS=-Wall `sdl-config --cflags --libs` -funroll-loops -fomit-frame-pointer -pipe -O9 -lSDL_mixer
 CC=gcc
+LD=gcc
+CFLAGS=-g -Wall `sdl-config --cflags`
+CFLAG_OPTS=-funroll-loops -fomit-frame-pointer
+LDFLAGS=`sdl-config --libs` -lSDL_mixer
 
 C_FILES=src/dlb.c src/linked.c src/sprite.c src/ag.c
 OBJ_FILES=src/dlb.o src/linked.o src/sprite.o src/ag.o
+TEST_OBJS=$(OBJ_FILES:src/ag.o=src/ag_test.o)
 OUT_FILE=ag
 
 all:ag
 
 ag: $(OBJ_FILES)
-       $(CC) $(CFLAGS) -o $(OUT_FILE) $(OBJ_FILES)
+       $(LD) $(LDFLAGS) -o $@ $^
+
+ag_test: $(TEST_OBJS)
+       $(LD) $(LDFLAGS) -o $@ $^
 
 src/dlb.o: src/dlb.c
-       $(CC) $(LFLAGS) -c -o $@ $^
+       $(CC) $(CFLAGS) -c -o $@ $^
 
 src/linked.o: src/linked.c
-       $(CC) $(LFLAGS) -c -o $@ $^
-       
+       $(CC) $(CFLAGS) -c -o $@ $^
+
 src/sprite.o: src/sprite.c
-       $(CC) $(LFLAGS) -c -o $@ $^
+       $(CC) $(CFLAGS) -c -o $@ $^
 
 src/ag.o: src/ag.c
-       $(CC) $(LFLAGS) -c -o $@ $^
+       $(CC) $(CFLAGS) -c -o $@ $^
 
 clean:
        rm -f src/*.o
diff --git a/src/ag_test.c b/src/ag_test.c
new file mode 100644 (file)
index 0000000..6bea8a4
--- /dev/null
@@ -0,0 +1,80 @@
+#define UNIT_TEST
+#include "unittest.h"
+#define main ag_main
+#include "ag.c"
+#undef main
+
+static int test_nextBlank()
+{
+    char a[7] = {'a','b',SPACE_CHAR,'c',SPACE_CHAR,'d', 0};
+    test_equals_int("nextBlank", 3, nextBlank(a));
+    test_equals_int("nextBlank substr", 2, nextBlank(a+3));
+    test_equals_int("nextBlank no-blanks", 0, nextBlank("abcdef"));
+    test_equals_int("nextBlank zero-length", 0, nextBlank(""));
+    return 0;
+}
+
+static int test_shiftLeftKill()
+{
+    char a[7] = { 'a','b','c','d','e','f', 0 };
+    test_equals_str("shiftLeftKill", "bcdef", shiftLeftKill(a));
+    test_equals_str("shiftLeftKill const str", "bcdef", shiftLeftKill("abcdef"));
+    return 0;
+}
+
+static int test_shiftLeft()
+{
+    char a[7] = { 'a','b','c','d','e','f', 0 };
+    char b[2] = { 'a', 0 };
+    test_equals_str("shiftLeft string", "bcdefa", shiftLeft(a));
+    test_equals_str("shiftLeft short string", "a", shiftLeft(b));
+    return 0;
+}
+
+static int test_swapChars()
+{
+    char a[7] = { 'a','b','c','d','e','f', 0 };
+    const char *p = a, *q = NULL;
+    test_equals_str("swapChars end", "fbcdea", swapChars(0, 5, a));
+    q = swapChars(2, 3, a);
+    test_equals_str("swapChars inner", "fbdcea", q);
+    test_equals_ptr("swapChars ptr equiv", p, q);
+    return 0;
+}
+
+static int test_revFirstNonSpace()
+{
+    char a[7] = { 'a','b','c','d','e','f', 0 };
+    char b[7] = { 'a','b',SPACE_CHAR,'d','e',SPACE_CHAR, 0 };
+    test_equals_int("rev no space", 6, revFirstNonSpace(a));
+    test_equals_int("rev find space", 5, revFirstNonSpace(b));
+    return 0;
+}
+static int test_whereinstr()
+{
+    test_equals_int("where is b", 1, whereinstr("abcdef",'b'));
+    test_equals_int("where is f", 5, whereinstr("abcdef",'f'));
+    test_equals_int("where is x", 0, whereinstr("abcdef",'x'));
+    return 0;
+}
+
+struct unit_test_t unit_tests[] = {
+    {NULL, test_shiftLeftKill, NULL},
+    {NULL, test_shiftLeft, NULL},
+    {NULL, test_nextBlank, NULL},
+    {NULL, test_swapChars, NULL},
+    {NULL, test_revFirstNonSpace, NULL},
+    {NULL, test_whereinstr, NULL},
+};
+
+int
+main(void)
+{
+    size_t n;
+    for (n = 0; n < sizeof(unit_tests)/sizeof(unit_tests[0]); ++n) {
+        run_tests(&unit_tests[n]);
+    }
+    test_print_results();
+    return 0;
+}
diff --git a/src/unittest.h b/src/unittest.h
new file mode 100644 (file)
index 0000000..9b4e7fc
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Simple C unit testing framework.
+ *
+ * Declare a table containing your tests and call the run_test function
+ * passing in this table. You can declare a setup and teardown function
+ * for each test and provide per-test custom data if needed.
+ *
+ * A number of test helpers are provided to check values. They all print
+ * to stdout and increment the pass/fail counters.
+ *
+ * For instance:
+ *
+ *   #ifdef UNIT_TEST
+ *   #include "unittest.h"
+ *
+ *   static int testHashInit(void *clientData) 
+ *   {
+ *       struct hash_table_t ht;
+ *   
+ *       hash_init(&ht, hash_algorithm_jim);
+ *       test_equals_int("new table has size 0", ht.size, 0);
+ *       test_equals_int("new table has usage 0", ht.used, 0);
+ *       test_equals_ptr("new table using jim hash", ht.hashfunc, hash_algorithm_jim);
+ *       
+ *       hash_init(&ht, hash_algorithm_jenkins);
+ *       test_equals_ptr("new table using jenkins hash", ht.hashfunc, hash_algorithm_jenkins);
+ *       
+ *       return 0;
+ *   }
+ *
+ *   struct unit_test_t unit_tests[] = {
+ *       {NULL, testHashInit, NULL},
+ *   };
+ *
+ *   int
+ *   main(void)
+ *   {
+ *       size_t n = 0;
+ *       for (n = 0; n < sizeof(unit_tests)/sizeof(unit_tests[0]); ++n) {
+ *           run_tests(&unit_tests[n]);
+ *       }
+ *       test_print_results();
+ *   }
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+#ifndef FAKE_STDINT
+#define FAKE_STDINT
+typedef   signed __int8  int8_t;
+typedef   signed __int16 int16_t;
+typedef   signed __int32 int32_t;
+typedef   signed __int64 int64_t;
+typedef unsigned __int8  uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#endif /* FAKE_STDINT*/
+#endif /* _MSC_VER */
+#ifndef FAKE_STDINT
+#include <stdint.h>
+#endif
+
+typedef void * (unit_test_setup_t)();
+typedef int    (unit_test_run_t)(void *);
+typedef void   (unit_test_teardown_t)(void *);
+
+struct unit_test_t {
+    unit_test_setup_t *setUp;
+    unit_test_run_t *runTest;
+    unit_test_teardown_t *tearDown;
+};
+
+static int test_count = 0;
+static int fail_count = 0;
+
+#define RUN(what) printf("\t%s\n", what); test_count++;
+
+static test_fail(const char *what)
+{
+    printf("\tFAIL: %s\n", what);
+    fflush(stdout);
+    fail_count++;
+}
+static void test_equals_int(const char *what, const int a, const int b)
+{
+    RUN(what);
+    if (a != b) test_fail(what);
+}
+static void test_equals_wide(const char *what, const uint64_t a, const uint64_t b)
+{
+    RUN(what);
+    if (a != b) test_fail(what);
+}
+static void test_equals_ptr(const char *what, const void *a, const void *b)
+{
+    RUN(what);
+    if (a != b) test_fail(what);
+}
+static void test_equals_str(const char *what, const uint8_t *a, const uint8_t *b)
+{
+    RUN(what);
+    if (strcmp((const char *)a,(const char *)b)) test_fail(what);
+}
+static void test_equals_strn(const char *what, const uint8_t *a, const uint8_t *b, size_t n)
+{
+    RUN(what);
+    if (strncmp((const char *)a,(const char *)b,n)) test_fail(what);
+}
+static void test_non_null_ptr(const char *what, const void *a)
+{
+    RUN(what);
+    if (NULL == a) test_fail(what);
+}
+
+static void
+test_print_results()
+{
+    printf("\t%d / %d pass\n", (test_count-fail_count),test_count);
+}
+
+static int
+run_tests(const struct unit_test_t *testPtr)
+{
+    int r = 0;
+    void *clientData = NULL;
+    if (testPtr->setUp)
+        clientData = testPtr->setUp();
+    r = testPtr->runTest(clientData);
+    if (testPtr->tearDown)
+        testPtr->tearDown(clientData);
+    return r;
+}