| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright (c) 2021 Google LLC |
| */ |
| |
| #ifndef _TEST_FRAMEWORK_H |
| #define _TEST_FRAMEWORK_H |
| |
| #include <stdbool.h> |
| #include <stdio.h> |
| |
| #ifdef __ANDROID__ |
| static int test_case_pass; |
| static int test_case_fail; |
| #define ksft_print_msg printf |
| #define ksft_test_result_pass(...) ({test_case_pass++; printf(__VA_ARGS__); }) |
| #define ksft_test_result_fail(...) ({test_case_fail++; printf(__VA_ARGS__); }) |
| #define ksft_exit_fail_msg(...) printf(__VA_ARGS__) |
| #define ksft_print_header() |
| #define ksft_set_plan(cnt) |
| #define ksft_get_fail_cnt() test_case_fail |
| #define ksft_exit_pass() 0 |
| #define ksft_exit_fail() 1 |
| #else |
| #include <kselftest.h> |
| #endif |
| |
| #define TEST_FAILURE 1 |
| #define TEST_SUCCESS 0 |
| |
| #define ptr_to_u64(p) ((__u64)p) |
| |
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| #define le16_to_cpu(x) (x) |
| #define le32_to_cpu(x) (x) |
| #define le64_to_cpu(x) (x) |
| #else |
| #error Big endian not supported! |
| #endif |
| |
| struct _test_options { |
| int file; |
| bool verbose; |
| }; |
| |
| extern struct _test_options test_options; |
| |
| #define TESTCOND(condition) \ |
| do { \ |
| if (!(condition)) { \ |
| ksft_print_msg("%s failed %d\n", \ |
| __func__, __LINE__); \ |
| goto out; \ |
| } else if (test_options.verbose) \ |
| ksft_print_msg("%s succeeded %d\n", \ |
| __func__, __LINE__); \ |
| } while (false) |
| |
| #define TESTCONDERR(condition) \ |
| do { \ |
| if (!(condition)) { \ |
| ksft_print_msg("%s failed %d\n", \ |
| __func__, __LINE__); \ |
| ksft_print_msg("Error %d (\"%s\")\n", \ |
| errno, strerror(errno)); \ |
| goto out; \ |
| } else if (test_options.verbose) \ |
| ksft_print_msg("%s succeeded %d\n", \ |
| __func__, __LINE__); \ |
| } while (false) |
| |
| #define TEST(statement, condition) \ |
| do { \ |
| statement; \ |
| TESTCOND(condition); \ |
| } while (false) |
| |
| #define TESTERR(statement, condition) \ |
| do { \ |
| statement; \ |
| TESTCONDERR(condition); \ |
| } while (false) |
| |
| enum _operator { |
| _eq, |
| _ne, |
| _ge, |
| }; |
| |
| static const char * const _operator_name[] = { |
| "==", |
| "!=", |
| ">=", |
| }; |
| |
| #define _TEST_OPERATOR(name, _type, format_specifier) \ |
| static inline int _test_operator_##name(const char *func, int line, \ |
| _type a, _type b, enum _operator o) \ |
| { \ |
| bool pass; \ |
| switch (o) { \ |
| case _eq: pass = a == b; break; \ |
| case _ne: pass = a != b; break; \ |
| case _ge: pass = a >= b; break; \ |
| } \ |
| \ |
| if (!pass) \ |
| ksft_print_msg("Failed: %s at line %d, " \ |
| format_specifier " %s " \ |
| format_specifier "\n", \ |
| func, line, a, _operator_name[o], b); \ |
| else if (test_options.verbose) \ |
| ksft_print_msg("Passed: %s at line %d, " \ |
| format_specifier " %s " \ |
| format_specifier "\n", \ |
| func, line, a, _operator_name[o], b); \ |
| \ |
| return pass ? TEST_SUCCESS : TEST_FAILURE; \ |
| } |
| |
| _TEST_OPERATOR(i, int, "%d") |
| _TEST_OPERATOR(ui, unsigned int, "%u") |
| _TEST_OPERATOR(lui, unsigned long, "%lu") |
| _TEST_OPERATOR(ss, ssize_t, "%zd") |
| _TEST_OPERATOR(vp, void *, "%px") |
| _TEST_OPERATOR(cp, char *, "%px") |
| |
| #define _CALL_TO(_type, name, a, b, o) \ |
| _type:_test_operator_##name(__func__, __LINE__, \ |
| (_type) (long long) (a), \ |
| (_type) (long long) (b), o) |
| |
| #define TESTOPERATOR(a, b, o) \ |
| do { \ |
| if (_Generic((a), \ |
| _CALL_TO(int, i, a, b, o), \ |
| _CALL_TO(unsigned int, ui, a, b, o), \ |
| _CALL_TO(unsigned long, lui, a, b, o), \ |
| _CALL_TO(ssize_t, ss, a, b, o), \ |
| _CALL_TO(void *, vp, a, b, o), \ |
| _CALL_TO(char *, cp, a, b, o) \ |
| )) \ |
| goto out; \ |
| } while (false) |
| |
| #define TESTEQUAL(a, b) TESTOPERATOR(a, b, _eq) |
| #define TESTNE(a, b) TESTOPERATOR(a, b, _ne) |
| #define TESTGE(a, b) TESTOPERATOR(a, b, _ge) |
| |
| /* For testing a syscall that returns 0 on success and sets errno otherwise */ |
| #define TESTSYSCALL(statement) TESTCONDERR((statement) == 0) |
| |
| #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
| |
| static inline void print_bytes(const void *data, size_t size) |
| { |
| const char *bytes = data; |
| int i; |
| |
| for (i = 0; i < size; ++i) { |
| if (i % 0x10 == 0) |
| printf("%08x:", i); |
| printf("%02x ", (unsigned int) (unsigned char) bytes[i]); |
| if (i % 0x10 == 0x0f) |
| printf("\n"); |
| } |
| |
| if (i % 0x10 != 0) |
| printf("\n"); |
| } |
| |
| |
| |
| #endif |