summaryrefslogtreecommitdiff
path: root/hyprtester/src/tests/main/hyprctl.cpp
blob: c67c8af9336258873376e5222ca9f8606ee60698 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "tests.hpp"
#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include <cstdint>
#include <print>
#include <string>
#include <thread>
#include <chrono>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
#include <csignal>
#include <cerrno>
#include "../shared.hpp"

using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;

#define UP CUniquePointer
#define SP CSharedPointer

static std::string getCommandStdOut(std::string command) {
    CProcess process("bash", {"-c", command});
    process.addEnv("HYPRLAND_INSTANCE_SIGNATURE", HIS);
    process.runSync();

    const std::string& stdOut = process.stdOut();

    // Remove trailing new line
    return stdOut.substr(0, stdOut.length() - 1);
}

static void setWindowProp(const std::string& selector, const std::string& prop, const std::string& value) {
    getFromSocket("/dispatch hl.dsp.window.set_prop({ window = '" + selector + "', prop = '" + prop + "', value = '" + value + "' })");
}

TEST_CASE(hyprctlDevicesActiveLayoutIndex) {
    // configure layouts
    OK(getFromSocket("r/eval hl.config({ input = { kb_layout = \"us,pl,ua\" } })"));

    for (uint8_t i = 0; i < 3; i++) {
        // set layout
        getFromSocket("/switchxkblayout all " + std::to_string(i));
        std::string devicesJson = getFromSocket("j/devices");
        std::string expected    = R"("active_layout_index": )" + std::to_string(i);
        // check layout index
        EXPECT_CONTAINS(devicesJson, expected);
    }
}

TEST_CASE(hyprctlGetprop) {
    if (!Tests::spawnKitty()) {
        FAIL_TEST("Could not spawn kitty");
    }

    // animation
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty animation"), "(unset)");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty animation -j"), R"({"animation": ""})");
    setWindowProp("class:kitty", "animation", "teststyle");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty animation"), "teststyle");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty animation -j"), R"({"animation": "teststyle"})");

    // max_size
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty max_size"), "inf inf");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty max_size -j"), R"({"max_size": [null,null]})");
    setWindowProp("class:kitty", "max_size", "200 150");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty max_size"), "200 150");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty max_size -j"), R"({"max_size": [200,150]})");

    // min_size
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty min_size"), "20 20");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty min_size -j"), R"({"min_size": [20,20]})");
    setWindowProp("class:kitty", "min_size", "100 50");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty min_size"), "100 50");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty min_size -j"), R"({"min_size": [100,50]})");

    // expr-based min/max _size
    getFromSocket("/dispatch hl.dsp.window.float({ action = 'set', window = 'class:kitty' })"); // need to set floating for tests below
    setWindowProp("class:kitty", "max_size", "90+10 25*2");                                     // set max to the same as min above, forcing window to 100*50
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty max_size"), "100 50");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty max_size -j"), R"({"max_size": [100,50]})");
    setWindowProp("class:kitty", "min_size", "window_w*0.5 window_h-10");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty min_size"), "50 40");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty min_size -j"), R"({"min_size": [50,40]})");
    getFromSocket("/dispatch hl.dsp.window.float({ action = 'unset', window = 'class:kitty' })"); // go back to tiled for consistency

    // opacity
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity"), "1");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity -j"), R"({"opacity": 1})");
    setWindowProp("class:kitty", "opacity", "0.3");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity"), "0.3");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity -j"), R"({"opacity": 0.3})");

    // opacity_inactive
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive"), "1");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive -j"), R"({"opacity_inactive": 1})");
    setWindowProp("class:kitty", "opacity_inactive", "0.5");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive"), "0.5");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive -j"), R"({"opacity_inactive": 0.5})");

    // opacity_fullscreen
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen"), "1");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen -j"), R"({"opacity_fullscreen": 1})");
    setWindowProp("class:kitty", "opacity_fullscreen", "0.75");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen"), "0.75");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen -j"), R"({"opacity_fullscreen": 0.75})");

    // opacity_override
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_override"), "false");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_override -j"), R"({"opacity_override": false})");
    setWindowProp("class:kitty", "opacity_override", "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_override"), "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_override -j"), R"({"opacity_override": true})");

    // opacity_inactive_override
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive_override"), "false");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive_override -j"), R"({"opacity_inactive_override": false})");
    setWindowProp("class:kitty", "opacity_inactive_override", "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive_override"), "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_inactive_override -j"), R"({"opacity_inactive_override": true})");

    // opacity_fullscreen_override
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen_override"), "false");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen_override -j"), R"({"opacity_fullscreen_override": false})");
    setWindowProp("class:kitty", "opacity_fullscreen_override", "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen_override"), "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty opacity_fullscreen_override -j"), R"({"opacity_fullscreen_override": true})");

    // active_border_color
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty active_border_color"), "ee33ccff ee00ff99 45deg");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty active_border_color -j"), R"({"active_border_color": "ee33ccff ee00ff99 45deg"})");
    setWindowProp("class:kitty", "active_border_color", "rgb(abcdef)");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty active_border_color"), "ffabcdef 0deg");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty active_border_color -j"), R"({"active_border_color": "ffabcdef 0deg"})");

    // bool window properties
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty allows_input"), "false");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty allows_input -j"), R"({"allows_input": false})");
    setWindowProp("class:kitty", "allows_input", "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty allows_input"), "true");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty allows_input -j"), R"({"allows_input": true})");

    // int window properties
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding"), "10");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding -j"), R"({"rounding": 10})");
    setWindowProp("class:kitty", "rounding", "4");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding"), "4");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding -j"), R"({"rounding": 4})");

    // float window properties
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding_power"), "2");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding_power -j"), R"({"rounding_power": 2})");
    setWindowProp("class:kitty", "rounding_power", "1.25");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding_power"), "1.25");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty rounding_power -j"), R"({"rounding_power": 1.25})");

    // errors
    EXPECT(getCommandStdOut("hyprctl getprop"), "not enough args");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty"), "not enough args");
    EXPECT(getCommandStdOut("hyprctl getprop class:nonexistantclass animation"), "window not found");
    EXPECT(getCommandStdOut("hyprctl getprop class:kitty nonexistantprop"), "prop not found");
}

TEST_CASE(hyprctlSubmap) {
    EXPECT(getCommandStdOut("hyprctl submap"), "default\n");
    EXPECT(getCommandStdOut("hyprctl submap -j | jq -r \".\""), "default");
}

TEST_CASE(hyprctlJsonErrors) {
    CProcess jqProc("bash", {"-c", "hyprctl descriptions | jq"});
    jqProc.addEnv("HYPRLAND_INSTANCE_SIGNATURE", HIS);
    jqProc.runSync();
    EXPECT(jqProc.exitCode(), 0);
}