#include "common/backend.h" #include "common/input.h" #include #include #include #include #include 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; }