summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/tests/test_kernel.cpp
blob: 6f8ce9bdb609e2ad2fd5fcbdce9bfbd7f435b7fd (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
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

#include <unbox/kernel/kernel.hpp>
#include <unbox/kernel/server.hpp>

#include <cstdlib>

TEST_CASE("kernel compiles against and links wlroots + libwayland-server") {
    CHECK(unbox::kernel::link_probe());
    CHECK(unbox::kernel::wlroots_version().substr(0, 4) == "0.20");
}

TEST_CASE("vendored RMLUi subproject compiled and linked") {
    CHECK(!unbox::kernel::rmlui_version().empty());
}

TEST_CASE("server boots and shuts down on the headless backend") {
    // Headless backend + pixman renderer: no GPU, no parent session needed.
    setenv("WLR_BACKENDS", "headless", 1);
    setenv("WLR_RENDERER", "pixman", 1);

    auto server = unbox::kernel::Server::create({});
    CHECK(!server->socket_name().empty());
    for (int i = 0; i < 3; ++i) {
        CHECK(server->dispatch(10));
    }
    // Destruction runs the full tinywl shutdown sequence.
}

TEST_CASE("ui spike defaults off and is the slice-2 server") {
    setenv("WLR_BACKENDS", "headless", 1);
    setenv("WLR_RENDERER", "pixman", 1);

    auto server = unbox::kernel::Server::create({});
    CHECK(server->ui_spike_frame_count() == 0);
    for (int i = 0; i < 3; ++i) {
        CHECK(server->dispatch(10));
    }
    CHECK(server->ui_spike_frame_count() == 0);
}

TEST_CASE("ui spike boots, renders frames, and shuts down cleanly") {
    // Drive the RMLUi -> wlr_scene bridge on the headless backend with the
    // gles2 renderer so the real GL path is exercised (Plan A attempted,
    // Plan B as fallback). The headless backend uses an EGL render node; if
    // GL is unavailable the bridge disables itself gracefully and frame_count
    // stays 0 (asserted as the no-crash fallback). A headless output must be
    // created so the frame handler (which drives tick()) fires.
    setenv("WLR_BACKENDS", "headless", 1);
    setenv("WLR_RENDERER", "gles2", 1);
    setenv("WLR_HEADLESS_OUTPUTS", "1", 1);

    auto server = unbox::kernel::Server::create({.ui_spike = true});
    CHECK(!server->socket_name().empty());

    // Pump enough turns for the headless output to emit frames.
    for (int i = 0; i < 200; ++i) {
        CHECK(server->dispatch(10));
    }

    const int frames = server->ui_spike_frame_count();
    INFO("ui_spike_frame_count() = ", frames);
    // Either the bridge ran (frames advanced) or it disabled itself on a
    // headless box without a usable GL path. Both are acceptable; a crash is
    // not. Clean shutdown is exercised on destruction below.
    CHECK(frames >= 0);
}

TEST_CASE("ui spike submits an upright (non-flipped) buffer") {
    // Orientation regression guard. The spike document carries distinctive
    // solid bands at its top and bottom edges; on the CPU-readback (Plan B)
    // path the bridge inspects the SUBMITTED buffer and reports +1 if the top
    // band is in the top rows (upright), -1 if vertically flipped. GL's
    // bottom-left framebuffer origin vs the wlr_buffer top-first convention
    // makes the flip the default failure mode, so this must never silently
    // regress. Force the shm path so the readback exists; if GL is
    // unavailable the spike disables itself and orientation() returns 0
    // (skipped, not failed — same graceful-degrade contract as above).
    setenv("WLR_BACKENDS", "headless", 1);
    setenv("WLR_RENDERER", "gles2", 1);
    setenv("WLR_HEADLESS_OUTPUTS", "1", 1);
    setenv("UNBOX_UI_SPIKE_FORCE_SHM", "1", 1);

    auto server = unbox::kernel::Server::create({.ui_spike = true});
    for (int i = 0; i < 200; ++i) {
        CHECK(server->dispatch(10));
    }

    const int orient = server->ui_spike_orientation();
    INFO("ui_spike_orientation() = ", orient);
    // MUST NOT be flipped. +1 = upright (the bridge ran), 0 = indeterminate
    // (no GL path on this box). A flip (-1) is the bug and fails here.
    CHECK(orient != -1);
    if (server->ui_spike_frame_count() > 0) {
        // The shm bridge ran: orientation must be positively confirmed upright.
        CHECK(orient == 1);
    }

    unsetenv("UNBOX_UI_SPIKE_FORCE_SHM");
}