Files

239 lines
8.1 KiB
C

/*
* Pruebas sin pantalla de la lógica de entrada: máquina de estados de
* teclado/ratón, cola de eventos y consultas públicas. Usa cabeceras internas.
*/
#include "check.h"
#include <fnix/fnix.h>
#include "core/window_internal.h"
#include "input/input_internal.h"
#include <string.h>
static FnixEvent key_event(FnixEventType type, FnixKey key)
{
FnixEvent e;
memset(&e, 0, sizeof e);
e.type = type;
e.key = key;
return e;
}
static FnixEvent mouse_event(FnixEventType type, FnixMouseButton button, int x, int y)
{
FnixEvent e;
memset(&e, 0, sizeof e);
e.type = type;
e.button = button;
e.x = x;
e.y = y;
return e;
}
static void test_key_lifecycle(void)
{
FnixInputState s;
memset(&s, 0, sizeof s);
FnixEvent down = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_A);
fnix_input_apply_event(&s, &down);
CHECK(s.key_down[FNIX_KEY_A] && s.key_pressed[FNIX_KEY_A]);
CHECK(!down.repeat);
/* Autorepeat: el sistema repite KEY_DOWN sin KEY_UP. */
FnixEvent again = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_A);
fnix_input_apply_event(&s, &again);
CHECK(again.repeat);
CHECK(s.key_down[FNIX_KEY_A]);
fnix_input_begin_frame(&s);
CHECK(s.key_down[FNIX_KEY_A]);
CHECK(!s.key_pressed[FNIX_KEY_A]);
/* Una repetición en un fotograma posterior tampoco vuelve a "pressed". */
FnixEvent repeat2 = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_A);
fnix_input_apply_event(&s, &repeat2);
CHECK(!s.key_pressed[FNIX_KEY_A]);
FnixEvent up = key_event(FNIX_EVENT_KEY_UP, FNIX_KEY_A);
fnix_input_apply_event(&s, &up);
CHECK(!s.key_down[FNIX_KEY_A] && s.key_released[FNIX_KEY_A]);
fnix_input_begin_frame(&s);
CHECK(!s.key_released[FNIX_KEY_A]);
/* Pulsar y soltar dentro del mismo fotograma no se pierde. */
FnixEvent quick_down = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_B);
FnixEvent quick_up = key_event(FNIX_EVENT_KEY_UP, FNIX_KEY_B);
fnix_input_apply_event(&s, &quick_down);
fnix_input_apply_event(&s, &quick_up);
CHECK(s.key_pressed[FNIX_KEY_B] && s.key_released[FNIX_KEY_B]);
CHECK(!s.key_down[FNIX_KEY_B]);
/* Soltar una tecla que no estaba pulsada no genera "released". */
FnixEvent stray_up = key_event(FNIX_EVENT_KEY_UP, FNIX_KEY_C);
fnix_input_apply_event(&s, &stray_up);
CHECK(!s.key_released[FNIX_KEY_C]);
/* Teclas inválidas se ignoran sin escribir fuera del arreglo. */
FnixEvent bad1 = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_UNKNOWN);
FnixEvent bad2 = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_COUNT);
FnixEvent bad3 = key_event(FNIX_EVENT_KEY_DOWN, (FnixKey)-5);
fnix_input_apply_event(&s, &bad1);
fnix_input_apply_event(&s, &bad2);
fnix_input_apply_event(&s, &bad3);
}
static void test_mouse(void)
{
FnixInputState s;
memset(&s, 0, sizeof s);
FnixEvent move = mouse_event(FNIX_EVENT_MOUSE_MOVE, FNIX_MOUSE_LEFT, 12, 34);
fnix_input_apply_event(&s, &move);
CHECK(s.mouse_x == 12 && s.mouse_y == 34);
FnixEvent down = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, FNIX_MOUSE_RIGHT, 50, 60);
fnix_input_apply_event(&s, &down);
CHECK(s.mouse_down[FNIX_MOUSE_RIGHT] && s.mouse_pressed[FNIX_MOUSE_RIGHT]);
CHECK(!s.mouse_down[FNIX_MOUSE_LEFT]);
CHECK(s.mouse_x == 50 && s.mouse_y == 60);
fnix_input_begin_frame(&s);
CHECK(s.mouse_down[FNIX_MOUSE_RIGHT] && !s.mouse_pressed[FNIX_MOUSE_RIGHT]);
FnixEvent up = mouse_event(FNIX_EVENT_MOUSE_BUTTON_UP, FNIX_MOUSE_RIGHT, 51, 61);
fnix_input_apply_event(&s, &up);
CHECK(!s.mouse_down[FNIX_MOUSE_RIGHT] && s.mouse_released[FNIX_MOUSE_RIGHT]);
/* Rueda: se acumula dentro del fotograma y se borra al empezar el siguiente. */
fnix_input_begin_frame(&s);
FnixEvent w1 = mouse_event(FNIX_EVENT_MOUSE_WHEEL, FNIX_MOUSE_LEFT, 0, 0);
FnixEvent w2 = w1;
FnixEvent w3 = w1;
w1.wheel = 1;
w2.wheel = 1;
w3.wheel = -1;
fnix_input_apply_event(&s, &w1);
fnix_input_apply_event(&s, &w2);
fnix_input_apply_event(&s, &w3);
CHECK(s.wheel == 1);
fnix_input_begin_frame(&s);
CHECK(s.wheel == 0);
/* Botón inválido: no escribe fuera del arreglo. */
FnixEvent bad = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, (FnixMouseButton)99, 0, 0);
fnix_input_apply_event(&s, &bad);
}
static void test_focus_lost(void)
{
FnixInputState s;
memset(&s, 0, sizeof s);
FnixEvent k = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_W);
FnixEvent m = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, FNIX_MOUSE_LEFT, 1, 1);
fnix_input_apply_event(&s, &k);
fnix_input_apply_event(&s, &m);
fnix_input_begin_frame(&s);
CHECK(s.key_down[FNIX_KEY_W] && s.mouse_down[FNIX_MOUSE_LEFT]);
FnixEvent lost;
memset(&lost, 0, sizeof lost);
lost.type = FNIX_EVENT_FOCUS_LOST;
fnix_input_apply_event(&s, &lost);
CHECK(!s.key_down[FNIX_KEY_W] && s.key_released[FNIX_KEY_W]);
CHECK(!s.mouse_down[FNIX_MOUSE_LEFT] && s.mouse_released[FNIX_MOUSE_LEFT]);
}
static void test_event_queue(void)
{
static FnixEventQueue q; /* es grande: fuera de la pila */
memset(&q, 0, sizeof q);
FnixEvent out;
CHECK(!fnix_event_queue_pop(&q, &out));
for (int i = 0; i < 5; i++) {
FnixEvent e = mouse_event(FNIX_EVENT_MOUSE_MOVE, FNIX_MOUSE_LEFT, i, 0);
fnix_event_queue_push(&q, &e);
}
for (int i = 0; i < 5; i++) {
CHECK(fnix_event_queue_pop(&q, &out) && out.x == i);
}
CHECK(!fnix_event_queue_pop(&q, &out));
/* Desbordamiento: se conservan los FNIX_EVENT_QUEUE_CAPACITY más recientes. */
const int total = FNIX_EVENT_QUEUE_CAPACITY + 44;
for (int i = 0; i < total; i++) {
FnixEvent e = mouse_event(FNIX_EVENT_MOUSE_MOVE, FNIX_MOUSE_LEFT, i, 0);
fnix_event_queue_push(&q, &e);
}
CHECK(q.count == FNIX_EVENT_QUEUE_CAPACITY);
for (int i = total - FNIX_EVENT_QUEUE_CAPACITY; i < total; i++) {
CHECK(fnix_event_queue_pop(&q, &out) && out.x == i);
}
CHECK(!fnix_event_queue_pop(&q, &out));
}
static void test_public_queries(void)
{
/* Una ventana "falsa" (sin plataforma) basta para probar la API pública. */
static FnixWindow w;
memset(&w, 0, sizeof w);
FnixEvent down = key_event(FNIX_EVENT_KEY_DOWN, FNIX_KEY_SPACE);
fnix_window_dispatch_event(&w, &down);
CHECK(fnix_key_down(&w, FNIX_KEY_SPACE));
CHECK(fnix_key_pressed(&w, FNIX_KEY_SPACE));
CHECK(!fnix_key_released(&w, FNIX_KEY_SPACE));
CHECK(!fnix_key_down(&w, FNIX_KEY_A));
FnixEvent click = mouse_event(FNIX_EVENT_MOUSE_BUTTON_DOWN, FNIX_MOUSE_MIDDLE, 7, 9);
fnix_window_dispatch_event(&w, &click);
CHECK(fnix_mouse_down(&w, FNIX_MOUSE_MIDDLE));
CHECK(fnix_mouse_pressed(&w, FNIX_MOUSE_MIDDLE));
CHECK(fnix_mouse_x(&w) == 7 && fnix_mouse_y(&w) == 9);
/* Los eventos quedaron en la cola, en orden. */
FnixEvent e;
CHECK(fnix_window_poll_event(&w, &e) && e.type == FNIX_EVENT_KEY_DOWN &&
e.key == FNIX_KEY_SPACE);
CHECK(fnix_window_poll_event(&w, &e) && e.type == FNIX_EVENT_MOUSE_BUTTON_DOWN);
CHECK(!fnix_window_poll_event(&w, &e));
CHECK(!fnix_window_poll_event(&w, NULL));
/* El cierre marca la ventana. */
CHECK(!fnix_window_should_close(&w));
FnixEvent close_event;
memset(&close_event, 0, sizeof close_event);
close_event.type = FNIX_EVENT_WINDOW_CLOSE;
fnix_window_dispatch_event(&w, &close_event);
CHECK(fnix_window_should_close(&w));
/* Argumentos inválidos: nunca fallan, devuelven falso/0. */
CHECK(!fnix_key_down(NULL, FNIX_KEY_A));
CHECK(!fnix_key_pressed(NULL, FNIX_KEY_A));
CHECK(!fnix_key_released(NULL, FNIX_KEY_A));
CHECK(!fnix_key_down(&w, FNIX_KEY_UNKNOWN));
CHECK(!fnix_key_down(&w, FNIX_KEY_COUNT));
CHECK(!fnix_key_down(&w, (FnixKey)-1));
CHECK(!fnix_mouse_down(NULL, FNIX_MOUSE_LEFT));
CHECK(!fnix_mouse_down(&w, FNIX_MOUSE_BUTTON_COUNT));
CHECK(!fnix_mouse_pressed(&w, (FnixMouseButton)-1));
CHECK(!fnix_mouse_released(NULL, FNIX_MOUSE_LEFT));
CHECK(fnix_mouse_x(NULL) == 0 && fnix_mouse_y(NULL) == 0);
CHECK(fnix_mouse_wheel(NULL) == 0);
}
int main(void)
{
test_key_lifecycle();
test_mouse();
test_focus_lost();
test_event_queue();
test_public_queries();
return CHECK_REPORT("test_input");
}