diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-12 22:12:02 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-12 22:12:02 +0300 |
| commit | 94c5e361fbb229b0cd6853e2102a7d95f1f358b3 (patch) | |
| tree | 3c0f11af9dcb84dac8067a31a6979acd6dd56fbf /tests/common | |
| parent | 08dc9047098d6d96791024ac7d8f5837633673ef (diff) | |
better public interface and doxygen
Diffstat (limited to 'tests/common')
| -rw-r--r-- | tests/common/test_backends.c | 90 | ||||
| -rw-r--r-- | tests/common/test_contracts.c | 92 | ||||
| -rw-r--r-- | tests/common/test_keyboard.c | 32 | ||||
| -rw-r--r-- | tests/common/test_utf8.c | 27 |
4 files changed, 237 insertions, 4 deletions
diff --git a/tests/common/test_backends.c b/tests/common/test_backends.c index 4c99646..cf5b1f9 100644 --- a/tests/common/test_backends.c +++ b/tests/common/test_backends.c @@ -194,23 +194,105 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct yasl_display_copy(d, YASL_CLIPBOARD, "clipboard text"); yasl_display_paste(d, YASL_CLIPBOARD, w->surface); pump(loop, d, NULL); - bool saw_key = false, saw_paste = false; + bool saw_key = false, saw_paste = false, saw_text = false; struct yasl_input_event event; while (yasl_surface_input_poll(w->surface, &event)) { assert(event.surface == w->surface); if (event.kind == YASL_INPUT_KEY) { assert(event.key.codepoint == 'a'); assert(event.key.shifted == 'A'); - assert(event.key.base == 30); - saw_key = event.key.key == XK_a; + assert(event.key.native_code == key.xkey.keycode); + saw_key = event.key.key == YASL_KEY_A; } if (event.kind == YASL_INPUT_PASTE) { assert(event.paste.len == strlen("clipboard text")); assert(memcmp(event.paste.text, "clipboard text", event.paste.len) == 0); saw_paste = true; } + if (event.kind == YASL_INPUT_TEXT) { + assert(event.text.len == 1 && event.text.text[0] == 'a'); + saw_text = true; + } + } + assert(saw_key && saw_paste && saw_text); + /* Physical identity survives modifier and layout changes, including a + * release whose modifiers differ from its press. */ + key.xkey.state = ShiftMask; + XSendEvent(native, window, False, KeyPressMask, &key); + key.xkey.type = KeyRelease; + key.xkey.state = 0; + XSendEvent(native, window, False, KeyReleaseMask, &key); + XFlush(native); + pump(loop, d, NULL); + int key_count = 0, text_count = 0; + while (yasl_surface_input_poll(w->surface, &event)) { + if (event.kind == YASL_INPUT_KEY) { + assert(event.key.key == YASL_KEY_A); + assert(event.key.action == (key_count ? YASL_KEY_RELEASE : YASL_KEY_PRESS)); + key_count++; + } else if (event.kind == YASL_INPUT_TEXT) { + assert(event.text.len == 1 && event.text.text[0] == 'A'); + text_count++; + } + } + assert(key_count == 2 && text_count == 1); + key.xkey.type = KeyPress; + key.xkey.state = ControlMask; + XSendEvent(native, window, False, KeyPressMask, &key); + XFlush(native); + pump(loop, d, NULL); + assert(yasl_surface_input_poll(w->surface, &event)); + assert(event.kind == YASL_INPUT_KEY && event.key.key == YASL_KEY_A); + assert(event.key.mods & YASL_MOD_CTRL); + assert(!yasl_surface_input_poll(w->surface, &event)); + + int symbols_per_key = 0; + KeySym *saved_symbols = XGetKeyboardMapping(native, key.xkey.keycode, 1, &symbols_per_key); + assert(saved_symbols && symbols_per_key >= 2); + KeySym *changed_symbols = calloc((size_t)symbols_per_key, sizeof(KeySym)); + assert(changed_symbols); + changed_symbols[0] = XK_q; + changed_symbols[1] = XK_Q; + XChangeKeyboardMapping(native, key.xkey.keycode, symbols_per_key, changed_symbols, 1); + XSync(native, False); + pump(loop, d, NULL); /* Consume MappingNotify before translating the key. */ + key.xkey.state = 0; + XSendEvent(native, window, False, KeyPressMask, &key); + XFlush(native); + pump(loop, d, NULL); + saw_key = saw_text = false; + while (yasl_surface_input_poll(w->surface, &event)) { + if (event.kind == YASL_INPUT_KEY) { + assert(event.key.key == YASL_KEY_A && event.key.codepoint == 'q'); + saw_key = true; + } else if (event.kind == YASL_INPUT_TEXT) { + assert(event.text.len == 1 && event.text.text[0] == 'q'); + saw_text = true; + } + } + assert(saw_key && saw_text); + XChangeKeyboardMapping(native, key.xkey.keycode, symbols_per_key, saved_symbols, 1); + free(changed_symbols); + XFree(saved_symbols); + XSync(native, False); + pump(loop, d, NULL); + + for (unsigned button = 4; button <= 7; button++) { + XEvent wheel = {.xbutton = {.type = ButtonPress, .display = native, + .window = window, .root = DefaultRootWindow(native), + .same_screen = True, .button = button}}; + /* Direct delivery exercises the core fallback even with XI2 enabled. */ + XSendEvent(native, window, False, NoEventMask, &wheel); + wheel.xbutton.type = ButtonRelease; + XSendEvent(native, window, False, NoEventMask, &wheel); + XFlush(native); + pump(loop, d, NULL); + assert(yasl_surface_input_poll(w->surface, &event)); + assert(event.kind == YASL_INPUT_MOUSE && event.mouse.kind == YASL_PTR_SCROLL); + assert(event.mouse.scroll.x == (button == 6 ? -1 : button == 7 ? 1 : 0)); + assert(event.mouse.scroll.y == (button == 4 ? -1 : button == 5 ? 1 : 0)); + assert(!yasl_surface_input_poll(w->surface, &event)); } - assert(saw_key && saw_paste); assert(yasl_surface_timing(w->surface).source == YASL_TIMING_SUBMISSION); assert(!(yasl_display_caps(d) & YASL_CAP_FRAME_PACING)); diff --git a/tests/common/test_contracts.c b/tests/common/test_contracts.c index 4e22de1..8580dd6 100644 --- a/tests/common/test_contracts.c +++ b/tests/common/test_contracts.c @@ -232,6 +232,97 @@ static void test_scale(void) assert(yasl_scale_to_logical(1, 0) == 0); } +static int popup_calls; +static struct yasl_surface *popup_create(struct yasl_surface *parent, + const struct yasl_popup_spec *spec) +{ + (void)parent; (void)spec; + popup_calls++; + return NULL; /* Backend fails without setting errno. */ +} + +static bool popup_reposition(struct yasl_surface *popup, + const struct yasl_popup_spec *spec) +{ + (void)popup; (void)spec; + popup_calls++; + errno = EBUSY; + return false; +} + +static uint32_t popup_caps(const struct yasl_display *d) +{ (void)d; return YASL_CAP_POPUPS; } + +static int dispatch_failure(struct yasl_display *d, int timeout) +{ (void)d; (void)timeout; return -1; } + +static struct yasl_surface *create_failure(struct yasl_display *d, + const struct yasl_surface_spec *spec, void *device) +{ (void)d; (void)spec; (void)device; return NULL; } + +static int drag_starts; +static bool drag_without_listener(struct yasl_display *d, struct yasl_surface *s, + const struct yasl_drag_image *image, const struct yasl_drag_listener *listener, + void *ud) +{ + (void)d; (void)s; (void)image; (void)ud; + /* Backends may require a table even when no completion callback is needed. */ + assert(listener && !listener->end); + drag_starts++; + return true; +} + +static void test_errors(void) +{ + const struct yasl_backend_ops ops = {.display_caps = popup_caps, + .surface_create_toplevel = create_failure, + .surface_create_popup = popup_create, + .surface_popup_reposition = popup_reposition, + .display_drag_start = drag_without_listener, + .display_dispatch_timeout = dispatch_failure}; + struct yasl_display d = {.ops = &ops}; + struct yasl_surface s = {.display = &d}; + struct yasl_popup_spec spec = {.size = {120, 80}, .anchor = {0, 0, 1, 1}}; + assert(!yasl_surface_create_popup(NULL, &spec) && errno == EINVAL); + assert(!yasl_surface_create_popup(&s, NULL) && errno == EINVAL); + spec.anchor.width = -1; /* Must not reach Wayland's protocol marshaler. */ + assert(!yasl_surface_create_popup(&s, &spec) && errno == EINVAL); + assert(!yasl_surface_popup_reposition(&s, &spec) && errno == EINVAL); + spec.anchor.width = 1; + spec.content_offset.x = INT_MAX; + spec.content_size.x = INT_MAX; + assert(!yasl_surface_create_popup(&s, &spec) && errno == EINVAL); + spec.content_offset.x = spec.content_size.x = 0; + spec.size.x = 32768; + assert(!yasl_surface_create_popup(&s, &spec) && errno == EINVAL); + assert(!popup_calls); + spec.size.x = 120; + errno = ERANGE; + assert(!yasl_surface_create_popup(&s, &spec) && errno == ENODEV); + assert(!yasl_surface_popup_reposition(&s, &spec) && errno == EBUSY); + assert(popup_calls == 2); + const struct yasl_backend_ops unsupported = {0}; + d.ops = &unsupported; + assert(!yasl_surface_create_popup(&s, &spec) && errno == ENOTSUP); + assert(!yasl_surface_popup_reposition(&s, &spec) && errno == ENOTSUP); + assert(yasl_display_dispatch(&d, 0) == -1 && errno == ENOTSUP); + assert(yasl_display_dispatch(NULL, 0) == -1 && errno == EINVAL); + d.ops = &ops; + errno = ERANGE; + assert(yasl_display_dispatch(&d, 0) == -1 && errno == EIO); + struct yasl_surface_spec toplevel = {.size = {120, 80}}; + errno = ERANGE; + assert(!yasl_surface_create_toplevel(&d, &toplevel) && errno == ENODEV); + assert(yasl_display_drag_start(&d, &s, NULL, NULL, NULL)); + struct yasl_drag_image image = {.size = {1, 1}}; + assert(!yasl_display_drag_start(&d, &s, &image, NULL, NULL)); + uint32_t pixel = 0; + image.pixels = &pixel; + image.size.x = INT_MAX; + assert(!yasl_display_drag_start(&d, &s, &image, NULL, NULL)); + assert(drag_starts == 1); +} + int main(void) { test_timing_clock(); @@ -239,5 +330,6 @@ int main(void) test_validation(); test_native(); test_scale(); + test_errors(); return 0; } diff --git a/tests/common/test_keyboard.c b/tests/common/test_keyboard.c new file mode 100644 index 0000000..5a7f18e --- /dev/null +++ b/tests/common/test_keyboard.c @@ -0,0 +1,32 @@ +#include "common/keyboard.h" +#include "cocoa/keycodes.h" +#include <assert.h> + +int main(void) +{ + /* Same physical positions across native encodings, including keypad and + * left/right modifiers. macOS A is code zero, which is not UNKNOWN. */ + assert(yasl_key_from_evdev(30) == YASL_KEY_A); + assert(yasl_key_from_cocoa(kVK_ANSI_A) == YASL_KEY_A); + assert(yasl_key_from_xkb_name("AC01") == YASL_KEY_A); + assert(yasl_key_from_evdev(1) == YASL_KEY_ESCAPE); + assert(yasl_key_from_cocoa(kVK_Escape) == YASL_KEY_ESCAPE); + assert(yasl_key_from_xkb_name("ESC\0") == YASL_KEY_ESCAPE); + assert(yasl_key_from_evdev(96) == YASL_KEY_KP_ENTER); + assert(yasl_key_from_cocoa(kVK_ANSI_KeypadEnter) == YASL_KEY_KP_ENTER); + assert(yasl_key_from_cocoa(kVK_Return) == YASL_KEY_ENTER); + assert(yasl_key_from_evdev(100) == YASL_KEY_RIGHT_ALT); + assert(yasl_key_from_cocoa(kVK_RightOption) == YASL_KEY_RIGHT_ALT); + assert(yasl_key_from_evdev(42) == YASL_KEY_LEFT_SHIFT); + assert(yasl_key_from_cocoa(kVK_Shift) == YASL_KEY_LEFT_SHIFT); + assert(yasl_key_from_evdev(86) == YASL_KEY_ISO_BACKSLASH); + assert(yasl_key_from_cocoa(kVK_ISO_Section) == YASL_KEY_ISO_BACKSLASH); + assert(yasl_key_from_evdev(0) == YASL_KEY_UNKNOWN); + assert(yasl_key_from_evdev(UINT32_MAX) == YASL_KEY_UNKNOWN); + assert(yasl_key_from_cocoa(UINT32_MAX) == YASL_KEY_UNKNOWN); + assert(yasl_key_from_xkb_name("ZZZZ") == YASL_KEY_UNKNOWN); + assert(yasl_key_label(0x1f600) == 0x1f600); + assert(yasl_key_label(0xd800) == 0 && yasl_key_label(0x110000) == 0); + assert(yasl_key_label(0xf700) == 0 && yasl_key_label('\t') == 0); + return 0; +} diff --git a/tests/common/test_utf8.c b/tests/common/test_utf8.c new file mode 100644 index 0000000..72f8904 --- /dev/null +++ b/tests/common/test_utf8.c @@ -0,0 +1,27 @@ +#include "common/utf8.h" +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +int main(void) +{ + char latin1[256]; + for (int i = 1; i <= 255; i++) latin1[i - 1] = (char)i; + latin1[255] = '\0'; + size_t len = 0, back_len = 0; + char *utf8 = yasl_utf8_from_latin1(latin1, 255, &len); + assert(utf8 && yasl_utf8_validate(utf8, len)); + char *back = yasl_utf8_to_latin1(utf8, &back_len); + assert(back && back_len == 255 && memcmp(back, latin1, 256) == 0); + free(back); + free(utf8); + assert(!yasl_utf8_to_latin1("😀", &len)); + assert(!yasl_utf8_to_latin1("\xc3", &len)); + assert(!yasl_utf8_validate("\xc3", 1)); + assert(!yasl_utf8_validate("\xe2\x82", 2)); + assert(!yasl_utf8_validate("\xf0\x9f\x98", 3)); + assert(!yasl_utf8_validate("\xed\xa0\x80", 3)); /* Surrogate. */ + assert(yasl_utf8_validate("😀", sizeof("😀") - 1)); + assert(yasl_utf8_validate(NULL, 0)); + return 0; +} |
