diff --git a/test/utest.h b/test/utest.h index 073041a..1e2deee 100644 --- a/test/utest.h +++ b/test/utest.h @@ -255,8 +255,8 @@ UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceFrequency( static void __cdecl f(void); \ UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ __pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \ - UTEST_C_FUNC __declspec(allocate(".CRT$XCU")) void(__cdecl * \ - f##_)(void) = f; \ + UTEST_C_FUNC \ + __declspec(allocate(".CRT$XCU")) void(__cdecl * f##_)(void) = f; \ UTEST_INITIALIZER_END_DISABLE_WARNINGS \ static void __cdecl f(void) #else @@ -321,22 +321,32 @@ static UTEST_INLINE void *utest_realloc(void *const pointer, size_t new_size) { void *const new_pointer = realloc(pointer, new_size); if (UTEST_NULL == new_pointer) { - free(new_pointer); + free(pointer); } return new_pointer; } +// Prevent 64-bit integer overflow when computing a timestamp by using a trick +// from Sokol: +// https://github.com/floooh/sokol/blob/189843bf4f86969ca4cc4b6d94e793a37c5128a7/sokol_time.h#L204 +static UTEST_INLINE utest_int64_t utest_mul_div(const utest_int64_t value, + const utest_int64_t numer, + const utest_int64_t denom) { + const utest_int64_t q = value / denom; + const utest_int64_t r = value % denom; + return q * numer + r * numer / denom; +} + static UTEST_INLINE utest_int64_t utest_ns(void) { #if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) utest_large_integer counter; utest_large_integer frequency; QueryPerformanceCounter(&counter); QueryPerformanceFrequency(&frequency); - return UTEST_CAST(utest_int64_t, - (counter.QuadPart * 1000000000) / frequency.QuadPart); + return utest_mul_div(counter.QuadPart, 1000000000, frequency.QuadPart); #elif defined(__linux__) && defined(__STRICT_ANSI__) - return UTEST_CAST(utest_int64_t, clock()) * 1000000000 / CLOCKS_PER_SEC; + return utest_mul_div(clock(), 1000000000, CLOCKS_PER_SEC); #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \ defined(__HAIKU__) @@ -447,6 +457,15 @@ struct utest_type_deducer final { static void _(const T t); }; +template <> struct utest_type_deducer { + static void _(const char c) { + if (std::is_signed::value) { + UTEST_PRINTF("%d", static_cast(c)); + } else { + UTEST_PRINTF("%u", static_cast(c)); + } + } +}; template <> struct utest_type_deducer { static void _(const signed char c) { UTEST_PRINTF("%d", static_cast(c)); @@ -465,7 +484,7 @@ template <> struct utest_type_deducer { template <> struct utest_type_deducer { static void _(const unsigned short s) { - UTEST_PRINTF("%u", static_cast(s)); + UTEST_PRINTF("%u", static_cast(s)); } }; @@ -512,6 +531,10 @@ template <> struct utest_type_deducer { static void _(const unsigned long long i) { UTEST_PRINTF("%llu", i); } }; +template <> struct utest_type_deducer { + static void _(const bool i) { UTEST_PRINTF(i ? "true" : "false"); } +}; + template struct utest_type_deducer { static void _(const T *t) { UTEST_PRINTF("%p", static_cast(const_cast(t))); @@ -528,6 +551,12 @@ template struct utest_type_deducer { } }; +template <> struct utest_type_deducer { + static void _(std::nullptr_t t) { + UTEST_PRINTF("%p", static_cast(t)); + } +}; + template UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const T t) { utest_type_deducer::_(t); @@ -626,24 +655,23 @@ utest_type_printer(long long unsigned int i) { !(defined(__MINGW32__) || defined(__MINGW64__)) || \ defined(__TINYC__) #define utest_type_printer(val) \ - UTEST_PRINTF(_Generic((val), signed char \ - : "%d", unsigned char \ - : "%u", short \ - : "%d", unsigned short \ - : "%u", int \ - : "%d", long \ - : "%ld", long long \ - : "%lld", unsigned \ - : "%u", unsigned long \ - : "%lu", unsigned long long \ - : "%llu", float \ - : "%f", double \ - : "%f", long double \ - : "%Lf", default \ - : _Generic((val - val), ptrdiff_t \ - : "%p", default \ - : "undef")), \ - (val)) + UTEST_PRINTF( \ + _Generic((val), \ + signed char: "%d", \ + unsigned char: "%u", \ + short: "%d", \ + unsigned short: "%u", \ + int: "%d", \ + long: "%ld", \ + long long: "%lld", \ + unsigned: "%u", \ + unsigned long: "%lu", \ + unsigned long long: "%llu", \ + float: "%f", \ + double: "%f", \ + long double: "%Lf", \ + default: _Generic((val - val), ptrdiff_t: "%p", default: "undef")), \ + (val)) #else /* we don't have the ability to print the values we got, so we create a macro @@ -724,10 +752,12 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) { UTEST_AUTO(x) xEval = (x); \ UTEST_AUTO(y) yEval = (y); \ if (!((xEval)cond(yEval))) { \ + const char *const xAsString = #x; \ + const char *const yAsString = #y; \ _Pragma("clang diagnostic pop") \ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ UTEST_PRINTF(" Expected : ("); \ - UTEST_PRINTF(#x ") " #cond " (" #y); \ + UTEST_PRINTF("%s) " #cond " (%s", xAsString, yAsString); \ UTEST_PRINTF(")\n"); \ UTEST_PRINTF(" Actual : "); \ utest_type_printer(xEval); \ @@ -751,9 +781,11 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) { UTEST_AUTO(x) xEval = (x); \ UTEST_AUTO(y) yEval = (y); \ if (!((xEval)cond(yEval))) { \ + const char *const xAsString = #x; \ + const char *const yAsString = #y; \ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ UTEST_PRINTF(" Expected : ("); \ - UTEST_PRINTF(#x ") " #cond " (" #y); \ + UTEST_PRINTF("%s) " #cond " (%s", xAsString, yAsString); \ UTEST_PRINTF(")\n"); \ UTEST_PRINTF(" Actual : "); \ utest_type_printer(xEval); \ @@ -1138,13 +1170,19 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) { utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ sizeof(struct utest_test_state_s) * \ utest_state.tests_length)); \ - if (utest_state.tests) { \ + if (utest_state.tests && name) { \ utest_state.tests[index].func = &utest_##SET##_##NAME; \ utest_state.tests[index].name = name; \ utest_state.tests[index].index = 0; \ UTEST_SNPRINTF(name, name_size, "%s", name_part); \ - } else if (name) { \ - free(name); \ + } else { \ + if (utest_state.tests) { \ + free(utest_state.tests); \ + utest_state.tests = NULL; \ + } \ + if (name) { \ + free(name); \ + } \ } \ } \ UTEST_SURPRESS_WARNINGS_END \ @@ -1186,12 +1224,19 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) { utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ sizeof(struct utest_test_state_s) * \ utest_state.tests_length)); \ - if (utest_state.tests) { \ + if (utest_state.tests && name) { \ utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \ utest_state.tests[index].name = name; \ + utest_state.tests[index].index = 0; \ UTEST_SNPRINTF(name, name_size, "%s", name_part); \ - } else if (name) { \ - free(name); \ + } else { \ + if (utest_state.tests) { \ + free(utest_state.tests); \ + utest_state.tests = NULL; \ + } \ + if (name) { \ + free(name); \ + } \ } \ } \ UTEST_SURPRESS_WARNINGS_END \ @@ -1234,14 +1279,20 @@ utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) { utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ sizeof(struct utest_test_state_s) * \ utest_state.tests_length)); \ - if (utest_state.tests) { \ + if (utest_state.tests && name) { \ utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \ utest_state.tests[index].index = i; \ utest_state.tests[index].name = name; \ iUp = UTEST_CAST(utest_uint64_t, i); \ UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \ - } else if (name) { \ - free(name); \ + } else { \ + if (utest_state.tests) { \ + free(utest_state.tests); \ + utest_state.tests = NULL; \ + } \ + if (name) { \ + free(name); \ + } \ } \ } \ } \