Writing Tests
A basic unit test file looks like this:
#include "lily-test.h"
LILY_FILE_BEGIN(example_file)
LILY_TEST("example test 1")
{
CHECK_EQ(1+1, 2, "%d");
}
#include LILY_PUSH_TEST()
LILY_TEST("example test 2")
{
CHECK_LT(3.0, 4.0, "%0.2f");
}
#include LILY_PUSH_TEST()
#define LILY_FILE_END
#include LILY_REGISTER_TESTS()
This will define a function pointer example_file
with signature void ()
that, when called, will execute the two tests and display to stderr any errors that they generate. While there is more boilerplate than in comparable C++ libraries, this means that lily-test supports test auto-registration. To add a new test, just use the LILY_TEST
macro as shown, and then follow the function body with #include LILY_PUSH_TEST()
to register it. These macros will only work correctly when used between a LILY_FILE_BEGIN
and LILY_FILE_END
block, and only when used together; using LILY_TEST
without a LILY_PUSH_TEST
is probably going to throw up a ton of compile errors.
Using a single file
For very small projects, you may be able to get away with using only a single unit test file. In this case, you should set it up along the following lines:
#define LILY_IMPLEMENTATION
#include "lily-test.h"
/* any includes or code to get your tests working */
LILY_FILE_BEGIN(tests)
/* test definitions... */
#define LILY_FILE_END
#include LILY_REGISTER_TESTS()
int main()
{
lily_begin();
tests();
lily_finish();
return 0;
}
However, in most cases you will want to have multiple test files.
Multiple test files
You will need, in addition to your unit test files, a header file that contains extern declarations of the function pointers defined by your files and a main C source file that contains a main
function to run all of the function pointers. A nice way to set this up is to use X-macros, like this:
/* tests.h */
#define TESTS \
X(suite_1) \
X(suite_2) \
X(suite_3) \
#define X(suite) extern void (*suite)();
TESTS
#undef X
/* tests_main.c */
#define LILY_IMPLEMENTATION
#include "lily-test.h"
int main()
{
lily_begin();
#define X(suite) suite();
TESTS
#undef X
lily_finish();
return 0;
}
This is convenient, because it means that when you add a new test file you need only add a single line to the definition of the TESTS
macro in tests.h
and all of the other relevant code is added for you automatically.
Note that exactly ONE file should define LILY_IMPLEMENTATION
. I find it reasonable to make this the same file with the implementation of main
but YMMV.