From b8f18025225bd2f895a5e4f6396762614a6bace1 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Sat, 31 Mar 2018 15:21:36 +0300 Subject: [PATCH 1/5] Eliminate use of empty struct in test code Where GCC and Clang issue warnings such as "empty struct is a GNU extension" (with `-Wgnu-empty-struct`) or "empty struct has size 0 in C, size 1 in C++" (with `-Wc++-compat`), MSVC issues an error C2016 "C requires that a struct or union has at least one member". --- mytests.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mytests.c b/mytests.c index ff0ece3..a667d6b 100644 --- a/mytests.c +++ b/mytests.c @@ -54,7 +54,9 @@ CTEST2(memtest, test2) { } -CTEST_DATA(fail) {}; +CTEST_DATA(fail) { + int unused; +}; // Asserts can also be used in setup/teardown functions CTEST_SETUP(fail) { From fb4e0dda3c3594643e2fabcdad31845fdad90809 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Sat, 31 Mar 2018 15:26:58 +0300 Subject: [PATCH 2/5] Eliminate type casting warnings in test code This fixes MSVC warning C4013 "'type cast': conversion from 'unsigned int' to 'void *' of greater size". --- mytests.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mytests.c b/mytests.c index a667d6b..167d602 100644 --- a/mytests.c +++ b/mytests.c @@ -124,7 +124,7 @@ CTEST(ctest, test_assert_interval) { CTEST(ctest, test_assert_null) { ASSERT_NULL(NULL); - ASSERT_NULL((void*)0xdeadbeef); + ASSERT_NULL((void*)(intptr_t)0xdeadbeef); } CTEST(ctest, test_assert_not_null_const) { @@ -132,7 +132,7 @@ CTEST(ctest, test_assert_not_null_const) { } CTEST(ctest, test_assert_not_null) { - ASSERT_NOT_NULL((void*)0xdeadbeef); + ASSERT_NOT_NULL((void*)(intptr_t)0xdeadbeef); ASSERT_NOT_NULL(NULL); } From bb924ad04862ca8e9f484f5fc7fd42e903d195b2 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Sat, 31 Mar 2018 16:12:29 +0300 Subject: [PATCH 3/5] Use platform-specific sleep in test code On Windows, `Sleep` is used. It's not as precise as `usleep`: it accepts milliseconds instead of microseconds, and even then its precision is limited to about 16ms. This is a test code though so it doesn't matter much. --- mytests.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mytests.c b/mytests.c index 167d602..418fe13 100644 --- a/mytests.c +++ b/mytests.c @@ -1,10 +1,18 @@ -#include #include + +#ifndef _WIN32 +#include +#define MSLEEP(ms) usleep((ms) * 1000) +#else +#include +#define MSLEEP(ms) Sleep(ms) +#endif + #include "ctest.h" // basic test without setup/teardown CTEST(suite1, test1) { - usleep(2000); + MSLEEP(2); } // there are many different ASSERT macro's (see ctest.h) From 37c65d898bc00e782f4f4caf47713dee7589e8c2 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Sat, 31 Mar 2018 14:24:09 +0300 Subject: [PATCH 4/5] Use C99 `snprintf` instead of `sprintf` Since we're already using `vsnprintf` and other C99 features, it's only natural to use `snprintf` as well. Moreover, `sprintf` is "deprecated" in Microsoft's CRT in favor of more secure (Microsoft-specific) alternatives with its use resulting in a warning, while `snprintf` isn't (although requires recent enough CRT). --- ctest.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ctest.h b/ctest.h index fab67fc..40d4d99 100644 --- a/ctest.h +++ b/ctest.h @@ -425,7 +425,7 @@ static void color_print(const char* color, const char* text) { static void sighandler(int signum) { char msg[128]; - sprintf(msg, "[SIGNAL %d: %s]", signum, sys_siglist[signum]); + snprintf(msg, sizeof(msg), "[SIGNAL %d: %s]", signum, sys_siglist[signum]); color_print(ANSI_BRED, msg); fflush(stdout); @@ -523,7 +523,7 @@ int ctest_main(int argc, const char *argv[]) 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); + snprintf(results, sizeof(results), "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %" PRIu64 " ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000); color_print(color, results); return num_fail; } From 41ce2206af3fda86913be153dcd6afdf6d0a8aa1 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Sat, 31 Mar 2018 16:15:18 +0300 Subject: [PATCH 5/5] Support MSVC compiler This doesn't include changes to support `SIGSEGV` as even its support in its current form seems questionable to me. This means that to use ctest with MSVC you need to leave `CTEST_SIGSEGV` undefined. --- ctest.h | 36 ++++++++++++++++++++++++++++++------ main.c | 2 +- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/ctest.h b/ctest.h index 40d4d99..b39f569 100644 --- a/ctest.h +++ b/ctest.h @@ -79,14 +79,19 @@ CTEST_IMPL_DIAG_POP() #define CTEST_IMPL_TEARDOWN_FPNAME(sname) CTEST_IMPL_NAME(sname##_teardown_ptr) #define CTEST_IMPL_MAGIC (0xdeadbeef) -#ifdef __APPLE__ +#if defined(_MSC_VER) +#pragma data_seg(push) +#pragma data_seg(".ctest$u") +#pragma data_seg(pop) +#define CTEST_IMPL_SECTION __declspec(allocate(".ctest$u")) __declspec(align(1)) +#elif defined(__APPLE__) #define CTEST_IMPL_SECTION __attribute__ ((used, section ("__DATA, .ctest"), aligned(1))) #else #define CTEST_IMPL_SECTION __attribute__ ((used, section (".ctest"), aligned(1))) #endif #define CTEST_IMPL_STRUCT(sname, tname, tskip, tdata, tsetup, tteardown) \ - static struct ctest CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_SECTION = { \ + static struct ctest CTEST_IMPL_SECTION CTEST_IMPL_TNAME(sname, tname) = { \ .ssname=#sname, \ .ttname=#tname, \ .run = CTEST_IMPL_FNAME(sname, tname), \ @@ -187,11 +192,19 @@ void assert_dbl_far(double exp, double real, double tol, const char* caller, int #include #include #include -#include -#include #include #include +#ifndef _WIN32 +#include +#include +#define CTEST_IMPL_ISATTY isatty +#else +#include +#include +#define CTEST_IMPL_ISATTY _isatty +#endif + static size_t ctest_errorsize; static char* ctest_errormsg; #define MSG_SIZE 4096 @@ -405,11 +418,22 @@ static int suite_filter(struct ctest* t) { } static uint64_t getCurrentTime(void) { + uint64_t now64; +#ifndef _WIN32 struct timeval now; gettimeofday(&now, NULL); - uint64_t now64 = (uint64_t) now.tv_sec; + now64 = (uint64_t) now.tv_sec; now64 *= 1000000; now64 += ((uint64_t) now.tv_usec); +#else + LARGE_INTEGER frequency; + LARGE_INTEGER counter; + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + now64 = counter.QuadPart; + now64 *= 1000000; + now64 /= frequency.QuadPart; +#endif return now64; } @@ -458,7 +482,7 @@ int ctest_main(int argc, const char *argv[]) #ifdef CTEST_NO_COLORS color_output = 0; #else - color_output = isatty(1); + color_output = CTEST_IMPL_ISATTY(1); #endif uint64_t t1 = getCurrentTime(); diff --git a/main.c b/main.c index 3b047d9..5c3dbd1 100644 --- a/main.c +++ b/main.c @@ -3,7 +3,7 @@ #define CTEST_MAIN // uncomment lines below to enable/disable features. See README.md for details -#define CTEST_SEGFAULT +//#define CTEST_SEGFAULT //#define CTEST_NO_COLORS //#define CTEST_COLOR_OK