Commit a3c4a48e authored by Deomid Ryabkov's avatar Deomid Ryabkov Committed by Cesanta Bot

Make sure test assertions are evaluated once

E.g. if `ASSERT_EQ(myfunc(), 123)` fails, `myfunc()` would be invoked again to print the actual value.
This can cause confusion sometimes.
To avoid this, we cast arguments to double, which is wide enough for most cases and we provide a variant for 64 bit value types for when it's not.
We also perform a check and fail if argument to the check results in loss of precision.

CL: none

PUBLISHED_FROM=a14551289d92e8a5dead21d16471ebddebe938a8
parent 84a11fe3
...@@ -77,22 +77,67 @@ void _strfail(const char *a, const char *e, int len); ...@@ -77,22 +77,67 @@ void _strfail(const char *a, const char *e, int len);
if (msg) return msg; \ if (msg) return msg; \
} while (0) } 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) #if (defined(_MSC_VER) && _MSC_VER <= 1200)
#define AS_DOUBLE(d) (double)(int64_t)(d) #define LONG_TYPE int64_t
#else #else
#define AS_DOUBLE(d) (double)(d) #define LONG_TYPE long long
#endif #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 * Numeric equality assertion.
* printing both are convetrted to double. * 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) \ #define ASSERT_EQ(actual, expected) \
do { \ 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++; \ g_num_checks++; \
if (!((actual) == (expected))) { \ if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \
printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \ 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__); \ FAIL(#actual " == " #expected, __LINE__); \
} \ } \
} while (0) } while (0)
...@@ -100,9 +145,14 @@ void _strfail(const char *a, const char *e, int len); ...@@ -100,9 +145,14 @@ void _strfail(const char *a, const char *e, int len);
/* "Less than" assertion. */ /* "Less than" assertion. */
#define ASSERT_LT(a, b) \ #define ASSERT_LT(a, b) \
do { \ do { \
const double ad = AS_DOUBLE(a); \
const double bd = AS_DOUBLE(b); \
g_num_checks++; \ g_num_checks++; \
if (!((a) < (b))) { \ if (RANGE_CHECK(ad) || RANGE_CHECK(bd)) { \
printf("%f >= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ FAIL("loss of precision in comparison", __LINE__); \
} \
if (!(ad < bd)) { \
printf("%lf >= %lf\n", ad, bd); \
FAIL(#a " < " #b, __LINE__); \ FAIL(#a " < " #b, __LINE__); \
} \ } \
} while (0) } while (0)
...@@ -110,9 +160,11 @@ void _strfail(const char *a, const char *e, int len); ...@@ -110,9 +160,11 @@ void _strfail(const char *a, const char *e, int len);
/* "Greater than" assertion. */ /* "Greater than" assertion. */
#define ASSERT_GT(a, b) \ #define ASSERT_GT(a, b) \
do { \ do { \
const double ad = AS_DOUBLE(a); \
const double bd = AS_DOUBLE(b); \
g_num_checks++; \ g_num_checks++; \
if (!((a) > (b))) { \ if (!(ad > bd)) { \
printf("%f <= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ printf("%lf <= %lf\n", ad, bd); \
FAIL(#a " > " #b, __LINE__); \ FAIL(#a " > " #b, __LINE__); \
} \ } \
} while (0) } while (0)
...@@ -121,7 +173,7 @@ void _strfail(const char *a, const char *e, int len); ...@@ -121,7 +173,7 @@ void _strfail(const char *a, const char *e, int len);
#define ASSERT_STREQ(actual, expected) \ #define ASSERT_STREQ(actual, expected) \
do { \ do { \
g_num_checks++; \ g_num_checks++; \
if (!_assert_streq(actual, expected)) { \ if (!_assert_streq((actual), (expected))) { \
FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \ FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \
} \ } \
} while (0) } while (0)
...@@ -129,20 +181,24 @@ void _strfail(const char *a, const char *e, int len); ...@@ -129,20 +181,24 @@ void _strfail(const char *a, const char *e, int len);
/* Assert that actual == expected, where both are pointers */ /* Assert that actual == expected, where both are pointers */
#define ASSERT_PTREQ(actual, expected) \ #define ASSERT_PTREQ(actual, expected) \
do { \ do { \
const void *ap = (const void *) (actual); \
const void *ep = (const void *) (expected); \
g_num_checks++; \ g_num_checks++; \
if (actual != expected) { \ if (!(ap == ep)) { \
printf("%p != %p\n", actual, expected); \ printf("%p != %p\n", ap, ep); \
FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \ FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \
} \ } \
} while (0) } while (0)
/* Assert that actual != expected, where both are pointers */ /* Assert that actual != expected, where both are pointers */
#define ASSERT_PTRNEQ(actual, expected) \ #define ASSERT_PTRNE(actual, expected) \
do { \ do { \
const void *ap = (const void *) (actual); \
const void *ep = (const void *) (expected); \
g_num_checks++; \ g_num_checks++; \
if (actual == expected) { \ if (!(ap != ep)) { \
printf("%p == %p\n", actual, expected); \ printf("%p == %p\n", ap, ep); \
FAIL("ASSERT_PTRNEQ(" #actual ", " #expected ")", __LINE__); \ FAIL("ASSERT_PTRNE(" #actual ", " #expected ")", __LINE__); \
} \ } \
} while (0) } while (0)
......
...@@ -1533,7 +1533,7 @@ static const char *test_parse_http_message(void) { ...@@ -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_vcmp(&req.query_string, "a=b&c=d"), 0);
ASSERT_EQ(mg_parse_http(f, strlen(f), &req, 1), (int) strlen(f)); 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(mg_parse_http(g, strlen(g), &req, 1), (int) strlen(g));
ASSERT_EQ(req.body.len, 0); ASSERT_EQ(req.body.len, 0);
...@@ -1542,7 +1542,7 @@ static const char *test_parse_http_message(void) { ...@@ -1542,7 +1542,7 @@ static const char *test_parse_http_message(void) {
ASSERT_EQ(mg_vcmp(&req.proto, "HTTP/1.0"), 0); ASSERT_EQ(mg_vcmp(&req.proto, "HTTP/1.0"), 0);
ASSERT_EQ(req.resp_code, 200); ASSERT_EQ(req.resp_code, 200);
ASSERT_EQ(mg_vcmp(&req.resp_status_msg, "OK"), 0); 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); ASSERT_EQ(mg_parse_http(i, strlen(i), &req, 0), -1);
...@@ -3921,7 +3921,7 @@ static const char *test_http_chunk2(void) { ...@@ -3921,7 +3921,7 @@ static const char *test_http_chunk2(void) {
strcat(buf, "3\r\n...\r\na\r\n0123456789\r\n0\r"); strcat(buf, "3\r\n...\r\na\r\n0123456789\r\n0\r");
ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13);
ASSERT_STREQ(buf, "...01234567890\r"); 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"); strcat(buf, "\n\r\n");
ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment