/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. * Copyright (c) 2023 Tejun Heo * Copyright (c) 2023 David Vernet */ #ifndef __SCX_TEST_H__ #define __SCX_TEST_H__ #include #include #include enum scx_test_status { SCX_TEST_PASS = 0, SCX_TEST_SKIP, SCX_TEST_FAIL, }; #define EXIT_KIND(__ent) __COMPAT_ENUM_OR_ZERO("scx_exit_kind", #__ent) struct scx_test { /** * name - The name of the testcase. */ const char *name; /** * description - A description of your testcase: what it tests and is * meant to validate. */ const char *description; /* * setup - Setup the test. * @ctx: A pointer to a context object that will be passed to run and * cleanup. * * An optional callback that allows a testcase to perform setup for its * run. A test may return SCX_TEST_SKIP to skip the run. */ enum scx_test_status (*setup)(void **ctx); /* * run - Run the test. * @ctx: Context set in the setup() callback. If @ctx was not set in * setup(), it is NULL. * * The main test. Callers should return one of: * * - SCX_TEST_PASS: Test passed * - SCX_TEST_SKIP: Test should be skipped * - SCX_TEST_FAIL: Test failed * * This callback must be defined. */ enum scx_test_status (*run)(void *ctx); /* * cleanup - Perform cleanup following the test * @ctx: Context set in the setup() callback. If @ctx was not set in * setup(), it is NULL. * * An optional callback that allows a test to perform cleanup after * being run. This callback is run even if the run() callback returns * SCX_TEST_SKIP or SCX_TEST_FAIL. It is not run if setup() returns * SCX_TEST_SKIP or SCX_TEST_FAIL. */ void (*cleanup)(void *ctx); }; void scx_test_register(struct scx_test *test); #define REGISTER_SCX_TEST(__test) \ __attribute__((constructor)) \ static void ___scxregister##__LINE__(void) \ { \ scx_test_register(__test); \ } #define SCX_ERR(__fmt, ...) \ do { \ fprintf(stderr, "ERR: %s:%d\n", __FILE__, __LINE__); \ fprintf(stderr, __fmt"\n", ##__VA_ARGS__); \ } while (0) #define SCX_FAIL(__fmt, ...) \ do { \ SCX_ERR(__fmt, ##__VA_ARGS__); \ return SCX_TEST_FAIL; \ } while (0) #define SCX_FAIL_IF(__cond, __fmt, ...) \ do { \ if (__cond) \ SCX_FAIL(__fmt, ##__VA_ARGS__); \ } while (0) #define SCX_GT(_x, _y) SCX_FAIL_IF((_x) <= (_y), "Expected %s > %s (%lu > %lu)", \ #_x, #_y, (u64)(_x), (u64)(_y)) #define SCX_GE(_x, _y) SCX_FAIL_IF((_x) < (_y), "Expected %s >= %s (%lu >= %lu)", \ #_x, #_y, (u64)(_x), (u64)(_y)) #define SCX_LT(_x, _y) SCX_FAIL_IF((_x) >= (_y), "Expected %s < %s (%lu < %lu)", \ #_x, #_y, (u64)(_x), (u64)(_y)) #define SCX_LE(_x, _y) SCX_FAIL_IF((_x) > (_y), "Expected %s <= %s (%lu <= %lu)", \ #_x, #_y, (u64)(_x), (u64)(_y)) #define SCX_EQ(_x, _y) SCX_FAIL_IF((_x) != (_y), "Expected %s == %s (%lu == %lu)", \ #_x, #_y, (u64)(_x), (u64)(_y)) #define SCX_ASSERT(_x) SCX_FAIL_IF(!(_x), "Expected %s to be true (%lu)", \ #_x, (u64)(_x)) #define SCX_ECODE_VAL(__ecode) ({ \ u64 __val = 0; \ bool __found = false; \ \ __found = __COMPAT_read_enum("scx_exit_code", #__ecode, &__val); \ SCX_ASSERT(__found); \ (s64)__val; \ }) #define SCX_KIND_VAL(__kind) ({ \ u64 __val = 0; \ bool __found = false; \ \ __found = __COMPAT_read_enum("scx_exit_kind", #__kind, &__val); \ SCX_ASSERT(__found); \ __val; \ }) #endif // # __SCX_TEST_H__