diff --git a/src/shared/tests.h b/src/shared/tests.h index 0eb972ede51..e6dbccb1a8a 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -5,8 +5,11 @@ #include "errno-list.h" #include "forward.h" +#include "hexdump.h" /* IWYU pragma: keep */ +#include "iovec-util.h" /* IWYU pragma: keep */ #include "log.h" #include "log-assert-critical.h" +#include "memory-util.h" /* IWYU pragma: keep */ #include "path-util.h" /* IWYU pragma: keep */ #include "static-destruct.h" /* IWYU pragma: keep */ #include "signal-util.h" /* IWYU pragma: keep */ @@ -563,6 +566,53 @@ _noreturn_ void log_test_failed_internal(const char *file, int line, const char }) #endif +#ifdef __COVERITY__ +# define ASSERT_MEMEQ(p1, p2, n) __coverity_check__(memcmp_safe((p1), (p2), (n)) == 0) +#else +# define ASSERT_MEMEQ(p1, p2, n) \ + ({ \ + const void *_p1 = (p1), *_p2 = (p2); \ + size_t _n = (n); \ + if (memcmp_safe(_p1, _p2, _n) != 0) { \ + _cleanup_free_ char *_dump = hexdump_memcmp(_p1, _n, _p2, _n); \ + log_test_failed("Expected \"%s\" and \"%s\" to have equal contents (%zu bytes):\n%s", \ + #p1, #p2, _n, strnull(_dump)); \ + } \ + }) +#endif + +#ifdef __COVERITY__ +# define ASSERT_MEMEQ_NN(p1, l1, p2, l2) __coverity_check__(memcmp_nn((p1), (l1), (p2), (l2)) == 0) +#else +# define ASSERT_MEMEQ_NN(p1, l1, p2, l2) \ + ({ \ + const void *_p1 = (p1), *_p2 = (p2); \ + size_t _l1 = (l1), _l2 = (l2); \ + if (memcmp_nn(_p1, _l1, _p2, _l2) != 0) { \ + _cleanup_free_ char *_dump = hexdump_memcmp(_p1, _l1, _p2, _l2); \ + log_test_failed("Expected \"%s\" (%zu bytes) and \"%s\" (%zu bytes) to have equal contents:\n%s", \ + #p1, _l1, #p2, _l2, strnull(_dump)); \ + } \ + }) +#endif + +#ifdef __COVERITY__ +# define ASSERT_IOVEC_EQ(i1, i2) __coverity_check__(iovec_memcmp((i1), (i2)) == 0) +#else +# define ASSERT_IOVEC_EQ(i1, i2) \ + ({ \ + const struct iovec *_i1 = (i1), *_i2 = (i2); \ + if (iovec_memcmp(_i1, _i2) != 0) { \ + _cleanup_free_ char *_dump = hexdump_memcmp(_i1 ? _i1->iov_base : NULL, \ + _i1 ? _i1->iov_len : 0, \ + _i2 ? _i2->iov_base : NULL, \ + _i2 ? _i2->iov_len : 0); \ + log_test_failed("Expected iovec \"%s\" (%zu bytes) and \"%s\" (%zu bytes) to have equal contents:\n%s", \ + #i1, _i1 ? _i1->iov_len : 0, #i2, _i2 ? _i2->iov_len : 0, strnull(_dump)); \ + } \ + }) +#endif + /* DECIMAL_STR_FMT() uses _Generic which cannot be used in string concatenation so we have to format the * input into strings first and then format those into the final assertion message. */ diff --git a/src/test/test-tests.c b/src/test/test-tests.c index 40721a6f7c6..febe262b8a2 100644 --- a/src/test/test-tests.c +++ b/src/test/test-tests.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "errno-util.h" +#include "iovec-util.h" #include "tests.h" TEST(ASSERT) { @@ -151,6 +152,22 @@ TEST(ASSERT) { SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e)), SIGABRT); ASSERT_SIGNAL(ASSERT_NE_ID128(SD_ID128_NULL, SD_ID128_NULL), SIGABRT); + + static const uint8_t m1[] = { 0, 1, 2, 3 }, m2[] = { 0, 1, 2, 3 }, m3[] = { 0, 1, 9, 3 }; + + ASSERT_MEMEQ(m1, m2, sizeof(m1)); + ASSERT_MEMEQ(m1, m3, 2); + ASSERT_MEMEQ(NULL, NULL, 0); + ASSERT_SIGNAL(ASSERT_MEMEQ(m1, m3, sizeof(m1)), SIGABRT); + + ASSERT_MEMEQ_NN(m1, sizeof(m1), m2, sizeof(m2)); + ASSERT_MEMEQ_NN(NULL, 0, NULL, 0); + ASSERT_SIGNAL(ASSERT_MEMEQ_NN(m1, sizeof(m1), m2, sizeof(m2) - 1), SIGABRT); + ASSERT_SIGNAL(ASSERT_MEMEQ_NN(m1, sizeof(m1), m3, sizeof(m3)), SIGABRT); + + ASSERT_IOVEC_EQ(&IOVEC_MAKE(m1, sizeof(m1)), &IOVEC_MAKE(m2, sizeof(m2))); + ASSERT_SIGNAL(ASSERT_IOVEC_EQ(&IOVEC_MAKE(m1, sizeof(m1)), &IOVEC_MAKE(m3, sizeof(m3))), SIGABRT); + ASSERT_SIGNAL(ASSERT_IOVEC_EQ(&IOVEC_MAKE(m1, sizeof(m1)), &IOVEC_MAKE(m1, sizeof(m1) - 1)), SIGABRT); } TEST(ASSERT_OK_OR) {