A one part small stb-style/header-only library for testing c code and a .c file to be compiled which parsed, compiles, and runs test files. This is still a work-in-progress, thus only usable on linux/posix machines.
//file test.c
#define TOAST_IMPLEMENTATION
#include "toast.h"
void add(BurntToast *burnt) {
if ((1 + 2) == 3) {
eat_toast(burnt);
return;
}
burn_toast(burnt, "Adding went wrong");
return;
}
void sub(BurntToast *burnt) {
if ((4 - 2) == 1) {
eat_toast(burnt);
return;
}
burn_toast(burnt, "Substracting went wrong");
return;
}
void mul(BurntToast *burnt) {
if ((2 * 2) == 4) {
eat_toast(burnt);
return;
}
burn_toast(burnt, "Multiplying went wrong");
return;
}
int main() {
//initialize test suite
PackOfToast pack = plug_in_toaster("toast.h");
//prepare an array of tests
SliceOfToast toasts[2] = {
(SliceOfToast){
.toast = add,
.name = "add",
},
(SliceOfToast){
.toast = sub,
.name = "sub",
},
};
//and insert them as an array
insert_toasts(&pack, toasts, 2);
SliceOfToast slice = {
.toast = mul,
.name = "mul",
};
//or just insert one
insert_toast(&pack, slice);
//run the test suite
toast(pack);
//clean up
unplug_toaster(pack);
return 0;
}SliceOfToast- synonymous with a test case.PackOfToast- synonymous with a test suite.Toasting- the executor for a test case or simply a test-case-functionYUMMY- a success or as int0BURNT- a failure or as int1RAW- not run yet int-1BurnToast- Metadata/Result to be set in side the aToast
$ make Clean up can be performed with $ make clean.
- As of now test files need to be located in a source directory, which defaults to
./tests. - Testfiles should be named like so
*.test.c, e.g.foo.test.c(as a path relative to the executable it would be./tests/foo.test.c - Testfiles contain a collection of
SliceOfToasts. In the form of
typedef void(*Toasting)(BurntToast*);for example:
void add(BurntToast *burnt) {
if ((1 + 2) == 3) {
eat_toast(burnt);
return;
}
burn_toast(burnt, "Adding went wrong");
return;
}NOTE: no header files for toast need to be included nor a main() function is required as these cases get parsed and written to an actual .c file
4. Create a defin.test.c file in the same directory.
Here you can put all your #defines and #includes, which will placed after the stb-style #defines and #includes of toast.h
- Run the test like so:
./toaster [OPTIONS]
-d|--dir <dir>.......... specifies the src directory. [Default: './tests']
-k|--keep .............. toaster won't remove the files it generated
-v|--version ........... print the current version of this toaster
-h|--help .............. print this very textFrom the root of the project:
$ cd ./examples$ make harness
The exectution is triggered by the harness recipe. Comment the last line out if you want to run it with any arguments.
Use these to set the state/result of the outcome of a single test case.
Or just use the corresponding int. BurntToast.yummy\_or\_burnt always
defaults to RAW.
YUMMY - a successful test case as int 0
BURNT - a failed test case as int 1
RAW - a yet to run or not run state int -1
This is basically a test case.
| Field | Type | Domain | Description |
|---|---|---|---|
| toast | Toasting |
user-defined | The test case function |
| name | const char* |
user-defined | The name of the test-case. Will be printed to stdout. |
| result | int |
user-defined | Internally set to RAWor set to the result of each test case in the test case function. |
| time | double |
internal | The time a test-case took to finish. |
| time_unit | int |
internal | The unit to interpret the time |
This is basically the test-suite.
| Field | Type | Domain | Description |
|---|---|---|---|
| slices | SliceOfToast* |
user-defined | Array of test cases. |
| brand | const char* |
user-defined | The name of the set of test-cases |
| size | size_t |
internal | The size of slices |
| cap | size_t |
internal | Current capacity of slices |
| time | double |
internal | The time all test-cases took to finish. |
| time_unit | int |
internal | The unit to interpre t the time |
This is struct is passed a reference to each test function as an argument in order to to set diagnostics and result identifiers.
| Field | Type | Domain | Description |
|---|---|---|---|
| index | int |
toast-defined | The index the test-case has inside PackOfToast. |
| yummy_or_burnt | int |
internal/user-defined | The actual result, initialized to Raw, should be set inside the test-case-function |
| diagnostic | char* |
user-defined | The message to be printed in case of an error |
| print_diagnostic | int |
user-defined | Whether or not to print the message. This is required internally. |
A type definition for the test-case-function.
typedef void(*Toasting)(BurntToast*);Initializer function for a test-case/SliceOfToast.
SliceOfToast pre_bake_toast(const char* name, Toasting toast);Initializer function for a test-suite/PackOfToast.
PackOfToast plug_in_toaster(const char* brand);Insert an array of test-cases/SliceOfToasts.
void insert_toasts(PackOfToast *pack, SliceOfToast *slices, size_t len);Insert a single test-cases/SliceOfToast.
void insert_toasts(PackOfToast *pack, SliceOfToast *slices, size_t len);This function actually runs a PackOfToast.
int toast(PackOfToast pack);Short-cut helper function to set a BurntToast, i.e. a result of a test case.
It always marks the test case as failed and alaways sets print_diagnostic to 1 as well as assigning the provided diagnostic string.
void burn_toast(BurntToast *burnt, char* diagnostic);Short-cut helper function to set a BurntToast, i.e. a result of a test case.
It simply sets the yummy_or_burnt to YUMMY.
void eat_toast(BurntToast *burnt);Frees allocated memory in the PackOfToast
void unplug_toaster(PackOfToast pack);