Merge pull request #3345 from khaneliman/testing
Organize tests and start Hyprland testing
This commit is contained in:
		
						commit
						0251e25f23
					
				|  | @ -9,6 +9,7 @@ concurrency: | |||
| jobs: | ||||
|   build: | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         distro: | ||||
|           - alpine | ||||
|  |  | |||
|  | @ -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 -n refresh && \ | ||||
|     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 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <filesystem> | ||||
| #include <list> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
|  | @ -25,6 +26,10 @@ class IPC { | |||
| 
 | ||||
|   static std::string getSocket1Reply(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: | ||||
|   void startIPC(); | ||||
|  |  | |||
|  | @ -100,7 +100,7 @@ class Workspaces : public AModule, public EventHandler { | |||
|   void removeWorkspacesToRemove(); | ||||
|   void createWorkspacesToCreate(); | ||||
|   std::vector<std::string> getVisibleWorkspaces(); | ||||
|   void updateWorkspaceStates(const std::vector<std::string>& visibleWorkspaces); | ||||
|   void updateWorkspaceStates(); | ||||
|   bool updateWindowsToCreate(); | ||||
| 
 | ||||
|   void extendOrphans(int workspaceId, Json::Value const& clientsJson); | ||||
|  |  | |||
|  | @ -15,22 +15,31 @@ | |||
| 
 | ||||
| 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
 | ||||
|   static std::filesystem::path socketFolder; | ||||
|   if (!socketFolder.empty()) { | ||||
|     return socketFolder; | ||||
|   if (!socketFolder_.empty()) { | ||||
|     spdlog::warn("socketFolder already set, using {}", socketFolder_.c_str()); | ||||
|     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")) { | ||||
|     socketFolder = xdgRuntimeDir / "hypr"; | ||||
|     socketFolder_ = xdgRuntimeDir / "hypr"; | ||||
|   } else { | ||||
|     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() { | ||||
|  | @ -59,7 +68,7 @@ void IPC::startIPC() { | |||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     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}; | ||||
|   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
 | ||||
|   if (snprintf(serverAddress.sun_path, sizeof(serverAddress.sun_path), "%s", socketPath.c_str()) < | ||||
|  |  | |||
|  | @ -128,10 +128,7 @@ void Workspaces::doUpdate() { | |||
| 
 | ||||
|   removeWorkspacesToRemove(); | ||||
|   createWorkspacesToCreate(); | ||||
| 
 | ||||
|   std::vector<std::string> visibleWorkspaces = getVisibleWorkspaces(); | ||||
| 
 | ||||
|   updateWorkspaceStates(visibleWorkspaces); | ||||
|   updateWorkspaceStates(); | ||||
|   updateWindowCount(); | ||||
|   sortWorkspaces(); | ||||
| 
 | ||||
|  | @ -870,7 +867,8 @@ bool Workspaces::updateWindowsToCreate() { | |||
|   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"); | ||||
|   for (auto &workspace : m_workspaces) { | ||||
|     workspace->setActive(workspace->name() == m_activeWorkspaceName || | ||||
|  |  | |||
|  | @ -505,10 +505,8 @@ void Workspaces::onButtonReady(const Json::Value &node, Gtk::Button &button) { | |||
|     // that the workspace itself isn't focused.  Therefore we need to
 | ||||
|     // check if any of its nodes are focused as well.
 | ||||
|     bool focused = node["focused"].asBool() || | ||||
|       std::any_of(node["nodes"].begin(), node["nodes"].end(), | ||||
|                   [](const auto &child) { | ||||
|                     return child["focused"].asBool(); | ||||
|                   }); | ||||
|                    std::any_of(node["nodes"].begin(), node["nodes"].end(), | ||||
|                                [](const auto &child) { return child["focused"].asBool(); }); | ||||
| 
 | ||||
|     if (focused) { | ||||
|       button.show(); | ||||
|  |  | |||
|  | @ -1,12 +1,13 @@ | |||
| [wrap-file] | ||||
| directory = spdlog-1.11.0 | ||||
| source_url = https://github.com/gabime/spdlog/archive/v1.11.0.tar.gz | ||||
| source_filename = v1.11.0.tar.gz | ||||
| source_hash = ca5cae8d6cac15dae0ec63b21d6ad3530070650f68076f3a4a862ca293a858bb | ||||
| patch_filename = spdlog_1.11.0-2_patch.zip | ||||
| patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.11.0-2/get_patch | ||||
| patch_hash = db1364fe89502ac67f245a6c8c51290a52afd74a51eed26fa9ecb5b3443df57a | ||||
| wrapdb_version = 1.11.0-2 | ||||
| directory = spdlog-1.12.0 | ||||
| source_url = https://github.com/gabime/spdlog/archive/refs/tags/v1.12.0.tar.gz | ||||
| source_filename = spdlog-1.12.0.tar.gz | ||||
| source_hash = 4dccf2d10f410c1e2feaff89966bfc49a1abb29ef6f08246335b110e001e09a9 | ||||
| patch_filename = spdlog_1.12.0-2_patch.zip | ||||
| patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.12.0-2/get_patch | ||||
| patch_hash = 9596972d1eb2e0a69cea4a53273ca7bbbcb9b2fa872cd734864fc7232dc2d573 | ||||
| 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] | ||||
| spdlog = spdlog_dep | ||||
|  |  | |||
|  | @ -117,3 +117,42 @@ TEST_CASE("Load multiple bar config with include", "[config]") { | |||
|   REQUIRE(data.size() == 4); | ||||
|   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"); | ||||
| } | ||||
|  |  | |||
|  | @ -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" | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|  | @ -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); | ||||
| } | ||||
|  | @ -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: | ||||
| }; | ||||
|  | @ -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(), | ||||
| ) | ||||
|  | @ -1,4 +1,5 @@ | |||
| test_inc = include_directories('../include') | ||||
| 
 | ||||
| test_dep = [ | ||||
|     catch2, | ||||
|     fmt, | ||||
|  | @ -6,21 +7,13 @@ test_dep = [ | |||
|     jsoncpp, | ||||
|     spdlog, | ||||
| ] | ||||
| 
 | ||||
| test_src = files( | ||||
|     'main.cpp', | ||||
|     'JsonParser.cpp', | ||||
|     'SafeSignal.cpp', | ||||
|     'config.cpp', | ||||
|     'css_reload_helper.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', | ||||
|     test_src, | ||||
|  | @ -33,3 +26,6 @@ test( | |||
|     waybar_test, | ||||
|     workdir: meson.project_source_root(), | ||||
| ) | ||||
| 
 | ||||
| subdir('utils') | ||||
| subdir('hyprland') | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
| #include <thread> | ||||
| #include <type_traits> | ||||
| 
 | ||||
| #include "GlibTestsFixture.hpp" | ||||
| #include "fixtures/GlibTestsFixture.hpp" | ||||
| 
 | ||||
| using namespace waybar; | ||||
| 
 | ||||
|  | @ -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(), | ||||
| ) | ||||
		Loading…
	
		Reference in New Issue