mirror of
https://github.com/AuxXxilium/kmod.git
synced 2024-12-04 13:46:59 +07:00
b77251f08d
Add a new DEFINE_TEST_WITH_FUNC() that accepts the function alongside the test name. This will allow us to share a single function for different tests.
192 lines
5.5 KiB
C
192 lines
5.5 KiB
C
/*
|
|
* 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
|