summaryrefslogtreecommitdiff
path: root/tests/wayland/test_clipboard.c
blob: 0ee74b69033d6edb9969bf4e14e326fe87a7dfc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include "../../src/platform/wayland/clipboard.c"
#include "common/loop.h"
#include <assert.h>

struct received {
    int count;
    size_t len;
    uint64_t request_id;
    enum yasl_private_transfer_status status;
    struct clipboard *clipboard;
    bool forget_on_receive;
    char text[32];
};

static void receive(const char *text, size_t len, bool uri_list,
                    struct wl_surface *surface, uint64_t request_id,
                    enum yasl_private_transfer_status status, void *ud)
{
    (void)surface;
    struct received *r = ud;
    assert(!uri_list && len < sizeof(r->text));
    if (status == YASL_PRIVATE_TRANSFER_OK) {
        assert(text);
        memcpy(r->text, text, len);
        r->text[len] = '\0';
    } else {
        assert(!text && len == 0);
    }
    r->len = len;
    r->request_id = request_id;
    r->status = status;
    r->count++;
    if (r->forget_on_receive) {
        r->forget_on_receive = false;
        clipboard_forget_surface(r->clipboard, surface);
    }
}

int main(void)
{
    struct received received = {0};
    struct clipboard c = {.loop = yasl_private_loop_create(), .receive = receive, .ud = &received};
    received.clipboard = &c;
    assert(c.loop);
    const struct { const char *bytes; size_t len; bool valid; } cases[] = {
        {"é字😀", sizeof("é字😀") - 1, true},
        {"", 0, true},
        {"\xff", 1, false},
        {"\xf0\x9f\x98", 3, false}, /* Incomplete non-BMP character. */
    };
    for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
        received = (struct received){0};
        received.clipboard = &c;
        int fds[2];
        assert(pipe(fds) == 0);
        struct transfer *transfer = start_transfer_text(&c, fds[0], false, false, c.text);
        assert(transfer);
        yasl_private_timer_id timeout_id = transfer->timeout;
        assert(timeout_id && yasl_private_loop_timer_armed(c.loop, timeout_id));
        transfer->paste = true;
        transfer->request_id = 42;
        assert(write(fds[1], cases[i].bytes, cases[i].len) == (ssize_t)cases[i].len);
        close(fds[1]);
        for (int steps = 0; c.transfers && steps < 10; steps++)
            assert(yasl_private_loop_step(c.loop, 0) >= 0);
        assert(!c.transfers);
        assert(!yasl_private_loop_timer_armed(c.loop, timeout_id));
        assert(received.count == 1);
        assert(received.request_id == 42);
        assert(received.status == (cases[i].valid ? YASL_PRIVATE_TRANSFER_OK : YASL_PRIVATE_TRANSFER_FAILED));
        if (cases[i].valid) {
            assert(received.len == cases[i].len);
            assert(memcmp(received.text, cases[i].bytes, received.len) == 0);
        }
    }
    received = (struct received){0};
    received.clipboard = &c;
    int cancel_fds[2];
    assert(pipe(cancel_fds) == 0);
    struct transfer *pending = start_transfer_text(&c, cancel_fds[0], false, false, NULL);
    assert(pending);
    yasl_private_timer_id cancel_timeout_id = pending->timeout;
    assert(cancel_timeout_id && yasl_private_loop_timer_armed(c.loop, cancel_timeout_id));
    pending->paste = true;
    pending->request_id = 99;
    struct wl_surface *target = (struct wl_surface *)(uintptr_t)1;
    pending->drop_surface = target;
    clipboard_forget_surface(&c, target);
    close(cancel_fds[1]);
    assert(!c.transfers && received.count == 0);
    assert(!yasl_private_loop_timer_armed(c.loop, cancel_timeout_id));

    received.forget_on_receive = true;
    int timeout_fds[2];
    assert(pipe(timeout_fds) == 0);
    struct transfer *timed = start_transfer_text(&c, timeout_fds[0], false, false, NULL);
    assert(timed && timed->timeout);
    timed->paste = true;
    timed->request_id = 100;
    struct wl_surface *timeout_target = (struct wl_surface *)(uintptr_t)2;
    timed->drop_surface = timeout_target;
    yasl_private_timer_id timeout_id = timed->timeout;
    assert(yasl_private_loop_del_timer(c.loop, timeout_id));
    (void)transfer_timeout(timed, timeout_id, CLIPBOARD_TRANSFER_TIMEOUT_NS);
    close(timeout_fds[1]);
    assert(!c.transfers && received.count == 1);
    assert(received.request_id == 100 && received.status == YASL_PRIVATE_TRANSFER_FAILED);
    yasl_private_loop_destroy(c.loop);
    return 0;
}