ufbgc
is a simple unit test framework with the following features
- Versatile assert macros for different situations
- Only requires standard C-libraries, no dependency
- User arguments can be provided to test functions
- Iterations over test functions with different input parameters
- Time stamps and execution time of the tests
- Assigning verbosity level of tests (error, warning and info levels)
- File output can be printed to a specific file (for each test)
Setup
(called before test) andTeardown
(called after test) functions
- Assertion macros
Typical assert macro starts with ufbgc_assert
, basic assert macros takes only condition and required parameters and their name ends with no underscore such as ufbgc_assert*
, on the other hand printable macros takes format string and variadic arguments to print if assertion fails and their generic name looks like ufbgc_assert*_
//Assertions
ufbgc_assert(condition) //checks condition == true, fails if condition == false
ufbgc_assert_true(condition) //checks condition == true, fails if condition == false
ufbgc_assert_false(condition) //checks condition == false, fails if condition == true
//Assertions with user defined notes (these macros uses printf format)
ufbgc_assert_(condition,format, ...)
ufbgc_assert_true_(condition,format, ...)
ufbgc_assert_false_(condition,format, ...)
//likely and unlikely is used when error does not affect the rest of the test
ufbgc_likely(condition) //checks condition == true, fails if condition == false but test continues
ufbgc_likely_(condition,format, ...) //User defined message can be printed
ufbgc_unlikely(condition) //checks condition == false, fails if condition == true but test continues
ufbgc_unlikely_(condition,format, ...) //User defined message can be printed
ufbgc_assert_op(a,op,b) //Checks for condition a op b, e.g. a == b
ufbgc_assert_eq(a,b) //Same as ufbgc_assert(a == b)
ufbgc_assert_eqstr(a,b) //String comparison, same as ufbgc_assert(!strcmp(a,b))
ufbgc_assert_eqmem(a,b,size) //Block of memory comparison, same as ufbgc_assert(!memcmp(a,b,size))
//All macros have their printable versions ufbgc_assert_*_(<required arguments>, format, ...)
- Custom test function type
ufbgc_return_t test_function(ufbgc_test_parameters * parameters, void * uarg){
double pi = 3.141592654;
ufbgc_assert(0 != 1); //This condition is true
ufbgc_assert_op(pi ,==, pi); //This is also true
return UFBGC_OK; //Each test function must return UFBGC_OK at the end, this will tell test function is passed its tests
}
//Setup function type
ufbgc_return_t example_setup_function(ufbgc_test_parameters * parameters, void ** uarg);
//Teardown function type
ufbgc_return_t example_teardown_function(ufbgc_test_parameters * parameters, void * uarg);
- UFBGC_TEST macro
Note that array and structure definition is not possible with UFBGC_TEST macro, compiler will complain because braces are used for function entries
/*
UFBGC_TEST macro creates all the necessary fields and functions for the desired test
UFBGC_TEST( Test2, //Test function name
NO_OPTION, //Option of the test
UFBGC_LOG_WARNING, //Log level of the test
NULL, //Output file
NULL, //ufbgc_test_parameters
{...}, //Setup function
{...}, //Test function
{...}) //Teardown function
This macro creates "const ufbgc_test_frame " variable with the given test name + _frame
So for this case Test2_frame is created as const ufbgc_test_frame to provide to the test-suite
*/
UFBGC_TEST(Test2,NO_OPTION,UFBGC_LOG_WARNING,NULL,NULL,
{
printf("Test2 Setup function!\n");
printf("Address of uarg %p\n",uarg); //uarg is not NULL but *uarg is
*uarg = strdup("hello"); //Setup function provides void ** uarg, so *uarg is used here
},
{
printf("Test function of test2!\n");
char ch = 'b';
ufbgc_assert(0 != 1);
ufbgc_assert_op('a', ==, 'a');
ufbgc_assert_op(ch, ==, 'b');
printf("Message:%s\n",(char*)uarg); //Allocated user arg in the setup function is passed to test
},
{
printf("Test2 teardown\n");
printf("Address of uarg %p | message:%s\n",uarg, (char*)uarg); //Allocated user arg in the setup function is passed to teardown
free(uarg); //We need to free uarg because we used strdup in the test function
})
- UFBGC_TEST_FRAME macro
UFBGC_TEST_FRAME
macro creates test frame structure with the given arguments.
Also declares test function, setup function and tear-down function by the following names:
- test function : dummy_test,
- setup function : dummy_test_setup,
- teardown function : dummy_test_teardown,
User needs to define these functions!
UFBGC_TEST_FRAME( dummy_test, //Test function name
NO_OPTION, //Option of the test
UFBGC_LOG_WARNING, //Log level of the test
"out.txt", //Output file
NULL, //ufbgc_test_parameters
);
This macro creates "const ufbgc_test_frame " variable with the given test name + _frame So for this case dummy_test_frame is created as const ufbgc_test_frame to provide to the test-suite
-
User parameters and iterations
example/example.c
contains an example how to provide parameters, but basically
const char * val1[] = {"a1","a2","a3"};
int vali[] = {100,200,300,500};
double valdb[] = {1.1,1.2,1.3};
//ufbgc test parameters contains number of iteration and parameters field
ufbgc_test_parameters paramtest_param = {
.no_iteration = 3,
.parameters = {
{
.key = "string-inputs",
.value = val1
},
{
.key = "integer-inputs",
.value = vali
},
{
.key = "double-inputs",
.value = valdb
},
//Last parameter can be NULL, or its key must be NULL (either works to understand size of the parameters array)
{
.key = NULL,
.value = NULL,
}
}
};
//In the test function there are two options to extract a parameter
ufbgc_return_t parameter_test(ufbgc_test_parameters * parameters, ufbgc_args * uarg){
const char * str; //Pointer that holds our input string
//This macro takes three arguments, variable to store, key of the parameter, and value type of the parameter
//value type was array of char pointers so 'const char **' is used here
ufbgc_get_param(str,"string-inputs",const char **);
ufbgc_assert(str != NULL);
printf("Got string:'%s'\n",str); //This line prints extracted string
//Instead of using ufbgc_get_param macro, this macro finds the parameter from its key
double * dx = (double *)ufbgc_get_parameter("double-inputs"); //We cast it to double*
size_t it = 0;
ufbgc_get_current_test_iterator(&it); //Current test iterator fills it variable to which iteration is it
printf("Double with iterator: %g\n",dx[it]); //Printed double values depend on the iterator type
return UFBGC_OK;
}
-
Test frame
Test frame contains necessary information about the test, it is used to run the test It has the following struct type
typedef struct{
ufbgc_test_fun_t test_f; //<! Actual test function
const char * name; //<! Test name
ufbgc_setup_fun_t setup_f; //<! Setup function
ufbgc_teardown_fun_t teardown_f; //<! Teardown function
ufbgc_test_parameters * parameters; //<! Test parameters
ufbgc_option_t option; //<! Test options
ufbgc_log_verbosity_t log_level; //<! Log level of the test
const char * output_file; //<! Output file name
}ufbgc_test_frame;
Example of test frame can be created as following
.test_f = example_test1, //Test function
.name = "test1", //Name of the test function
.setup_f = NULL, //Setup function
.teardown_f = NULL, //Teardown function
.parameters = NULL, //Parameters
.option = NO_OPTION, //Test option
.log_level = UFBGC_LOG_WARNING, //Test verbosity
.output_file = "test1_output.txt", //Instead of stdout, all test results will be printed into test1_output.txt
-
Test Options
There is only one test option at the current version, which is
PASS_TEST
macro, if test has this option is set then its test function is not gonna be called (This is helpful for running multiple tests and suppress the output of the test) -
Test Log levels
Macro | Output | Color |
---|---|---|
UFBGC_LOG_ERROR (default) |
If ufbgc_assert* macros fail, results will be printed |
Red |
UFBGC_LOG_WARNING |
If ufbgc_assert* + ufbgc_likely* macros fail, results will be printed |
Yellow |
UFBGC_LOG_INFO |
Failure printing same as UFBGC_LOG_WARNING , but also prints all assert macro results |
Green |
-
Test suite
Test suite is called test lists in
ufbgc
and their type isufbgc_test_frame
. Example test suite fromexample/example.c
ufbgc_test_frame test_list[] = {
{
.test_f = example_test1, //Test function
.name = "test1", //Name of the test function
.setup_f = NULL, //Setup function
.teardown_f = NULL, //Teardown function
.parameters = NULL, //Parameters
.option = NO_OPTION, //Test option
.log_level = UFBGC_LOG_WARNING, //Test verbosity
.output_file = "test1_output.txt", //Instead of stdout, all test results will be printed into test1_output.txt
},
Test2_frame, //This variable is created with the UFBGC_TEST macro, hence needs to add into test list
{
.test_f = test3,
.name = "test3",
.setup_f = NULL,
.teardown_f = NULL,
.parameters = NULL,
.option = PASS_TEST, //ufbgc will pass this test and not run
},
{
.test_f = parameter_test,
.name = "parameter-test",
.setup_f = NULL,
.teardown_f = NULL,
.parameters = ¶mtest_param,
.option = NO_OPTION,
},
{
.test_f = operator_test,
.name = "operator-test",
.parameters = &operator_test_param,
.option = NO_OPTION,
.log_level = UFBGC_LOG_INFO, //Verbosity level set to UFBGC_LOG_INFO, so every information about test will be printed(even if assertion not fails)
}
};
//To run the test-suite call the function
//'ufbgc_test_frame_array_length' macro helps to calculate the element size inside provided test list
ufbgc_start_test(test_list,ufbgc_test_frame_array_length(test_list));
$ mkdir build
$ cd build
$ cmake ..
$ make
$ ./ufbgc_example
If you are using cmake, CMakeList.txt file is provided at the repository directory
-
Compiling with the existing project
src folder contains its own CMakeLists.txt file, just add the following lines into project cmake file (
ufbgc
exports itself asufbgc
so link the library with your target)
add_subdirectory("ufbgc/src")
target_link_libraries(<target_name> ufbgc)
- Using as a third party library (Shared object file .so)
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install # Default it puts into /usr/local/lib and /usr/local/bin
To compile an example file run:
$ gcc -L/usr/local/include/ -o <executable_name> example.c -lufbgc
$ ./<executable_name>
#If ./<executable_name> gives object file not found error, try this
$ LD_LIBRARY_PATH=/usr/local/lib
#This will add path of ufbgc.so file
- Taking the source code
- License allows to copy
ufbgc
, so just copy the src folder which has only two filesufbgc.c
andufbgc.h
and compile it with your project
- License allows to copy