diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:03:56 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:03:56 +0000 |
commit | 18da3ffcd7f3c8a0c5f790c801b5813503c2273d (patch) | |
tree | 84caf98dc5cef3d123c56ba12e35fd67026e0693 /testsuite/testsuite.h | |
parent | Initial commit. (diff) | |
download | kmod-18da3ffcd7f3c8a0c5f790c801b5813503c2273d.tar.xz kmod-18da3ffcd7f3c8a0c5f790c801b5813503c2273d.zip |
Adding upstream version 31+20240202.upstream/31+20240202
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testsuite/testsuite.h')
-rw-r--r-- | testsuite/testsuite.h | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/testsuite/testsuite.h b/testsuite/testsuite.h new file mode 100644 index 0000000..44d1730 --- /dev/null +++ b/testsuite/testsuite.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2012-2013 ProFUSION embedded systems + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdbool.h> +#include <stdarg.h> +#include <stdio.h> + +#include <shared/macro.h> + +struct test; +typedef int (*testfunc)(const struct test *t); + +enum test_config { + /* + * Where's the roots dir for this test. It will LD_PRELOAD path.so in + * order to trap calls to functions using paths. + */ + TC_ROOTFS = 0, + + /* + * What's the desired string to be returned by `uname -r`. It will + * trap calls to uname(3P) by LD_PRELOAD'ing uname.so and then filling + * in the information in u.release. + */ + TC_UNAME_R, + + /* + * Fake calls to init_module(2), returning return-code and setting + * errno to err-code. Set this variable with the following format: + * + * modname:return-code:err-code + * + * When this variable is used, all calls to init_module() are trapped + * and by default the return code is 0. In other words, they fake + * "success" for all modules, except the ones in the list above, for + * which the return codes are used. + */ + TC_INIT_MODULE_RETCODES, + + /* + * Fake calls to delete_module(2), returning return-code and setting + * errno to err-code. Set this variable with the following format: + * + * modname:return-code:err-code + * + * When this variable is used, all calls to init_module() are trapped + * and by default the return code is 0. In other words, they fake + * "success" for all modules, except the ones in the list above, for + * which the return codes are used. + */ + TC_DELETE_MODULE_RETCODES, + + _TC_LAST, +}; + +#define S_TC_ROOTFS "TESTSUITE_ROOTFS" +#define S_TC_UNAME_R "TESTSUITE_UNAME_R" +#define S_TC_INIT_MODULE_RETCODES "TESTSUITE_INIT_MODULE_RETCODES" +#define S_TC_DELETE_MODULE_RETCODES "TESTSUITE_DELETE_MODULE_RETCODES" + +struct keyval { + const char *key; + const char *val; +}; + +struct test { + const char *name; + const char *description; + struct { + /* File with correct stdout */ + const char *out; + /* File with correct stderr */ + const char *err; + + /* + * whether to treat the correct files as regex to the real + * output + */ + bool regex; + + /* + * Vector with pair of files + * key = correct file + * val = file to check + */ + const struct keyval *files; + } output; + /* comma-separated list of loaded modules at the end of the test */ + const char *modules_loaded; + testfunc func; + const char *config[_TC_LAST]; + const char *path; + const struct keyval *env_vars; + bool need_spawn; + bool expected_fail; + /* allow to skip tests that don't meet compile-time dependencies */ + bool skip; + bool print_outputs; +} __attribute__((aligned(8))); + + +int test_init(const struct test *start, const struct test *stop, + int argc, char *const argv[]); +const struct test *test_find(const struct test *start, const struct test *stop, + const char *name); +int test_spawn_prog(const char *prog, const char *const args[]); +int test_run(const struct test *t); + +#define TS_EXPORT __attribute__ ((visibility("default"))) + +#define _LOG(prefix, fmt, ...) printf("TESTSUITE: " prefix fmt, ## __VA_ARGS__) +#define LOG(fmt, ...) _LOG("", fmt, ## __VA_ARGS__) +#define WARN(fmt, ...) _LOG("WARN: ", fmt, ## __VA_ARGS__) +#define ERR(fmt, ...) _LOG("ERR: ", fmt, ## __VA_ARGS__) + +#define assert_return(expr, r) \ + do { \ + if ((!(expr))) { \ + ERR("Failed assertion: " #expr " %s:%d %s\n", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return (r); \ + } \ + } while (false) + + +/* Test definitions */ +#define DEFINE_TEST_WITH_FUNC(_name, _func, ...) \ + static const struct test UNIQ(s##_name) \ + __attribute__((used, section("kmod_tests"), aligned(8))) = { \ + .name = #_name, \ + .func = _func, \ + ## __VA_ARGS__ \ + }; + +#define DEFINE_TEST(_name, ...) DEFINE_TEST_WITH_FUNC(_name, _name, __VA_ARGS__) + +#define TESTSUITE_MAIN() \ + extern struct test __start_kmod_tests[] __attribute__((weak, visibility("hidden"))); \ + extern struct test __stop_kmod_tests[] __attribute__((weak, visibility("hidden"))); \ + int main(int argc, char *argv[]) \ + { \ + const struct test *t; \ + int arg; \ + \ + arg = test_init(__start_kmod_tests, __stop_kmod_tests, argc, argv); \ + if (arg == 0) \ + return 0; \ + if (arg < 0) \ + return EXIT_FAILURE; \ + \ + if (arg < argc) { \ + t = test_find(__start_kmod_tests, __stop_kmod_tests, argv[arg]); \ + if (t == NULL) { \ + fprintf(stderr, "could not find test %s\n", argv[arg]); \ + exit(EXIT_FAILURE); \ + } \ + \ + return test_run(t); \ + } \ + \ + for (t = __start_kmod_tests; t < __stop_kmod_tests; t++) { \ + if (test_run(t) != 0) \ + exit(EXIT_FAILURE); \ + } \ + \ + exit(EXIT_SUCCESS); \ + } \ + +#ifdef noreturn +# define __noreturn noreturn +#elif __STDC_VERSION__ >= 201112L +# define __noreturn _Noreturn +#else +# define __noreturn __attribute__((noreturn)) +#endif |