diff options
Diffstat (limited to 'source/test.h')
| -rw-r--r-- | source/test.h | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/source/test.h b/source/test.h new file mode 100644 index 0000000..d45c2fe --- /dev/null +++ b/source/test.h @@ -0,0 +1,120 @@ +#ifndef EXITEST_TEST_H_INCLUDED +#define EXITEST_TEST_H_INCLUDED + +#include <gccore.h> +#include <assert.h> +#include "state.h" +#include "macros.h" + +typedef enum { + TEST_INTERACTIVE = 0x01u, + TEST_PAUSE_ON_ERROR = 0x02u /* for "essential" tests that should pass */ +} et_test_flags; + +struct et_test; +struct et_test_plan; + +struct et_test { + struct et_state parent; + const char *name; + et_test_flags flags; + + et_state_init_f *test_init_f; + et_state_cleanup_f *test_cleanup_f; +}; + +/* 0000eeee eeeeeeee eeeeeeee x00000ss */ +/* e = error code bits, + * x = 1 if this test is still in the "clean" (not executed) state + * ss = status type (pass/fail/etc.) */ +typedef u32 et_test_status; + +typedef enum { + TEST_ENONE = (u32)0, + + /* test was aborted (i.e., requested to go to next test without setting a status code) */ + TEST_EABORT, + + /* minimum private test error (define test-private error codes as TEST_EPRIV_BASE+n) */ + TEST_EPRIV_BASE = 32, + + /* largest error code allowed */ + TEST_EMAX = ((u32)1 << 20) - 1 +} et_test_error; + +typedef enum { + TEST_SSKIPPED = 0u, + TEST_SERROR, + TEST_SFAIL, + TEST_SPASS, + + TEST_SMAX = ((u32)1 << 2) - 1 +} et_test_status_type; + +#define TEST_STATUS_GET_ERROR(_status) (et_test_error)(((u32)(_status) >> 8) & TEST_EMAX) +#define TEST_STATUS_GET_TYPE(_status) (et_test_status_type)((u32)(_status) & TEST_SMAX) +#define TEST_STATUS_IS_CLEAN(_status) (!!((u32)(_status) & 0x80u)) + +#define TEST_MAKE_STATUS(_type, _error, _clean) (et_test_status) \ + (((u32)(_type) & TEST_SMAX) | \ + (((u32)(_clean) & 1) << 7) | \ + (((u32)(_error) & TEST_EMAX) << 8)) + +#define TEST_SKIPPED TEST_MAKE_STATUS(TEST_SSKIPPED, TEST_ENONE, 0) +#define TEST_FAIL TEST_MAKE_STATUS(TEST_SFAIL, TEST_ENONE, 0) +#define TEST_PASS TEST_MAKE_STATUS(TEST_SPASS, TEST_ENONE, 0) +#define TEST_ERROR(_e) TEST_MAKE_STATUS(TEST_SERROR, _e, 0) + +#define TEST_PRIMORDIAL TEST_MAKE_STATUS(TEST_SSKIPPED, TEST_ENONE, 1) + +/* Expected setup date: pointer to test plan */ +extern const struct et_state *et_state_begin_testing; +extern const struct et_state *et_state_summarize_test_plan; + +const char *et_test_get_status_mnemonic(et_test_status status); + +struct et_test_plan_entry { + const struct et_test *test; + et_test_status status; + const char *ext_status; + void (*ext_status_free)(void *); +}; + +/* a properly initialized test plan will have all the tests' statuses set to TEST_PRIMORDIAL */ +struct et_test_plan { + int exi_channel; + + /* this state will be set after testing is complete. + * NOTE: next_state_init should somehow point to this test plan, + * since it's probably dynamically allocated and will be leaked if not + * freed. */ + const struct et_state *next_state; + et_state_init_data next_state_init; + + size_t num_tests; + size_t current_test; + struct et_test_plan_entry *tests; +}; + +void et_test_plan_entry_cleanup(struct et_test_plan_entry *entry); + +#define FOREACH_TEST(O, _sep) \ + O(check_id) + +#define TEST_SYM(_name) PASTE(et_test_, _name) +#define DECL_TEST(_name) extern const struct et_test *const TEST_SYM(_name) + +FOREACH_TEST(DECL_TEST, ;); +#undef DECL_TEST + +const struct et_test *const *et_get_tests(size_t *ntests); + +#if defined(ET_TEST_IMPL) || defined(TEST_INTERNAL) +#define ET__ALLOW_TEST_IMPL_INC +#include "test-impl.inc.h" +#else +#undef FOREACH_TEST +#undef TEST_SYM +#endif + +#endif /* include guard */ |
