summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 00:09:38 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 00:09:38 +0300
commit624d1371304a5ae4b3429ad5e4267aac7cd03dfd (patch)
tree32de069f6eec83686521fc4bf39cc9874b123e93 /tests
parente813252e685d761235ad45e170d97c9375f51958 (diff)
missing impls and hardening
Diffstat (limited to 'tests')
-rw-r--r--tests/cocoa/test_native.c14
-rw-r--r--tests/cocoa/test_ownership.m45
-rw-r--r--tests/common/test_backends.c92
-rw-r--r--tests/common/test_contracts.c175
-rw-r--r--tests/common/test_input_alloc.c48
-rw-r--r--tests/meson.build28
-rw-r--r--tests/wayland/test_input.c26
7 files changed, 421 insertions, 7 deletions
diff --git a/tests/cocoa/test_native.c b/tests/cocoa/test_native.c
index 03fde88..41df79a 100644
--- a/tests/cocoa/test_native.c
+++ b/tests/cocoa/test_native.c
@@ -19,7 +19,16 @@ static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *u
struct yasl_vector2i size = yasl_surface_size(surface);
assert(size.x == frame->target.size.x && size.y == frame->target.size.y);
for (int i = 0; i < size.x * size.y; i++) frame->target.pixels[i] = 0xff4080c0;
- struct yasl_damage_list damage = {.n = -1};
+ struct yasl_damage_list damage = {.n = YASL_DAMAGE_MAX + 1};
+ assert(!yasl_surface_present(surface, &frame->target, &damage));
+ damage.n = -1;
+ struct yasl_framebuffer invalid = frame->target;
+ invalid.buffer++;
+ assert(!yasl_surface_present(surface, &invalid, &damage));
+ invalid = frame->target;
+ invalid.generation--;
+ assert(!yasl_surface_present(surface, &invalid, &damage));
+ assert(!yasl_surface_present(surface, &frame->target, NULL));
assert(yasl_surface_present(surface, &frame->target, &damage));
assert(!yasl_surface_present(surface, &frame->target, &damage));
state->draws++;
@@ -36,8 +45,9 @@ static void test_window(enum yasl_backend request, bool null_spec)
struct yasl_surface_spec surface = {.title = "Native backend test", .size = {160, 100}};
state.surface = yasl_surface_create_toplevel(state.display, &surface);
assert(state.surface);
- static const struct yasl_surface_cbs callbacks = {.draw = draw};
+ struct yasl_surface_cbs callbacks = {.draw = draw};
yasl_surface_set_callbacks(state.surface, &callbacks, &state);
+ callbacks.draw = NULL;
yasl_surface_schedule_redraw(state.surface);
uint64_t deadline = yasl_loop_now_ns() + 3000000000ull;
while (!state.draws && yasl_loop_now_ns() < deadline) {
diff --git a/tests/cocoa/test_ownership.m b/tests/cocoa/test_ownership.m
new file mode 100644
index 0000000..aa75b1c
--- /dev/null
+++ b/tests/cocoa/test_ownership.m
@@ -0,0 +1,45 @@
+#import <AppKit/AppKit.h>
+#include "yasl/yasl.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+ struct yasl_display *d = yasl_display_open(NULL, NULL);
+ assert(d);
+ struct yasl_surface_spec spec = {.title = "Ownership test", .size = {160, 100}};
+ struct yasl_surface *s = yasl_surface_create_toplevel(d, &spec);
+ assert(s);
+ struct yasl_input_event event;
+ while (yasl_surface_input_poll(s, &event)) {}
+ @autoreleasepool {
+ for (int i = 0; i < 600; i++) {
+ char text[32];
+ snprintf(text, sizeof(text), "paste-%d", i);
+ yasl_display_copy(d, YASL_CLIPBOARD, text);
+ yasl_display_paste(d, YASL_CLIPBOARD, s);
+ memset(text, 'x', sizeof(text));
+ }
+ }
+ /* All NSString/UTF8String temporaries have now expired. */
+ for (int i = 0; i < 600; i++) {
+ char text[32];
+ snprintf(text, sizeof(text), "paste-%d", i);
+ assert(yasl_surface_input_poll(s, &event));
+ assert(event.kind == YASL_INPUT_PASTE && strcmp(event.paste.text, text) == 0);
+ }
+ const char *last = event.paste.text;
+ assert(!yasl_surface_input_poll(s, &event));
+ @autoreleasepool { yasl_display_copy(d, YASL_CLIPBOARD, "new selection"); }
+ assert(strcmp(last, "paste-599") == 0);
+ @autoreleasepool {
+ yasl_display_copy(d, YASL_CLIPBOARD, "");
+ yasl_display_paste(d, YASL_CLIPBOARD, s);
+ }
+ assert(yasl_surface_input_poll(s, &event));
+ assert(event.kind == YASL_INPUT_PASTE && !event.paste.len && !event.paste.text[0]);
+ yasl_surface_destroy(s);
+ yasl_display_close(d);
+ return 0;
+}
diff --git a/tests/common/test_backends.c b/tests/common/test_backends.c
index 48a6b68..3372290 100644
--- a/tests/common/test_backends.c
+++ b/tests/common/test_backends.c
@@ -67,7 +67,24 @@ static void draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
assert(size.x == frame->target.size.x && size.y == frame->target.size.y);
assert(frame->target.pixels);
for (int i = 0; i < size.x * size.y; i++) frame->target.pixels[i] = 0xff4080c0;
- struct yasl_damage_list damage = {.n = -1};
+ struct yasl_damage_list damage = {.n = YASL_DAMAGE_MAX + 1};
+ assert(!yasl_surface_present(s, &frame->target, &damage));
+ damage.n = -2;
+ assert(!yasl_surface_present(s, &frame->target, &damage));
+ damage.n = 1;
+ damage.rects[0].width = -1;
+ assert(!yasl_surface_present(s, &frame->target, &damage));
+ damage.n = -1;
+ struct yasl_framebuffer invalid = frame->target;
+ invalid.buffer++;
+ assert(!yasl_surface_present(s, &invalid, &damage));
+ invalid = frame->target;
+ invalid.generation--;
+ assert(!yasl_surface_present(s, &invalid, &damage));
+ invalid = frame->target;
+ invalid.native_drawable = (void *)(uintptr_t)1;
+ assert(!yasl_surface_present(s, &invalid, &damage));
+ assert(!yasl_surface_present(s, &frame->target, NULL));
assert(yasl_surface_present(s, &frame->target, &damage));
assert(!yasl_surface_present(s, &frame->target, &damage));
w->draws++;
@@ -98,12 +115,22 @@ static const struct yasl_surface_cbs callbacks = {
.draw = draw, .configure = configure, .close = close_window,
};
+static void attach(struct window *w)
+{
+ struct yasl_surface_cbs temporary = callbacks;
+ yasl_surface_set_callbacks(w->surface, &temporary, w);
+ temporary.draw = NULL;
+ temporary.configure = NULL;
+ temporary.close = NULL;
+}
+
static struct window create(struct yasl_display *d)
{
struct yasl_surface_spec spec = {.title = "Backend test", .size = {160, 100}};
struct yasl_surface *s = yasl_surface_create_toplevel(d, &spec);
assert(s);
assert(yasl_surface_display(s) == d);
+ assert(yasl_surface_timing(s).source == YASL_TIMING_UNKNOWN);
return (struct window){.surface = s, .display = d};
}
@@ -153,6 +180,61 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct
}
}
assert(saw_key && saw_paste);
+ assert(yasl_surface_timing(w->surface).source == YASL_TIMING_SUBMISSION);
+ assert(!(yasl_display_caps(d) & YASL_CAP_FRAME_PACING));
+
+ /* Reuse caller storage, replace the selection, and exceed the old queue
+ * cap before polling: each paste must retain its own original contents. */
+ for (int i = 0; i < 300; i++) {
+ char text[32];
+ snprintf(text, sizeof(text), "owned-%d", i);
+ yasl_display_copy(d, YASL_CLIPBOARD, text);
+ yasl_display_paste(d, YASL_CLIPBOARD, w->surface);
+ memset(text, 'x', sizeof(text));
+ }
+ for (int i = 0; i < 300; i++) {
+ char text[32];
+ snprintf(text, sizeof(text), "owned-%d", i);
+ assert(yasl_surface_input_poll(w->surface, &event));
+ assert(event.kind == YASL_INPUT_PASTE && strcmp(event.paste.text, text) == 0);
+ }
+ const char *last = event.paste.text;
+ assert(!yasl_surface_input_poll(w->surface, &event));
+ yasl_display_copy(d, YASL_CLIPBOARD, "changed");
+ pump(loop, d, NULL);
+ assert(strcmp(last, "owned-299") == 0);
+ yasl_display_copy(d, YASL_CLIPBOARD, "");
+ yasl_display_paste(d, YASL_CLIPBOARD, w->surface);
+ assert(yasl_surface_input_poll(w->surface, &event));
+ assert(event.kind == YASL_INPUT_PASTE && !event.paste.len && !event.paste.text[0]);
+
+ /* Concurrent external conversions must not share a mutable target slot. */
+ struct yasl_display_spec ds = {.backend = YASL_BACKEND_X11};
+ struct yasl_display *owner = yasl_display_open(loop, &ds);
+ assert(owner);
+ yasl_display_copy(owner, YASL_CLIPBOARD, "external");
+ struct window other = create(d), cancelled = create(d);
+ yasl_display_paste(d, YASL_CLIPBOARD, w->surface);
+ yasl_display_paste(d, YASL_CLIPBOARD, other.surface);
+ yasl_display_paste(d, YASL_CLIPBOARD, cancelled.surface);
+ yasl_surface_destroy(cancelled.surface);
+ pump(loop, d, owner);
+ int first_pastes = 0, second_pastes = 0;
+ while (yasl_surface_input_poll(w->surface, &event)) {
+ if (event.kind == YASL_INPUT_PASTE) {
+ assert(strcmp(event.paste.text, "external") == 0);
+ first_pastes++;
+ }
+ }
+ while (yasl_surface_input_poll(other.surface, &event)) {
+ if (event.kind == YASL_INPUT_PASTE) {
+ assert(strcmp(event.paste.text, "external") == 0);
+ second_pastes++;
+ }
+ }
+ assert(first_pastes == 1 && second_pastes == 1);
+ yasl_surface_destroy(other.surface);
+ yasl_display_close(owner);
key.xclient = (XClientMessageEvent){.type = ClientMessage, .display = native,
.window = window, .message_type = XInternAtom(native, "WM_PROTOCOLS", False),
.format = 32, .data.l = {(long)XInternAtom(native, "WM_DELETE_WINDOW", False)}};
@@ -177,8 +259,8 @@ int main(int argc, char **argv)
struct yasl_display *b = yasl_display_open(loop, &spec);
assert(a && b);
struct window wa = create(a), wb = create(b);
- yasl_surface_set_callbacks(wa.surface, &callbacks, &wa);
- yasl_surface_set_callbacks(wb.surface, &callbacks, &wb);
+ attach(&wa);
+ attach(&wb);
pump(loop, a, b);
assert(wa.draws && wb.draws);
yasl_surface_destroy(wa.surface);
@@ -195,7 +277,7 @@ int main(int argc, char **argv)
struct window w = create(d);
pump(loop, d, NULL);
assert(w.draws == 0);
- yasl_surface_set_callbacks(w.surface, &callbacks, &w);
+ attach(&w);
yasl_surface_schedule_redraw(w.surface);
pump(loop, d, NULL);
assert(w.draws > 0);
@@ -204,7 +286,7 @@ int main(int argc, char **argv)
if (w.surface) yasl_surface_destroy(w.surface);
w = create(d);
w.destroy_on_draw = true;
- yasl_surface_set_callbacks(w.surface, &callbacks, &w);
+ attach(&w);
pump(loop, d, NULL);
assert(w.draws && !w.surface);
yasl_display_close(d);
diff --git a/tests/common/test_contracts.c b/tests/common/test_contracts.c
new file mode 100644
index 0000000..65eebcd
--- /dev/null
+++ b/tests/common/test_contracts.c
@@ -0,0 +1,175 @@
+#include "common/backend.h"
+#include "common/input.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void test_queue(void)
+{
+ struct input_queue q = {0};
+ struct yasl_surface surface = {0};
+ const enum yasl_input_kind kinds[] = {
+ YASL_INPUT_TEXT, YASL_INPUT_PASTE, YASL_INPUT_DROP_FILES,
+ };
+ for (size_t k = 0; k < sizeof(kinds) / sizeof(kinds[0]); k++) {
+ char *source = malloc(4);
+ assert(source);
+ memcpy(source, "a\0b", 4);
+ struct yasl_input_event in = {.surface = &surface, .kind = kinds[k]};
+ if (in.kind == YASL_INPUT_TEXT) { in.text.text = source; in.text.len = 3; }
+ if (in.kind == YASL_INPUT_PASTE) { in.paste.text = source; in.paste.len = 3; }
+ if (in.kind == YASL_INPUT_DROP_FILES) { in.drop_files.files = source; in.drop_files.len = 3; }
+ assert(input_queue_push(&q, &in));
+ memset(source, 'x', 4);
+ free(source);
+ struct yasl_input_event out;
+ assert(input_queue_pop(&q, &out));
+ const char *payload = out.kind == YASL_INPUT_TEXT ? out.text.text :
+ out.kind == YASL_INPUT_PASTE ? out.paste.text : out.drop_files.files;
+ assert(out.surface == &surface && out.kind == kinds[k]);
+ assert(memcmp(payload, "a\0b", 4) == 0);
+ assert(!input_queue_pop(&q, &out));
+ assert(memcmp(payload, "a\0b", 4) == 0);
+ /* Growth/wraparound must not invalidate a previously polled payload. */
+ for (unsigned i = 0; i < 4096; i++) {
+ in = (struct yasl_input_event){.kind = YASL_INPUT_KEY, .key.key = i};
+ assert(input_queue_push(&q, &in));
+ }
+ assert(memcmp(payload, "a\0b", 4) == 0);
+ for (unsigned i = 0; i < 2048; i++) {
+ assert(input_queue_pop(&q, &out));
+ assert(out.key.key == i);
+ }
+ for (unsigned i = 4096; i < 6144; i++) {
+ in.key.key = i;
+ assert(input_queue_push(&q, &in));
+ }
+ for (unsigned i = 2048; i < 6144; i++) {
+ assert(input_queue_pop(&q, &out));
+ assert(out.key.key == i);
+ }
+ assert(!input_queue_pop(&q, &out));
+ }
+ struct yasl_input_event empty = {.surface = &surface, .kind = YASL_INPUT_PASTE};
+ struct yasl_input_event out;
+ assert(input_queue_push(&q, &empty));
+ assert(input_queue_pop(&q, &out));
+ assert(out.paste.text && !out.paste.len && out.paste.text[0] == '\0');
+ struct yasl_input_event in = {.surface = &surface, .kind = YASL_INPUT_TEXT,
+ .text = {"owned", 5}};
+ assert(input_queue_push(&q, &in));
+ assert(input_queue_pop(&q, &out));
+ const char *last = out.text.text;
+ assert(input_queue_push(&q, &in));
+ /* Exercise the allocation-failure reset path without allocating huge RAM. */
+ in.text.len = SIZE_MAX;
+ assert(!input_queue_push(&q, &in));
+ assert(strcmp(last, "owned") == 0);
+ in = (struct yasl_input_event){.surface = &surface, .kind = YASL_INPUT_KEY};
+ assert(input_queue_push(&q, &in));
+ assert(input_queue_pop(&q, &out) && out.kind == YASL_INPUT_RESET);
+ assert(out.surface == &surface);
+ assert(input_queue_pop(&q, &out) && out.kind == YASL_INPUT_KEY);
+ assert(!input_queue_pop(&q, &out));
+ in = (struct yasl_input_event){.kind = YASL_INPUT_PASTE, .paste = {"pending", 7}};
+ assert(input_queue_push(&q, &in));
+ input_queue_clear(&q);
+ input_queue_clear(&q);
+ assert(!q.events && !q.last_text && !q.count && !q.reset_pending);
+}
+
+static int presents, copies, pastes, creates;
+static struct yasl_damage_list received;
+static bool present(struct yasl_surface *s, const struct yasl_framebuffer *fb,
+ const struct yasl_damage_list *damage)
+{
+ (void)s; (void)fb;
+ presents++;
+ received = *damage;
+ return true;
+}
+static uint32_t caps(const struct yasl_display *d) { (void)d; return 0; }
+static void copy(struct yasl_display *d, enum yasl_selection sel, const char *text)
+{ (void)d; (void)sel; (void)text; copies++; }
+static void paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *s)
+{ (void)d; (void)sel; (void)s; pastes++; }
+static struct yasl_surface *create(struct yasl_display *d, const struct yasl_surface_spec *spec)
+{ (void)d; (void)spec; creates++; return NULL; }
+
+static void test_validation(void)
+{
+ const struct yasl_backend_ops ops = {.surface_present = present,
+ .display_caps = caps, .display_copy = copy, .display_paste = paste,
+ .surface_create_toplevel = create};
+ struct yasl_display d = {.ops = &ops};
+ struct yasl_surface s = {.display = &d, .frame_generation = 1};
+ struct yasl_framebuffer fb = {.generation = 1, .size = {100, 80}};
+ struct yasl_damage_list damage = {.n = -2};
+ assert(!yasl_surface_present(&s, &fb, &damage));
+ damage.n = YASL_DAMAGE_MAX + 1;
+ assert(!yasl_surface_present(&s, &fb, &damage));
+ damage.n = 1;
+ damage.rects[0] = (struct yasl_rect2i){0, 0, -1, 1};
+ assert(!yasl_surface_present(&s, &fb, &damage));
+ assert(!yasl_surface_present(&s, &fb, NULL));
+ assert(!presents);
+ damage.n = -1;
+ fb.generation = 0;
+ assert(!yasl_surface_present(&s, &fb, &damage));
+ fb.generation = 2;
+ assert(!yasl_surface_present(&s, &fb, &damage));
+ fb.generation = 1;
+ damage.n = 4;
+ damage.rects[0] = (struct yasl_rect2i){-10, -10, 30, 30};
+ damage.rects[1] = (struct yasl_rect2i){90, 70, INT_MAX, INT_MAX};
+ damage.rects[2] = (struct yasl_rect2i){INT_MAX, INT_MAX, INT_MAX, INT_MAX};
+ damage.rects[3] = (struct yasl_rect2i){INT_MIN, INT_MIN, INT_MAX, INT_MAX};
+ assert(yasl_surface_present(&s, &fb, &damage));
+ assert(received.n == 2 && received.rects[0].x == 0 && received.rects[0].width == 20);
+ assert(received.rects[1].width == 10 && received.rects[1].height == 10);
+ assert(damage.n == 4 && damage.rects[0].x == -10);
+ damage.n = -1;
+ assert(yasl_surface_present(&s, &fb, &damage) && received.n == -1);
+ damage.n = 0;
+ assert(yasl_surface_present(&s, &fb, &damage) && received.n == 0);
+ yasl_display_copy(&d, YASL_PRIMARY, "no alias");
+ yasl_display_copy(&d, (enum yasl_selection)255, "invalid");
+ yasl_display_paste(&d, YASL_PRIMARY, &s);
+ yasl_display_paste(&d, (enum yasl_selection)255, &s);
+ assert(!copies && !pastes);
+ yasl_display_copy(&d, YASL_CLIPBOARD, "yes");
+ yasl_display_paste(&d, YASL_CLIPBOARD, &s);
+ assert(copies == 1 && pastes == 1);
+ struct yasl_surface_spec spec = {.size = {100, 80}, .graphics_device = &d};
+ assert(!yasl_surface_create_toplevel(&d, &spec) && errno == ENOTSUP);
+ spec.graphics_device = NULL;
+ spec.size.x = 0;
+ assert(!yasl_surface_create_toplevel(&d, &spec) && errno == EINVAL);
+ assert(!creates);
+}
+
+static void test_scale(void)
+{
+ assert(yasl_scale_to_device(-10, 120) == -10);
+ assert(yasl_scale_to_device(-0.5, 120) == -1);
+ assert(yasl_scale_to_device(0.5, 120) == 1);
+ assert(yasl_scale_to_device(NAN, 120) == 0);
+ assert(yasl_scale_to_device(INFINITY, 120) == 0);
+ assert(yasl_scale_to_device(DBL_MAX, 240) == INT_MAX);
+ assert(yasl_scale_to_logical(-1, 240) == -1);
+ assert(yasl_scale_to_logical(1, 240) == 1);
+ assert(yasl_scale_to_logical(INT_MAX, 1) == INT_MAX);
+ assert(yasl_scale_to_logical(INT_MIN, 1) == INT_MIN);
+ assert(yasl_scale_to_logical(1, 0) == 0);
+}
+
+int main(void)
+{
+ test_queue();
+ test_validation();
+ test_scale();
+ return 0;
+}
diff --git a/tests/common/test_input_alloc.c b/tests/common/test_input_alloc.c
new file mode 100644
index 0000000..e311dc0
--- /dev/null
+++ b/tests/common/test_input_alloc.c
@@ -0,0 +1,48 @@
+#include "common/input.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* This executable compiles input.c with malloc redirected here. */
+static int allocations = -1;
+void *yasl_test_malloc(size_t bytes)
+{
+ if (allocations == 0) return NULL;
+ if (allocations > 0) allocations--;
+ return calloc(1, bytes);
+}
+
+int main(void)
+{
+ struct yasl_surface *surface = (struct yasl_surface *)(uintptr_t)1;
+ for (int failure = 0; failure < 2; failure++) {
+ struct input_queue q = {0};
+ struct yasl_input_event in = {.surface = surface, .kind = YASL_INPUT_PASTE,
+ .paste = {"payload", 7}}, out;
+ /* Fail either payload allocation or the initial event-array allocation. */
+ allocations = failure;
+ assert(!input_queue_push(&q, &in));
+ assert(input_queue_pop(&q, &out) && out.kind == YASL_INPUT_RESET);
+ assert(out.surface == surface);
+ assert(!input_queue_pop(&q, &out));
+ input_queue_clear(&q);
+
+ allocations = -1;
+ assert(input_queue_push(&q, &in));
+ assert(input_queue_pop(&q, &out));
+ const char *last = out.paste.text;
+ for (size_t i = 0; i < q.capacity; i++) assert(input_queue_push(&q, &in));
+ allocations = failure;
+ assert(!input_queue_push(&q, &in));
+ assert(strcmp(last, "payload") == 0);
+ assert(!q.count && q.reset_pending);
+ allocations = -1;
+ in = (struct yasl_input_event){.surface = surface, .kind = YASL_INPUT_KEY,
+ .key.action = YASL_KEY_RELEASE};
+ assert(input_queue_push(&q, &in));
+ assert(input_queue_pop(&q, &out) && out.kind == YASL_INPUT_RESET);
+ assert(input_queue_pop(&q, &out) && out.key.action == YASL_KEY_RELEASE);
+ input_queue_clear(&q);
+ }
+ return 0;
+}
diff --git a/tests/meson.build b/tests/meson.build
index 950f5f5..1fcac3e 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -12,6 +12,22 @@ add_test_setup('msan')
test('basic', test_exe)
+contracts_test = executable(
+ 'yasl-contracts-test',
+ 'common/test_contracts.c',
+ include_directories: inc,
+ dependencies: yasl_dep,
+)
+test('contracts', contracts_test)
+
+input_alloc_test = executable(
+ 'yasl-input-alloc-test',
+ ['common/test_input_alloc.c', '../src/common/input.c'],
+ include_directories: inc,
+ c_args: ['-Dmalloc=yasl_test_malloc'],
+)
+test('input-allocation-failure', input_alloc_test)
+
selection_test = executable(
'yasl-selection-test',
'common/test_selection.c',
@@ -19,12 +35,24 @@ selection_test = executable(
)
test('selection', selection_test)
+if has_wayland
+ ime_test = executable('yasl-ime-test', 'wayland/test_input.c',
+ include_directories: inc,
+ dependencies: yasl_dep,
+ )
+ test('ime-ownership', ime_test)
+endif
+
if get_option('integration_tests')
if has_cocoa
native_test = executable('yasl-native-test', 'cocoa/test_native.c',
dependencies: yasl_dep,
)
test('native', native_test, timeout: 20)
+ ownership_test = executable('yasl-ownership-test', 'cocoa/test_ownership.m',
+ dependencies: yasl_dep,
+ )
+ test('native-ownership', ownership_test, timeout: 20)
else
if not has_wayland or not has_x11
error('Linux integration tests require Wayland and X11.')
diff --git a/tests/wayland/test_input.c b/tests/wayland/test_input.c
new file mode 100644
index 0000000..f421e6c
--- /dev/null
+++ b/tests/wayland/test_input.c
@@ -0,0 +1,26 @@
+#include "wayland/internal.h"
+#include <assert.h>
+
+int main(void)
+{
+ struct wayland_surface w = {0};
+ struct seat seat = {.ime_focus = &w};
+ wayland_surface_set_callbacks(&w, NULL, NULL);
+ for (int i = 0; i < 600; i++) {
+ char text[32];
+ snprintf(text, sizeof(text), "commit-%d", i);
+ text_input_listener.commit_string(&seat, NULL, text);
+ text_input_listener.done(&seat, NULL, (uint32_t)i);
+ assert(!w.ime_commit);
+ }
+ for (int i = 0; i < 600; i++) {
+ char text[32];
+ snprintf(text, sizeof(text), "commit-%d", i);
+ struct yasl_input_event event;
+ assert(wayland_surface_input_poll(&w, &event));
+ assert(event.kind == YASL_INPUT_TEXT && event.surface == &w.base);
+ assert(strcmp(event.text.text, text) == 0);
+ }
+ input_queue_clear(&w.input);
+ return 0;
+}