diff options
Diffstat (limited to 'tests/test.h')
-rw-r--r-- | tests/test.h | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 0000000..ca349b0 --- /dev/null +++ b/tests/test.h @@ -0,0 +1,172 @@ +/* PipeWire + * + * Copyright © 2021 Red Hat, Inc. + * Copyright © 2021 Collabora Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> + +#ifdef __GNUC__ +#define TEST_NORETURN __attribute__ ((noreturn)) +#define TEST_LIKELY(x) (__builtin_expect(!!(x),1)) +#else +#define TEST_NORETURN +#define TEST_LIKELY(x) (x) +#endif + +enum { + TEST_PASS = EXIT_SUCCESS, + TEST_FAIL = EXIT_FAILURE, + TEST_SKIP = 77, +}; + +#define test_log(...) fprintf(stderr, __VA_ARGS__) +#define test_vlog(format_, args_) vfprintf(stderr, format_, args_) + +static inline bool _test_streq(const char *s1, const char *s2) { + return TEST_LIKELY(s1 && s2) ? strcmp(s1, s2) == 0 : s1 == s2; +} + +TEST_NORETURN +static inline void _test_fail( + const char *file, int line, const char *func, + const char *message) { + test_log("FAILED: %s\n", message); + test_log("in %s() (%s:%d)\n", func, file, line); + exit(TEST_FAIL); +} + +TEST_NORETURN +static inline void _test_fail_comparison_bool( + const char *file, int line, const char *func, + const char *operator, bool a, bool b, + const char *astr, const char *bstr) { + test_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr); + test_log("Resolved to: %s %s %s\n", a ? "true" : "false", operator, + b ? "true" : "false"); + test_log("in %s() (%s:%d)\n", func, file, line); + exit(TEST_FAIL); +} + +TEST_NORETURN +static inline void _test_fail_comparison_int( + const char *file, int line, const char *func, + const char *operator, int a, int b, + const char *astr, const char *bstr) { + test_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr); + test_log("Resolved to: %d %s %d\n", a, operator, b); + test_log("in %s() (%s:%d)\n", func, file, line); + exit(TEST_FAIL); +} + +TEST_NORETURN +static inline void _test_fail_comparison_double( + const char *file, int line, const char *func, + const char *operator, double a, double b, + const char *astr, const char *bstr) { + test_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr); + test_log("Resolved to: %.3f %s %.3f\n", a, operator, b); + test_log("in %s() (%s:%d)\n", func, file, line); + exit(TEST_FAIL); +} + +TEST_NORETURN +static inline void _test_fail_comparison_ptr( + const char *file, int line, const char *func, + const char *comparison) { + test_log("FAILED COMPARISON: %s\n", comparison); + test_log("in %s() (%s:%d)\n", func, file, line); + exit(TEST_FAIL); +} + +TEST_NORETURN +static inline void _test_fail_comparison_str( + const char *file, int line, const char *func, + const char *comparison, const char *a, const char *b) { + test_log("FAILED COMPARISON: %s, expanded (\"%s\" vs \"%s\")\n", + comparison, a, b); + test_log("in %s() (%s:%d)\n", func, file, line); + exit(TEST_FAIL); +} + +#define test_fail_if_reached() \ + _test_fail(__FILE__, __LINE__, __func__, \ + "This line is supposed to be unreachable") + +#define test_cmpbool(a_, op_, b_) \ + do { \ + bool _a = !!(a_); \ + bool _b = !!(b_); \ + if (!(_a op_ _b)) \ + _test_fail_comparison_bool(__FILE__, __LINE__, __func__,\ + #op_, _a, _b, #a_, #b_); \ + } while(0) + +#define test_bool_true(cond_) \ + test_cmpbool(cond_, ==, true) + +#define test_bool_false(cond_) \ + test_cmpbool(cond_, ==, false) + +#define test_cmpint(a_, op_, b_) \ + do { \ + __typeof__(a_) _a = a_; \ + __typeof__(b_) _b = b_; \ + if (trunc(_a) != _a || trunc(_b) != _b) \ + _test_fail(__FILE__, __LINE__, __func__, \ + "test_int_* used for non-integer value"); \ + if (!((_a) op_ (_b))) \ + _test_fail_comparison_int(__FILE__, __LINE__, __func__,\ + #op_, _a, _b, #a_, #b_); \ + } while(0) + +#define test_cmpptr(a_, op_, b_) \ + do { \ + __typeof__(a_) _a = a_; \ + __typeof__(b_) _b = b_; \ + if (!((_a) op_ (_b))) \ + _test_fail_comparison_ptr(__FILE__, __LINE__, __func__,\ + #a_ " " #op_ " " #b_); \ + } while(0) + +#define test_ptr_null(a_) \ + test_cmpptr(a_, ==, NULL) + +#define test_ptr_notnull(a_) \ + test_cmpptr(a_, !=, NULL) + +#define test_cmpdouble(a_, op_, b_) \ + do { \ + const double EPSILON = 1.0/256; \ + __typeof__(a_) _a = a_; \ + __typeof__(b_) _b = b_; \ + if (!((_a) op_ (_b)) && fabs((_a) - (_b)) > EPSILON) \ + _test_fail_comparison_double(__FILE__, __LINE__, __func__,\ + #op_, _a, _b, #a_, #b_); \ + } while(0) + +#define test_str_eq(a_, b_) \ + do { \ + const char *_a = a_; \ + const char *_b = b_; \ + if (!_test_streq(_a, _b)) \ + _test_fail_comparison_str(__FILE__, __LINE__, __func__, \ + #a_ " equals " #b_, _a, _b); \ + } while(0) + +#define test_str_ne(a_, b_) \ + do { \ + const char *_a = a_; \ + const char *_b = b_; \ + if (_test_streq(_a, _b)) \ + _test_fail_comparison_str(__FILE__, __LINE__, __func__, \ + #a_ " not equal to " #b_, _a, _b); \ + } while(0) |