Basic Unit Test Library

While unit tests provide greater assurance for developed software, setting up existing C unit test libraries can be tiresome. These notes will show how to create a basic unit test library using some simple regex and function pointers.

Creating the Unit Test Source

The first step is to create a C source file containing the unit tests. This should import the header for the code you want to test. Each test function should start with the word “test”, return 0 on success, and return -1 on failure. The code below shows an example for testing a function which always returns zero. This will then need to be compiled into an object file.

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

#include "uut.h"

int test_1(){
    int output = return_zero();
    if(output == 0){
        return 0;
    } else {
        return -1;
    }
}

Creating the Unit Test add_executable

There is a good chance you will have a lot of unit test functions - this bash script will create a C source file which calls them all in sequence using an array of function pointers.

#!/bin/bash

# Assume $1 is a .o object file
# Assume $2 is the include file

output=$(nm -g $1| grep "test_")

SAVEIFS=$IFS
IFS=$'\n'
output=($output)
IFS=$SAVEIFS

cat > test.c <<EOF
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include "$2"
EOF

for i in "${output[@]}"
do
    len=`expr length "$i"`
    echo "int ${i:19:$len-19}();" >> test.c
done

cat >> test.c <<EOF

int main(){
    int (*tests[])() = {
EOF

for i in "${output[@]}"
do
    len=`expr length "$i"`
    echo "      &${i:19:$len-19}," >> test.c
done

cat >> test.c <<EOF
    };
    for(int i = 0; i < 62; i++){
            int result = (*tests[i])();
            if(result == 0){
                printf("PASS\n");
            } else {
                printf("FAIL\n");
            }
        }

    return 0;
}
EOF

Writing a Makefile

All these steps can be combined with the help of a Makefile, such as the one below.

uut.o:
    $(CC) -Wall -c uut.c -o uut.o

unit_tests.o:
    $(CC) -Wall -c unit_tests.c -o unit_tests.o

test:
    bash create_tests.sh unit_tests.o uut.h
    $(CC) -Wall -c test.c -o test.o
    $(CC) -Wall test.o uut.o unit_tests.o -o test
    ./test