diff --git a/src/common/test_util.h b/src/common/test_util.h index fbc0eae3..60618f10 100644 --- a/src/common/test_util.h +++ b/src/common/test_util.h @@ -77,51 +77,103 @@ void _strfail(const char *a, const char *e, int len); if (msg) return msg; \ } while (0) -/* VC6 doesn't know how to cast an unsigned 64-bit int to double */ +/* VC6 doesn't have long long. */ #if (defined(_MSC_VER) && _MSC_VER <= 1200) -#define AS_DOUBLE(d) (double)(int64_t)(d) +#define LONG_TYPE int64_t #else -#define AS_DOUBLE(d) (double)(d) +#define LONG_TYPE long long #endif +#define AS_DOUBLE(d) (double)(d) + +#define RANGE_CHECK(x) (fabs(x) > 4503599627370496.0 /* 2 << 51 */) /* - * Numeric equality assertion. Comparison is made in native types but for - * printing both are convetrted to double. + * Numeric equality assertion. + * Args are cast to double to ensure aruemnts are only evaluated once. + * This will work fine for all integer types except large 64-bit values. */ -#define ASSERT_EQ(actual, expected) \ - do { \ - g_num_checks++; \ - if (!((actual) == (expected))) { \ - printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \ - FAIL(#actual " == " #expected, __LINE__); \ - } \ +#define ASSERT_EQ(actual, expected) \ + do { \ + const double ad = AS_DOUBLE(actual); \ + const double ed = AS_DOUBLE(expected); \ + if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \ + FAIL("loss of precision, use ASSERT_EQ64", __LINE__); \ + } \ + g_num_checks++; \ + if (!(ad == ed)) { \ + printf("%lf != %lf\n", ad, ed); \ + FAIL(#actual " != " #expected, __LINE__); \ + } \ + } while (0) + +#define ASSERT_EQ64(actual, expected) \ + do { \ + const LONG_TYPE a64 = (LONG_TYPE)(actual); \ + const LONG_TYPE e64 = (LONG_TYPE)(expected); \ + g_num_checks++; \ + if (!(a64 == e64)) { \ + printf("%lld != %lld\n", a64, e64); \ + FAIL(#actual " != " #expected, __LINE__); \ + } \ + } while (0) + +#define ASSERT_NE(actual, expected) \ + do { \ + const double ad = AS_DOUBLE(actual); \ + const double ed = AS_DOUBLE(expected); \ + g_num_checks++; \ + if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \ + FAIL("loss of precision, use ASSERT_NE64", __LINE__); \ + } \ + if (!(ad != ed)) { \ + printf("%lf == %lf\n", ad, ed); \ + FAIL(#actual " == " #expected, __LINE__); \ + } \ + } while (0) + +#define ASSERT_NE64(actual, expected) \ + do { \ + const LONG_TYPE a64 = (LONG_TYPE)(actual); \ + const LONG_TYPE e64 = (LONG_TYPE)(expected); \ + g_num_checks++; \ + if (!(a64 != e64)) { \ + printf("%lld == %lld\n", a64, e64); \ + FAIL(#actual " == " #expected, __LINE__); \ + } \ } while (0) /* "Less than" assertion. */ -#define ASSERT_LT(a, b) \ - do { \ - g_num_checks++; \ - if (!((a) < (b))) { \ - printf("%f >= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ - FAIL(#a " < " #b, __LINE__); \ - } \ +#define ASSERT_LT(a, b) \ + do { \ + const double ad = AS_DOUBLE(a); \ + const double bd = AS_DOUBLE(b); \ + g_num_checks++; \ + if (RANGE_CHECK(ad) || RANGE_CHECK(bd)) { \ + FAIL("loss of precision in comparison", __LINE__); \ + } \ + if (!(ad < bd)) { \ + printf("%lf >= %lf\n", ad, bd); \ + FAIL(#a " < " #b, __LINE__); \ + } \ } while (0) /* "Greater than" assertion. */ -#define ASSERT_GT(a, b) \ - do { \ - g_num_checks++; \ - if (!((a) > (b))) { \ - printf("%f <= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ - FAIL(#a " > " #b, __LINE__); \ - } \ +#define ASSERT_GT(a, b) \ + do { \ + const double ad = AS_DOUBLE(a); \ + const double bd = AS_DOUBLE(b); \ + g_num_checks++; \ + if (!(ad > bd)) { \ + printf("%lf <= %lf\n", ad, bd); \ + FAIL(#a " > " #b, __LINE__); \ + } \ } while (0) /* Assert that actual == expected, where both are NUL-terminated. */ #define ASSERT_STREQ(actual, expected) \ do { \ g_num_checks++; \ - if (!_assert_streq(actual, expected)) { \ + if (!_assert_streq((actual), (expected))) { \ FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \ } \ } while (0) @@ -129,21 +181,25 @@ void _strfail(const char *a, const char *e, int len); /* Assert that actual == expected, where both are pointers */ #define ASSERT_PTREQ(actual, expected) \ do { \ + const void *ap = (const void *) (actual); \ + const void *ep = (const void *) (expected); \ g_num_checks++; \ - if (actual != expected) { \ - printf("%p != %p\n", actual, expected); \ + if (!(ap == ep)) { \ + printf("%p != %p\n", ap, ep); \ FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \ } \ } while (0) /* Assert that actual != expected, where both are pointers */ -#define ASSERT_PTRNEQ(actual, expected) \ - do { \ - g_num_checks++; \ - if (actual == expected) { \ - printf("%p == %p\n", actual, expected); \ - FAIL("ASSERT_PTRNEQ(" #actual ", " #expected ")", __LINE__); \ - } \ +#define ASSERT_PTRNE(actual, expected) \ + do { \ + const void *ap = (const void *) (actual); \ + const void *ep = (const void *) (expected); \ + g_num_checks++; \ + if (!(ap != ep)) { \ + printf("%p == %p\n", ap, ep); \ + FAIL("ASSERT_PTRNE(" #actual ", " #expected ")", __LINE__); \ + } \ } while (0) /* Same as STREQ, but only expected is NUL-terminated. */ diff --git a/test/unit_test.c b/test/unit_test.c index ff080c58..d9cee8a3 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1533,7 +1533,7 @@ static const char *test_parse_http_message(void) { ASSERT_EQ(mg_vcmp(&req.query_string, "a=b&c=d"), 0); ASSERT_EQ(mg_parse_http(f, strlen(f), &req, 1), (int) strlen(f)); - ASSERT_EQ(req.body.len, (size_t) ~0); + ASSERT_EQ64(req.body.len, (size_t) ~0); ASSERT_EQ(mg_parse_http(g, strlen(g), &req, 1), (int) strlen(g)); ASSERT_EQ(req.body.len, 0); @@ -1542,7 +1542,7 @@ static const char *test_parse_http_message(void) { ASSERT_EQ(mg_vcmp(&req.proto, "HTTP/1.0"), 0); ASSERT_EQ(req.resp_code, 200); ASSERT_EQ(mg_vcmp(&req.resp_status_msg, "OK"), 0); - ASSERT_EQ(req.body.len, (size_t) ~0); + ASSERT_EQ64(req.body.len, (size_t) ~0); ASSERT_EQ(mg_parse_http(i, strlen(i), &req, 0), -1); @@ -3921,7 +3921,7 @@ static const char *test_http_chunk2(void) { strcat(buf, "3\r\n...\r\na\r\n0123456789\r\n0\r"); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); ASSERT_STREQ(buf, "...01234567890\r"); - ASSERT_EQ(hm.message.len, (size_t) ~0); + ASSERT_EQ64(hm.message.len, (size_t) ~0); strcat(buf, "\n\r\n"); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13);