Files
systemd/src/shared/tests.h
T
Daan De Meyer 79862d33a0 chase: add explicit root_fd parameter to chaseat() and drop CHASE_AT_RESOLVE_IN_ROOT
Split the single directory fd that chaseat() used to take into two separate
fds: a root_fd that sets the chroot boundary (symlinks may not escape it,
absolute symlinks resolve relative to it), and a dir_fd that path resolution
starts from. This makes the chroot semantics of chaseat() explicit at every
call site instead of encoding them in the CHASE_AT_RESOLVE_IN_ROOT flag,
which is removed. It also decouples the starting directory from the root
boundary, so callers can descend from any inode inside the tree without
having to reopen the root separately.

XAT_FDROOT passed as root_fd means "no containment" (host root); as dir_fd
it means "start at root_fd". For a smoother transition, AT_FDCWD is also
accepted as root_fd and treated as XAT_FDROOT. When root_fd points to a
directory that is actually the host root, it is normalized to XAT_FDROOT
up front so the existing shortcut path can kick in.

Absolute paths returned by chaseat() are now relative to root_fd, and
relative paths are relative to dir_fd. The result is absolute only when
there is no chroot boundary (root_fd is XAT_FDROOT), or when an absolute
symlink made resolution jump out of the dir_fd subtree; otherwise callers
get a relative path they can feed straight back into an openat()-style
call against dir_fd. Specifically, when dir_fd == root_fd and we're not
operating on the host's root directory, we return a relative path even if
we received an absolute path or resolved an absolute symlink to allow
passing the path directly to openat() style functions. We do this to not
have to go modify every caller of chaseat() to make sure they deal properly
with any absolute paths they might receive. Only when root_fd != dir_fd do
we have to return an absolute path to indicate that the path is relative to
root_fd and not dir_fd.

The shortcut that skips the per-component walk is reworked around a new
chase_xopenat() helper that funnels CHASE_NOFOLLOW, CHASE_MUST_BE_* and
CHASE_TRIGGER_AUTOFS through xopenat_full()'s O_NOFOLLOW, O_DIRECTORY,
XO_REGULAR, XO_SOCKET and XO_TRIGGER_AUTOMOUNT flags. As a result these
flags no longer force us off the shortcut and can be dropped from
CHASE_NO_SHORTCUT_MASK, and the old openat_opath_with_automount() helper
goes away. A CHASE_MUST_BE_ANY alias is introduced for shortcut callers
(stat/access paths) that don't go through xopenat_full() and still need
to bail on those flags locally.

All *_and_* helpers built on top of chaseat() (chase_and_openat,
chase_and_opendirat, chase_and_statat, chase_and_accessat,
chase_and_fopenat_unlocked, chase_and_unlinkat, chase_and_open_parent_at)
gain the same root_fd parameter, and every call site in the tree is
ported to the new signature.

chase_and_open() is also fixed to correctly handle CHASE_EXTRACT_FILENAME
without CHASE_PARENT.
2026-04-20 23:35:31 +02:00

717 lines
49 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <unistd.h>
#include "errno-list.h"
#include "shared-forward.h"
#include "log.h"
#include "log-assert-critical.h"
#include "static-destruct.h" /* IWYU pragma: keep */
#include "signal-util.h" /* IWYU pragma: keep */
#include "stdio-util.h"
#include "string-util.h" /* IWYU pragma: keep */
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,
EACCES,
EADDRINUSE,
EHOSTDOWN,
ENOENT,
ENOMEDIUM /* cannot determine cgroup */
);
}
char* setup_fake_runtime_dir(void);
int enter_cgroup_subroot(char **ret_cgroup);
int enter_cgroup_root(char **ret_cgroup);
int get_testdata_dir(const char *suffix, char **ret);
const char* get_catalog_dir(void);
bool slow_tests_enabled(void);
void test_setup_logging(int level);
#define log_tests_skipped(fmt, ...) \
({ \
log_notice("%s: " fmt ", skipping tests.", \
program_invocation_short_name, \
##__VA_ARGS__); \
EXIT_TEST_SKIP; \
})
#define log_tests_skipped_errno(error, fmt, ...) \
({ \
log_notice_errno(error, \
"%s: " fmt ", skipping tests: %m", \
program_invocation_short_name, \
##__VA_ARGS__); \
EXIT_TEST_SKIP; \
})
int write_tmpfile(char *pattern, const char *contents);
bool have_namespaces(void);
bool userns_has_single_user(void);
/* We use the small but non-trivial limit here */
#define CAN_MEMLOCK_SIZE (512 * 1024U)
bool can_memlock(void);
int define_hex_ptr_internal(const char *hex, void **name, size_t *name_len);
/* Define void* buffer and size_t length variables from a hex string. */
#define DEFINE_HEX_PTR(name, hex) \
_cleanup_free_ void *name = NULL; \
size_t name##_len = 0; \
ASSERT_OK(define_hex_ptr_internal(hex, &name, &name##_len))
/* Provide a convenient way to check if we're running in CI. */
const char* ci_environment(void);
typedef struct TestFunc {
union f {
void (*void_func)(void);
int (*int_func)(void);
} f;
const char * const name;
bool has_ret:1;
bool sd_booted:1;
} TestFunc;
/* See static-destruct.h for an explanation of how this works. */
#define REGISTER_TEST(func, ...) \
_section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _retain_ _variable_no_sanitize_address_ \
static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
.f = (union f) &(func), \
.name = STRINGIFY(func), \
.has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \
##__VA_ARGS__ \
}
extern const TestFunc __start_SYSTEMD_TEST_TABLE[];
extern const TestFunc __stop_SYSTEMD_TEST_TABLE[];
#define TEST(name, ...) \
static void test_##name(void); \
REGISTER_TEST(test_##name, ##__VA_ARGS__); \
static void test_##name(void)
#define TEST_RET(name, ...) \
static int test_##name(void); \
REGISTER_TEST(test_##name, ##__VA_ARGS__); \
static int test_##name(void)
#define TEST_LOG_FUNC() \
log_info("/* %s() */", __func__)
int run_test_table(const TestFunc *start, const TestFunc *end);
void test_prepare(int argc, char *argv[], int log_level);
#define DEFINE_TEST_MAIN_FULL(log_level, intro, outro) \
int main(int argc, char *argv[]) { \
int (*_intro)(void) = intro; \
int (*_outro)(void) = outro; \
int _r, _q; \
test_prepare(argc, argv, log_level); \
_r = _intro ? _intro() : EXIT_SUCCESS; \
if (_r == EXIT_SUCCESS) \
_r = run_test_table(__start_SYSTEMD_TEST_TABLE, __stop_SYSTEMD_TEST_TABLE); \
_q = _outro ? _outro() : EXIT_SUCCESS; \
static_destruct(); \
if (_r < 0) \
return EXIT_FAILURE; \
if (_r != EXIT_SUCCESS) \
return _r; \
if (_q < 0) \
return EXIT_FAILURE; \
return _q; \
}
#define DEFINE_TEST_MAIN_WITH_INTRO(log_level, intro) \
DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
#define DEFINE_TEST_MAIN(log_level) \
DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
_noreturn_ void log_test_failed_internal(const char *file, int line, const char *func, const char *format, ...) _printf_(4,5);
#define log_test_failed(format, ...) \
log_test_failed_internal(PROJECT_FILE, __LINE__, __func__, "%s:%i: Assertion failed: " format, PROJECT_FILE, __LINE__, ##__VA_ARGS__)
#define DECIMAL_STR_FMT(x) _Generic((x), \
char: "%c", \
bool: "%d", \
unsigned char: "%d", \
short: "%hd", \
unsigned short: "%hu", \
int: "%d", \
unsigned: "%u", \
long: "%ld", \
unsigned long: "%lu", \
long long: "%lld", \
unsigned long long: "%llu")
#ifdef __COVERITY__
# define ASSERT_OK(expr) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result >= 0); \
_result; \
})
#else
# define ASSERT_OK(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) \
log_test_failed("Expected \"%s\" to succeed, but got error: %"PRIiMAX"/%s", \
#expr, (intmax_t) _result, ERRNO_NAME(_result)); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_OK_OR(expr, ...) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result >= 0 || IN_SET(_result, 0, __VA_ARGS__); \
_result; \
})
#else
# define ASSERT_OK_OR(expr, ...) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0 && !IN_SET(_result, 0, __VA_ARGS__)) \
log_test_failed("\"%s\" failed with unexpected error: %"PRIiMAX"/%s", \
#expr, (intmax_t) _result, ERRNO_NAME(_result)); \
_result; \
})
#endif
/* For functions that return a boolean on success and a negative errno on failure. */
#ifdef __COVERITY__
# define ASSERT_OK_POSITIVE(expr) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result > 0); \
_result; \
})
#else
# define ASSERT_OK_POSITIVE(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) \
log_test_failed("Expected \"%s\" to succeed, but got error: %"PRIiMAX"/%s", \
#expr, (intmax_t) _result, ERRNO_NAME(_result)); \
if (_result == 0) \
log_test_failed("Expected \"%s\" to be positive, but it is zero.", #expr); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_OK_ZERO(expr) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result == 0); \
_result; \
})
#else
# define ASSERT_OK_ZERO(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) \
log_test_failed("Expected \"%s\" to succeed, but got error: %"PRIiMAX"/%s", \
#expr, (intmax_t) _result, ERRNO_NAME(_result)); \
if (_result != 0) \
log_test_failed("Expected \"%s\" to be zero, but it is %"PRIiMAX".", \
#expr, (intmax_t) _result); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_OK_EQ(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
__coverity_check__(_expr1 == _expr2); \
_expr1; \
})
#else
# define ASSERT_OK_EQ(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (_expr1 < 0) \
log_test_failed("Expected \"%s\" to succeed, but got error: %"PRIiMAX"/%s", \
#expr1, (intmax_t) _expr1, ERRNO_NAME(_expr1)); \
if (_expr1 != _expr2) \
log_test_failed("Expected \"%s == %s\", got %"PRIiMAX" != %"PRIiMAX, \
#expr1, #expr2, (intmax_t) _expr1, (intmax_t) _expr2); \
_expr1; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_OK_NE(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
__coverity_check__(_expr1 != _expr2); \
_expr1; \
})
#else
# define ASSERT_OK_NE(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (_expr1 < 0) \
log_test_failed("Expected \"%s\" to succeed, but got error: %"PRIiMAX"/%s", \
#expr1, (intmax_t) _expr1, ERRNO_NAME(_expr1)); \
if (_expr1 == _expr2) \
log_test_failed("Expected \"%s != %s\", got %"PRIiMAX" != %"PRIiMAX, \
#expr1, #expr2, (intmax_t) _expr1, (intmax_t) _expr2); \
_expr1; \
})
#endif
/* For functions that return a boolean on success and set errno on failure. */
#ifdef __COVERITY__
# define ASSERT_OK_ERRNO(expr) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result >= 0); \
_result; \
})
#else
# define ASSERT_OK_ERRNO(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) \
log_test_failed("Expected \"%s\" to succeed, but got errno: %d/%s", \
#expr, errno, ERRNO_NAME(errno)); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_OK_ZERO_ERRNO(expr) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result == 0); \
_result; \
})
#else
# define ASSERT_OK_ZERO_ERRNO(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) \
log_test_failed("Expected \"%s\" to succeed, but got errno: %d/%s", \
#expr, errno, ERRNO_NAME(errno)); \
if (_result != 0) \
log_test_failed("Expected \"%s\" to be zero, but it is %"PRIiMAX".", \
#expr, (intmax_t) _result); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_OK_EQ_ERRNO(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
__coverity_check__(_expr1 == _expr2); \
_expr1; \
})
#else
# define ASSERT_OK_EQ_ERRNO(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (_expr1 < 0) \
log_test_failed("Expected \"%s\" to succeed, but got errno: %d/%s", \
#expr1, errno, ERRNO_NAME(errno)); \
if (_expr1 != _expr2) \
log_test_failed("Expected \"%s == %s\", but %"PRIiMAX" != %"PRIiMAX, \
#expr1, #expr2, (intmax_t) _expr1, (intmax_t) _expr2); \
_expr1; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_FAIL(expr) \
({ \
typeof(expr) _result = (expr); \
__coverity_check__(_result < 0); \
_result; \
})
#else
# define ASSERT_FAIL(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result >= 0) \
log_test_failed("Expected \"%s\" to fail, but it succeeded.", #expr); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_ERROR(expr1, expr2) \
({ \
int _expr1 = (expr1); \
int _expr2 = (expr2); \
__coverity_check__((_expr1) == -(_expr2)); \
_expr1; \
})
#else
# define ASSERT_ERROR(expr1, expr2) \
({ \
int _expr1 = (expr1); \
int _expr2 = (expr2); \
if (_expr1 >= 0) \
log_test_failed("Expected \"%s\" to fail with error %d/%s, but it succeeded", \
#expr1, -_expr2, ERRNO_NAME(_expr2)); \
else if (-_expr1 != _expr2) \
log_test_failed("Expected \"%s\" to fail with error %d/%s, but got %d/%s", \
#expr1, -_expr2, ERRNO_NAME(_expr2), _expr1, ERRNO_NAME(_expr1)); \
_expr1; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_ERROR_ERRNO(expr1, expr2) \
({ \
int _expr1 = (expr1); \
int _expr2 = (expr2); \
__coverity_check__(_expr1 < 0 && errno == _expr2); \
_expr1; \
})
#else
# define ASSERT_ERROR_ERRNO(expr1, expr2) \
({ \
int _expr1 = (expr1); \
int _expr2 = (expr2); \
if (_expr1 >= 0) \
log_test_failed("Expected \"%s\" to fail with errno %d/%s, but it succeeded", \
#expr1, _expr2, ERRNO_NAME(_expr2)); \
else if (errno != _expr2) \
log_test_failed("Expected \"%s\" to fail with errno %d/%s, but got %d/%s", \
#expr1, _expr2, ERRNO_NAME(_expr2), errno, ERRNO_NAME(errno)); \
_expr1; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_TRUE(expr) __coverity_check__(!!(expr))
#else
# define ASSERT_TRUE(expr) \
({ \
if (!(expr)) \
log_test_failed("Expected \"%s\" to be true", #expr); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_FALSE(expr) __coverity_check__(!(expr))
#else
# define ASSERT_FALSE(expr) \
({ \
if ((expr)) \
log_test_failed("Expected \"%s\" to be false", #expr); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_NULL(expr) __coverity_check__((expr) == NULL)
#else
# define ASSERT_NULL(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result != NULL) \
log_test_failed("Expected \"%s\" to be NULL, got \"%p\" != NULL", #expr, _result); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_NOT_NULL(expr) __coverity_check__((expr) != NULL)
#else
# define ASSERT_NOT_NULL(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result == NULL) \
log_test_failed("Expected \"%s\" to be not NULL", #expr); \
_result; \
})
#endif
#ifdef __COVERITY__
# define ASSERT_STREQ(expr1, expr2) __coverity_check__(streq_ptr((expr1), (expr2)))
#else
# define ASSERT_STREQ(expr1, expr2) \
({ \
const char *_expr1 = (expr1), *_expr2 = (expr2); \
if (!streq_ptr(_expr1, _expr2)) \
log_test_failed("Expected \"%s == %s\", got \"%s != %s\"", \
#expr1, #expr2, strnull(_expr1), strnull(_expr2)); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_PATH_EQ(expr1, expr2) __coverity_check__(path_equal((expr1), (expr2)))
#else
# define ASSERT_PATH_EQ(expr1, expr2) \
({ \
const char *_expr1 = (expr1), *_expr2 = (expr2); \
if (!path_equal(_expr1, _expr2)) \
log_test_failed("Expected \"%s == %s\", got \"%s != %s\"", \
#expr1, #expr2, strnull(_expr1), strnull(_expr2)); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_NOT_STREQ(expr1, expr2) __coverity_check__(!streq_ptr((expr1), (expr2)))
#else
# define ASSERT_NOT_STREQ(expr1, expr2) \
({ \
const char *_expr1 = (expr1), *_expr2 = (expr2); \
if (streq_ptr(_expr1, _expr2)) \
log_test_failed("Expected \"%s != %s\", got \"%s == %s\"", \
#expr1, #expr2, strnull(_expr1), strnull(_expr2)); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_STRNEQ(expr1, expr2, n) __coverity_check__(strneq_ptr((expr1), (expr2), (n)))
#else
# define ASSERT_STRNEQ(expr1, expr2, n) \
({ \
const char *_expr1 = (expr1), *_expr2 = (expr2); \
size_t _n = (n); \
if (!strneq_ptr(_expr1, _expr2, _n)) \
log_test_failed("Expected \"%s == %s\", got \"%s != %s\" (first %zu characters)", \
#expr1, #expr2, strnull(_expr1), strnull(_expr2), _n); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_PTR_EQ(expr1, expr2) __coverity_check__((expr1) == (expr2))
#else
# define ASSERT_PTR_EQ(expr1, expr2) \
({ \
const void *_expr1 = (expr1), *_expr2 = (expr2); \
if (_expr1 != _expr2) \
log_test_failed("Expected \"%s == %s\", got \"0x%p != 0x%p\"", \
#expr1, #expr2, _expr1, _expr2); \
})
#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. */
#ifdef __COVERITY__
# define ASSERT_EQ(expr1, expr2) __coverity_check__((expr1) == (expr2))
#else
# 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_test_failed("Expected \"%s == %s\", but %s != %s", \
#expr1, #expr2, _sexpr1, _sexpr2); \
} \
})
#endif
#ifdef __COVERITY__
# define ASSERT_GE(expr1, expr2) __coverity_check__((expr1) >= (expr2))
#else
# 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_test_failed("Expected \"%s >= %s\", but %s < %s", \
#expr1, #expr2, _sexpr1, _sexpr2); \
} \
})
#endif
#ifdef __COVERITY__
# define ASSERT_LE(expr1, expr2) __coverity_check__((expr1) <= (expr2))
#else
# 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_test_failed("Expected \"%s <= %s\", but %s > %s", \
#expr1, #expr2, _sexpr1, _sexpr2); \
} \
})
#endif
#ifdef __COVERITY__
# define ASSERT_NE(expr1, expr2) __coverity_check__((expr1) != (expr2))
#else
# 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_test_failed("Expected \"%s != %s\", but %s == %s", \
#expr1, #expr2, _sexpr1, _sexpr2); \
} \
})
#endif
#ifdef __COVERITY__
# define ASSERT_GT(expr1, expr2) __coverity_check__((expr1) > (expr2))
#else
# 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_test_failed("Expected \"%s > %s\", but %s <= %s", \
#expr1, #expr2, _sexpr1, _sexpr2); \
} \
})
#endif
#ifdef __COVERITY__
# define ASSERT_LT(expr1, expr2) __coverity_check__((expr1) < (expr2))
#else
# 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_test_failed("Expected \"%s < %s\", but %s >= %s", \
#expr1, #expr2, _sexpr1, _sexpr2); \
} \
})
#endif
enum {
ASSERT_SIGNAL_FORK_CHILD = 0, /* We are in the child process */
ASSERT_SIGNAL_FORK_PARENT = 1, /* We are in the parent process */
};
int assert_signal_internal(int *ret_signal);
#ifdef __COVERITY__
# define ASSERT_SIGNAL(expr, signal) __coverity_check__(((expr), false))
#else
# define ASSERT_SIGNAL(expr, signal) __ASSERT_SIGNAL(UNIQ, expr, signal)
# define __ASSERT_SIGNAL(uniq, expr, sgnl) \
({ \
ASSERT_TRUE(SIGNAL_VALID(sgnl)); \
int UNIQ_T(_status, uniq); \
int UNIQ_T(_path, uniq) = assert_signal_internal(&UNIQ_T(_status, uniq)); \
ASSERT_OK_ERRNO(UNIQ_T(_path, uniq)); \
if (UNIQ_T(_path, uniq) == ASSERT_SIGNAL_FORK_CHILD) { \
(void) signal(sgnl, SIG_DFL); \
expr; \
_exit(EXIT_SUCCESS); \
} \
ASSERT_EQ(UNIQ_T(_path, uniq), ASSERT_SIGNAL_FORK_PARENT); \
if (UNIQ_T(_status, uniq) != sgnl) \
log_test_failed("\"%s\" died with signal %s, but %s was expected", \
#expr, signal_to_string(UNIQ_T(_status, uniq)), \
signal_to_string(sgnl)); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_EQ_ID128(expr1, expr2) __coverity_check__(sd_id128_equal((expr1), (expr2)))
#else
# define ASSERT_EQ_ID128(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (!sd_id128_equal(_expr1, _expr2)) \
log_test_failed("\"%s == %s\", but %s != %s", \
#expr1, #expr2, \
SD_ID128_TO_STRING(_expr1), SD_ID128_TO_STRING(_expr2)); \
})
#endif
#ifdef __COVERITY__
# define ASSERT_NE_ID128(expr1, expr2) __coverity_check__(!sd_id128_equal((expr1), (expr2)))
#else
# define ASSERT_NE_ID128(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (sd_id128_equal(_expr1, _expr2)) \
log_test_failed("\"%s != %s\", but %s == %s", \
#expr1, #expr2, \
SD_ID128_TO_STRING(_expr1), SD_ID128_TO_STRING(_expr2)); \
})
#endif
#define EFI_GUID_Fmt "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define EFI_GUID_Arg(guid) (guid).Data1, (guid).Data2, (guid).Data3, \
(guid).Data4[0], (guid).Data4[1], (guid).Data4[2], (guid).Data4[3], \
(guid).Data4[4], (guid).Data4[5], (guid).Data4[6], (guid).Data4[7] \
#ifdef __COVERITY__
# define ASSERT_EQ_EFI_GUID(expr1, expr2) __coverity_check__(efi_guid_equal((expr1), (expr2)))
#else
# define ASSERT_EQ_EFI_GUID(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (!efi_guid_equal(_expr1, _expr2)) \
log_test_failed("Expected \"%s == %s\", but " EFI_GUID_Fmt \
" != " EFI_GUID_Fmt, \
#expr1, #expr2, \
EFI_GUID_Arg(*_expr1), EFI_GUID_Arg(*_expr2)); \
})
#endif