1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "static-destruct.h"
13 static inline void log_set_assert_return_is_criticalp(bool *p
) {
14 log_set_assert_return_is_critical(*p
);
17 #define _SAVE_ASSERT_RETURN_IS_CRITICAL(b) \
18 _unused_ _cleanup_(log_set_assert_return_is_criticalp) bool b = \
19 log_get_assert_return_is_critical()
21 #define SAVE_ASSERT_RETURN_IS_CRITICAL \
22 _SAVE_ASSERT_RETURN_IS_CRITICAL(UNIQ_T(saved, UNIQ))
24 #define ASSERT_RETURN_IS_CRITICAL(b, expr) \
26 SAVE_ASSERT_RETURN_IS_CRITICAL; \
27 log_set_assert_return_is_critical(b); \
31 #define ASSERT_RETURN_EXPECTED(expr) ASSERT_RETURN_IS_CRITICAL(false, expr)
32 #define ASSERT_RETURN_EXPECTED_SE(expr) ASSERT_RETURN_EXPECTED(assert_se(expr));
34 static inline bool manager_errno_skip_test(int r
) {
41 ENOMEDIUM
/* cannot determine cgroup */
45 char* setup_fake_runtime_dir(void);
46 int enter_cgroup_subroot(char **ret_cgroup
);
47 int enter_cgroup_root(char **ret_cgroup
);
48 int get_testdata_dir(const char *suffix
, char **ret
);
49 const char* get_catalog_dir(void);
50 bool slow_tests_enabled(void);
51 void test_setup_logging(int level
);
53 #define log_tests_skipped(fmt, ...) \
55 log_notice("%s: " fmt ", skipping tests.", \
56 program_invocation_short_name, \
61 #define log_tests_skipped_errno(error, fmt, ...) \
63 log_notice_errno(error, \
64 "%s: " fmt ", skipping tests: %m", \
65 program_invocation_short_name, \
70 int write_tmpfile(char *pattern
, const char *contents
);
72 bool have_namespaces(void);
74 /* We use the small but non-trivial limit here */
75 #define CAN_MEMLOCK_SIZE (512 * 1024U)
76 bool can_memlock(void);
78 /* Define void* buffer and size_t length variables from a hex string. */
79 #define DEFINE_HEX_PTR(name, hex) \
80 _cleanup_free_ void *name = NULL; \
81 size_t name##_len = 0; \
82 assert_se(unhexmem_full(hex, strlen_ptr(hex), false, &name, &name##_len) >= 0);
84 #define TEST_REQ_RUNNING_SYSTEMD(x) \
85 if (sd_booted() > 0) { \
88 printf("systemd not booted, skipping '%s'\n", #x); \
91 /* Provide a convenient way to check if we're running in CI. */
92 const char *ci_environment(void);
94 typedef struct TestFunc
{
96 void (*void_func
)(void);
97 int (*int_func
)(void);
99 const char * const name
;
104 /* See static-destruct.h for an explanation of how this works. */
105 #define REGISTER_TEST(func, ...) \
106 _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
107 _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _retain_ _variable_no_sanitize_address_ \
108 static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
109 .f = (union f) &(func), \
110 .name = STRINGIFY(func), \
111 .has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \
115 extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE
[];
116 extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE
[];
118 #define TEST(name, ...) \
119 static void test_##name(void); \
120 REGISTER_TEST(test_##name, ##__VA_ARGS__); \
121 static void test_##name(void)
123 #define TEST_RET(name, ...) \
124 static int test_##name(void); \
125 REGISTER_TEST(test_##name, ##__VA_ARGS__); \
126 static int test_##name(void)
128 #define TEST_LOG_FUNC() \
129 log_info("/* %s() */", __func__)
131 static inline int run_test_table(void) {
132 _cleanup_strv_free_
char **tests
= NULL
;
133 int r
= EXIT_SUCCESS
;
137 if (!__start_SYSTEMD_TEST_TABLE
)
140 e
= getenv("TESTFUNCS");
142 r
= strv_split_full(&tests
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
144 return log_error_errno(r
, "Failed to parse $TESTFUNCS: %m");
147 for (const TestFunc
*t
= ALIGN_PTR(__start_SYSTEMD_TEST_TABLE
);
148 t
+ 1 <= __stop_SYSTEMD_TEST_TABLE
;
149 t
= ALIGN_PTR(t
+ 1)) {
151 if (tests
&& !strv_contains(tests
, t
->name
))
154 if (t
->sd_booted
&& sd_booted() <= 0) {
155 log_info("/* systemd not booted, skipping %s */", t
->name
);
156 if (t
->has_ret
&& r
== EXIT_SUCCESS
)
159 log_info("/* %s */", t
->name
);
162 int r2
= t
->f
.int_func();
163 if (r
== EXIT_SUCCESS
)
173 return log_error_errno(SYNTHETIC_ERRNO(ENXIO
), "No matching tests found.");
178 #define DEFINE_TEST_MAIN_FULL(log_level, intro, outro) \
179 int main(int argc, char *argv[]) { \
180 int (*_intro)(void) = intro; \
181 int (*_outro)(void) = outro; \
183 test_setup_logging(log_level); \
184 save_argc_argv(argc, argv); \
185 _r = _intro ? _intro() : EXIT_SUCCESS; \
186 if (_r == EXIT_SUCCESS) \
187 _r = run_test_table(); \
188 _q = _outro ? _outro() : EXIT_SUCCESS; \
191 return EXIT_FAILURE; \
192 if (_r != EXIT_SUCCESS) \
195 return EXIT_FAILURE; \
199 #define DEFINE_TEST_MAIN_WITH_INTRO(log_level, intro) \
200 DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
201 #define DEFINE_TEST_MAIN(log_level) \
202 DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
204 #define ASSERT_OK(expr) \
206 typeof(expr) _result = (expr); \
208 log_error_errno(_result, "%s:%i: Assertion failed: %s: %m", \
209 PROJECT_FILE, __LINE__, #expr); \
214 #define ASSERT_TRUE(expr) \
217 log_error("%s:%i: Assertion failed: expected \"%s\" to be true", \
218 PROJECT_FILE, __LINE__, #expr); \
223 #define ASSERT_FALSE(expr) \
226 log_error("%s:%i: Assertion failed: expected \"%s\" to be false", \
227 PROJECT_FILE, __LINE__, #expr); \
232 #define ASSERT_NULL(expr) \
234 if ((expr) != NULL) { \
235 log_error("%s:%i: Assertion failed: expected \"%s\" to be NULL", \
236 PROJECT_FILE, __LINE__, #expr); \
241 #define ASSERT_NOT_NULL(expr) \
243 if ((expr) == NULL) { \
244 log_error("%s:%i: Assertion failed: expected \"%s\" to be not NULL", \
245 PROJECT_FILE, __LINE__, #expr); \
250 #define ASSERT_STREQ(expr1, expr2) \
252 const char *_expr1 = (expr1), *_expr2 = (expr2); \
253 if (!streq_ptr(_expr1, _expr2)) { \
254 log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
255 PROJECT_FILE, __LINE__, #expr1, #expr2, strnull(_expr1), strnull(_expr2)); \
260 /* DECIMAL_STR_FMT() uses _Generic which cannot be used in string concatenation so we have to format the
261 * input into strings first and then format those into the final assertion message. */
263 #define ASSERT_EQ(expr1, expr2) \
265 typeof(expr1) _expr1 = (expr1); \
266 typeof(expr2) _expr2 = (expr2); \
267 if (_expr1 != _expr2) { \
268 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
269 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
270 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
271 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
272 log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
273 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
278 #define ASSERT_GE(expr1, expr2) \
280 typeof(expr1) _expr1 = (expr1); \
281 typeof(expr2) _expr2 = (expr2); \
282 if (_expr1 < _expr2) { \
283 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
284 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
285 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
286 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
287 log_error("%s:%i: Assertion failed: expected \"%s >= %s\", but \"%s < %s\"", \
288 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
293 #define ASSERT_LE(expr1, expr2) \
295 typeof(expr1) _expr1 = (expr1); \
296 typeof(expr2) _expr2 = (expr2); \
297 if (_expr1 > _expr2) { \
298 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
299 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
300 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
301 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
302 log_error("%s:%i: Assertion failed: expected \"%s <= %s\", but \"%s > %s\"", \
303 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
308 #define ASSERT_NE(expr1, expr2) \
310 typeof(expr1) _expr1 = (expr1); \
311 typeof(expr2) _expr2 = (expr2); \
312 if (_expr1 == _expr2) { \
313 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
314 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
315 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
316 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
317 log_error("%s:%i: Assertion failed: expected \"%s != %s\", but \"%s == %s\"", \
318 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
323 #define ASSERT_GT(expr1, expr2) \
325 typeof(expr1) _expr1 = (expr1); \
326 typeof(expr2) _expr2 = (expr2); \
327 if (!(_expr1 > _expr2)) { \
328 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
329 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
330 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
331 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
332 log_error("%s:%i: Assertion failed: expected \"%s > %s\", but \"%s <= %s\"", \
333 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
338 #define ASSERT_LT(expr1, expr2) \
340 typeof(expr1) _expr1 = (expr1); \
341 typeof(expr2) _expr2 = (expr2); \
342 if (!(_expr1 < _expr2)) { \
343 char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
344 char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
345 xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
346 xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
347 log_error("%s:%i: Assertion failed: expected \"%s < %s\", but \"%s >= %s\"", \
348 PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \