summaryrefslogtreecommitdiff
path: root/tests/common
diff options
context:
space:
mode:
Diffstat (limited to 'tests/common')
-rw-r--r--tests/common/test_gl.c19
-rw-r--r--tests/common/test_loop.c45
-rw-r--r--tests/common/test_surface_integration.c46
3 files changed, 108 insertions, 2 deletions
diff --git a/tests/common/test_gl.c b/tests/common/test_gl.c
index 1bb5bec..0b91bff 100644
--- a/tests/common/test_gl.c
+++ b/tests/common/test_gl.c
@@ -146,6 +146,25 @@ int main(int argc, char **argv)
clear(GL_COLOR_BUFFER_BIT_);
REQUIRE((yasl_gl_present(primary) == 0), "swap resized GL surface");
+ /* An animation that asks for each next frame gets one REFRESH per frame
+ * shown, even though GL surfaces also get a REFRESH when a frame is shown. */
+ REQUIRE(yasl_surface_request_frame(primary) == 0, "request a frame");
+ int frames = 0;
+ double animation_end = seconds_now() + 1.0;
+ while (seconds_now() < animation_end) {
+ yasl_event event = {0};
+ int result = yasl_wait_event(&event, 50);
+ REQUIRE(result >= 0, "wait during animation");
+ if (result == 0 || event.type != YASL_EVENT_REFRESH || event.surface != primary)
+ continue;
+ frames++;
+ REQUIRE(yasl_surface_request_frame(primary) == 0, "request the next frame");
+ clear(GL_COLOR_BUFFER_BIT_);
+ REQUIRE(yasl_gl_present(primary) == 0, "present an animation frame");
+ }
+ fprintf(stderr, "%d REFRESH events in 1 s of GL animation\n", frames);
+ REQUIRE(frames >= 20 && frames <= 75, "one REFRESH per frame shown");
+
REQUIRE(yasl_surface_create(&(struct yasl_surface_options){.title="invalid attrs", .width=100, .height=100, .type=YASL_SURFACE_GL, .gl = {.major = -1}}) == NULL && errno == EINVAL,
"reject invalid GL context options");
cpu = yasl_surface_create(&(struct yasl_surface_options){.title="CPU surface", .width=100, .height=100});
diff --git a/tests/common/test_loop.c b/tests/common/test_loop.c
index bdc33b7..a77b6a5 100644
--- a/tests/common/test_loop.c
+++ b/tests/common/test_loop.c
@@ -237,6 +237,47 @@ static void test_signals(void)
sigaction(SIGUSR2, &dfl, NULL);
}
+struct order_log {
+ char order[8];
+ int count;
+};
+
+static void order_signal(void *ud, int signo)
+{
+ (void)signo;
+ struct order_log *log = ud;
+ log->order[log->count++] = 's';
+}
+
+static void order_fd(void *ud, int fd, short revents)
+{
+ (void)revents;
+ struct order_log *log = ud;
+ char b;
+ assert(read(fd, &b, 1) == 1);
+ log->order[log->count++] = 'f';
+}
+
+/* A signal runs after the descriptors of its step, so a child's last output
+ * is read before its exit is handled. */
+static void test_signal_order(void)
+{
+ yasl_loop *l = yasl_loop_create();
+ assert(l);
+ struct order_log log = {0};
+ assert(yasl_loop_watch_signals(l, (const int[]){SIGUSR1}, 1, order_signal, &log) == 0);
+ int p[2];
+ assert(pipe(p) == 0);
+ assert(yasl_loop_add_fd(l, p[0], POLLIN, order_fd, &log) > 0);
+ assert(write(p[1], "x", 1) == 1);
+ raise(SIGUSR1);
+ assert(yasl_loop_step(l, 0) >= 1);
+ assert(log.count == 2 && memcmp(log.order, "fs", 2) == 0);
+ close(p[0]);
+ close(p[1]);
+ assert(yasl_loop_destroy(l) == 0);
+}
+
struct fd_log {
int calls;
short revents;
@@ -364,7 +405,8 @@ static void test_interrupted_wait(void)
assert(yasl_loop_step(l, 100) == 0);
uint64_t elapsed_ms = (yasl_time_ns() - start) / 1000000u;
pthread_join(t, NULL);
- assert(elapsed_ms >= 90 && elapsed_ms < 140);
+ /* Lateness under load is not the bug; an early return is. */
+ assert(elapsed_ms >= 90 && elapsed_ms < 1000);
assert(yasl_loop_destroy(l) == 0);
sigaction(SIGUSR2, &old, NULL);
}
@@ -376,6 +418,7 @@ int main(void)
test_post_order();
test_cross_thread();
test_signals();
+ test_signal_order();
test_fds();
test_reentry_and_quit();
test_interrupted_wait();
diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c
index 7862bfc..6946cf9 100644
--- a/tests/common/test_surface_integration.c
+++ b/tests/common/test_surface_integration.c
@@ -37,7 +37,8 @@ static void *wrong_thread(void *data)
struct callback_state {
yasl_loop *loop;
yasl_surface *window;
- int refreshes;
+ int refreshes, resizes, refreshes_at_resize, final_losses;
+ bool animating;
int wait_result, shutdown_result;
yasl_surface *made;
int made_destroy;
@@ -45,8 +46,18 @@ struct callback_state {
static void on_event(void *userdata, const yasl_event *e)
{
struct callback_state *st = userdata;
+ if (e->type == YASL_EVENT_DISPLAY_LOST && e->action == YASL_LOST_FINAL)
+ st->final_losses++;
+ if (e->type == YASL_EVENT_WINDOW && e->surface == st->window &&
+ e->window.width == 120 && e->window.height == 80) {
+ st->resizes++;
+ st->refreshes_at_resize = st->refreshes;
+ }
if (e->type == YASL_EVENT_REFRESH && e->surface == st->window) {
st->refreshes++;
+ /* An animation asks for its next frame before it presents this one. */
+ if (st->animating)
+ assert(yasl_surface_request_frame(e->surface) == 0);
int w = 0, h = 0;
uint32_t *pixels = yasl_cpu_pixels(e->surface, &w, &h);
assert(pixels && w > 0 && h > 0);
@@ -111,6 +122,32 @@ static void test_callback_mode(enum yasl_backend backend)
assert(yasl_loop_step(st.loop, 25) >= 0);
assert(st.refreshes == before + 1);
+ /* The frame an animation presents after its request is the frame the
+ * request waits for: one REFRESH per display refresh, not two. */
+ st.animating = true;
+ assert(yasl_surface_request_frame(st.window) == 0);
+ before = st.refreshes;
+ uint64_t start = yasl_time_ns();
+ while (yasl_time_ns() - start < 1000000000ull)
+ assert(yasl_loop_step(st.loop, 50) >= 0);
+ st.animating = false;
+ int frames = st.refreshes - before;
+ fprintf(stderr, "%d REFRESH events in 1 s of animation\n", frames);
+ assert(frames >= 20 && frames <= 75);
+
+ /* A resize owes one REFRESH, after its WINDOW event. */
+ for (int i = 0; i < 6; i++)
+ assert(yasl_loop_step(st.loop, 25) >= 0);
+ before = st.refreshes;
+ assert(yasl_surface_request_size(st.window, 120, 80) == 0);
+ step_until(&st, &st.resizes, 1);
+ for (int i = 0; i < 8; i++)
+ assert(yasl_loop_step(st.loop, 25) >= 0);
+ fprintf(stderr, "%d REFRESH events for one resize, %d before its WINDOW event\n",
+ st.refreshes - before, st.refreshes_at_resize - before);
+ assert(st.resizes == 1 && st.refreshes_at_resize == before);
+ assert(st.refreshes == before + 1);
+
/* An idle loop waits instead of spinning. */
int steps = 0;
uint64_t end = yasl_time_ns() + 300000000ull;
@@ -125,6 +162,13 @@ static void test_callback_mode(enum yasl_backend backend)
assert(yasl_loop_step(st.loop, 50) >= 0);
assert(st.made_destroy == 0);
+ /* A lost event ends the session: on_event hears it as a final loss. A
+ * string event with no text cannot be queued. */
+ struct yasl_private_event broken = {.type = YASL_PRIVATE_EVENT_PASTE, .surface = st.window,
+ .text = {NULL, 1}};
+ assert(!yasl_private_events_push(st.window->display, st.window, &broken));
+ step_until(&st, &st.final_losses, 1);
+
assert(yasl_loop_add_timer(st.loop, YASL_PRIVATE_MS_TO_NS(10), quit_in_timer, st.loop));
assert(yasl_loop_run(st.loop) == 0);
assert(yasl_shutdown() == 0);