Last active
February 28, 2017 08:33
-
-
Save w-vi/1fa9cf80b449f58909fba706b2e815cf to your computer and use it in GitHub Desktop.
C unit tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "testing.h" | |
TEST_IMPL(fail) { | |
return TEST_FAIL; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "testing.h" | |
TEST_IMPL(pass) { | |
return TEST_OK; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "testing.h" | |
#include "tests.h" | |
#ifdef HAVE_GETOPT_LONG | |
# include <getopt.h> | |
#else | |
# include "my_getopt.h" | |
#endif | |
int quiet = TRUE; | |
int tap = TRUE; | |
static void | |
tap_progress(int current, | |
int total, | |
int passed, | |
int failed, | |
int xfailed, | |
int skipped, | |
test_status_t result, | |
test_instance_t *test) | |
{ | |
switch (result) { | |
case TEST_OK: printf("ok %d %s\n", current, test->test_name); break; | |
case TEST_SKIP: | |
printf("ok %d %s # SKIP %s\n", current, test->test_name, test->comment); | |
break; | |
case TEST_XFAIL: | |
printf("not ok %d %s # TODO %s\n", | |
current, | |
test->test_name, | |
test->comment); | |
break; | |
default: printf("not ok %d %s\n", current, test->test_name); | |
} | |
} | |
static void | |
no_tap_progress(int current, | |
int total, | |
int passed, | |
int failed, | |
int xfailed, | |
int skipped, | |
test_status_t result, | |
test_instance_t *test) | |
{ | |
int progress = 0; | |
char *status = NULL; | |
switch (result) { | |
case TEST_OK: status = "PASSED"; break; | |
case TEST_SKIP: status = "SKIPPED"; break; | |
case TEST_XFAIL: status = "X FAILED"; break; | |
default: status = "FAILED"; | |
} | |
if (total == 0) total = 1; | |
progress = 100 * (passed + failed + xfailed + skipped) / total; | |
LOGF("[%% %3d|P %3d|F %3d|X %3d|S %3d]: %s (%s)\n", | |
progress, | |
passed, | |
failed, | |
xfailed, | |
skipped, | |
test->test_name, | |
status); | |
} | |
int | |
run_test(test_instance_t *t, int curr) | |
{ | |
return t->main(); | |
} | |
void | |
print_usage() | |
{ | |
printf("run-tests: "PACKAGE" unit tests\n"); | |
printf("Usage: run-tests [hVn]\n"); | |
printf("\ | |
-n, --no-tap Do not output TAP protocol messages but use internal\n\ | |
reporting\n"); | |
printf("\ | |
-h, --help print this help\n"); | |
printf("\ | |
-V, --version print version information\n"); | |
exit(EXIT_SUCCESS); | |
} | |
void | |
print_version() | |
{ | |
printf("run-tests "PACKAGE" unit tests version: "VERSION"\n"); | |
printf("send bugs to: "PACKAGE_BUGREPORT"\n"); | |
#ifdef CONFIG_ARGS | |
printf("\n"); | |
printf(PACKAGE" was built with "CONFIG_ARGS"\n"); | |
#endif | |
exit(EXIT_SUCCESS); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
int opt; | |
int long_index = 0; | |
extern char *optarg; | |
int total = 0; | |
int passed = 0; | |
int failed = 0; | |
int xfailed = 0; | |
int skipped = 0; | |
int current = 1; | |
test_status_t test_result = TEST_FAIL; | |
test_instance_t* t = NULL; | |
void (*progress)(int, int, int, int, int, int, | |
test_status_t, test_instance_t *); | |
/*COMMAND LINE ARGS*/ | |
static const struct option long_opts[] = { | |
{ "no-tap", no_argument, NULL, 'n' }, | |
{ "help", no_argument, NULL, 'h' }, | |
{ "version", no_argument, NULL, 'V'}, | |
{ NULL, 0, NULL, 0 } | |
}; | |
while ((opt = getopt_long(argc, argv,"hVn", | |
long_opts, &long_index )) != -1) { | |
switch (opt) { | |
case 'n': tap = FALSE; break; | |
case 'h': print_usage(); break; | |
case 'V': print_version(); break; | |
case '?': | |
default: print_usage(); | |
} | |
} | |
/* How many tests we have? */ | |
for (t = test_instances; t->main; t++) { | |
total++; | |
} | |
if (tap) { | |
printf("1..%d\n", total); | |
progress = tap_progress; | |
} else { | |
LOGF("Runing tests 1 ... %d\n", total); | |
progress = no_tap_progress; | |
} | |
/* Run all tests. */ | |
for (t = test_instances; t->main; t++) { | |
test_result = run_test(t, current); | |
switch (test_result) { | |
case TEST_OK: passed++; break; | |
case TEST_SKIP: skipped++; break; | |
case TEST_XFAIL: xfailed++; break; | |
default: failed++; | |
} | |
progress(current, | |
total, | |
passed, | |
failed, | |
xfailed, | |
skipped, | |
test_result, | |
t); | |
current++; | |
} | |
if (!tap) { | |
LOGF("\nTest run summary:\n"); | |
LOGF("=================\n"); | |
LOGF("Total: %3d\nSuccess: %3d\nFailed: %3d\nX Failed: %3d\nSkipped: %3d\n", | |
total, | |
passed, | |
failed, | |
xfailed, | |
skipped); | |
} | |
exit(0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef TESTING_H_ | |
#define TESTING_H_ | |
#include <stddef.h> /* size_t and family */ | |
#include <stdint.h> /* std int types */ | |
#include <inttypes.h> | |
#include <stdio.h> /* FILE etc */ | |
#include <stdlib.h> /* malloc */ | |
#include <string.h> /* memset */ | |
#include <errno.h> | |
#if !defined(_WIN32) | |
# include <unistd.h> /* Posix file and dir */ | |
# include <sys/types.h> /* *nix types*/ | |
#endif | |
typedef enum test_status { | |
TEST_OK = 0, | |
TEST_FAIL, | |
TEST_XFAIL, | |
TEST_SKIP | |
} test_status_t; | |
/* Check test case and possibly fail */ | |
#define CHECK(expr) \ | |
do { \ | |
if (!(expr)) { \ | |
fprintf(stderr, \ | |
"Check failed in %s on line %d: %s\n", \ | |
__FILE__, \ | |
__LINE__, \ | |
#expr); \ | |
return TEST_FAIL; \ | |
} \ | |
} while (0) | |
/* Check test case and possibly fail */ | |
#define THR_CHECK(expr) \ | |
do { \ | |
if (!(expr)) { \ | |
fprintf(stderr, \ | |
"Check failed in %s on line %d: %s\n", \ | |
__FILE__, \ | |
__LINE__, \ | |
#expr); \ | |
return NULL; \ | |
} \ | |
} while (0) | |
/* Test logging to stderr. */ | |
#define LOGF(...) \ | |
do { \ | |
fprintf(stderr, __VA_ARGS__); \ | |
fflush(stderr); \ | |
} while (0) | |
/* Die with fatal error. */ | |
#define DIE(msg) \ | |
do { \ | |
fprintf(stderr, \ | |
"Fatal error in %s on line %d: %s\n", \ | |
__FILE__, \ | |
__LINE__, \ | |
msg); \ | |
fflush(stderr); \ | |
abort(); \ | |
} while (0) | |
#define TEST_INSTANCE(name) \ | |
{ #name, #name, &test_##name} | |
#define TEST_INSTANCE_CMT(name, comment) \ | |
{ #name, #comment, &test_##name} | |
/* Declare test */ | |
#define TEST_DECL(name) \ | |
test_status_t test_##name(void) | |
/* Easy way to implement new test */ | |
#define TEST_IMPL(name) \ | |
test_status_t test_##name(void) | |
#endif /* TESTING_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef TESTS_H_ | |
#define TESTS_H_ | |
#include "testing.h" | |
extern "C" { | |
/* Test instance definiton */ | |
typedef struct { | |
char *test_name; | |
char *comment; | |
test_status_t (*main)(void); | |
} test_instance_t; | |
/* First declare new test function here, using the TEST_DECL macro */ | |
TEST_DECL(pass); | |
TEST_DECL(fail); | |
/* Add test instances to this list. | |
* If they are not here they are ignored. | |
*/ | |
test_instance_t test_instances[] = { | |
#ifdef TEST_RUNNER /* define if you want to test the test runner */ | |
TEST_INSTANCE(pass), | |
TEST_INSTANCE(fail), | |
#endif | |
{0, 0, 0} /* Last item in the list, do not put anything after this line*/ | |
}; | |
} | |
#endif /* TESTS_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment