Merge pull request #3345 from khaneliman/testing

Organize tests and start Hyprland testing
This commit is contained in:
Alexis Rouillard 2024-06-10 21:38:01 +02:00 committed by GitHub
commit 0251e25f23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 259 additions and 40 deletions

View File

@ -9,6 +9,7 @@ concurrency:
jobs: jobs:
build: build:
strategy: strategy:
fail-fast: false
matrix: matrix:
distro: distro:
- alpine - alpine

View File

@ -6,4 +6,4 @@ RUN zypper -n up && \
zypper addrepo https://download.opensuse.org/repositories/X11:Wayland/openSUSE_Tumbleweed/X11:Wayland.repo | echo 'a' && \ zypper addrepo https://download.opensuse.org/repositories/X11:Wayland/openSUSE_Tumbleweed/X11:Wayland.repo | echo 'a' && \
zypper -n refresh && \ zypper -n refresh && \
zypper -n install -t pattern devel_C_C++ && \ zypper -n install -t pattern devel_C_C++ && \
zypper -n install git meson clang libinput10 libinput-devel pugixml-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel libxkbregistry-devel scdoc playerctl-devel zypper -n install git meson clang libinput10 libinput-devel pugixml-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel libxkbregistry-devel scdoc playerctl-devel python3-packaging

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <filesystem>
#include <list> #include <list>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
@ -25,6 +26,10 @@ class IPC {
static std::string getSocket1Reply(const std::string& rq); static std::string getSocket1Reply(const std::string& rq);
Json::Value getSocket1JsonReply(const std::string& rq); Json::Value getSocket1JsonReply(const std::string& rq);
static std::filesystem::path getSocketFolder(const char* instanceSig);
protected:
static std::filesystem::path socketFolder_;
private: private:
void startIPC(); void startIPC();

View File

@ -100,7 +100,7 @@ class Workspaces : public AModule, public EventHandler {
void removeWorkspacesToRemove(); void removeWorkspacesToRemove();
void createWorkspacesToCreate(); void createWorkspacesToCreate();
std::vector<std::string> getVisibleWorkspaces(); std::vector<std::string> getVisibleWorkspaces();
void updateWorkspaceStates(const std::vector<std::string>& visibleWorkspaces); void updateWorkspaceStates();
bool updateWindowsToCreate(); bool updateWindowsToCreate();
void extendOrphans(int workspaceId, Json::Value const& clientsJson); void extendOrphans(int workspaceId, Json::Value const& clientsJson);

View File

@ -15,22 +15,31 @@
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
std::filesystem::path getSocketFolder(const char* instanceSig) { std::filesystem::path IPC::socketFolder_;
std::filesystem::path IPC::getSocketFolder(const char* instanceSig) {
// socket path, specified by EventManager of Hyprland // socket path, specified by EventManager of Hyprland
static std::filesystem::path socketFolder; if (!socketFolder_.empty()) {
if (!socketFolder.empty()) { spdlog::warn("socketFolder already set, using {}", socketFolder_.c_str());
return socketFolder; return socketFolder_;
}
const char* xdgRuntimeDirEnv = std::getenv("XDG_RUNTIME_DIR");
std::filesystem::path xdgRuntimeDir;
// Only set path if env variable is set
if (xdgRuntimeDirEnv) {
xdgRuntimeDir = std::filesystem::path(xdgRuntimeDirEnv);
} }
std::filesystem::path xdgRuntimeDir = std::filesystem::path(getenv("XDG_RUNTIME_DIR"));
if (!xdgRuntimeDir.empty() && std::filesystem::exists(xdgRuntimeDir / "hypr")) { if (!xdgRuntimeDir.empty() && std::filesystem::exists(xdgRuntimeDir / "hypr")) {
socketFolder = xdgRuntimeDir / "hypr"; socketFolder_ = xdgRuntimeDir / "hypr";
} else { } else {
spdlog::warn("$XDG_RUNTIME_DIR/hypr does not exist, falling back to /tmp/hypr"); spdlog::warn("$XDG_RUNTIME_DIR/hypr does not exist, falling back to /tmp/hypr");
socketFolder = std::filesystem::path("/tmp") / "hypr"; socketFolder_ = std::filesystem::path("/tmp") / "hypr";
} }
socketFolder = socketFolder / instanceSig;
return socketFolder; socketFolder_ = socketFolder_ / instanceSig;
return socketFolder_;
} }
void IPC::startIPC() { void IPC::startIPC() {
@ -59,7 +68,7 @@ void IPC::startIPC() {
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
auto socketPath = getSocketFolder(his) / ".socket2.sock"; auto socketPath = IPC::getSocketFolder(his) / ".socket2.sock";
strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
addr.sun_path[sizeof(addr.sun_path) - 1] = 0; addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
@ -169,7 +178,7 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
sockaddr_un serverAddress = {0}; sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX; serverAddress.sun_family = AF_UNIX;
std::string socketPath = getSocketFolder(instanceSig) / ".socket.sock"; std::string socketPath = IPC::getSocketFolder(instanceSig) / ".socket.sock";
// Use snprintf to copy the socketPath string into serverAddress.sun_path // Use snprintf to copy the socketPath string into serverAddress.sun_path
if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) < if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) <

View File

@ -128,10 +128,7 @@ void Workspaces::doUpdate() {
removeWorkspacesToRemove(); removeWorkspacesToRemove();
createWorkspacesToCreate(); createWorkspacesToCreate();
updateWorkspaceStates();
std::vector<std::string> visibleWorkspaces = getVisibleWorkspaces();
updateWorkspaceStates(visibleWorkspaces);
updateWindowCount(); updateWindowCount();
sortWorkspaces(); sortWorkspaces();
@ -870,7 +867,8 @@ bool Workspaces::updateWindowsToCreate() {
return anyWindowCreated; return anyWindowCreated;
} }
void Workspaces::updateWorkspaceStates(const std::vector<std::string> &visibleWorkspaces) { void Workspaces::updateWorkspaceStates() {
const std::vector<std::string> visibleWorkspaces = getVisibleWorkspaces();
auto updatedWorkspaces = gIPC->getSocket1JsonReply("workspaces"); auto updatedWorkspaces = gIPC->getSocket1JsonReply("workspaces");
for (auto &workspace : m_workspaces) { for (auto &workspace : m_workspaces) {
workspace->setActive(workspace->name() == m_activeWorkspaceName || workspace->setActive(workspace->name() == m_activeWorkspaceName ||

View File

@ -506,9 +506,7 @@ void Workspaces::onButtonReady(const Json::Value &node, Gtk::Button &button) {
// check if any of its nodes are focused as well. // check if any of its nodes are focused as well.
bool focused = node["focused"].asBool() || bool focused = node["focused"].asBool() ||
std::any_of(node["nodes"].begin(), node["nodes"].end(), std::any_of(node["nodes"].begin(), node["nodes"].end(),
[](const auto &child) { [](const auto &child) { return child["focused"].asBool(); });
return child["focused"].asBool();
});
if (focused) { if (focused) {
button.show(); button.show();

View File

@ -1,12 +1,13 @@
[wrap-file] [wrap-file]
directory = spdlog-1.11.0 directory = spdlog-1.12.0
source_url = https://github.com/gabime/spdlog/archive/v1.11.0.tar.gz source_url = https://github.com/gabime/spdlog/archive/refs/tags/v1.12.0.tar.gz
source_filename = v1.11.0.tar.gz source_filename = spdlog-1.12.0.tar.gz
source_hash = ca5cae8d6cac15dae0ec63b21d6ad3530070650f68076f3a4a862ca293a858bb source_hash = 4dccf2d10f410c1e2feaff89966bfc49a1abb29ef6f08246335b110e001e09a9
patch_filename = spdlog_1.11.0-2_patch.zip patch_filename = spdlog_1.12.0-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.11.0-2/get_patch patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.12.0-2/get_patch
patch_hash = db1364fe89502ac67f245a6c8c51290a52afd74a51eed26fa9ecb5b3443df57a patch_hash = 9596972d1eb2e0a69cea4a53273ca7bbbcb9b2fa872cd734864fc7232dc2d573
wrapdb_version = 1.11.0-2 source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/spdlog_1.12.0-2/spdlog-1.12.0.tar.gz
wrapdb_version = 1.12.0-2
[provide] [provide]
spdlog = spdlog_dep spdlog = spdlog_dep

View File

@ -117,3 +117,42 @@ TEST_CASE("Load multiple bar config with include", "[config]") {
REQUIRE(data.size() == 4); REQUIRE(data.size() == 4);
REQUIRE(data[0]["output"].asString() == "OUT-0"); REQUIRE(data[0]["output"].asString() == "OUT-0");
} }
TEST_CASE("Load Hyprland Workspaces bar config", "[config]") {
waybar::Config conf;
conf.load("test/config/hyprland-workspaces.json");
auto& data = conf.getConfig();
auto hyprland = data[0]["hyprland/workspaces"];
auto hyprland_window_rewrite = data[0]["hyprland/workspaces"]["window-rewrite"];
auto hyprland_format_icons = data[0]["hyprland/workspaces"]["format-icons"];
auto hyprland_persistent_workspaces = data[0]["hyprland/workspaces"]["persistent-workspaces"];
REQUIRE(data.isArray());
REQUIRE(data.size() == 1);
REQUIRE(data[0]["height"].asInt() == 20);
REQUIRE(data[0]["layer"].asString() == "bottom");
REQUIRE(data[0]["output"].isArray());
REQUIRE(data[0]["output"][0].asString() == "HDMI-0");
REQUIRE(data[0]["output"][1].asString() == "DP-0");
REQUIRE(hyprland["active-only"].asBool() == true);
REQUIRE(hyprland["all-outputs"].asBool() == false);
REQUIRE(hyprland["move-to-monitor"].asBool() == true);
REQUIRE(hyprland["format"].asString() == "{icon} {windows}");
REQUIRE(hyprland["format-window-separator"].asString() == " ");
REQUIRE(hyprland["on-scroll-down"].asString() == "hyprctl dispatch workspace e-1");
REQUIRE(hyprland["on-scroll-up"].asString() == "hyprctl dispatch workspace e+1");
REQUIRE(hyprland["show-special"].asBool() == true);
REQUIRE(hyprland["window-rewrite-default"].asString() == "");
REQUIRE(hyprland["window-rewrite-separator"].asString() == " ");
REQUIRE(hyprland_format_icons["1"].asString() == "󰎤");
REQUIRE(hyprland_format_icons["2"].asString() == "󰎧");
REQUIRE(hyprland_format_icons["3"].asString() == "󰎪");
REQUIRE(hyprland_format_icons["default"].asString() == "");
REQUIRE(hyprland_format_icons["empty"].asString() == "󱓼");
REQUIRE(hyprland_format_icons["urgent"].asString() == "󱨇");
REQUIRE(hyprland_persistent_workspaces["1"].asString() == "HDMI-0");
REQUIRE(hyprland_window_rewrite["title<Steam>"].asString() == "");
REQUIRE(hyprland["sort-by"].asString() == "number");
}

View File

@ -0,0 +1,37 @@
[
{
"height": 20,
"layer": "bottom",
"output": [
"HDMI-0",
"DP-0"
],
"hyprland/workspaces": {
"active-only": true,
"all-outputs": false,
"show-special": true,
"move-to-monitor": true,
"format": "{icon} {windows}",
"format-window-separator": " ",
"format-icons": {
"1": "󰎤",
"2": "󰎧",
"3": "󰎪",
"default": "",
"empty": "󱓼",
"urgent": "󱨇"
},
"persistent-workspaces": {
"1": "HDMI-0"
},
"on-scroll-down": "hyprctl dispatch workspace e-1",
"on-scroll-up": "hyprctl dispatch workspace e+1",
"window-rewrite": {
"title<Steam>": ""
},
"window-rewrite-default": "",
"window-rewrite-separator": " ",
"sort-by": "number"
}
}
]

55
test/hyprland/backend.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <cstdlib>
#if __has_include(<catch2/catch_test_macros.hpp>)
#include <catch2/catch_test_macros.hpp>
#else
#include <catch2/catch.hpp>
#endif
#include "fixtures/IPCTestFixture.hpp"
#include "modules/hyprland/backend.hpp"
namespace fs = std::filesystem;
namespace hyprland = waybar::modules::hyprland;
TEST_CASE_METHOD(IPCTestFixture, "XDGRuntimeDirExists", "[getSocketFolder]") {
// Test case: XDG_RUNTIME_DIR exists and contains "hypr" directory
// Arrange
tempDir = fs::temp_directory_path() / "hypr_test/run/user/1000";
fs::path expectedPath = tempDir / "hypr" / instanceSig;
fs::create_directories(tempDir / "hypr" / instanceSig);
setenv("XDG_RUNTIME_DIR", tempDir.c_str(), 1);
// Act
fs::path actualPath = getSocketFolder(instanceSig);
// Assert expected result
REQUIRE(actualPath == expectedPath);
}
TEST_CASE_METHOD(IPCTestFixture, "XDGRuntimeDirDoesNotExist", "[getSocketFolder]") {
// Test case: XDG_RUNTIME_DIR does not exist
// Arrange
unsetenv("XDG_RUNTIME_DIR");
fs::path expectedPath = fs::path("/tmp") / "hypr" / instanceSig;
// Act
fs::path actualPath = getSocketFolder(instanceSig);
// Assert expected result
REQUIRE(actualPath == expectedPath);
}
TEST_CASE_METHOD(IPCTestFixture, "XDGRuntimeDirExistsNoHyprDir", "[getSocketFolder]") {
// Test case: XDG_RUNTIME_DIR exists but does not contain "hypr" directory
// Arrange
fs::path tempDir = fs::temp_directory_path() / "hypr_test/run/user/1000";
fs::create_directories(tempDir);
setenv("XDG_RUNTIME_DIR", tempDir.c_str(), 1);
fs::path expectedPath = fs::path("/tmp") / "hypr" / instanceSig;
// Act
fs::path actualPath = getSocketFolder(instanceSig);
// Assert expected result
REQUIRE(actualPath == expectedPath);
}

View File

@ -0,0 +1,16 @@
#include "modules/hyprland/backend.hpp"
namespace fs = std::filesystem;
namespace hyprland = waybar::modules::hyprland;
class IPCTestFixture : public hyprland::IPC {
public:
IPCTestFixture() : IPC() { IPC::socketFolder_ = ""; }
~IPCTestFixture() { fs::remove_all(tempDir); }
protected:
const char* instanceSig = "instance_sig";
fs::path tempDir = fs::temp_directory_path() / "hypr_test";
private:
};

28
test/hyprland/meson.build Normal file
View File

@ -0,0 +1,28 @@
test_inc = include_directories('../../include')
test_dep = [
catch2,
fmt,
gtkmm,
jsoncpp,
spdlog,
]
test_src = files(
'../main.cpp',
'backend.cpp',
'../../src/modules/hyprland/backend.cpp'
)
hyprland_test = executable(
'hyprland_test',
test_src,
dependencies: test_dep,
include_directories: test_inc,
)
test(
'hyprland',
hyprland_test,
workdir: meson.project_source_root(),
)

View File

@ -1,4 +1,5 @@
test_inc = include_directories('../include') test_inc = include_directories('../include')
test_dep = [ test_dep = [
catch2, catch2,
fmt, fmt,
@ -6,21 +7,13 @@ test_dep = [
jsoncpp, jsoncpp,
spdlog, spdlog,
] ]
test_src = files( test_src = files(
'main.cpp', 'main.cpp',
'JsonParser.cpp',
'SafeSignal.cpp',
'config.cpp', 'config.cpp',
'css_reload_helper.cpp',
'../src/config.cpp', '../src/config.cpp',
'../src/util/css_reload_helper.cpp',
) )
if tz_dep.found()
test_dep += tz_dep
test_src += files('date.cpp')
endif
waybar_test = executable( waybar_test = executable(
'waybar_test', 'waybar_test',
test_src, test_src,
@ -33,3 +26,6 @@ test(
waybar_test, waybar_test,
workdir: meson.project_source_root(), workdir: meson.project_source_root(),
) )
subdir('utils')
subdir('hyprland')

View File

@ -10,7 +10,7 @@
#include <thread> #include <thread>
#include <type_traits> #include <type_traits>
#include "GlibTestsFixture.hpp" #include "fixtures/GlibTestsFixture.hpp"
using namespace waybar; using namespace waybar;

36
test/utils/meson.build Normal file
View File

@ -0,0 +1,36 @@
test_inc = include_directories('../../include')
test_dep = [
catch2,
fmt,
gtkmm,
jsoncpp,
spdlog,
]
test_src = files(
'../main.cpp',
'../config.cpp',
'../../src/config.cpp',
'JsonParser.cpp',
'SafeSignal.cpp',
'css_reload_helper.cpp',
'../../src/util/css_reload_helper.cpp',
)
if tz_dep.found()
test_dep += tz_dep
test_src += files('date.cpp')
endif
utils_test = executable(
'utils_test',
test_src,
dependencies: test_dep,
include_directories: test_inc,
)
test(
'utils',
utils_test,
workdir: meson.project_source_root(),
)