summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 08:41:51 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 08:41:51 +0300
commit3b8af02be94a510e385f44d58c35c86bb89424a6 (patch)
tree2573fb5ac41700d458109ee1cea4bfd875ecf1a2 /tests
parentf7fa0930cb46046f995fa1ab927aef62466e995e (diff)
refactor: simplify public API and isolate native extensions
Separate loop/timer and native interoperability APIs from the portable surface header. Unify dispatch, geometry queries, and timer callbacks; keep framebuffer bookkeeping and frame clocks private, and hide implementation symbols. Update backends, documentation, examples, and API/integration coverage. Verify exports, strict C/C++ installed consumers, and normal plus ASan/UBSan suites.
Diffstat (limited to 'tests')
-rw-r--r--tests/cocoa/test_native.c12
-rw-r--r--tests/cocoa/test_ownership.m4
-rw-r--r--tests/common/test_backends.c20
-rw-r--r--tests/common/test_contracts.c78
-rw-r--r--tests/common/test_timers.c29
-rw-r--r--tests/helpers/check_exports.py42
-rw-r--r--tests/helpers/run_backends.py9
-rw-r--r--tests/meson.build51
-rw-r--r--tests/test_api.cpp27
-rw-r--r--tests/test_lifecycle.c22
-rw-r--r--tests/wayland/test_input.c25
11 files changed, 266 insertions, 53 deletions
diff --git a/tests/cocoa/test_native.c b/tests/cocoa/test_native.c
index 41df79a..0c101dd 100644
--- a/tests/cocoa/test_native.c
+++ b/tests/cocoa/test_native.c
@@ -1,4 +1,6 @@
#define _POSIX_C_SOURCE 200809L
+#include "yasl/native.h"
+#include "yasl/loop.h"
#include "yasl/yasl.h"
#include <assert.h>
@@ -16,20 +18,24 @@ static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *u
assert(surface == state->surface && frame->surface == surface);
assert(yasl_surface_display(surface) == state->display);
assert(frame->target.pixels);
- struct yasl_vector2i size = yasl_surface_size(surface);
+ struct yasl_native_frame native;
+ assert(yasl_surface_get_native_frame(surface, &frame->target, &native));
+ assert(native.drawable);
+ struct yasl_vector2i size = yasl_surface_geometry(surface).size;
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 = YASL_DAMAGE_MAX + 1};
assert(!yasl_surface_present(surface, &frame->target, &damage));
damage.n = -1;
struct yasl_framebuffer invalid = frame->target;
- invalid.buffer++;
+ invalid.size.x++;
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_get_native_frame(surface, &frame->target, &native));
assert(!yasl_surface_present(surface, &frame->target, &damage));
state->draws++;
yasl_surface_destroy(surface);
@@ -51,7 +57,7 @@ static void test_window(enum yasl_backend request, bool null_spec)
yasl_surface_schedule_redraw(state.surface);
uint64_t deadline = yasl_loop_now_ns() + 3000000000ull;
while (!state.draws && yasl_loop_now_ns() < deadline) {
- yasl_display_dispatch(state.display);
+ yasl_display_dispatch(state.display, 0);
yasl_display_flush(state.display);
nanosleep(&(struct timespec){.tv_nsec = 1000000}, NULL);
}
diff --git a/tests/cocoa/test_ownership.m b/tests/cocoa/test_ownership.m
index aa75b1c..168a47b 100644
--- a/tests/cocoa/test_ownership.m
+++ b/tests/cocoa/test_ownership.m
@@ -1,3 +1,4 @@
+#include "yasl/native.h"
#import <AppKit/AppKit.h>
#include "yasl/yasl.h"
#include <assert.h>
@@ -11,6 +12,9 @@ int main(void)
struct yasl_surface_spec spec = {.title = "Ownership test", .size = {160, 100}};
struct yasl_surface *s = yasl_surface_create_toplevel(d, &spec);
assert(s);
+ assert(yasl_display_get_native_handle(d) == (void *)NSApp);
+ NSWindow *window = (NSWindow *)yasl_surface_get_native_handle(s);
+ assert([window isKindOfClass:[NSWindow class]] && window.contentView);
struct yasl_input_event event;
while (yasl_surface_input_poll(s, &event)) {}
@autoreleasepool {
diff --git a/tests/common/test_backends.c b/tests/common/test_backends.c
index 3372290..4f49765 100644
--- a/tests/common/test_backends.c
+++ b/tests/common/test_backends.c
@@ -1,4 +1,6 @@
#define _POSIX_C_SOURCE 200809L
+#include "yasl/native.h"
+#include "yasl/loop.h"
#include "yasl/yasl.h"
#include <X11/Xatom.h>
@@ -35,7 +37,7 @@ static int tick(int fd, short events, void *ud)
struct pump *p = ud;
for (int i = 0; i < 2; i++) {
if (p->displays[i]) {
- yasl_display_dispatch(p->displays[i]);
+ yasl_display_dispatch(p->displays[i], 0);
yasl_display_flush(p->displays[i]);
}
}
@@ -63,9 +65,11 @@ static void draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
assert(s == w->surface);
assert(frame->surface == s);
assert(yasl_surface_display(s) == w->display);
- struct yasl_vector2i size = yasl_surface_size(s);
+ struct yasl_vector2i size = yasl_surface_geometry(s).size;
assert(size.x == frame->target.size.x && size.y == frame->target.size.y);
assert(frame->target.pixels);
+ struct yasl_native_frame native = {0};
+ assert(!yasl_surface_get_native_frame(s, &frame->target, &native));
for (int i = 0; i < size.x * size.y; i++) frame->target.pixels[i] = 0xff4080c0;
struct yasl_damage_list damage = {.n = YASL_DAMAGE_MAX + 1};
assert(!yasl_surface_present(s, &frame->target, &damage));
@@ -76,13 +80,13 @@ static void draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
assert(!yasl_surface_present(s, &frame->target, &damage));
damage.n = -1;
struct yasl_framebuffer invalid = frame->target;
- invalid.buffer++;
+ invalid.size.x++;
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;
+ invalid.pixels = (uint32_t *)(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));
@@ -95,9 +99,9 @@ static void configure(struct yasl_surface *s, struct yasl_geometry geometry, voi
{
struct window *w = ud;
assert(w->surface == s);
- struct yasl_vector2i size = yasl_surface_size(s);
+ struct yasl_vector2i size = yasl_surface_geometry(s).size;
assert(geometry.size.x == size.x && geometry.size.y == size.y);
- assert(geometry.scale_120 == yasl_surface_scale_120(s));
+ assert(geometry.scale_120 == yasl_surface_geometry(s).scale_120);
w->configures++;
if (w->destroy_on_configure) { yasl_surface_destroy(s); w->surface = NULL; }
}
@@ -129,6 +133,8 @@ 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_display_get_native_handle(d));
+ assert(yasl_surface_get_native_handle(s));
assert(yasl_surface_display(s) == d);
assert(yasl_surface_timing(s).source == YASL_TIMING_UNKNOWN);
return (struct window){.surface = s, .display = d};
@@ -152,7 +158,7 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct
XFlush(native);
pump(loop, d, NULL);
assert(w->configures > 0);
- struct yasl_vector2i size = yasl_surface_size(w->surface);
+ struct yasl_vector2i size = yasl_surface_geometry(w->surface).size;
assert(size.x == 200 && size.y == 120);
XEvent key = {0};
key.xkey = (XKeyEvent){.type = KeyPress, .display = native, .window = window,
diff --git a/tests/common/test_contracts.c b/tests/common/test_contracts.c
index 65eebcd..4e22de1 100644
--- a/tests/common/test_contracts.c
+++ b/tests/common/test_contracts.c
@@ -1,5 +1,6 @@
#include "common/backend.h"
#include "common/input.h"
+#include "common/timing.h"
#include <assert.h>
#include <errno.h>
@@ -7,6 +8,23 @@
#include <stdlib.h>
#include <string.h>
+static void test_timing_clock(void)
+{
+ struct yasl_frame_clock clock = {.refresh_ns = YASL_REFRESH_DEFAULT_NS};
+ yasl_clock_presented(&clock, 1000000000, true);
+ assert(clock.last_present_ns == 1000000000);
+ uint64_t next = yasl_clock_next_present_ns(&clock);
+ assert(next > 1000000000);
+ assert(yasl_clock_extend_ms(1000, 1000000000) == 1000000000);
+ assert(yasl_clock_frame_timestamp_ns(&clock, next) == next);
+
+ yasl_clock_note_resize(&clock, 500000);
+ struct yasl_resize_stats stats;
+ yasl_clock_resize_stats(&clock, &stats);
+ assert(stats.count == 1);
+ assert(stats.max_us == 500.0);
+}
+
static void test_queue(void)
{
struct input_queue q = {0};
@@ -96,8 +114,56 @@ static void copy(struct yasl_display *d, enum yasl_selection sel, const char *te
{ (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 struct yasl_surface *create(struct yasl_display *d, const struct yasl_surface_spec *spec, void *graphics_device)
+{ (void)d; (void)spec; (void)graphics_device; creates++; return NULL; }
+
+static void *native_device;
+static int native_queries;
+static struct yasl_surface native_surface;
+static uint32_t native_caps(const struct yasl_display *d)
+{ (void)d; return YASL_CAP_NATIVE_GRAPHICS; }
+static struct yasl_surface *native_create(struct yasl_display *d,
+ const struct yasl_surface_spec *spec, void *device)
+{
+ (void)spec;
+ native_device = device;
+ native_surface = (struct yasl_surface){.display = d, .frame_generation = 1};
+ return &native_surface;
+}
+static bool native_frame(struct yasl_surface *s, const struct yasl_framebuffer *fb,
+ struct yasl_native_frame *out)
+{
+ (void)s; (void)fb;
+ native_queries++;
+ *out = (struct yasl_native_frame){.drawable = native_device};
+ return true;
+}
+
+static void test_native(void)
+{
+ const struct yasl_backend_ops ops = {.display_caps = native_caps,
+ .surface_create_toplevel = native_create, .surface_get_native_frame = native_frame};
+ struct yasl_display d = {.ops = &ops};
+ struct yasl_surface_spec spec = {.size = {100, 80}};
+ assert(yasl_surface_create_toplevel(&d, &spec) == &native_surface);
+ assert(!native_device);
+ assert(yasl_surface_create_native(&d, &spec, &d) == &native_surface);
+ assert(native_device == &d);
+
+ struct yasl_framebuffer fb = {.generation = 1, .size = {100, 80}};
+ struct yasl_native_frame out = {0};
+ assert(!yasl_surface_get_native_frame(NULL, &fb, &out));
+ assert(!yasl_surface_get_native_frame(&native_surface, NULL, &out));
+ assert(!yasl_surface_get_native_frame(&native_surface, &fb, NULL));
+ fb.generation = 0;
+ assert(!yasl_surface_get_native_frame(&native_surface, &fb, &out));
+ fb.generation = 2;
+ assert(!yasl_surface_get_native_frame(&native_surface, &fb, &out));
+ assert(!native_queries && !out.drawable);
+ fb.generation = 1;
+ assert(yasl_surface_get_native_frame(&native_surface, &fb, &out));
+ assert(native_queries == 1 && out.drawable == &d);
+}
static void test_validation(void)
{
@@ -143,9 +209,9 @@ static void test_validation(void)
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;
+ struct yasl_surface_spec spec = {.size = {100, 80}};
+ assert(!yasl_surface_create_native(&d, &spec, &d) && errno == ENOTSUP);
+ assert(!yasl_surface_create_native(&d, &spec, NULL) && errno == EINVAL);
spec.size.x = 0;
assert(!yasl_surface_create_toplevel(&d, &spec) && errno == EINVAL);
assert(!creates);
@@ -168,8 +234,10 @@ static void test_scale(void)
int main(void)
{
+ test_timing_clock();
test_queue();
test_validation();
+ test_native();
test_scale();
return 0;
}
diff --git a/tests/common/test_timers.c b/tests/common/test_timers.c
index 9b6499d..d02bfe9 100644
--- a/tests/common/test_timers.c
+++ b/tests/common/test_timers.c
@@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L
+#include "common/loop.h"
#include "yasl/yasl.h"
#include <assert.h>
@@ -95,18 +96,18 @@ static uint64_t killer_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns
return 0;
}
-/* 6. Millisecond variant timer. */
-static uint32_t ms_timer_cb(void *ud, yasl_timer_id id, uint32_t interval_ms)
+/* 6. Millisecond convenience conversion uses the same timer callback. */
+static uint64_t ms_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns)
{
struct test_ctx *ctx = ud;
assert(id == ctx->id);
- assert(interval_ms == 5);
+ assert(interval_ns == YASL_MS_TO_NS(5));
ctx->count++;
if (ctx->count >= 3) {
ctx->done = true;
return 0;
}
- return interval_ms;
+ return interval_ns;
}
static void test_loop_timers(void)
@@ -185,9 +186,9 @@ static void test_loop_timers(void)
assert(ctx6.count == 1);
yasl_loop_step(l, 20);
- /* Test 7: Millisecond API */
+ /* Test 7: Millisecond conversion */
struct test_ctx ctx7 = { .loop = l };
- ctx7.id = yasl_loop_add_timer_ms(l, 5, ms_timer_cb, &ctx7);
+ ctx7.id = yasl_loop_add_timer(l, YASL_MS_TO_NS(5), ms_timer_cb, &ctx7);
assert(ctx7.id > 0);
while (!ctx7.done) {
yasl_loop_step(l, 50);
@@ -239,14 +240,14 @@ static void test_surface_timers(void)
};
struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec);
assert(s);
- assert(yasl_surface_loop(s) == loop);
+ assert(yasl_display_loop(yasl_surface_display(s)) == loop);
- /* Display timers */
+ /* Application timers use the display's loop. */
struct test_ctx dctx = {0};
- dctx.id = yasl_display_add_timer(d, 2000000ull, oneshot_cb, &dctx);
+ dctx.id = yasl_loop_add_timer(yasl_display_loop(d), 2000000ull, oneshot_cb, &dctx);
assert(dctx.id > 0);
while (dctx.count == 0) {
- yasl_display_dispatch_timeout(d, 50);
+ yasl_display_dispatch(d, 50);
}
assert(dctx.count == 1);
@@ -255,12 +256,12 @@ static void test_surface_timers(void)
sctx.id = yasl_surface_add_timer(s, 2000000ull, surface_timer_repeat_cb, &sctx);
assert(sctx.id > 0);
while (sctx.count < 3) {
- yasl_display_dispatch_timeout(d, 50);
+ yasl_display_dispatch(d, 50);
}
assert(sctx.count >= 3);
assert(yasl_surface_del_timer(s, sctx.id));
int count_before = sctx.count;
- yasl_display_dispatch_timeout(d, 10);
+ yasl_display_dispatch(d, 10);
assert(sctx.count == count_before);
/* Surface timer auto-cleanup on surface destruction */
@@ -269,7 +270,7 @@ static void test_surface_timers(void)
assert(sctx2.id > 0);
yasl_surface_destroy(s);
/* Step display/loop; timer must not fire on dead surface */
- yasl_display_dispatch_timeout(d, 10);
+ yasl_display_dispatch(d, 10);
assert(sctx2.count == 0);
/* Surface suicide from timer callback */
@@ -279,7 +280,7 @@ static void test_surface_timers(void)
sctx3.id = yasl_surface_add_timer(s, 2000000ull, surface_suicide_cb, &sctx3);
assert(sctx3.id > 0);
while (sctx3.count == 0) {
- yasl_display_dispatch_timeout(d, 50);
+ yasl_display_dispatch(d, 50);
}
assert(sctx3.count == 1);
assert(sctx3.surface == NULL);
diff --git a/tests/helpers/check_exports.py b/tests/helpers/check_exports.py
new file mode 100644
index 0000000..0d10014
--- /dev/null
+++ b/tests/helpers/check_exports.py
@@ -0,0 +1,42 @@
+"""Require the shared library to export exactly the public header functions."""
+
+import argparse
+from pathlib import Path
+import re
+import subprocess
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--allow-export', action='append', default=[])
+ parser.add_argument('nm')
+ parser.add_argument('library')
+ parser.add_argument('headers', nargs='+')
+ args = parser.parse_args()
+ declarations = re.compile(
+ r"^[^\n;{}]*\b(yasl_\w+)\s*\([^;{}]*\);", re.MULTILINE
+ )
+ expected = set()
+ for header in args.headers:
+ source = re.sub(r"/\*.*?\*/|//[^\n]*", "", Path(header).read_text(), flags=re.DOTALL)
+ expected.update(declarations.findall(source))
+ if not expected:
+ raise SystemExit("No public function declarations found")
+
+ output = subprocess.check_output(
+ [args.nm, "-D", "--defined-only", "--format=posix", args.library], text=True
+ )
+ exported = {line.split()[0] for line in output.splitlines() if line.strip()}
+ missing = expected - exported
+ leaked = exported - expected - set(args.allow_export)
+ if missing or leaked:
+ if missing:
+ print("Missing public exports:", ", ".join(sorted(missing)))
+ if leaked:
+ print("Unexpected exports:", ", ".join(sorted(leaked)))
+ raise SystemExit(1)
+ print(f"Verified {len(expected)} public exports")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/helpers/run_backends.py b/tests/helpers/run_backends.py
index 9ad9b0d..8c5428a 100644
--- a/tests/helpers/run_backends.py
+++ b/tests/helpers/run_backends.py
@@ -21,7 +21,7 @@ def wait_for(process, ready):
def main():
- weston, xwayland, test = sys.argv[1:]
+ weston, xwayland, test, timers = sys.argv[1:]
servers = []
with tempfile.TemporaryDirectory(prefix="yasl-backends-") as directory:
root = Path(directory)
@@ -73,6 +73,13 @@ def main():
run("failure", 2, DISPLAY=":59999")
run("failure", 0, WAYLAND_DISPLAY="missing-socket", DISPLAY=":59999")
run("mixed")
+ print("Test: Wayland surface timers", flush=True)
+ subprocess.run([timers], env=env, check=True, timeout=8)
+ x_env = env.copy()
+ x_env.pop("WAYLAND_DISPLAY", None)
+ x_env["XDG_SESSION_TYPE"] = "x11"
+ print("Test: X11 surface timers", flush=True)
+ subprocess.run([timers], env=x_env, check=True, timeout=8)
except BaseException:
for log in (wl_log, x_log):
log.flush()
diff --git a/tests/meson.build b/tests/meson.build
index f2d5e79..0f28c39 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -12,6 +12,47 @@ add_test_setup('msan')
test('basic', test_exe)
+shared_dep = declare_dependency(
+ link_with: yasl_lib.get_shared_lib(),
+ include_directories: include_directories('../include'),
+)
+
+shared_api_test = executable(
+ 'yasl-shared-api-test',
+ 'test_lifecycle.c',
+ dependencies: shared_dep,
+)
+test('shared-api', shared_api_test)
+
+if add_languages('cpp', native: false, required: false)
+ cpp = meson.get_compiler('cpp')
+ cpp_api_test = executable(
+ 'yasl-cpp-api-test',
+ 'test_api.cpp',
+ dependencies: shared_dep,
+ cpp_args: cpp.get_supported_arguments('-pedantic-errors'),
+ override_options: ['cpp_std=c++11'],
+ )
+ test('cpp-api', cpp_api_test)
+endif
+
+python = find_program('python3')
+if system == 'linux'
+ nm = find_program('nm')
+ export_args = []
+ if get_option('b_sanitize').contains('address')
+ # Clang's ASan instrumentation exports these linker-generated markers.
+ export_args += ['--allow-export=__start_asan_globals',
+ '--allow-export=__stop_asan_globals']
+ endif
+ test('public-exports', python,
+ args: [files('helpers/check_exports.py')] + export_args +
+ [nm, yasl_lib.get_shared_lib(),
+ files('../include/yasl/yasl.h', '../include/yasl/timing.h',
+ '../include/yasl/loop.h', '../include/yasl/native.h')],
+ )
+endif
+
contracts_test = executable(
'yasl-contracts-test',
'common/test_contracts.c',
@@ -54,11 +95,11 @@ endif
if get_option('integration_tests')
if has_cocoa
native_test = executable('yasl-native-test', 'cocoa/test_native.c',
- dependencies: yasl_dep,
+ dependencies: shared_dep,
)
test('native', native_test, timeout: 20)
ownership_test = executable('yasl-ownership-test', 'cocoa/test_ownership.m',
- dependencies: yasl_dep,
+ dependencies: [shared_dep, deps],
)
test('native-ownership', ownership_test, timeout: 20)
else
@@ -68,13 +109,13 @@ if get_option('integration_tests')
backend_test = executable(
'yasl-backend-test',
'common/test_backends.c',
- dependencies: yasl_dep,
+ dependencies: [shared_dep, deps],
)
- python = find_program('python3')
weston = find_program('weston')
xwayland = find_program('Xwayland')
test('backends', python,
- args: [files('helpers/run_backends.py'), weston, xwayland, backend_test],
+ args: [files('helpers/run_backends.py'), weston, xwayland,
+ backend_test, timer_test],
timeout: 60,
)
endif
diff --git a/tests/test_api.cpp b/tests/test_api.cpp
new file mode 100644
index 0000000..70c4ff7
--- /dev/null
+++ b/tests/test_api.cpp
@@ -0,0 +1,27 @@
+#include "yasl/native.h"
+#include "yasl/loop.h"
+#include <yasl/timing.h>
+#include <yasl/yasl.h>
+#include <cassert>
+
+int main()
+{
+ yasl_timing timing = yasl_surface_timing(nullptr);
+ assert(timing.source == YASL_TIMING_UNKNOWN);
+ assert(yasl_scale_to_device(10.0, 240) == 20);
+ yasl_geometry geometry = yasl_surface_geometry(nullptr);
+ assert(geometry.scale_120 == YASL_SCALE_UNIT);
+ assert(!yasl_display_get_native_handle(nullptr));
+ assert(!yasl_surface_get_native_handle(nullptr));
+ yasl_native_frame native{};
+ assert(!yasl_surface_get_native_frame(nullptr, nullptr, &native));
+
+ yasl_loop *loop = yasl_loop_create();
+ assert(loop);
+ assert(yasl_loop_step(loop, 0) >= 0);
+ yasl_loop_destroy(loop);
+
+ yasl_input_event event{};
+ assert(!yasl_surface_input_poll(nullptr, &event));
+ return 0;
+}
diff --git a/tests/test_lifecycle.c b/tests/test_lifecycle.c
index 681e5fc..d04662f 100644
--- a/tests/test_lifecycle.c
+++ b/tests/test_lifecycle.c
@@ -1,3 +1,5 @@
+#include "yasl/loop.h"
+#include "yasl/timing.h"
#include "yasl/yasl.h"
#include <assert.h>
#include <poll.h>
@@ -11,21 +13,6 @@ static void test_scaling(void)
assert(yasl_scale_to_logical(20, 240) == 10);
}
-static void test_timing_clock(void)
-{
- struct yasl_frame_clock clock = { .refresh_ns = 16666666.0 };
- yasl_clock_presented(&clock, 1000000000, true);
- assert(clock.last_present_ns == 1000000000);
- uint64_t next = yasl_clock_next_present_ns(&clock);
- assert(next > 1000000000);
-
- yasl_clock_note_resize(&clock, 500000);
- struct yasl_resize_stats stats;
- yasl_clock_resize_stats(&clock, &stats);
- assert(stats.count == 1);
- assert(stats.max_us == 500.0);
-}
-
static int dummy_cb(int fd, short revents, void *ud)
{
(void)fd; (void)revents; (void)ud;
@@ -68,12 +55,12 @@ static void test_display_lifecycle_standalone(void)
assert(s != NULL);
assert(yasl_surface_display(s) == d);
- struct yasl_vector2i sz = yasl_surface_size(s);
+ struct yasl_vector2i sz = yasl_surface_geometry(s).size;
assert(sz.x > 0 && sz.y > 0);
yasl_surface_schedule_redraw(s);
yasl_display_flush(d);
- yasl_display_dispatch_timeout(d, 0);
+ yasl_display_dispatch(d, 0);
yasl_surface_destroy(s);
yasl_display_close(d);
@@ -82,7 +69,6 @@ static void test_display_lifecycle_standalone(void)
int main(void)
{
test_scaling();
- test_timing_clock();
test_loop();
test_display_lifecycle_standalone();
printf("All YASL basic tests passed.\n");
diff --git a/tests/wayland/test_input.c b/tests/wayland/test_input.c
index f421e6c..7b91a9d 100644
--- a/tests/wayland/test_input.c
+++ b/tests/wayland/test_input.c
@@ -1,8 +1,33 @@
#include "wayland/internal.h"
#include <assert.h>
+static void test_popup_bounds(void)
+{
+ struct seat seat = {.input_serial = 1};
+ struct wayland_display d = {.base.ops = &yasl_wayland_backend, .seats = &seat};
+ struct wayland_surface w = {.base.display = &d.base, .conn = &d};
+ w.parent = &w;
+ w.content.x = w.content.y = 1;
+ /* Invalid bounds must be rejected before accessing any protocol object. */
+ w.xdg_surface = (struct xdg_surface *)&w;
+ w.popup = (struct xdg_popup *)&w;
+ struct yasl_popup_spec specs[] = {
+ {.size = {100, 100}, .content_offset = {INT_MAX, 0}, .content_size = {1, 0}},
+ {.size = {100, 100}, .content_offset = {0, INT_MAX}, .content_size = {0, 1}},
+ {.size = {100, 100}, .content_offset = {1, 0}, .content_size = {INT_MAX, 0}},
+ {.size = {100, 100}, .content_offset = {0, 1}, .content_size = {0, INT_MAX}},
+ {.size = {100, 100}, .anchor = {INT_MIN, 0, 1, 1}},
+ {.size = {100, 100}, .anchor = {0, INT_MIN, 1, 1}},
+ };
+ for (size_t i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) {
+ assert(!yasl_surface_create_popup(&w.base, &specs[i]));
+ assert(!yasl_surface_popup_reposition(&w.base, &specs[i]));
+ }
+}
+
int main(void)
{
+ test_popup_bounds();
struct wayland_surface w = {0};
struct seat seat = {.ime_focus = &w};
wayland_surface_set_callbacks(&w, NULL, NULL);