1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 * Copyright (c) 2023 Tejun Heo <tj@kernel.org> 5 * Copyright (c) 2023 David Vernet <dvernet@meta.com> 6 */ 7 8 #ifndef __SCX_TEST_H__ 9 #define __SCX_TEST_H__ 10 11 #include <errno.h> 12 #include <scx/common.h> 13 #include <scx/compat.h> 14 15 enum scx_test_status { 16 SCX_TEST_PASS = 0, 17 SCX_TEST_SKIP, 18 SCX_TEST_FAIL, 19 }; 20 21 #define EXIT_KIND(__ent) __COMPAT_ENUM_OR_ZERO("scx_exit_kind", #__ent) 22 23 struct scx_test { 24 /** 25 * name - The name of the testcase. 26 */ 27 const char *name; 28 29 /** 30 * description - A description of your testcase: what it tests and is 31 * meant to validate. 32 */ 33 const char *description; 34 35 /* 36 * setup - Setup the test. 37 * @ctx: A pointer to a context object that will be passed to run and 38 * cleanup. 39 * 40 * An optional callback that allows a testcase to perform setup for its 41 * run. A test may return SCX_TEST_SKIP to skip the run. 42 */ 43 enum scx_test_status (*setup)(void **ctx); 44 45 /* 46 * run - Run the test. 47 * @ctx: Context set in the setup() callback. If @ctx was not set in 48 * setup(), it is NULL. 49 * 50 * The main test. Callers should return one of: 51 * 52 * - SCX_TEST_PASS: Test passed 53 * - SCX_TEST_SKIP: Test should be skipped 54 * - SCX_TEST_FAIL: Test failed 55 * 56 * This callback must be defined. 57 */ 58 enum scx_test_status (*run)(void *ctx); 59 60 /* 61 * cleanup - Perform cleanup following the test 62 * @ctx: Context set in the setup() callback. If @ctx was not set in 63 * setup(), it is NULL. 64 * 65 * An optional callback that allows a test to perform cleanup after 66 * being run. This callback is run even if the run() callback returns 67 * SCX_TEST_SKIP or SCX_TEST_FAIL. It is not run if setup() returns 68 * SCX_TEST_SKIP or SCX_TEST_FAIL. 69 */ 70 void (*cleanup)(void *ctx); 71 }; 72 73 void scx_test_register(struct scx_test *test); 74 75 #define REGISTER_SCX_TEST(__test) \ 76 __attribute__((constructor)) \ 77 static void ___scxregister##__LINE__(void) \ 78 { \ 79 scx_test_register(__test); \ 80 } 81 82 #define SCX_ERR(__fmt, ...) \ 83 do { \ 84 fprintf(stderr, "ERR: %s:%d\n", __FILE__, __LINE__); \ 85 fprintf(stderr, __fmt"\n", ##__VA_ARGS__); \ 86 } while (0) 87 88 #define SCX_FAIL(__fmt, ...) \ 89 do { \ 90 SCX_ERR(__fmt, ##__VA_ARGS__); \ 91 return SCX_TEST_FAIL; \ 92 } while (0) 93 94 #define SCX_FAIL_IF(__cond, __fmt, ...) \ 95 do { \ 96 if (__cond) \ 97 SCX_FAIL(__fmt, ##__VA_ARGS__); \ 98 } while (0) 99 100 #define SCX_GT(_x, _y) SCX_FAIL_IF((_x) <= (_y), "Expected %s > %s (%lu > %lu)", \ 101 #_x, #_y, (u64)(_x), (u64)(_y)) 102 #define SCX_GE(_x, _y) SCX_FAIL_IF((_x) < (_y), "Expected %s >= %s (%lu >= %lu)", \ 103 #_x, #_y, (u64)(_x), (u64)(_y)) 104 #define SCX_LT(_x, _y) SCX_FAIL_IF((_x) >= (_y), "Expected %s < %s (%lu < %lu)", \ 105 #_x, #_y, (u64)(_x), (u64)(_y)) 106 #define SCX_LE(_x, _y) SCX_FAIL_IF((_x) > (_y), "Expected %s <= %s (%lu <= %lu)", \ 107 #_x, #_y, (u64)(_x), (u64)(_y)) 108 #define SCX_EQ(_x, _y) SCX_FAIL_IF((_x) != (_y), "Expected %s == %s (%lu == %lu)", \ 109 #_x, #_y, (u64)(_x), (u64)(_y)) 110 #define SCX_ASSERT(_x) SCX_FAIL_IF(!(_x), "Expected %s to be true (%lu)", \ 111 #_x, (u64)(_x)) 112 113 #define SCX_ECODE_VAL(__ecode) ({ \ 114 u64 __val = 0; \ 115 bool __found = false; \ 116 \ 117 __found = __COMPAT_read_enum("scx_exit_code", #__ecode, &__val); \ 118 SCX_ASSERT(__found); \ 119 (s64)__val; \ 120 }) 121 122 #define SCX_KIND_VAL(__kind) ({ \ 123 u64 __val = 0; \ 124 bool __found = false; \ 125 \ 126 __found = __COMPAT_read_enum("scx_exit_kind", #__kind, &__val); \ 127 SCX_ASSERT(__found); \ 128 __val; \ 129 }) 130 131 #endif // # __SCX_TEST_H__ 132