improved assertion message for memory assertions

This commit is contained in:
Gwendolyn 2022-01-03 17:26:10 +01:00
parent 19ebe3d7b6
commit e15b1af7e0
2 changed files with 40 additions and 11 deletions

44
xtest.c
View file

@ -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 " : "",
"<value of unknown type>", "<value of unknown type>", 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;
}
}

View file

@ -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) { \