summaryrefslogtreecommitdiffstats
path: root/source/test.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <bigfoot@figboot.dev>2026-06-29 03:00:12 -0500
committerLibravatar bigfoot547 <bigfoot@figboot.dev>2026-06-29 03:00:12 -0500
commit6bb84fe005fc151df1a67259242da9c0eaf3fe93 (patch)
tree683d6e160bf48fd0c235635be874a8fef697402c /source/test.c
parentadd new tests (diff)
begin work on pc side
Diffstat (limited to 'source/test.c')
-rw-r--r--source/test.c453
1 files changed, 0 insertions, 453 deletions
diff --git a/source/test.c b/source/test.c
deleted file mode 100644
index c59deaf..0000000
--- a/source/test.c
+++ /dev/null
@@ -1,453 +0,0 @@
-#include <assert.h>
-#include <stdio.h>
-#include <gccore.h>
-#include <wiiuse/wpad.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <inttypes.h>
-
-#define TEST_INTERNAL
-#include "test.h"
-#include "term.h"
-
-typedef u32 et_test_status;
-
-#define test_current(_plan) ((_plan)->tests + (_plan)->current_test)
-
-static int crit_test_fail_init(const struct et_state *state, void *data, et_state_init_data init_data) {
- struct et_test_plan *plan = init_data.p;
- struct et_test_plan_entry *last_ent;
-
- *(void **)data = plan;
-
- assert(plan->current_test > 0); /* NOTE: current_test has been incremented by this point */
-
- last_ent = plan->tests + (plan->current_test - 1);
-
- printf("\nCritical test failed: [%4s] %s\n", et_test_get_status_mnemonic(last_ent->status), last_ent->test->name);
- if (last_ent->ext_status) {
- printf("Test says:\n%s\n", last_ent->ext_status);
- } else {
- printf("No extended status.\n");
- }
-
- putchar('\n');
-
- printf("Press A to continue.\n");
- printf("Press B to finish testing.\n");
- printf("Press HOME/START to exit.\n");
-
- return 0;
-}
-
-static int crit_test_fail_tick(const struct et_state *state, void *data, struct et_next_state *next_state) {
- struct et_test_plan *plan = *(void **)data;
- u32 wpad_pressed = WPAD_ButtonsDown(0);
- u32 pad_pressed = PAD_ButtonsDown(0);
-
- if (wpad_pressed & WPAD_BUTTON_A || pad_pressed & PAD_BUTTON_A) {
- next_state->state = et_state_begin_testing; /* also works to resume testing */
- next_state->init_data.p = plan; /* test plan */
- return 1;
- }
-
- if (wpad_pressed & WPAD_BUTTON_B || pad_pressed & PAD_BUTTON_B) {
- next_state->state = plan->next_state;
- next_state->init_data = plan->next_state_init;
- return 1;
- }
-
- if (wpad_pressed & WPAD_BUTTON_HOME || pad_pressed & PAD_BUTTON_START) {
- printf("Goodbye!\n");
- exit(0);
- }
-
- return 0;
-}
-
-static void crit_test_fail_cleanup(const struct et_state *state, void *data) {
- /* do nothing */
-}
-
-static const struct et_state state_crit_test_fail = {
- .private_size = sizeof(struct et_test_plan *),
- .init_f = crit_test_fail_init,
- .tick_f = crit_test_fail_tick,
- .cleanup_f = crit_test_fail_cleanup
-};
-
-int test_next(struct et_test_plan *plan, struct et_next_state *next_state) {
- /* NOTE: this function doesn't increment current_test because the incremented value
- * would be visible in the cleanup function of the test state. */
-
- /* NOTE: this condition will not trigger for states that leak their TEST_PRIMORDIAL status.
- * I don't care about this situation so much, since that should only happen for bugged tests. */
- const struct et_test_plan_entry *ent = test_current(plan);
- switch (TEST_STATUS_GET_TYPE(ent->status)) {
- case TEST_SERROR:
- case TEST_SFAIL:
- if (ent->test->flags & TEST_PAUSE_ON_ERROR) {
- next_state->state = &state_crit_test_fail;
- next_state->init_data.p = plan;
- return 1;
- }
- break;
- default:
- /* do nothing */
- (void)0;
- }
-
- if (plan->current_test == plan->num_tests - 1) {
- /* this is the last state... we're done! */
- next_state->state = plan->next_state;
- next_state->init_data = plan->next_state_init;
- } else {
- next_state->state = &plan->tests[plan->current_test + 1].test->parent;
- next_state->init_data.p = plan;
- }
-
- return 1; /* always return 1: advance to next state */
-}
-
-int test_state_init(const struct et_state *state, void *data, et_state_init_data init_data) {
- struct et_test_plan *plan = init_data.p;
- struct et_test_state_private_base *testdata = data;
- struct et_test_plan_entry *cur = test_current(plan);
- const struct et_test *test = (const struct et_test *)state;
-
- testdata->plan = plan;
-
- assert(cur->test == test); /* ensure correct test was loaded */
- assert(TEST_STATUS_IS_CLEAN(cur->status));
-
- if (test->test_init_f) {
- return test->test_init_f(state, data, init_data);
- }
-
- return 0;
-}
-
-void test_state_cleanup(const struct et_state *state, void *data) {
- struct et_test_state_private_base *testdata = data;
- struct et_test_plan_entry *cur = test_current(testdata->plan);
- const struct et_test *test = (const struct et_test *)state;
-
- if (test->test_cleanup_f) {
- test->test_cleanup_f(state, data);
- }
-
- if (TEST_STATUS_IS_CLEAN(cur->status)) {
- /* test didn't set status :( */
- test_plan_entry_set_error_static(cur, "test aborted");
- cur->status = TEST_ERROR(TEST_EABORT);
- }
-
- printf("[%4s] %s\n", et_test_get_status_mnemonic(cur->status), test->name);
-
- ++testdata->plan->current_test;
-}
-
-static int begin_testing_init(const struct et_state *state, void *state_data, et_state_init_data init_data) {
- struct et_test_plan *test_plan = init_data.p;
- struct et_test_plan **pst_test_plan = state_data;
- *pst_test_plan = test_plan;
- return 0;
-}
-
-static int begin_testing_tick(const struct et_state *state, void *state_data, struct et_next_state *next_state) {
- struct et_test_plan **ptest_plan = state_data;
- struct et_test_plan *test_plan = *ptest_plan;
-
- assert(test_plan->current_test <= test_plan->num_tests);
-
- if (test_plan->current_test < test_plan->num_tests) {
- const struct et_test_plan_entry *next_test = test_plan->tests + test_plan->current_test;
- assert(test_plan->tests);
- assert(next_test->status == TEST_PRIMORDIAL);
-
- next_state->state = &next_test->test->parent;
- next_state->init_data.p = test_plan;
- } else {
- /* no tests to run in this plan */
- next_state->state = test_plan->next_state;
- next_state->init_data = test_plan->next_state_init;
- }
-
- return 1;
-
-}
-
-static void begin_testing_cleanup(const struct et_state *state, void *state_data) {
- /* do nothing */
-}
-
-static const struct et_state state_begin_testing_struct = {
- .private_size = sizeof(const struct et_test_plan *),
- .init_f = begin_testing_init,
- .tick_f = begin_testing_tick,
- .cleanup_f = begin_testing_cleanup
-};
-
-const struct et_state *et_state_begin_testing = &state_begin_testing_struct;
-
-struct summ_test_plan_private {
- struct et_test_plan *plan;
- size_t selected_test;
-};
-
-#define SUMM_MENU_ROWS 3
-
-static void summ_test_print_menu(struct summ_test_plan_private *priv) {
- const struct et_test *test = priv->plan->tests[priv->selected_test].test;
-
- fputs(TERM_CUR_UP(SUMM_MENU_ROWS), stdout);
- puts(TERM_CLEARLINE "Press A to test again. Press HOME/START to exit.");
- puts(TERM_CLEARLINE "Press +/X to show output for [DL/DR]:");
- printf(TERM_CLEARLINE "%s\n", test->name);
-}
-
-static int summ_test_plan_init(const struct et_state *state, void *state_data, et_state_init_data init_data) {
- struct summ_test_plan_private *priv = state_data;
- struct et_test_plan *ptest_plan = init_data.p;
- size_t passed = 0;
- size_t failed = 0;
- size_t errored = 0;
- size_t skipped = 0;
- size_t unknown = 0;
-
- priv->plan = ptest_plan;
- priv->selected_test = 0;
-
- for (size_t i = 0; i < ptest_plan->num_tests; ++i) {
- switch (TEST_STATUS_GET_TYPE(ptest_plan->tests[i].status)) {
- case TEST_SPASS: ++passed; break;
- case TEST_SFAIL: ++failed; break;
- case TEST_SERROR: ++errored; break;
- case TEST_SSKIPPED: ++skipped; break;
- default: ++unknown; break;
- }
- }
-
- printf("\nTesting complete.\nPASS: %zu, FAIL: %zu, ERROR: %zu, SKIP: %zu, UNK: %zu\n\n", passed, failed, errored, skipped, unknown);
-
- for (int i = 0; i < SUMM_MENU_ROWS; ++i) putchar('\n');
- summ_test_print_menu(priv);
-
- return 0;
-}
-
-static int summ_test_plan_tick(const struct et_state *state, void *state_data, struct et_next_state *next_state) {
- struct summ_test_plan_private *priv = state_data;
-
- u32 wpad_buttons = WPAD_ButtonsDown(0);
- u32 pad_buttons = PAD_ButtonsDown(0);
-
- if (wpad_buttons & WPAD_BUTTON_A || pad_buttons & PAD_BUTTON_A) {
- next_state->state = et_state_setup;
- next_state->init_data = et_init_data_null;
- return 1;
- }
-
- if (wpad_buttons & WPAD_BUTTON_HOME || pad_buttons & PAD_BUTTON_START) {
- puts("Goodbye!");
- exit(0);
- }
-
- if (wpad_buttons & WPAD_BUTTON_LEFT || pad_buttons & PAD_BUTTON_LEFT) {
- if (priv->selected_test > 0) {
- --priv->selected_test;
- } else {
- priv->selected_test = priv->plan->num_tests - 1;
- }
-
- summ_test_print_menu(priv);
- }
-
- if (wpad_buttons & WPAD_BUTTON_RIGHT || pad_buttons & PAD_BUTTON_RIGHT) {
- if (priv->selected_test < priv->plan->num_tests - 1) {
- ++priv->selected_test;
- } else {
- priv->selected_test = 0;
- }
-
- summ_test_print_menu(priv);
- }
-
- if (wpad_buttons & WPAD_BUTTON_1 || pad_buttons & PAD_BUTTON_X) {
- struct et_test_plan_entry *entry = priv->plan->tests + priv->selected_test;
- printf("\nExtended status for %s:\n", entry->test->name);
- if (entry->ext_status) {
- puts(entry->ext_status);
- } else {
- puts("(no status)");
- }
-
- for (int i = 0; i < SUMM_MENU_ROWS + 1; ++i) putchar('\n');
- summ_test_print_menu(priv);
- }
-
- return 0;
-}
-
-static void summ_test_plan_cleanup(const struct et_state *state, void *state_data) {
- struct summ_test_plan_private *priv = state_data;
- struct et_test_plan *ptest_plan = priv->plan;
-
- for (size_t i = 0; i < ptest_plan->num_tests; ++i) {
- et_test_plan_entry_cleanup(ptest_plan->tests + i);
- }
-
- free(ptest_plan->tests);
- free(ptest_plan);
-}
-
-static const struct et_state summ_test_plan_struct = {
- .private_size = sizeof(struct summ_test_plan_private),
- .init_f = summ_test_plan_init,
- .tick_f = summ_test_plan_tick,
- .cleanup_f = summ_test_plan_cleanup
-};
-
-const struct et_state *et_state_summarize_test_plan = &summ_test_plan_struct;
-
-#define COUNT_TESTS(_x) 1
-#define NUM_TESTS FOREACH_TEST(COUNT_TESTS, +)
-static const struct et_test *all_tests[NUM_TESTS + 1];
-static bool tests_array_initialized = false;
-
-const struct et_test *const *et_get_tests(size_t *ntests) {
- size_t idx = 0;
-
- if (ntests) *ntests = NUM_TESTS;
- if (tests_array_initialized) return all_tests;
-
-#define A(_name) all_tests[idx++] = TEST_SYM(_name)
- FOREACH_TEST(A, ;);
-#undef A
-
- all_tests[idx] = NULL;
-
- tests_array_initialized = true;
- return all_tests;
-}
-
-static const char *error_oom = "(failed to allocate error message)";
-static const char *error_bad_fmt = "(bad extended error format)";
-
-void et_test_plan_entry_cleanup(struct et_test_plan_entry *entry) {
- if (entry->ext_status_free) {
- /* okay to cast away const here. we're careful about making sure this pointer is non-NULL iff this pointer
- * was malloc'd */
- entry->ext_status_free((void *)entry->ext_status);
- }
-
- entry->ext_status = NULL;
- entry->ext_status_free = NULL;
-}
-
-void test_plan_entry_set_error(struct et_test_plan_entry *entry, const char *fmt, ...) {
- int res;
- va_list vp;
- char *dest;
- size_t dest_sz;
-
- et_test_plan_entry_cleanup(entry);
-
- va_start(vp, fmt);
- res = vsnprintf(NULL, 0, fmt, vp);
- va_end(vp);
-
- if (res < 0) {
- entry->ext_status = error_bad_fmt;
- entry->ext_status_free = NULL;
- return;
- }
-
- dest_sz = MIN((size_t)res + 1, (size_t)1024);
- dest = malloc(dest_sz);
- dest[0] = '\0';
-
- if (!dest) {
- entry->ext_status = error_oom;
- entry->ext_status_free = NULL;
- return;
- }
-
- va_start(vp, fmt);
- res = vsnprintf(dest, dest_sz, fmt, vp);
- va_end(vp);
-
- dest[dest_sz - 1] = '\0';
-
- assert(res >= 0);
-
- entry->ext_status = dest;
- entry->ext_status_free = free;
-}
-
-void test_plan_entry_set_error_static(struct et_test_plan_entry *entry, const char *str) {
- et_test_plan_entry_cleanup(entry);
- entry->ext_status = str;
- entry->ext_status_free = NULL;
-}
-
-const char *et_test_get_status_mnemonic(et_test_status status) {
- switch (TEST_STATUS_GET_TYPE(status)) {
- case TEST_SPASS: return "PASS";
- case TEST_SFAIL: return "FAIL";
- case TEST_SSKIPPED:
- if (TEST_STATUS_IS_CLEAN(status)) {
- return "SKI!";
- } else {
- return "SKIP";
- }
- case TEST_SERROR:
- switch (TEST_STATUS_GET_ERROR(status)) {
- case TEST_ENONE: return "ERR0";
- case TEST_EABORT: return "ERRA";
- default: return "ERRP";
- }
- default:
- return "UNKS";
- }
-}
-
-et_test_status test_exi_readwrite(struct et_test_plan *plan, void *data, size_t data_sz, et_test_error base) {
- struct et_test_plan_entry *cur = test_current(plan);
- int chan = plan->exi_channel;
- et_test_status status = TEST_PASS;
- s32 exi_res;
-
- if ((exi_res = EXI_Lock(chan, EXI_DEVICE_0, NULL)) <= 0) {
- status = TEST_ERROR(base);
- test_plan_entry_set_error(cur, "failed to lock EXI channel: %" PRId32, exi_res);
- goto fail_lock;
- }
-
- if ((exi_res = EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED32MHZ)) <= 0) {
- status = TEST_ERROR(base + 1);
- test_plan_entry_set_error(cur, "failed to select EXI channel: %" PRId32, exi_res);
- goto fail_select;
- }
-
- if ((exi_res = EXI_Imm(chan, data, data_sz, EXI_READWRITE, NULL)) <= 0) {
- status = TEST_ERROR(base + 2);
- test_plan_entry_set_error(cur, "failed to send EXI data: %" PRId32, exi_res);
- goto fail_data;
- }
-
- if ((exi_res = EXI_Sync(chan)) <= 0) {
- status = TEST_ERROR(base + 3);
- test_plan_entry_set_error(cur, "failed to complete transfer: %" PRId32, exi_res);
- goto fail_data;
- }
-
-fail_data:
- EXI_Deselect(chan);
-
-fail_select:
- EXI_Unlock(chan);
-
-fail_lock:
- return status;
-}