Browse Source

Update ctest.h from github.com:xianyi/ctest.git.

tags/v0.2.16.rc1
Zhang Xianyi 10 years ago
parent
commit
8e98478ff3
1 changed files with 256 additions and 34 deletions
  1. +256
    -34
      utest/ctest.h

+ 256
- 34
utest/ctest.h View File

@@ -33,6 +33,7 @@

typedef void (*SetupFunc)(void*);
typedef void (*TearDownFunc)(void*);
typedef void (*RunWithDataFunc)(void*);

struct ctest {
const char* ssname; // suite name
@@ -44,21 +45,70 @@ struct ctest {
SetupFunc setup;
TearDownFunc teardown;

struct ctest *next;

unsigned int magic;
};

#define __FNAME(sname, tname) __ctest_##sname##_##tname##_run
#define __TNAME(sname, tname) __ctest_##sname##_##tname
#define __PNAME(sname, tname) __ctest_##sname##_##tname##_pointer

#define __CTEST_MAGIC (0xdeadbeef)
#ifdef __APPLE__
#define __CTEST_APPLE
#endif

#if defined(_WIN32) && defined(_MSC_VER)
#define __CTEST_MSVC
#endif

//config for MSVC compiler
#ifdef __CTEST_MSVC

#define __CTEST_NO_TIME
#define CTEST_NO_COLORS

#ifndef CTEST_ADD_TESTS_MANUALLY
#pragma section(".ctest$a")
#pragma section(".ctest$u")
#pragma section(".ctest$z")
#endif

//clear this flag for msvc
#ifdef CTEST_SEGFAULT
#undef CTEST_SEGFAULT
#endif

#if _MSC_VER < 1900
#define snprintf _snprintf_s
#endif

#ifndef __cplusplus
#define inline __inline
#endif
#endif

#ifdef CTEST_NO_JMP
#define __CTEST_NO_JMP
#endif

#define __CTEST_MAGIC (0xdeadbeef)

#ifdef CTEST_ADD_TESTS_MANUALLY
# define __Test_Section
#else
#ifdef __CTEST_APPLE
#define __Test_Section __attribute__ ((used, section ("__DATA, .ctest")))
#elif defined (__CTEST_MSVC)
#define __Test_Section __declspec( allocate(".ctest$u"))
#else
#define __Test_Section __attribute__ ((used, section (".ctest")))
#endif
#endif

#ifndef __CTEST_MSVC
#define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \
static struct ctest __TNAME(sname, tname) __Test_Section = { \
static struct ctest __TNAME(sname, tname) = { \
.ssname=#sname, \
.ttname=#tname, \
.run = __FNAME(sname, tname), \
@@ -66,7 +116,24 @@ struct ctest {
.data = __data, \
.setup = (SetupFunc)__setup, \
.teardown = (TearDownFunc)__teardown, \
.magic = __CTEST_MAGIC };
.next = NULL, \
.magic = __CTEST_MAGIC}; \
static void * __PNAME(sname, tname)[2] __Test_Section = {(void*)& __TNAME(sname,tname), (void*)__CTEST_MAGIC};
#else
//for msvc
#define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \
static struct ctest __TNAME(sname, tname) = { \
#sname, \
#tname, \
__FNAME(sname, tname), \
_skip, \
__data, \
(SetupFunc)__setup, \
(TearDownFunc)__teardown, \
NULL, \
__CTEST_MAGIC}; \
__Test_Section static void * __PNAME(sname, tname)[2]= {(void*)& __TNAME(sname,tname), (void *)__CTEST_MAGIC};
#endif

#define CTEST_DATA(sname) struct sname##_data

@@ -81,7 +148,7 @@ struct ctest {
__CTEST_STRUCT(sname, tname, _skip, NULL, NULL, NULL) \
void __FNAME(sname, tname)()

#ifdef __APPLE__
#ifdef __CTEST_APPLE
#define SETUP_FNAME(sname) NULL
#define TEARDOWN_FNAME(sname) NULL
#else
@@ -108,6 +175,22 @@ void CTEST_ERR(const char* fmt, ...); // doesn't return
#define CTEST2_SKIP(sname, tname) __CTEST2_INTERNAL(sname, tname, 1)


#ifdef CTEST_ADD_TESTS_MANUALLY

void __ctest_addTest(struct ctest *);

#define CTEST_ADD(sname, tname) do { \
extern struct ctest __TNAME(sname, tname); \
__ctest_addTest(&__TNAME(sname, tname)); \
} while (0)

#define CTEST_ADD2(sname, tname) do { \
extern struct ctest __TNAME(sname, tname); \
__ctest_addTest(&__TNAME(sname, tname)); \
} while (0)

#endif // CTEST_ADD_TESTS_MANUALLY

void assert_str(const char* exp, const char* real, const char* caller, int line);
#define ASSERT_STR(exp, real) assert_str(exp, real, __FILE__, __LINE__)

@@ -144,6 +227,29 @@ void assert_false(int real, const char* caller, int line);
void assert_fail(const char* caller, int line);
#define ASSERT_FAIL() assert_fail(__FILE__, __LINE__)

/* If longjmp() is not available, integer flag will be used instead of jmp_buf.
*
* __CTEST_SETJMP() will clear the flag and return zero, and __CTEST_LONGJMP()
* will set the flag to its argument. __CTEST_ERROR_CODE() will return that flag.
*
* If longjmp() is available, jmp_buf will be used as usual and __CTEST_ERROR_CODE()
* will always return zero.
*
* You can check both __CTEST_SETJMP() and __CTEST_ERROR_CODE() return value
* to detect error in a portable way.
*/
#ifdef __CTEST_NO_JMP
# define __CTEST_JMPBUF int
# define __CTEST_ERROR_CODE(_var) (_var)
# define __CTEST_SETJMP(_var) (_var = 0)
# define __CTEST_LONGJMP(_var, _err) (_var = _err)
#else // !__CTEST_NO_JMP
# define __CTEST_JMPBUF jmp_buf
# define __CTEST_ERROR_CODE(_var) (0)
# define __CTEST_SETJMP(_var) setjmp(_var)
# define __CTEST_LONGJMP(_var, _err) longjmp(_var, _err)
#endif // __CTEST_NO_JMP

void assert_dbl_near(double exp, double real, double tol, const char* caller, int line);
#define ASSERT_DBL_NEAR(exp, real) assert_dbl_near(exp, real, 1e-4, __FILE__, __LINE__)
#define ASSERT_DBL_NEAR_TOL(exp, real, tol) assert_dbl_near(exp, real, tol, __FILE__, __LINE__)
@@ -154,16 +260,28 @@ void assert_dbl_far(double exp, double real, double tol, const char* caller, int

#ifdef CTEST_MAIN

#ifndef __CTEST_NO_JMP
#include <setjmp.h>
#endif

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#ifndef __CTEST_NO_TIME
#include <sys/time.h>
#include <unistd.h>
#endif
#include <stdint.h>

#ifdef __CTEST_MSVC
#include <io.h>
#else
#include <unistd.h>
#endif

#include <stdlib.h>

#ifdef __APPLE__
#ifdef __CTEST_APPLE
#include <dlfcn.h>
#endif

@@ -171,9 +289,10 @@ static size_t ctest_errorsize;
static char* ctest_errormsg;
#define MSG_SIZE 4096
static char ctest_errorbuffer[MSG_SIZE];
static jmp_buf ctest_err;
static __CTEST_JMPBUF ctest_err;
static int color_output = 1;
static const char* suite_name;
static const char* test_name;

typedef int (*filter_func)(struct ctest*);

@@ -195,8 +314,96 @@ typedef int (*filter_func)(struct ctest*);
#define ANSI_WHITE "\033[01;37m"
#define ANSI_NORMAL "\033[0m"

#ifdef __CTEST_MSVC
#ifndef CTEST_ADD_TESTS_MANUALLY
__declspec(allocate(".ctest$a")) struct ctest * ctest_win_begin;
__declspec(allocate(".ctest$z")) struct ctest * ctest_win_end;
#endif
#endif

static CTEST(suite, test) { }

#define __CTEST_POINTER_NEXT(_test) (struct ctest **)((struct ctest **)(_test) + 2)
#define __CTEST_POINTER_PREV(_test) (struct ctest **)((struct ctest **)(_test) - 2)

/* First element of test list.
*/
static struct ctest * * __ctest_head_p = (struct ctest **)__PNAME(suite, test);

#ifdef CTEST_ADD_TESTS_MANUALLY

/* Last element of test list.
*/
static struct ctest *__ctest_tail = &__TNAME(suite, test);

/* Add test to linked list manually.
*/
void __ctest_addTest(struct ctest *test)
{
__ctest_tail->next = test;
__ctest_tail = test;
}
#else // !CTEST_ADD_TESTS_MANUALLY

#ifndef __CTEST_MSVC
/* Add all tests to linked list automatically.
*/
static void __ctest_linkTests()
{
struct ctest ** test;
struct ctest ** ctest_begin = (struct ctest **)__PNAME(suite, test);
struct ctest ** ctest_end = (struct ctest **)__PNAME(suite, test);

// find begin and end of section by comparing magics
while (1) {
struct ctest** t = __CTEST_POINTER_PREV(ctest_begin);
if (t[0] == NULL) break;
if (t[1] != (struct ctest*)__CTEST_MAGIC) break;
ctest_begin = t;
}
while (1) {
struct ctest** t = __CTEST_POINTER_NEXT(ctest_end);
if (t[0] == NULL) break;
if (t[1] != (struct ctest*)__CTEST_MAGIC) break;
ctest_end = t;
}
ctest_end = __CTEST_POINTER_NEXT(ctest_end); // end after last one

for (test = ctest_begin; test != ctest_end; test = __CTEST_POINTER_NEXT(test)) {
struct ctest ** next_p = __CTEST_POINTER_NEXT(test);
struct ctest * next;
if (next_p == ctest_end)
next = NULL;
else
next = next_p[0];

(*test)->next = next;
}

__ctest_head_p = ctest_begin;
}
#else //for msvc
static void __ctest_linkTests()
{
struct ctest ** ctest_start = __ctest_head_p;
struct ctest ** test;
struct ctest * cur=ctest_start[0];

for(test=&ctest_win_begin; test!=&ctest_win_end; test++){
//check
if(test[1] == (struct ctest*)__CTEST_MAGIC){
//skip the start
if((test[0]) == ctest_start[0]) continue;
cur->next = test[0];
cur=cur->next;
cur->next=NULL;
}
}
}
#endif
#endif

inline static void vprint_errormsg(const char* const fmt, va_list ap) {
// (v)snprintf returns the number that would have been written
const int ret = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, ap);
@@ -254,7 +461,7 @@ void CTEST_ERR(const char* fmt, ...)
va_end(argp);

msg_end();
longjmp(ctest_err, 1);
__CTEST_LONGJMP(ctest_err, 1);
}

void assert_str(const char* exp, const char* real, const char* caller, int line) {
@@ -366,6 +573,15 @@ static int suite_filter(struct ctest* t) {
return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
}

static int suite_test_filter(struct ctest* t) {
int suit_match, test_match;
suit_match=(strncmp(suite_name, t->ssname, strlen(suite_name)) == 0);
test_match=(strncmp(test_name, t->ttname, strlen(test_name)) == 0);
return (suit_match & test_match);
}


#ifndef __CTEST_NO_TIME
static uint64_t getCurrentTime() {
struct timeval now;
gettimeofday(&now, NULL);
@@ -374,6 +590,7 @@ static uint64_t getCurrentTime() {
now64 += ((uint64_t) now.tv_usec);
return now64;
}
#endif

static void color_print(const char* color, const char* text) {
if (color_output)
@@ -382,7 +599,7 @@ static void color_print(const char* color, const char* text) {
printf("%s\n", text);
}

#ifdef __APPLE__
#ifdef __CTEST_APPLE
static void *find_symbol(struct ctest *test, const char *fname)
{
size_t len = strlen(test->ssname) + 1 + strlen(fname);
@@ -427,6 +644,10 @@ int ctest_main(int argc, const char *argv[])
static int index = 1;
static filter_func filter = suite_all;

const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
char results[80];
static struct ctest* test;

#ifdef CTEST_SEGFAULT
signal(SIGSEGV, sighandler);
#endif
@@ -434,37 +655,34 @@ int ctest_main(int argc, const char *argv[])
if (argc == 2) {
suite_name = argv[1];
filter = suite_filter;
}else if (argc == 3) {
suite_name = argv[1];
test_name = argv[2];
filter = suite_test_filter;
}

#ifdef CTEST_NO_COLORS
color_output = 0;
#else
color_output = isatty(1);
#endif

#ifndef __CTEST_NO_TIME
uint64_t t1 = getCurrentTime();
#endif

struct ctest* ctest_begin = &__TNAME(suite, test);
struct ctest* ctest_end = &__TNAME(suite, test);
// find begin and end of section by comparing magics
while (1) {
struct ctest* t = ctest_begin-1;
if (t->magic != __CTEST_MAGIC) break;
ctest_begin--;
}
while (1) {
struct ctest* t = ctest_end+1;
if (t->magic != __CTEST_MAGIC) break;
ctest_end++;
}
ctest_end++; // end after last one
#ifndef CTEST_ADD_TESTS_MANUALLY
__ctest_linkTests();
#endif

static struct ctest* test;
for (test = ctest_begin; test != ctest_end; test++) {
if (test == &__TNAME(suite, test)) continue;

for (test = *(__ctest_head_p); test != NULL; test=test->next) {
if (test == &__ctest_suite_test) continue;
if (filter(test)) total++;
}

for (test = ctest_begin; test != ctest_end; test++) {
if (test == &__TNAME(suite, test)) continue;
for (test = *(__ctest_head_p); test != NULL; test=test->next) {
if (test == &__ctest_suite_test) continue;
if (filter(test)) {
ctest_errorbuffer[0] = 0;
ctest_errorsize = MSG_SIZE-1;
@@ -475,9 +693,9 @@ int ctest_main(int argc, const char *argv[])
color_print(ANSI_BYELLOW, "[SKIPPED]");
num_skip++;
} else {
int result = setjmp(ctest_err);
int result = __CTEST_SETJMP(ctest_err);
if (result == 0) {
#ifdef __APPLE__
#ifdef __CTEST_APPLE
if (!test->setup) {
test->setup = (SetupFunc) find_symbol(test, "setup");
}
@@ -488,7 +706,7 @@ int ctest_main(int argc, const char *argv[])

if (test->setup) test->setup(test->data);
if (test->data)
test->run(test->data);
((RunWithDataFunc)test->run)(test->data);
else
test->run();
if (test->teardown) test->teardown(test->data);
@@ -508,11 +726,15 @@ int ctest_main(int argc, const char *argv[])
index++;
}
}
#ifndef __CTEST_NO_TIME
uint64_t t2 = getCurrentTime();
#endif

const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
char results[80];
sprintf(results, "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %" PRIu64 " ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000);
#ifndef __CTEST_NO_TIME
sprintf(results, "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %"PRIu64" ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000);
#else
sprintf(results, "RESULTS: %d tests (%d ok, %d failed, %d skipped)", total, num_ok, num_fail, num_skip);
#endif
color_print(color, results);
return num_fail;
}


Loading…
Cancel
Save