[PATCH bpf-next 1/4] bpf/selftests: move assert macros into a dedicated header

Alexis Lothoré (eBPF Foundation)
2026-01-14T08:59:38Z

The test_progs runner defines a large set of convenient assert macros to
perform all the tests. Writing a new runner involves rewriting some
macros if we want some basic testing features like standardized failure
log.

Export those assert macros from test_progs into a dedicated header so
that we can use those in any test_runner. The sole requirement to be
able to use those macros is to define a test__fail function in the
runner that will be called whenever an assert fails.

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
---
tools/testing/selftests/bpf/assert_helpers.h | 231 +++++++++++++++++++++++++++
tools/testing/selftests/bpf/test_progs.h | 226 +-------------------------
2 files changed, 232 insertions(+), 225 deletions(-)

diff --git a/tools/testing/selftests/bpf/assert_helpers.h b/tools/testing/selftests/bpf/assert_helpers.h
new file mode 100644
index 000000000000..93ab5bf39431
--- /dev/null
+++ b/tools/testing/selftests/bpf/assert_helpers.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#pragma once
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#define _CHECK(condition, tag, duration, format...) ({ \
+ int __ret = !!(condition); \
+ int __save_errno = errno; \
+ if (__ret) { \
+ test__fail(); \
+ fprintf(stdout, "%s:FAIL:%s ", __func__, tag); \
+ fprintf(stdout, ##format); \
+ } else { \
+ fprintf(stdout, "%s:PASS:%s %d nsec\n", \
+ __func__, tag, duration); \
+ } \
+ errno = __save_errno; \
+ __ret; \
+})
+
+#define CHECK_FAIL(condition) ({ \
+ int __ret = !!(condition); \
+ int __save_errno = errno; \
+ if (__ret) { \
+ test__fail(); \
+ fprintf(stdout, "%s:FAIL:%d\n", __func__, __LINE__); \
+ } \
+ errno = __save_errno; \
+ __ret; \
+})
+
+#define CHECK(condition, tag, format...) \
+ _CHECK(condition, tag, duration, format)
+#define CHECK_ATTR(condition, tag, format...) \
+ _CHECK(condition, tag, tattr.duration, format)
+
+#define ASSERT_FAIL(fmt, args...) ({ \
+ static int duration; \
+ CHECK(false, "", fmt"\n", ##args); \
+ false; \
+})
+
+#define ASSERT_TRUE(actual, name) ({ \
+ static int duration; \
+ bool ___ok = (actual); \
+ CHECK(!___ok, (name), "unexpected %s: got FALSE\n", (name)); \
+ ___ok; \
+})
+
+#define ASSERT_FALSE(actual, name) ({ \
+ static int duration; \
+ bool ___ok = !(actual); \
+ CHECK(!___ok, (name), "unexpected %s: got TRUE\n", (name)); \
+ ___ok; \
+})
+
+#define ASSERT_EQ(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act == ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld != expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_NEQ(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act != ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld == expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_LT(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act < ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld >= expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_LE(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act <= ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld > expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_GT(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act > ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld <= expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_GE(actual, expected, name) ({ \
+ static int duration; \
+ typeof(actual) ___act = (actual); \
+ typeof(expected) ___exp = (expected); \
+ bool ___ok = ___act >= ___exp; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual %lld < expected %lld\n", \
+ (name), (long long)(___act), (long long)(___exp)); \
+ ___ok; \
+})
+
+#define ASSERT_STREQ(actual, expected, name) ({ \
+ static int duration; \
+ const char *___act = actual; \
+ const char *___exp = expected; \
+ bool ___ok = strcmp(___act, ___exp) == 0; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual '%s' != expected '%s'\n", \
+ (name), ___act, ___exp); \
+ ___ok; \
+})
+
+#define ASSERT_STRNEQ(actual, expected, len, name) ({ \
+ static int duration; \
+ const char *___act = actual; \
+ const char *___exp = expected; \
+ int ___len = len; \
+ bool ___ok = strncmp(___act, ___exp, ___len) == 0; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: actual '%.*s' != expected '%.*s'\n", \
+ (name), ___len, ___act, ___len, ___exp); \
+ ___ok; \
+})
+
+#define ASSERT_HAS_SUBSTR(str, substr, name) ({ \
+ static int duration; \
+ const char *___str = str; \
+ const char *___substr = substr; \
+ bool ___ok = strstr(___str, ___substr) != NULL; \
+ CHECK(!___ok, (name), \
+ "unexpected %s: '%s' is not a substring of '%s'\n", \
+ (name), ___substr, ___str); \
+ ___ok; \
+})
+
+#define ASSERT_MEMEQ(actual, expected, len, name) ({ \
+ static int duration; \
+ const void *__act = actual; \
+ const void *__exp = expected; \
+ int __len = len; \
+ bool ___ok = memcmp(__act, __exp, __len) == 0; \
+ CHECK(!___ok, (name), "unexpected memory mismatch\n"); \
+ fprintf(stdout, "actual:\n"); \
+ hexdump("\t", __act, __len); \
+ fprintf(stdout, "expected:\n"); \
+ hexdump("\t", __exp, __len); \
+ ___ok; \
+})
+
+#define ASSERT_OK(res, name) ({ \
+ static int duration; \
+ long long ___res = (res); \
+ bool ___ok = ___res == 0; \
+ CHECK(!___ok, (name), "unexpected error: %lld (errno %d)\n", \
+ ___res, errno); \
+ ___ok; \
+})
+
+#define ASSERT_ERR(res, name) ({ \
+ static int duration; \
+ long long ___res = (res); \
+ bool ___ok = ___res < 0; \
+ CHECK(!___ok, (name), "unexpected success: %lld\n", ___res); \
+ ___ok; \
+})
+
+#define ASSERT_NULL(ptr, name) ({ \
+ static int duration; \
+ const void *___res = (ptr); \
+ bool ___ok = !___res; \
+ CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
+ ___ok; \
+})
+
+#define ASSERT_OK_PTR(ptr, name) ({ \
+ static int duration; \
+ const void *___res = (ptr); \
+ int ___err = libbpf_get_error(___res); \
+ bool ___ok = ___err == 0; \
+ CHECK(!___ok, (name), "unexpected error: %d\n", ___err); \
+ ___ok; \
+})
+
+#define ASSERT_ERR_PTR(ptr, name) ({ \
+ static int duration; \
+ const void *___res = (ptr); \
+ int ___err = libbpf_get_error(___res); \
+ bool ___ok = ___err != 0; \
+ CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
+ ___ok; \
+})
+
+#define ASSERT_OK_FD(fd, name) ({ \
+ static int duration; \
+ int ___fd = (fd); \
+ bool ___ok = ___fd >= 0; \
+ CHECK(!___ok, (name), "unexpected fd: %d (errno %d)\n", \
+ ___fd, errno); \
+ ___ok; \
+})
+
+#define ASSERT_ERR_FD(fd, name) ({ \
+ static int duration; \
+ int ___fd = (fd); \
+ bool ___ok = ___fd < 0; \
+ CHECK(!___ok, (name), "unexpected fd: %d\n", ___fd); \
+ ___ok; \
+})
+
diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h
index eebfc18cdcd2..bb876d8f6bcc 100644
--- a/tools/testing/selftests/bpf/test_progs.h
+++ b/tools/testing/selftests/bpf/test_progs.h
@@ -42,6 +42,7 @@ typedef __u16 __sum16;
#include <bpf/bpf_endian.h>
#include "trace_helpers.h"
#include "testing_helpers.h"
+#include "assert_helpers.h"

enum verbosity {
VERBOSE_NONE,
@@ -195,231 +196,6 @@ void hexdump(const char *prefix, const void *buf, size_t len);
fprintf(stdout, ##format); \
})

-#define _CHECK(condition, tag, duration, format...) ({ \
- int __ret = !!(condition); \
- int __save_errno = errno; \
- if (__ret) { \
- test__fail(); \
- fprintf(stdout, "%s:FAIL:%s ", __func__, tag); \
- fprintf(stdout, ##format); \
- } else { \
- fprintf(stdout, "%s:PASS:%s %d nsec\n", \
- __func__, tag, duration); \
- } \
- errno = __save_errno; \
- __ret; \
-})
-
-#define CHECK_FAIL(condition) ({ \
- int __ret = !!(condition); \
- int __save_errno = errno; \
- if (__ret) { \
- test__fail(); \
- fprintf(stdout, "%s:FAIL:%d\n", __func__, __LINE__); \
- } \
- errno = __save_errno; \
- __ret; \
-})
-
-#define CHECK(condition, tag, format...) \
- _CHECK(condition, tag, duration, format)
-#define CHECK_ATTR(condition, tag, format...) \
- _CHECK(condition, tag, tattr.duration, format)
-
-#define ASSERT_FAIL(fmt, args...) ({ \
- static int duration = 0; \
- CHECK(false, "", fmt"\n", ##args); \
- false; \
-})
-
-#define ASSERT_TRUE(actual, name) ({ \
- static int duration = 0; \
- bool ___ok = (actual); \
- CHECK(!___ok, (name), "unexpected %s: got FALSE\n", (name)); \
- ___ok; \
-})
-
-#define ASSERT_FALSE(actual, name) ({ \
- static int duration = 0; \
- bool ___ok = !(actual); \
- CHECK(!___ok, (name), "unexpected %s: got TRUE\n", (name)); \
- ___ok; \
-})
-
-#define ASSERT_EQ(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act == ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld != expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_NEQ(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act != ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld == expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_LT(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act < ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld >= expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_LE(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act <= ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld > expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_GT(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act > ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld <= expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_GE(actual, expected, name) ({ \
- static int duration = 0; \
- typeof(actual) ___act = (actual); \
- typeof(expected) ___exp = (expected); \
- bool ___ok = ___act >= ___exp; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual %lld < expected %lld\n", \
- (name), (long long)(___act), (long long)(___exp)); \
- ___ok; \
-})
-
-#define ASSERT_STREQ(actual, expected, name) ({ \
- static int duration = 0; \
- const char *___act = actual; \
- const char *___exp = expected; \
- bool ___ok = strcmp(___act, ___exp) == 0; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual '%s' != expected '%s'\n", \
- (name), ___act, ___exp); \
- ___ok; \
-})
-
-#define ASSERT_STRNEQ(actual, expected, len, name) ({ \
- static int duration = 0; \
- const char *___act = actual; \
- const char *___exp = expected; \
- int ___len = len; \
- bool ___ok = strncmp(___act, ___exp, ___len) == 0; \
- CHECK(!___ok, (name), \
- "unexpected %s: actual '%.*s' != expected '%.*s'\n", \
- (name), ___len, ___act, ___len, ___exp); \
- ___ok; \
-})
-
-#define ASSERT_HAS_SUBSTR(str, substr, name) ({ \
- static int duration = 0; \
- const char *___str = str; \
- const char *___substr = substr; \
- bool ___ok = strstr(___str, ___substr) != NULL; \
- CHECK(!___ok, (name), \
- "unexpected %s: '%s' is not a substring of '%s'\n", \
- (name), ___substr, ___str); \
- ___ok; \
-})
-
-#define ASSERT_MEMEQ(actual, expected, len, name) ({ \
- static int duration = 0; \
- const void *__act = actual; \
- const void *__exp = expected; \
- int __len = len; \
- bool ___ok = memcmp(__act, __exp, __len) == 0; \
- CHECK(!___ok, (name), "unexpected memory mismatch\n"); \
- fprintf(stdout, "actual:\n"); \
- hexdump("\t", __act, __len); \
- fprintf(stdout, "expected:\n"); \
- hexdump("\t", __exp, __len); \
- ___ok; \
-})
-
-#define ASSERT_OK(res, name) ({ \
- static int duration = 0; \
- long long ___res = (res); \
- bool ___ok = ___res == 0; \
- CHECK(!___ok, (name), "unexpected error: %lld (errno %d)\n", \
- ___res, errno); \
- ___ok; \
-})
-
-#define ASSERT_ERR(res, name) ({ \
- static int duration = 0; \
- long long ___res = (res); \
- bool ___ok = ___res < 0; \
- CHECK(!___ok, (name), "unexpected success: %lld\n", ___res); \
- ___ok; \
-})
-
-#define ASSERT_NULL(ptr, name) ({ \
- static int duration = 0; \
- const void *___res = (ptr); \
- bool ___ok = !___res; \
- CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
- ___ok; \
-})
-
-#define ASSERT_OK_PTR(ptr, name) ({ \
- static int duration = 0; \
- const void *___res = (ptr); \
- int ___err = libbpf_get_error(___res); \
- bool ___ok = ___err == 0; \
- CHECK(!___ok, (name), "unexpected error: %d\n", ___err); \
- ___ok; \
-})
-
-#define ASSERT_ERR_PTR(ptr, name) ({ \
- static int duration = 0; \
- const void *___res = (ptr); \
- int ___err = libbpf_get_error(___res); \
- bool ___ok = ___err != 0; \
- CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \
- ___ok; \
-})
-
-#define ASSERT_OK_FD(fd, name) ({ \
- static int duration = 0; \
- int ___fd = (fd); \
- bool ___ok = ___fd >= 0; \
- CHECK(!___ok, (name), "unexpected fd: %d (errno %d)\n", \
- ___fd, errno); \
- ___ok; \
-})
-
-#define ASSERT_ERR_FD(fd, name) ({ \
- static int duration = 0; \
- int ___fd = (fd); \
- bool ___ok = ___fd < 0; \
- CHECK(!___ok, (name), "unexpected fd: %d\n", ___fd); \
- ___ok; \
-})
-
#define SYS(goto_label, fmt, ...) \
({ \
char cmd[1024]; \

--
2.52.0