Add basic C++ support

This commit adds C++ support with the following modifications:
- Remove the use of C-only features including designated initializers
  and non-strict prototypes.
- Add spaces between literals and string macros to silence the C++-only
  -Wliteral-suffix warning.
- Conditionally use template specialization instead of tentative
  definitions to implement optional setup/teardown functions.

Note that no C++-specific features have been added.  The goal of this
commit is to simply enable compiling in C++ mode.
This commit is contained in:
Andrew Eckel 2020-08-19 23:09:41 -04:00
parent f12e0d811b
commit f8a83d694b
2 changed files with 60 additions and 17 deletions

View File

@ -1,6 +1,6 @@
# CTEST
ctest is a unit test framework for software written in C.
ctest is a unit test framework for software written in C/C++.
Features:
* adding tests with minimal hassle (no manual adding to suites or testlists!)

75
ctest.h
View File

@ -16,6 +16,10 @@
#ifndef CTEST_H
#define CTEST_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __GNUC__
#define CTEST_IMPL_FORMAT_PRINTF(a, b) __attribute__ ((format(printf, a, b)))
#else
@ -25,9 +29,16 @@
#include <inttypes.h> /* intmax_t, uintmax_t, PRI* */
#include <stddef.h> /* size_t */
typedef void (*ctest_nullary_run_func)(void);
typedef void (*ctest_unary_run_func)(void*);
typedef void (*ctest_setup_func)(void*);
typedef void (*ctest_teardown_func)(void*);
union ctest_run_func_union {
ctest_nullary_run_func nullary;
ctest_unary_run_func unary;
};
#define CTEST_IMPL_PRAGMA(x) _Pragma (#x)
#if defined(__GNUC__)
@ -50,12 +61,10 @@ typedef void (*ctest_teardown_func)(void*);
#define CTEST_IMPL_DIAG_POP()
#endif
CTEST_IMPL_DIAG_PUSH_IGNORED(strict-prototypes)
struct ctest {
const char* ssname; // suite name
const char* ttname; // test name
void (*run)();
union ctest_run_func_union run;
void* data;
ctest_setup_func* setup;
@ -66,8 +75,6 @@ struct ctest {
unsigned int magic;
};
CTEST_IMPL_DIAG_POP()
#define CTEST_IMPL_NAME(name) ctest_##name
#define CTEST_IMPL_FNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_run)
#define CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname)
@ -75,8 +82,10 @@ CTEST_IMPL_DIAG_POP()
#define CTEST_IMPL_DATA_TNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_data)
#define CTEST_IMPL_SETUP_FNAME(sname) CTEST_IMPL_NAME(sname##_setup)
#define CTEST_IMPL_SETUP_FPNAME(sname) CTEST_IMPL_NAME(sname##_setup_ptr)
#define CTEST_IMPL_SETUP_TPNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_setup_ptr)
#define CTEST_IMPL_TEARDOWN_FNAME(sname) CTEST_IMPL_NAME(sname##_teardown)
#define CTEST_IMPL_TEARDOWN_FPNAME(sname) CTEST_IMPL_NAME(sname##_teardown_ptr)
#define CTEST_IMPL_TEARDOWN_TPNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_teardown_ptr)
#define CTEST_IMPL_MAGIC (0xdeadbeef)
#ifdef __APPLE__
@ -87,14 +96,43 @@ CTEST_IMPL_DIAG_POP()
#define CTEST_IMPL_STRUCT(sname, tname, tskip, tdata, tsetup, tteardown) \
static struct ctest CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_SECTION = { \
.ssname=#sname, \
.ttname=#tname, \
.run = CTEST_IMPL_FNAME(sname, tname), \
.data = tdata, \
.setup = (ctest_setup_func*) tsetup, \
.teardown = (ctest_teardown_func*) tteardown, \
.skip = tskip, \
.magic = CTEST_IMPL_MAGIC }
#sname, \
#tname, \
{ (ctest_nullary_run_func) CTEST_IMPL_FNAME(sname, tname) }, \
tdata, \
(ctest_setup_func*) tsetup, \
(ctest_teardown_func*) tteardown, \
tskip, \
CTEST_IMPL_MAGIC, \
}
#ifdef __cplusplus
#define CTEST_SETUP(sname) \
template <> void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
#define CTEST_TEARDOWN(sname) \
template <> void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
#define CTEST_DATA(sname) \
template <typename T> void CTEST_IMPL_SETUP_FNAME(sname)(T* data) { } \
template <typename T> void CTEST_IMPL_TEARDOWN_FNAME(sname)(T* data) { } \
struct CTEST_IMPL_DATA_SNAME(sname)
#define CTEST_IMPL_CTEST(sname, tname, tskip) \
static void CTEST_IMPL_FNAME(sname, tname)(void); \
CTEST_IMPL_STRUCT(sname, tname, tskip, NULL, NULL, NULL); \
static void CTEST_IMPL_FNAME(sname, tname)(void)
#define CTEST_IMPL_CTEST2(sname, tname, tskip) \
static struct CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_DATA_TNAME(sname, tname); \
static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
static void (*CTEST_IMPL_SETUP_TPNAME(sname, tname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_SETUP_FNAME(sname)<struct CTEST_IMPL_DATA_SNAME(sname)>; \
static void (*CTEST_IMPL_TEARDOWN_TPNAME(sname, tname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_TEARDOWN_FNAME(sname)<struct CTEST_IMPL_DATA_SNAME(sname)>; \
CTEST_IMPL_STRUCT(sname, tname, tskip, &CTEST_IMPL_DATA_TNAME(sname, tname), &CTEST_IMPL_SETUP_TPNAME(sname, tname), &CTEST_IMPL_TEARDOWN_TPNAME(sname, tname)); \
static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
#else
#define CTEST_SETUP(sname) \
static void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* data); \
@ -123,6 +161,7 @@ CTEST_IMPL_DIAG_POP()
CTEST_IMPL_STRUCT(sname, tname, tskip, &CTEST_IMPL_DATA_TNAME(sname, tname), &CTEST_IMPL_SETUP_FPNAME(sname), &CTEST_IMPL_TEARDOWN_FPNAME(sname)); \
static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* data)
#endif
void CTEST_LOG(const char* fmt, ...) CTEST_IMPL_FORMAT_PRINTF(1, 2);
void CTEST_ERR(const char* fmt, ...) CTEST_IMPL_FORMAT_PRINTF(1, 2); // doesn't return
@ -427,7 +466,7 @@ static uint64_t getCurrentTime(void) {
static void color_print(const char* color, const char* text) {
if (color_output)
printf("%s%s"ANSI_NORMAL"\n", color, text);
printf("%s%s" ANSI_NORMAL "\n", color, text);
else
printf("%s\n", text);
}
@ -512,9 +551,9 @@ __attribute__((no_sanitize_address)) int ctest_main(int argc, const char *argv[]
if (result == 0) {
if (test->setup && *test->setup) (*test->setup)(test->data);
if (test->data)
test->run(test->data);
test->run.unary(test->data);
else
test->run();
test->run.nullary();
if (test->teardown && *test->teardown) (*test->teardown)(test->data);
// if we got here it's ok
#ifdef CTEST_COLOR_OK
@ -543,5 +582,9 @@ __attribute__((no_sanitize_address)) int ctest_main(int argc, const char *argv[]
#endif
#ifdef __cplusplus
}
#endif
#endif