:: End of manually writing unit tests. Why not generate test cases automatically and smartly?

CUTE :: A Concolic Unit Testing Engine for C and Java

Open System Laboratory | Computer Science Department | University of Illinois at Urbana Champaign
Micro Tutorial for CUTE

Suppose, we want to test the function testme in the following small program contained in the file cell.c.

#include <stdio.h>:
#include <assert.h>

/* This example appeared in the ESEC/FSE 05 paper */

typedef struct cell {
    int v;
    struct cell *next;
} cell;

int g(int v) {
    return 2*v + 1;
}

int testme(cell *p, int x) {
    if (x > 0)
	if (p != NULL)
	    if (g(x) == p->v)
		if (p->next == p)
		    assert(0);
    return 0;
}
In concolic testing, we want to explore all possible distinct execution paths of the function testme for all possible values of its arguments p and x. For this we write the following test driver in the file cell.c:

f(){
    cell *p;
    int x;
    CUTE_input(p);
    CUTE_input(x);
    testme(p,x);
}

The test driver declares two variables p and x. It then specifies that p and x get inputs from the environment. The function testme is invoked with p and x.

We can now test the function testme by first compiling the program with cutec as follows:

cutec cell.c f
The above command specifies that f is the unit function that we want to test. The compilation process generates two executables: cell.exe and cell.g.exe. cell.exe is executed repeatedly to generate new inputs on which the program executions take different paths. The inputs for the last execution is stored in the hard drive to aid the process of debugging using gdb or similar tools. To debug the last execution, one needs to invoke gdb on cell.g.exe and run cell.g.exe with the option "-m 1". This invocation replays cell.c with the last generated inputs without performing any symbolic execution.

After compilation, concolic testing can be performed by running

cute cell -i 100
The command specifies that the program must be tested by generating at most 100 inputs. In other words, if all execution paths of the program is not explored in 100 iterations, then the testing stops. The testing also stops if any error is encountered during the execution of the program. In such a situation, the debugger can be invoked on cell.g.exe with option -m 1 to replay the erroneous execution. For example, invoke
gdb cell.g 
Then inside gdb set breakpoint to f by giving the command
b f
After this, execute cell by giving the command
run -m 1
Copyright © 2006 University of Illinois at Urbana Champaign. All rights Reserved