From e15b1af7e09f3bfc923d30b1aca6c76ca8ef51b8 Mon Sep 17 00:00:00 2001 From: Gwendolyn Date: Mon, 3 Jan 2022 17:26:10 +0100 Subject: [PATCH] improved assertion message for memory assertions --- xtest.c | 44 +++++++++++++++++++++++++++++++++++--------- xtest.h | 7 +++++-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/xtest.c b/xtest.c index 39643da..2cd8af5 100644 --- a/xtest.c +++ b/xtest.c @@ -24,7 +24,7 @@ struct xtest_assert_info assertion_info; #define XTEST_INDENT 2 #endif -const char * group_nesting[XTEST_MAX_GROUP_NESTING]; +const char *group_nesting[XTEST_MAX_GROUP_NESTING]; int group_nesting_pos = 0; jmp_buf xtest_jmp; @@ -38,8 +38,6 @@ const char *skip_reason; int xtest_indent = 0; - - int expecting_assertion = 0; int num_tests = 0; int successful_tests = 0; @@ -55,7 +53,7 @@ int xtest_complete() { return failed_tests != 0 ? 1 : 0; } -void subunit_message(const char * name, const char * message, const char * details) { +void subunit_message(const char *name, const char *message, const char *details) { printf("%s: %s", message, name); if (details == NULL) { printf("\n"); @@ -212,12 +210,12 @@ void xtest_internal_assert(const char *file, int line, const char *func, const c #define PRINT_ASSERT_MESSAGE(fmt, type) snprintf(assert_message, XTEST_ASSERT_MESSAGE_MAX_LEN, FAIL_ASSERT_FORMAT(fmt), \ expression, invert ? "not " : "", CAST_PTR(type, expected), CAST_PTR(type, actual), file, line) - void xtest_fail_assert(const char *expression, const char *file, int line, void *expected, void *actual, int invert, enum xtest_type type) { switch (type) { case xtest_type_bool: - snprintf(assert_message, XTEST_ASSERT_MESSAGE_MAX_LEN, FAIL_ASSERT_FORMAT("%s"), expression, invert ? "not " : "", + snprintf(assert_message, XTEST_ASSERT_MESSAGE_MAX_LEN, FAIL_ASSERT_FORMAT("%s"), expression, + invert ? "not " : "", CAST_PTR(_Bool, expected) ? "true" : "false", CAST_PTR(_Bool, actual) ? "true" : "false", file, line); break; @@ -265,7 +263,8 @@ void xtest_fail_assert(const char *expression, const char *file, int line, void break; case xtest_type_other: default: - snprintf(assert_message, XTEST_ASSERT_MESSAGE_MAX_LEN, FAIL_ASSERT_FORMAT("%s"), expression, invert ? "not " : "", + snprintf(assert_message, XTEST_ASSERT_MESSAGE_MAX_LEN, FAIL_ASSERT_FORMAT("%s"), expression, + invert ? "not " : "", "", "", file, line); break; } @@ -283,11 +282,38 @@ xtest_assert_float(double expected, double actual, int precision, int invert, co int equals = diff < epsilon; int failed = invert == equals; // invert = true: fail if equals, invert = false: fail if not equals if (!failed) return; - snprintf(assert_message, 1024, "assertion failed: %s, expected %s%g but got %g (difference %g, precision %d) (%s:%d)", + snprintf(assert_message, 1024, + "assertion failed: %s, expected %s%g but got %g (difference %g, precision %d) (%s:%d)", expression, invert ? "not " : "", expected, actual, diff, precision, file, line); longjmp(xtest_jmp, 1); } +size_t find_diff_offset(const char *a, const char *b, size_t length) { + size_t offset = 0; + while (offset < length && *(a + offset) == *(b + offset)) offset++; + return offset; +} + +void xtest_assert_mem(const char *expected, const char *actual, size_t length, int invert, const char *expression, + const char *file, + int line) { + size_t offset = find_diff_offset(expected, actual, length); + int equals = offset == length; + int failed = invert == equals; // invert = true: fail if equals, invert = false: fail if not equals + if (!failed) return; + + if (invert) { + snprintf(assert_message, 1024, + "assertion failed: %s, expected memory to not match but did (%s:%d)", + expression, file, line); + } else { + snprintf(assert_message, 1024, + "assertion failed: %s, expected memory to match but did not (first different byte at offset %zu, expected 0x%2x but got 0x%2x) (%s:%d)", + expression, offset, (unsigned int) expected[offset], (unsigned int) actual[offset], file, line); + } + + longjmp(xtest_jmp, 1); +} void xtest_skip(const char *reason) { skip_reason = reason; @@ -311,4 +337,4 @@ void xtest_internal_end_group() { void xtest_expect_assertion_failure() { expecting_assertion = 1; -} \ No newline at end of file +} diff --git a/xtest.h b/xtest.h index 5650eb4..1d9a2ba 100644 --- a/xtest.h +++ b/xtest.h @@ -49,6 +49,9 @@ void xtest_assert_float(double expected, double actual, int precision, int invert, const char *expression, const char *file, int line); +void xtest_assert_mem(const char *expected, const char *actual, size_t length, int invert, const char *expression, const char *file, + int line); + void xtest_internal_run(xtest_test_fn fn, const char *name, xtest_param *params, xtest_setup_fn setup, xtest_teardown_fn teardown); @@ -121,8 +124,8 @@ int xtest_complete(); #define xtest_assert_float_is_not(actual, expected, precision) xtest_assert_float(expected, actual, precision, 1, #actual " is not " #expected, __FILE__, __LINE__) #define xtest_assert_str_is(actual, expected) xtest_assert_(strcmp(actual, expected) == 0, #actual " is " #expected, (const char*)(actual), (const char*)(expected), 0) #define xtest_assert_str_is_not(actual, expected) xtest_assert_(strcmp(actual, expected) != 0, #actual " is not " #expected, (const char*)(actual), (const char*)(expected), 1) -#define xtest_assert_mem_is(actual, expected, len) xtest_assert_(memcmp(actual, expected, len) == 0, #actual " is " #expected " (" #len " bytes)", NULL, NULL, 0) -#define xtest_assert_mem_is_not(actual, expected, len) xtest_assert_(memcmp(actual, expected, len) != 0, #actual " is not " #expected " (" #len " bytes)", NULL, NULL, 1) +#define xtest_assert_mem_is(actual, expected, len) xtest_assert_mem(expected, actual, len, 0, #actual " is " #expected " (" #len " bytes)", __FILE__, __LINE__) +#define xtest_assert_mem_is_not(actual, expected, len) xtest_assert_mem(expected, actual, len, 1, #actual " is not " #expected " (" #len " bytes)", __FILE__, __LINE__) #define XTEST_RUN_MAIN(fn) int main(int argc, char ** argv) { \