summaryrefslogtreecommitdiffstats
path: root/source/test.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/test.h')
-rw-r--r--source/test.h120
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 */