2018-02-28 21:07:06 -06:00
// 27 february 2018
2018-11-07 09:11:51 -06:00
// TODO
2018-11-11 20:25:45 -06:00
// - https://blogs.msdn.microsoft.com/oldnewthing/20181107-00/?p=100155 https://blogs.msdn.microsoft.com/oldnewthing/20181108-00/?p=100165 https://blogs.msdn.microsoft.com/oldnewthing/20181109-00/?p=100175
// - also in the above: note the unspecified order of data in the sub-segments...
2018-11-07 09:11:51 -06:00
2018-02-28 21:07:06 -06:00
# ifndef testingprivIncludeGuard_testing_h
# define testingprivIncludeGuard_testing_h
# include <stdarg.h>
# undef testingprivBadLanguageVersion
# ifdef __cplusplus
// TODO https://stackoverflow.com/questions/2324658/how-to-determine-the-version-of-the-c-standard-used-by-the-compiler implies this won't do with C++0x-era compilers, and https://wiki.apache.org/stdcxx/C++0xCompilerSupport doesn't talk about va_copy() so a simple version check for the C99 preprocessor may be wrong...
// TODO what if __cplusplus is blank (maybe only in that case, since IIRC C++98 requires __cplusplus to have a value)?
# if __cplusplus < 201103L
# define testingprivBadLanguageVersion
# endif
# elif !defined(__STDC_VERSION__)
# define testingprivBadLanguageVersion
# elif __STDC_VERSION__ < 199901L
# define testingprivBadLanguageVersion
# endif
# ifdef testingprivBadLanguageVersion
# error sorry, TODO requires either C99 or C++11; cannot continue
# endif
# ifdef __cplusplus
extern " C " {
# endif
2018-03-01 19:25:36 -06:00
# ifdef __cplusplus
# define testingprivMkScaffold(name) \
static inline void testingprivScaffold # # name ( testingT * t ) \
{ \
2018-03-03 13:08:17 -06:00
bool failedNow = false , skippedNow = false ; \
2018-03-01 19:25:36 -06:00
try { name ( t ) ; } \
catch ( testingprivFailNowException e ) { failedNow = true ; } \
2018-03-03 13:08:17 -06:00
catch ( testingprivSkipNowException e ) { skippedNow = true ; } \
2018-03-01 19:25:36 -06:00
/* TODO see if we should catch other exceptions too */ \
2018-03-03 13:08:17 -06:00
/* don't call these in the catch blocks as they call longjmp() */ \
2018-03-01 19:25:36 -06:00
if ( failedNow ) testingprivTDoFailNow ( t ) ; \
2018-03-03 13:08:17 -06:00
if ( skippedNow ) testingprivTDoSkipNow ( t ) ; \
2018-03-01 19:25:36 -06:00
}
# else
# define testingprivMkScaffold(name) \
static inline void testingprivScaffold # # name ( testingT * t ) { name ( t ) ; }
# endif
2018-03-04 10:15:18 -06:00
// references:
// - https://gitlab.gnome.org/GNOME/glib/blob/master/glib/gconstructor.h
// - https://gitlab.gnome.org/GNOME/glib/blob/master/gio/glib-compile-resources.c
// - https://msdn.microsoft.com/en-us/library/bb918180.aspx
2018-03-01 19:25:36 -06:00
# if defined(__cplusplus)
# define testingprivMkCtor(name, reg) \
static reg # # Class testingprivCtor # # name ( # name , testingprivScaffold # # name ) ;
# elif defined(__GNUC__)
2018-02-28 21:07:06 -06:00
# define testingprivMkCtor(name, reg) \
2018-03-01 19:25:36 -06:00
__attribute__ ( ( constructor ) ) static void testingprivCtor # # name ( void ) { reg ( # name , testingprivScaffold # # name ) ; }
2018-02-28 21:07:06 -06:00
# elif defined(_MSC_VER)
# define testingprivMkCtorPrototype(name, reg) \
2018-03-01 19:25:36 -06:00
static int name ( void ) testingprivCtor # # name ( void ) { reg ( # name , testingprivScaffold # # name ) ; return 0 ; } \
2018-02-28 21:07:06 -06:00
__pragma ( section ( " .CRT$XCU " , read ) ) \
__declspec ( allocate ( " .CRT$XCU " ) ) static int ( * testingprivCtorPtr # # name ) ( void ) = testingprivCtor # # name ;
# elif defined(__SUNPRO_C)
# define testingprivMkCtor(name, reg) \
2018-03-01 19:25:36 -06:00
_Pragma ( " init(testingprivCtor " # name " ) " ) static void testingprivCtor # # name ( void ) { reg ( # name , testingprivScaffold # # name ) ; }
2018-02-28 21:07:06 -06:00
# else
2018-03-01 19:25:36 -06:00
# error unknown compiler for making constructors in C; cannot continue
2018-02-28 21:07:06 -06:00
# endif
# define testingTest(Name) \
void Test # # Name ( testingT * t ) ; \
2018-03-01 19:25:36 -06:00
testingprivMkScaffold ( Test # # Name ) \
2018-02-28 21:07:06 -06:00
testingprivMkCtor ( Test # # Name , testingprivRegisterTest ) \
void Test # # Name ( testingT * t )
extern int testingMain ( void ) ;
typedef struct testingT testingT ;
2018-03-03 13:22:34 -06:00
# define testingTLogf(t, ...) \
testingprivExpand ( testingprivTLogfThen ( ( void ) , t , __VA_ARGS__ ) )
# define testingTLogvf(t, format, ap) \
testingprivTLogvfThen ( ( void ) , t , format , ap )
# define testingTErrorf(t, ...) \
testingprivExpand ( testingprivTLogfThen ( testingTFail , t , __VA_ARGS__ ) )
# define testingTErrorvf(t, format, ap) \
testingprivTLogvfThen ( testingTFail , t , format , ap )
# define testingTFatalf(t, ...) \
testingprivExpand ( testingprivTLogfThen ( testingTFailNow , t , __VA_ARGS__ ) )
# define testingTFatalvf(t, format, ap) \
testingprivTLogvfThen ( testingTFailNow , t , format , ap )
# define testingTSkipf(t, ...) \
testingprivExpand ( testingprivTLogfThen ( testingTSkipNow , t , __VA_ARGS__ ) )
# define testingTSkipvf(t, format, ap) \
testingprivTLogvfThen ( testingTSkipNow , t , format , ap )
extern void testingTFail ( testingT * t ) ;
2018-03-01 19:25:36 -06:00
# ifdef __cplusplus
# define testingTFailNow(t) (throw testingprivFailNowException())
2018-03-03 13:08:17 -06:00
# define testingTSkipNow(t) (throw testingprivSkipNowException())
2018-03-01 19:25:36 -06:00
# else
2018-03-03 13:08:17 -06:00
# define testingTFailNow(t) (testingprivTDoFailNow(t))
# define testingTSkipNow(t) (testingprivTDoSkipNow(t))
2018-03-01 19:25:36 -06:00
# endif
2018-03-03 15:24:10 -06:00
// TODO should the defered function also have t passed to it?
extern void testingTDefer ( testingT * t , void ( * f ) ( void * data ) , void * data ) ;
2018-02-28 21:07:06 -06:00
2018-03-04 10:25:06 -06:00
// TODO IEEE 754 helpers
// references:
// - https://www.sourceware.org/ml/libc-alpha/2009-04/msg00005.html
// - https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
// - https://stackoverflow.com/questions/5085533/is-a-c-preprocessor-identical-to-a-c-preprocessor
2018-02-28 21:07:06 -06:00
// TODO should __LINE__ arguments use intmax_t or uintmax_t instead of int?
extern void testingprivRegisterTest ( const char * , void ( * ) ( testingT * ) ) ;
2018-03-03 13:22:34 -06:00
// see https://stackoverflow.com/questions/32399191/va-args-expansion-using-msvc
# define testingprivExpand(x) x
# define testingprivTLogfThen(then, t, ...) ((testingprivTLogfFull(t, __FILE__, __LINE__, __VA_ARGS__)), (then(t)))
# define testingprivTLogvfThen(then, t, format, ap) ((testingprivTLogvfFull(t, __FILE__, __LINE__, format, ap)), (then(t)))
2018-03-03 13:08:17 -06:00
extern void testingprivTLogfFull ( testingT * , const char * , int , const char * , . . . ) ;
extern void testingprivTLogvfFull ( testingT * , const char * , int , const char * , va_list ) ;
2018-03-01 19:25:36 -06:00
extern void testingprivTDoFailNow ( testingT * ) ;
2018-03-03 13:08:17 -06:00
extern void testingprivTDoSkipNow ( testingT * ) ;
2018-02-28 21:07:06 -06:00
# ifdef __cplusplus
}
2018-03-01 19:25:36 -06:00
namespace {
class testingprivFailNowException { } ;
2018-03-03 13:08:17 -06:00
class testingprivSkipNowException { } ;
2018-03-01 19:25:36 -06:00
class testingprivRegisterTestClass {
public :
testingprivRegisterTestClass ( const char * name , void ( * f ) ( testingT * ) ) { testingprivRegisterTest ( name , f ) ; }
} ;
}
2018-02-28 21:07:06 -06:00
# endif
# endif