summaryrefslogtreecommitdiffstats
path: root/src/shared/tests.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/tests.h')
-rw-r--r--src/shared/tests.h242
1 files changed, 241 insertions, 1 deletions
diff --git a/src/shared/tests.h b/src/shared/tests.h
index d76cf2e..09fdfd6 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -2,14 +2,41 @@
#pragma once
#include <stdbool.h>
+#include <sys/prctl.h>
+#include <unistd.h>
#include "sd-daemon.h"
#include "argv-util.h"
+#include "errno-util.h"
#include "macro.h"
+#include "process-util.h"
+#include "rlimit-util.h"
+#include "signal-util.h"
#include "static-destruct.h"
#include "strv.h"
+static inline void log_set_assert_return_is_criticalp(bool *p) {
+ log_set_assert_return_is_critical(*p);
+}
+
+#define _SAVE_ASSERT_RETURN_IS_CRITICAL(b) \
+ _unused_ _cleanup_(log_set_assert_return_is_criticalp) bool b = \
+ log_get_assert_return_is_critical()
+
+#define SAVE_ASSERT_RETURN_IS_CRITICAL \
+ _SAVE_ASSERT_RETURN_IS_CRITICAL(UNIQ_T(saved, UNIQ))
+
+#define ASSERT_RETURN_IS_CRITICAL(b, expr) \
+ ({ \
+ SAVE_ASSERT_RETURN_IS_CRITICAL; \
+ log_set_assert_return_is_critical(b); \
+ expr; \
+ })
+
+#define ASSERT_RETURN_EXPECTED(expr) ASSERT_RETURN_IS_CRITICAL(false, expr)
+#define ASSERT_RETURN_EXPECTED_SE(expr) ASSERT_RETURN_EXPECTED(assert_se(expr));
+
static inline bool manager_errno_skip_test(int r) {
return IN_SET(abs(r),
EPERM,
@@ -58,7 +85,7 @@ bool can_memlock(void);
#define DEFINE_HEX_PTR(name, hex) \
_cleanup_free_ void *name = NULL; \
size_t name##_len = 0; \
- assert_se(unhexmem(hex, strlen_ptr(hex), &name, &name##_len) >= 0);
+ assert_se(unhexmem_full(hex, strlen_ptr(hex), false, &name, &name##_len) >= 0);
#define TEST_REQ_RUNNING_SYSTEMD(x) \
if (sd_booted() > 0) { \
@@ -179,3 +206,216 @@ static inline int run_test_table(void) {
DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
#define DEFINE_TEST_MAIN(log_level) \
DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
+
+#define ASSERT_OK(expr) \
+ ({ \
+ typeof(expr) _result = (expr); \
+ if (_result < 0) { \
+ log_error_errno(_result, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_OK_ERRNO(expr) \
+ ({ \
+ typeof(expr) _result = (expr); \
+ if (_result < 0) { \
+ log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_ERROR(expr1, expr2) \
+ ({ \
+ int _expr1 = (expr1); \
+ int _expr2 = (expr2); \
+ if (_expr1 >= 0) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but it succeeded", \
+ PROJECT_FILE, __LINE__, #expr1, STRERROR(_expr2)); \
+ abort(); \
+ } else if (-_expr1 != _expr2) { \
+ log_error_errno(_expr1, "%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but got the following error: %m", \
+ PROJECT_FILE, __LINE__, #expr1, STRERROR(_expr2)); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_ERROR_ERRNO(expr1, expr2) \
+ ({ \
+ int _expr1 = (expr1); \
+ int _expr2 = (expr2); \
+ if (_expr1 >= 0) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but it succeeded", \
+ PROJECT_FILE, __LINE__, #expr1, STRERROR(_expr2)); \
+ abort(); \
+ } else if (errno != _expr2) { \
+ log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but got the following error: %m", \
+ PROJECT_FILE, __LINE__, #expr1, STRERROR(errno)); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_TRUE(expr) \
+ ({ \
+ if (!(expr)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be true", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_FALSE(expr) \
+ ({ \
+ if ((expr)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be false", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NULL(expr) \
+ ({ \
+ typeof(expr) _result = (expr); \
+ if (_result != NULL) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be NULL, but \"%p\" != NULL", \
+ PROJECT_FILE, __LINE__, #expr, _result); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NOT_NULL(expr) \
+ ({ \
+ if ((expr) == NULL) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be not NULL", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_STREQ(expr1, expr2) \
+ ({ \
+ const char *_expr1 = (expr1), *_expr2 = (expr2); \
+ if (!streq_ptr(_expr1, _expr2)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, strnull(_expr1), strnull(_expr2)); \
+ abort(); \
+ } \
+ })
+
+/* 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. */
+
+#define ASSERT_EQ(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 != _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_GE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 < _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s >= %s\", but \"%s < %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_LE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 > _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s <= %s\", but \"%s > %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 == _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s != %s\", but \"%s == %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_GT(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (!(_expr1 > _expr2)) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s > %s\", but \"%s <= %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_LT(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (!(_expr1 < _expr2)) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s < %s\", but \"%s >= %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_SIGNAL(expr, signal) \
+ ({ \
+ ASSERT_TRUE(SIGNAL_VALID(signal)); \
+ siginfo_t _siginfo = {}; \
+ int _pid = fork(); \
+ ASSERT_OK(_pid); \
+ if (_pid == 0) { \
+ /* Speed things up by never even attempting to generate a coredump */ \
+ (void) prctl(PR_SET_DUMPABLE, 0); \
+ /* But still set an rlimit just in case */ \
+ (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(0)); \
+ expr; \
+ _exit(EXIT_SUCCESS); \
+ } \
+ (void) wait_for_terminate(_pid, &_siginfo); \
+ if (_siginfo.si_status != signal) { \
+ log_error("%s:%i: Assertion failed: \"%s\" died with signal %s, but %s was expected", \
+ PROJECT_FILE, __LINE__, #expr, signal_to_string(_siginfo.si_status), \
+ signal_to_string(signal)); \
+ abort(); \
+ } \
+ })