#ifndef EXITEST_TEST_H_INCLUDED #define EXITEST_TEST_H_INCLUDED #include #include #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) _sep \ O(bad_commands) _sep \ O(flash_led) #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 */