java-topology/defects/hatari-0001/test/test_hatari_0001.c

199 lines
7 KiB
C

/*
* test_hatari_0001.c
*
* Unit test for hatari-0001: IKBD_RunKeyboardCommand O(C) linear scan
* replaced with O(1) dispatch table.
*
* Tests that the dispatch table correctly maps all known command bytes
* and returns -1 for unknown bytes, verifying O(1) correctness.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
/* Minimal reproduction of the KeyboardCommands table and dispatch logic. */
typedef struct {
uint8_t Command;
uint8_t NumParameters;
void (*pCallFunction)(void);
} KeyboardCommand;
/* Representative subset of IKBD commands from Hatari's ikbd.c */
static const KeyboardCommand KeyboardCommands[] = {
{ 0x80, 2, NULL }, /* Reset */
{ 0x07, 2, NULL }, /* MouseAction */
{ 0x08, 1, NULL }, /* RelMouseMode */
{ 0x09, 5, NULL }, /* AbsMouseMode */
{ 0x0A, 3, NULL }, /* MouseCursorKeycodes */
{ 0x0B, 3, NULL }, /* SetMouseThreshold */
{ 0x0C, 3, NULL }, /* SetMouseScale */
{ 0x0D, 1, NULL }, /* ReadAbsMousePos */
{ 0x0E, 6, NULL }, /* SetInternalMousePos */
{ 0x0F, 1, NULL }, /* SetYAxisDown */
{ 0x10, 1, NULL }, /* SetYAxisUp */
{ 0x11, 1, NULL }, /* StartKeyboardTransfer */
{ 0x12, 1, NULL }, /* TurnMouseOff */
{ 0x13, 1, NULL }, /* StopKeyboardTransfer */
{ 0x14, 1, NULL }, /* ReturnJoystickAuto */
{ 0x15, 1, NULL }, /* StopJoystick */
{ 0x16, 1, NULL }, /* ReturnJoystick */
{ 0x17, 2, NULL }, /* SetJoystickMonitoring */
{ 0x18, 1, NULL }, /* SetJoystickFireDuration */
{ 0x19, 7, NULL }, /* SetCursorForJoystick */
{ 0x1A, 1, NULL }, /* DisableJoysticks */
{ 0x1B, 7, NULL }, /* SetClock */
{ 0x1C, 1, NULL }, /* ReadClock */
{ 0x20, 4, NULL }, /* LoadMemory */
{ 0x21, 3, NULL }, /* ReadMemory */
{ 0x22, 3, NULL }, /* Execute */
/* Report messages */
{ 0x87, 1, NULL }, /* ReportMouseAction */
{ 0x88, 1, NULL }, /* ReportMouseMode */
{ 0x89, 1, NULL }, /* ReportMouseMode */
{ 0x8A, 1, NULL }, /* ReportMouseMode */
{ 0x8B, 1, NULL }, /* ReportMouseThreshold */
{ 0x8C, 1, NULL }, /* ReportMouseScale */
{ 0x8F, 1, NULL }, /* ReportMouseVertical */
{ 0x90, 1, NULL }, /* ReportMouseVertical */
{ 0x92, 1, NULL }, /* ReportMouseAvailability */
{ 0x94, 1, NULL }, /* ReportJoystickMode */
{ 0x95, 1, NULL }, /* ReportJoystickMode */
{ 0x99, 1, NULL }, /* ReportJoystickMode */
{ 0x9A, 1, NULL }, /* ReportJoystickAvailability */
{ 0xFF, 0, NULL } /* Terminator */
};
/* O(C) original: linear scan */
static int ikbd_find_command_linear(uint8_t cmd)
{
int i = 0;
while (KeyboardCommands[i].Command != 0xFF) {
if (KeyboardCommands[i].Command == cmd)
return i;
i++;
}
return -1;
}
/* O(1) patched: dispatch table */
static int IKBDCmdIndex[256];
static void ikbd_init_dispatch(void)
{
int i;
for (i = 0; i < 256; i++)
IKBDCmdIndex[i] = -1;
for (i = 0; KeyboardCommands[i].Command != 0xFF; i++)
IKBDCmdIndex[KeyboardCommands[i].Command] = i;
}
static int ikbd_find_command_dispatch(uint8_t cmd)
{
return IKBDCmdIndex[cmd];
}
/* Count iterations in linear scan for given command byte */
static int ikbd_linear_iterations(uint8_t cmd)
{
int i = 0, count = 0;
while (KeyboardCommands[i].Command != 0xFF) {
count++;
if (KeyboardCommands[i].Command == cmd)
return count;
i++;
}
return count; /* not found, scanned all */
}
int main(void)
{
int i, linear_idx, dispatch_idx;
int total_tests = 0, pass = 0;
int max_linear_iter = 0, total_linear_iter = 0;
ikbd_init_dispatch();
/* Test 1: dispatch table matches linear scan for all 256 byte values */
printf("Test 1: dispatch table correctness for all 256 command bytes\n");
for (i = 0; i < 256; i++) {
linear_idx = ikbd_find_command_linear((uint8_t)i);
dispatch_idx = ikbd_find_command_dispatch((uint8_t)i);
total_tests++;
if (linear_idx == dispatch_idx) {
pass++;
} else {
printf(" FAIL byte=0x%02x linear=%d dispatch=%d\n", i, linear_idx, dispatch_idx);
}
}
printf(" %d/%d passed\n", pass, total_tests);
assert(pass == total_tests);
/* Test 2: O(1) vs O(C) -- dispatch always 1 step, linear varies */
printf("Test 2: iteration count reduction\n");
{
/* Known commands: reset (first entry scanned), 0x9A (last entry scanned) */
int iter_first = ikbd_linear_iterations(0x80); /* 0x80 is first */
int iter_last = ikbd_linear_iterations(0x9A); /* 0x9A is near last */
int iter_unknown = ikbd_linear_iterations(0x01); /* unknown -- scans all */
/* Count total commands (excluding terminator) */
int num_cmds = 0;
while (KeyboardCommands[num_cmds].Command != 0xFF) num_cmds++;
printf(" first-cmd iterations: %d (linear) vs 1 (dispatch)\n", iter_first);
printf(" last-cmd iterations: %d (linear) vs 1 (dispatch)\n", iter_last);
printf(" unknown-cmd iterations: %d (linear) vs 1 (dispatch)\n", iter_unknown);
printf(" total commands in table: %d\n", num_cmds);
assert(iter_first >= 1);
assert(iter_last > iter_first); /* later entries cost more in linear */
assert(iter_unknown >= num_cmds); /* unknown scans everything */
/* dispatch is O(1): always 1 table lookup regardless */
total_linear_iter += iter_first + iter_last + iter_unknown;
max_linear_iter = iter_unknown;
printf(" PASS: dispatch eliminates up to %dx overhead vs worst-case linear\n",
max_linear_iter);
}
/* Test 3: NumParameters preserved correctly */
printf("Test 3: NumParameters preserved in dispatch table\n");
{
int idx;
/* 0x09 AbsMouseMode expects 5 parameters */
idx = ikbd_find_command_dispatch(0x09);
assert(idx >= 0);
assert(KeyboardCommands[idx].NumParameters == 5);
/* 0x19 SetCursorForJoystick expects 7 parameters */
idx = ikbd_find_command_dispatch(0x19);
assert(idx >= 0);
assert(KeyboardCommands[idx].NumParameters == 7);
/* 0x08 RelMouseMode expects 1 parameter */
idx = ikbd_find_command_dispatch(0x08);
assert(idx >= 0);
assert(KeyboardCommands[idx].NumParameters == 1);
printf(" PASS: NumParameters correct for 0x09 (5), 0x19 (7), 0x08 (1)\n");
}
/* Test 4: unknown commands return -1 */
printf("Test 4: unknown command bytes return -1\n");
{
/* 0x01, 0x02, 0x03 are not in the IKBD command set */
assert(ikbd_find_command_dispatch(0x01) == -1);
assert(ikbd_find_command_dispatch(0x02) == -1);
assert(ikbd_find_command_dispatch(0x03) == -1);
assert(ikbd_find_command_dispatch(0x00) == -1);
printf(" PASS: 0x00, 0x01, 0x02, 0x03 all return -1\n");
}
printf("\nAll tests passed. O(1) dispatch table eliminates O(%d) linear scan.\n",
max_linear_iter);
return 0;
}