summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hyprtester/src/Log.hpp6
-rw-r--r--hyprtester/src/hyprctlCompat.cpp6
-rw-r--r--hyprtester/src/main.cpp281
-rw-r--r--hyprtester/src/shared.hpp235
-rw-r--r--hyprtester/src/tests/clients/child-window.cpp113
-rw-r--r--hyprtester/src/tests/clients/pointer-scroll.cpp115
-rw-r--r--hyprtester/src/tests/clients/pointer-warp.cpp129
-rw-r--r--hyprtester/src/tests/clients/shortcut-inhibitor.cpp110
-rw-r--r--hyprtester/src/tests/clients/tests.hpp13
-rw-r--r--hyprtester/src/tests/main/animations.cpp11
-rw-r--r--hyprtester/src/tests/main/colors.cpp24
-rw-r--r--hyprtester/src/tests/main/dwindle.cpp83
-rw-r--r--hyprtester/src/tests/main/exec.cpp20
-rw-r--r--hyprtester/src/tests/main/follow_mouse_shrink.cpp48
-rw-r--r--hyprtester/src/tests/main/gestures.cpp32
-rw-r--r--hyprtester/src/tests/main/groups.cpp123
-rw-r--r--hyprtester/src/tests/main/hyprctl.cpp51
-rw-r--r--hyprtester/src/tests/main/keybinds.cpp124
-rw-r--r--hyprtester/src/tests/main/layer.cpp26
-rw-r--r--hyprtester/src/tests/main/layout.cpp75
-rw-r--r--hyprtester/src/tests/main/master.cpp122
-rw-r--r--hyprtester/src/tests/main/misc.cpp46
-rw-r--r--hyprtester/src/tests/main/moveintoorcreategroup.cpp26
-rw-r--r--hyprtester/src/tests/main/persistent.cpp24
-rw-r--r--hyprtester/src/tests/main/scroll.cpp123
-rw-r--r--hyprtester/src/tests/main/snap.cpp121
-rw-r--r--hyprtester/src/tests/main/solitary.cpp27
-rw-r--r--hyprtester/src/tests/main/tags.cpp22
-rw-r--r--hyprtester/src/tests/main/tests.hpp13
-rw-r--r--hyprtester/src/tests/main/window.cpp344
-rw-r--r--hyprtester/src/tests/main/workspaces.cpp282
-rw-r--r--hyprtester/src/tests/shared.cpp4
32 files changed, 1131 insertions, 1648 deletions
diff --git a/hyprtester/src/Log.hpp b/hyprtester/src/Log.hpp
index 7eeb3ece..87f0890d 100644
--- a/hyprtester/src/Log.hpp
+++ b/hyprtester/src/Log.hpp
@@ -3,6 +3,8 @@
#include <format>
#include <print>
+#include "shared.hpp"
+
namespace NLog {
template <typename... Args>
//NOLINTNEXTLINE
@@ -11,7 +13,7 @@ namespace NLog {
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
- std::println("{}", logMsg);
+ std::println("{}{}", logMsg, Colors::RESET);
std::fflush(stdout);
}
-} \ No newline at end of file
+}
diff --git a/hyprtester/src/hyprctlCompat.cpp b/hyprtester/src/hyprctlCompat.cpp
index 2c8e0644..dbeee93d 100644
--- a/hyprtester/src/hyprctlCompat.cpp
+++ b/hyprtester/src/hyprctlCompat.cpp
@@ -43,7 +43,7 @@ std::vector<SInstanceData> instances() {
} catch (std::exception& e) { return {}; }
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
- if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
+ if (!std::filesystem::exists(el.path() / "hyprland.lock"))
continue;
// read lock
@@ -74,7 +74,7 @@ std::vector<SInstanceData> instances() {
std::erase_if(result, [&](const auto& el) { return kill(el.pid, 0) != 0 && errno == ESRCH; });
- std::sort(result.begin(), result.end(), [&](const auto& a, const auto& b) { return a.time < b.time; });
+ std::ranges::sort(result, [&](const auto& a, const auto& b) { return a.time < b.time; });
return result;
}
@@ -135,4 +135,4 @@ std::string getFromSocket(const std::string& cmd) {
close(SERVERSOCKET);
return reply;
-} \ No newline at end of file
+}
diff --git a/hyprtester/src/main.cpp b/hyprtester/src/main.cpp
index 2fc78201..0da9a20e 100644
--- a/hyprtester/src/main.cpp
+++ b/hyprtester/src/main.cpp
@@ -17,14 +17,17 @@
#include "shared.hpp"
#include "hyprctlCompat.hpp"
#include "tests/main/tests.hpp"
+#undef TEST_CASES_STORAGE // Prevent redefinition warning
#include "tests/clients/tests.hpp"
+#undef TEST_CASES_STORAGE // Prevent redefinition warning
#include "tests/plugin/plugin.hpp"
+#include "tests/shared.hpp"
+#include <algorithm>
#include <filesystem>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
#include <hyprutils/memory/Casts.hpp>
-using namespace Hyprutils::Memory;
#include <csignal>
#include <cerrno>
@@ -38,35 +41,13 @@ using namespace Hyprutils::Memory;
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
+using Path = std::filesystem::path;
#define SP CSharedPointer
-static int ret = 0;
-static SP<CProcess> hyprlandProc;
-static const std::string cwd = std::filesystem::current_path().string();
-
-//
-static bool launchHyprland(std::string configPath, std::string binaryPath) {
- if (binaryPath == "") {
- std::error_code ec;
- if (!std::filesystem::exists(cwd + "/../build/Hyprland", ec) || ec) {
- NLog::log("{}No Hyprland binary", Colors::RED);
- return false;
- }
-
- binaryPath = cwd + "/../build/Hyprland";
- }
-
- if (configPath == "") {
- std::error_code ec;
- if (!std::filesystem::exists(cwd + "/test.lua", ec) || ec) {
- NLog::log("{}No test config", Colors::RED);
- return false;
- }
-
- configPath = cwd + "/test.lua";
- }
+static SP<CProcess> hyprlandProc;
+static bool launchHyprland(Path configPath, Path binaryPath) {
NLog::log("{}Launching Hyprland", Colors::YELLOW);
hyprlandProc = makeShared<CProcess>(binaryPath, std::vector<std::string>{"--config", configPath});
hyprlandProc->addEnv("HYPRLAND_HEADLESS_ONLY", "1");
@@ -78,121 +59,147 @@ static bool launchHyprland(std::string configPath, std::string binaryPath) {
static bool hyprlandAlive() {
NLog::log("{}hyprlandAlive", Colors::YELLOW);
- kill(hyprlandProc->pid(), 0);
- return errno != ESRCH;
+ return kill(hyprlandProc->pid(), 0) == 0 || errno != ESRCH;
}
-static void help() {
+[[noreturn]] static void helpAndDie(int exit_code) {
NLog::log("usage: hyprtester [arg [...]].\n");
NLog::log(R"(Arguments:
--help -h - Show this message again
- --config FILE -c FILE - Specify config file to use
- --binary FILE -b FILE - Specify Hyprland binary to use
- --plugin FILE -p FILE - Specify the location of the test plugin)");
-}
-
-int main(int argc, char** argv, char** envp) {
-
- std::string configPath = "";
- std::string binaryPath = "";
- std::string pluginPath = std::filesystem::current_path().string();
-
- if (argc > 1) {
- std::span<char*> args{argv + 1, sc<std::size_t>(argc - 1)};
+ --config FILE -c FILE - Specify config file to use (default: './test.lua')
+ --binary FILE -b FILE - Specify Hyprland binary to use (default: '../build/Hyprland')
+ --plugin FILE -p FILE - Specify the location of the test plugin (default: './'))");
- for (auto it = args.begin(); it != args.end(); it++) {
- std::string_view value = *it;
-
- if (value == "--config" || value == "-c") {
- if (std::next(it) == args.end()) {
- help();
-
- return 1;
- }
-
- configPath = *std::next(it);
-
- try {
- configPath = std::filesystem::canonical(configPath);
-
- if (!std::filesystem::is_regular_file(configPath)) {
- throw std::exception();
- }
- } catch (...) {
- std::println(stderr, "[ ERROR ] Config file '{}' doesn't exist!", configPath);
- help();
-
- return 1;
- }
-
- it++;
+ std::exit(exit_code);
+}
- continue;
- } else if (value == "--binary" || value == "-b") {
- if (std::next(it) == args.end()) {
- help();
+static Path validatePathOrDie(Path path) {
+ try {
+ if (!std::filesystem::is_regular_file(path)) {
+ throw std::exception();
+ }
+ } catch (...) {
+ std::println(stderr, "[ ERROR ] File '{}' is not accessible or not a regular file", path.string());
+ helpAndDie(EXIT_FAILURE);
+ }
+ return path;
+}
- return 1;
- }
+namespace {
+ struct SSettings {
+ Path configPath;
+ Path binaryPath;
+ Path pluginPath;
+ };
+}
- binaryPath = *std::next(it);
+static SSettings parseSettings(const std::span<const char*> args) {
+ static const auto cwd = std::filesystem::current_path();
+ SSettings settings{};
- try {
- binaryPath = std::filesystem::canonical(binaryPath);
+ for (auto it = args.begin(); it < args.end(); it++) {
+ std::string_view value = *it;
- if (!std::filesystem::is_regular_file(binaryPath)) {
- throw std::exception();
- }
- } catch (...) {
- std::println(stderr, "[ ERROR ] Binary '{}' doesn't exist!", binaryPath);
- help();
+ if (value == "--config" || value == "-c") {
+ if (std::next(it) == args.end()) {
+ helpAndDie(EXIT_FAILURE);
+ }
- return 1;
- }
+ settings.configPath = validatePathOrDie(*std::next(it));
+ it++;
+ } else if (value == "--binary" || value == "-b") {
+ if (std::next(it) == args.end()) {
+ helpAndDie(EXIT_FAILURE);
+ }
- it++;
+ settings.binaryPath = validatePathOrDie(*std::next(it));
+ it++;
+ } else if (value == "--plugin" || value == "-p") {
+ if (std::next(it) == args.end()) {
+ helpAndDie(EXIT_FAILURE);
+ }
- continue;
- } else if (value == "--plugin" || value == "-p") {
- if (std::next(it) == args.end()) {
- help();
+ settings.pluginPath = validatePathOrDie(*std::next(it));
+ it++;
+ } else if (value == "--help" || value == "-h") {
+ helpAndDie(EXIT_SUCCESS);
+ } else {
+ std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it);
+ helpAndDie(EXIT_SUCCESS);
+ }
+ }
- return 1;
- }
+ // Default options
+ if (settings.configPath.empty())
+ settings.configPath = validatePathOrDie(cwd / "test.lua");
+ if (settings.binaryPath.empty())
+ settings.binaryPath = validatePathOrDie(cwd / "../build/Hyprland");
+ if (settings.pluginPath.empty())
+ settings.pluginPath = cwd;
- pluginPath = *std::next(it);
+ return settings;
+}
- try {
- pluginPath = std::filesystem::canonical(pluginPath);
+static bool preTestCleanup() {
+ bool failed = false;
- if (!std::filesystem::is_regular_file(pluginPath)) {
- throw std::exception();
- }
- } catch (...) {
- std::println(stderr, "[ ERROR ] plugin '{}' doesn't exist!", pluginPath);
- help();
+ if (!Tests::killAllWindows()) {
+ NLog::log("{}Internal failure: failed to kill all windows", Colors::RED);
+ failed = true;
+ }
+ if (!Tests::killAllLayers()) {
+ NLog::log("{}Internal failure: failed to kill all layers", Colors::RED);
+ failed = true;
+ }
+ if (getFromSocket("/reload") != "ok") {
+ NLog::log("{}Internal failure: failed to reload", Colors::RED);
+ failed = true;
+ }
+ if (!getFromSocket("/activeworkspace").contains("workspace ID 1 (1)")) {
+ if (getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })") != "ok") {
+ NLog::log("{}Internal failure: failed to switch to workspace 1", Colors::RED);
+ failed = true;
+ }
+ }
+ if (getFromSocket("/dispatch hl.dsp.cursor.move({ x = 960, y = 540 })") != "ok") {
+ NLog::log("{}Internal failure: failed to reset cursor position", Colors::RED);
+ failed = true;
+ }
- return 1;
- }
+ return !failed;
+}
- it++;
+static void runTests(std::map<const char*, CTestCase&>& testCases) {
+ for (auto& [name, tc] : testCases) {
+ // Clean up before every test
+ NLog::log("{}Cleaning up", Colors::YELLOW);
+ (void)preTestCleanup();
+
+ NLog::log("{}Running test {}", Colors::BLUE, name);
+ tc.test();
+ if (tc.failed)
+ NLog::log("{}Test failed: {}", Colors::RED, name);
+ else
+ NLog::log("{}Test passed: {}", Colors::GREEN, name);
+ }
+}
- continue;
- } else if (value == "--help" || value == "-h") {
- help();
+static long long countFailed(const std::map<const char*, CTestCase&>& testCases) {
+ long long ans = 0;
+ for (const auto& [_, tc] : testCases) {
+ if (tc.failed)
+ ans++;
+ }
+ return ans;
+}
- return 0;
- } else {
- std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it);
- help();
+int main(int argc, char** argv, char** envp) {
- return 1;
- }
- }
- }
+ std::span<const char*> args{const_cast<const char**>(argv + 1), sc<std::size_t>(argc - 1)};
+ const SSettings settings = parseSettings(args);
NLog::log("{}launching hl", Colors::YELLOW);
- if (!launchHyprland(configPath, binaryPath)) {
+ if (!launchHyprland(settings.configPath, settings.binaryPath)) {
NLog::log("{}well it failed", Colors::RED);
return 1;
}
@@ -220,7 +227,7 @@ int main(int argc, char** argv, char** envp) {
getFromSocket("/output create headless");
NLog::log("{}trying to load plugin", Colors::YELLOW);
- if (const auto R = getFromSocket(std::format("/plugin load {}", pluginPath)); R != "ok") {
+ if (const auto R = getFromSocket(std::format("/plugin load {}", settings.pluginPath.string())); R != "ok") {
NLog::log("{}Failed to load the test plugin: {}", Colors::RED, R);
getFromSocket("/dispatch hl.dsp.exit()");
return 1;
@@ -228,34 +235,50 @@ int main(int argc, char** argv, char** envp) {
NLog::log("{}Loaded plugin", Colors::YELLOW);
- NLog::log("{}Running main tests", Colors::YELLOW);
+ long long failedTests = 0, totalTests = 0;
- for (const auto& fn : testFns) {
- EXPECT(fn(), true);
- }
+ NLog::log("{}Running main tests", Colors::YELLOW);
+ runTests(mainTestCases);
+ failedTests += countFailed(mainTestCases);
+ totalTests += mainTestCases.size();
NLog::log("{}Running protocol client tests", Colors::YELLOW);
+ runTests(clientTestCases);
+ failedTests += countFailed(clientTestCases);
+ totalTests += clientTestCases.size();
- for (const auto& fn : clientTestFns) {
- EXPECT(fn(), true);
- }
+ // TODO: the two tests below should not be hardcoded, include them somewhere
NLog::log("{}running plugin test", Colors::YELLOW);
- EXPECT(testPlugin(), true);
+ if (!testPlugin()) {
+ NLog::log("{}Test failed: plugin test", Colors::RED);
+ failedTests++;
+ } else {
+ NLog::log("{}Test passed: plugin test", Colors::GREEN);
+ }
+ totalTests++;
NLog::log("{}running vkb test from plugin", Colors::YELLOW);
- EXPECT(testVkb(), true);
+ if (!testVkb()) {
+ NLog::log("{}Test failed: vkb test from plugin", Colors::RED);
+ failedTests++;
+ } else {
+ NLog::log("{}Test passed: vkb test from plugin", Colors::GREEN);
+ }
+ totalTests++;
// kill hyprland
NLog::log("{}dispatching exit", Colors::YELLOW);
getFromSocket("/dispatch hl.dsp.exit()");
- NLog::log("\n{}Summary:\n\tPASSED: {}{}{}/{}\n\tFAILED: {}{}{}/{}\n{}", Colors::RESET, Colors::GREEN, TESTS_PASSED, Colors::RESET, TESTS_PASSED + TESTS_FAILED, Colors::RED,
- TESTS_FAILED, Colors::RESET, TESTS_PASSED + TESTS_FAILED, (TESTS_FAILED > 0 ? std::string{Colors::RED} + "\nSome tests failed.\n" : ""));
+ NLog::log("\nSummary:\n\tPASSED: {}{}{}/{}", Colors::GREEN, totalTests - failedTests, Colors::RESET, totalTests);
+ NLog::log("\tFAILED: {}{}{}/{}", Colors::RED, failedTests, Colors::RESET, totalTests);
+ if (failedTests > 0)
+ NLog::log("{}Some tests failed.", Colors::RED);
kill(hyprlandProc->pid(), SIGKILL);
hyprlandProc.reset();
- return ret || TESTS_FAILED;
+ return failedTests > 0;
}
diff --git a/hyprtester/src/shared.hpp b/hyprtester/src/shared.hpp
index 941788fd..d40b2f1f 100644
--- a/hyprtester/src/shared.hpp
+++ b/hyprtester/src/shared.hpp
@@ -1,12 +1,12 @@
// Stolen from hyprutils
#pragma once
-#include <iostream>
+#include <cmath>
+#include <string>
-inline std::string HIS = "";
-inline std::string WLDISPLAY = "";
-inline int TESTS_PASSED = 0;
-inline int TESTS_FAILED = 0;
+// TODO: localize these global variables
+inline std::string HIS = "";
+inline std::string WLDISPLAY = "";
namespace Colors {
constexpr const char* RED = "\x1b[31m";
@@ -18,94 +18,229 @@ namespace Colors {
constexpr const char* RESET = "\x1b[0m";
};
+// =================================
+// TEST CASES DEFINITION
+// =================================
+
+class CTestCase {
+ public:
+ CTestCase() = default;
+ CTestCase(const CTestCase&) = delete; // Test cases probably should not be copied
+ bool failed = false;
+ virtual ~CTestCase() = default;
+
+ // TODO: `test` will be protected
+ virtual void test() = 0;
+};
+
+#define TEST_CASE(name) \
+ namespace { \
+ class TestCase_##name : public CTestCase { \
+ public: \
+ void test() override; \
+ }; \
+ } \
+ \
+ static TestCase_##name test_case_##name{}; \
+ static auto register_test_case_##name = [] { \
+ /* `TEST_CASES_STORAGE` must be defined by the caller */ \
+ TEST_CASES_STORAGE.emplace(#name, test_case_##name); \
+ return 1; \
+ }(); \
+ \
+ void TestCase_##name::test()
+
+#define SUBTEST(name, ...) \
+ namespace { \
+ class Subtest_##name { \
+ public: \
+ bool failed = false; \
+ \
+ void main(__VA_ARGS__); \
+ }; \
+ } \
+ \
+ void Subtest_##name::main(__VA_ARGS__)
+
+#define CALL_SUBTEST(name, ...) \
+ do { \
+ auto subtest_##name = Subtest_##name{}; \
+ subtest_##name.main(__VA_ARGS__); \
+ if (subtest_##name.failed) { \
+ NLog::log("{}Subtest {}({}) failed", Colors::RED, #name, #__VA_ARGS__); \
+ this->failed = true; \
+ return; \
+ } \
+ } while (0)
+
+// =================================
+// IN-TEST MACROS
+// =================================
+
+/// Marks the test as failed without terminating it
+#define MARK_TEST_FAILED_SILENT() this->failed = true
+
+/// Prints a failure message and makrs the test as failed without terminating it
+#define MARK_TEST_FAILED(fmt, ...) \
+ do { \
+ NLog::log("{}Failed:{} " fmt ". Source: {}@{}.", Colors::RED, Colors::RESET __VA_OPT__(, ) __VA_ARGS__, __FILE__, __LINE__); \
+ MARK_TEST_FAILED_SILENT(); \
+ } while (0)
+
+/// Terminates the test execution and marks it as failed
+#define FAIL_TEST_SILENT() \
+ do { \
+ MARK_TEST_FAILED_SILENT(); \
+ return; \
+ } while (0)
+
+/// Prints a failure message, terminates the test execution, and marks it as failed
+#define FAIL_TEST(fmt, ...) \
+ do { \
+ MARK_TEST_FAILED(fmt, __VA_ARGS__); \
+ return; \
+ } while (0)
+
+#define LOG_OK(fmt, ...) \
+ do { \
+ NLog::log("{}OK:{} " fmt ". Source: {}@{}", Colors::GREEN, Colors::RESET, __VA_ARGS__, __FILE__, __LINE__); \
+ } while (0)
+
+// In case of failure:
+// - All the `EXPECT*` macros will print a message and mark the test as failed without terminating its execution;
+// - All the `ASSERT*` macros will print a message, mark the test as failed, and terminate it.
+//
+// `OK` acts like `ASSERT_OK`.
+
#define EXPECT_MAX_DELTA(expr, desired, delta) \
if (const auto RESULT = expr; std::abs(RESULT - (desired)) > delta) { \
- NLog::log("{}Failed: {}{}, expected max delta of {}, got delta {} ({} - {}). Source: {}@{}.", Colors::RED, Colors::RESET, #expr, delta, (RESULT - (desired)), RESULT, \
- desired, __FILE__, __LINE__); \
- ret = 1; \
- TESTS_FAILED++; \
+ MARK_TEST_FAILED("{}, expected max delta of {}, got delta {} ({} - {})", #expr, delta, (RESULT - (desired)), RESULT, desired); \
} else { \
- NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, (RESULT - (desired))); \
- TESTS_PASSED++; \
+ LOG_OK("{}. Got {}", #expr, (RESULT - (desired))); \
}
#define EXPECT(expr, val) \
- if (const auto RESULT = expr; RESULT != (val)) { \
- NLog::log("{}Failed: {}{}, expected {}, got {}. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, val, RESULT, __FILE__, __LINE__); \
- ret = 1; \
- TESTS_FAILED++; \
- } else { \
- NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, val); \
- TESTS_PASSED++; \
- }
+ do { \
+ if (const auto RESULT = expr; RESULT != (val)) { \
+ MARK_TEST_FAILED("{}, expected {}, got {}", #expr, val, RESULT); \
+ } else { \
+ LOG_OK("{}. Got {}", #expr, val); \
+ } \
+ } while (0)
#define EXPECT_NOT(expr, val) \
if (const auto RESULT = expr; RESULT == (val)) { \
- NLog::log("{}Failed: {}{}, expected not {}, got {}. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, val, RESULT, __FILE__, __LINE__); \
- ret = 1; \
- TESTS_FAILED++; \
+ MARK_TEST_FAILED("{}, expected not {}, got {}", #expr, val, RESULT); \
} else { \
- NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, val); \
- TESTS_PASSED++; \
+ LOG_OK("{}. Got {}", #expr, val); \
}
#define EXPECT_VECTOR2D(expr, val) \
do { \
const auto& RESULT = expr; \
- const auto& EXPECTED = val; \
- if (!(std::abs(RESULT.x - EXPECTED.x) < 1e-6 && std::abs(RESULT.y - EXPECTED.y) < 1e-6)) { \
- NLog::log("{}Failed: {}{}, expected [{}, {}], got [{}, {}]. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, EXPECTED.x, EXPECTED.y, RESULT.x, RESULT.y, __FILE__, \
- __LINE__); \
- ret = 1; \
- TESTS_FAILED++; \
+ const auto& ASSERTED = val; \
+ if (!(std::abs(RESULT.x - ASSERTED.x) < 1e-6 && std::abs(RESULT.y - ASSERTED.y) < 1e-6)) { \
+ MARK_TEST_FAILED("{}, expected [{}, {}], got [{}, {}]", #expr, ASSERTED.x, ASSERTED.y, RESULT.x, RESULT.y); \
} else { \
- NLog::log("{}Passed: {}{}. Got [{}, {}].", Colors::GREEN, Colors::RESET, #expr, RESULT.x, RESULT.y); \
- TESTS_PASSED++; \
+ LOG_OK("{}. Got [{}, {}].", #expr, RESULT.x, RESULT.y); \
} \
} while (0)
+// String check macros below use a special error message layout, putting the Source reference before `haystack`,
+// since `haystack` may be a large multi-line string. Thus, they use bare `NLog::log` + `MARK_TEST_FAILED_SILENT`.
+
#define EXPECT_CONTAINS(haystack, needle) \
- if (const auto EXPECTED = needle; !std::string{haystack}.contains(EXPECTED)) { \
+ if (const auto ASSERTED = needle; !std::string{haystack}.contains(ASSERTED)) { \
NLog::log("{}Failed: {}{} should contain {} but doesn't. Source: {}@{}. Haystack is:\n{}", Colors::RED, Colors::RESET, #haystack, #needle, __FILE__, __LINE__, \
std::string{haystack}); \
- ret = 1; \
- TESTS_FAILED++; \
+ MARK_TEST_FAILED_SILENT(); \
} else { \
- NLog::log("{}Passed: {}{} contains {}.", Colors::GREEN, Colors::RESET, #haystack, EXPECTED); \
- TESTS_PASSED++; \
+ LOG_OK("{} contains {}.", #haystack, ASSERTED); \
}
#define EXPECT_NOT_CONTAINS(haystack, needle) \
if (std::string{haystack}.contains(needle)) { \
NLog::log("{}Failed: {}{} shouldn't contain {} but does. Source: {}@{}. Haystack is:\n{}", Colors::RED, Colors::RESET, #haystack, #needle, __FILE__, __LINE__, \
std::string{haystack}); \
- ret = 1; \
- TESTS_FAILED++; \
+ MARK_TEST_FAILED_SILENT(); \
} else { \
- NLog::log("{}Passed: {}{} doesn't contain {}.", Colors::GREEN, Colors::RESET, #haystack, #needle); \
- TESTS_PASSED++; \
+ LOG_OK("{} doesn't contain {}.", #haystack, #needle); \
}
#define EXPECT_STARTS_WITH(str, what) \
if (!std::string{str}.starts_with(what)) { \
NLog::log("{}Failed: {}{} should start with {} but doesn't. Source: {}@{}. String is:\n{}", Colors::RED, Colors::RESET, #str, #what, __FILE__, __LINE__, \
std::string{str}); \
- ret = 1; \
- TESTS_FAILED++; \
+ MARK_TEST_FAILED_SILENT(); \
} else { \
- NLog::log("{}Passed: {}{} starts with {}.", Colors::GREEN, Colors::RESET, #str, #what); \
- TESTS_PASSED++; \
+ LOG_OK("{} starts with {}.", #str, #what); \
}
#define EXPECT_COUNT_STRING(str, what, no) \
if (Tests::countOccurrences(str, what) != no) { \
NLog::log("{}Failed: {}{} should contain {} {} times, but doesn't. Source: {}@{}. String is:\n{}", Colors::RED, Colors::RESET, #str, #what, no, __FILE__, __LINE__, \
std::string{str}); \
- ret = 1; \
- TESTS_FAILED++; \
+ MARK_TEST_FAILED_SILENT(); \
} else { \
- NLog::log("{}Passed: {}{} contains {} {} times.", Colors::GREEN, Colors::RESET, #str, #what, no); \
- TESTS_PASSED++; \
+ LOG_OK("{} contains {} {} times.", #str, #what, no); \
}
-#define OK(x) EXPECT(x, "ok")
+#define EXPECT_OK(x) EXPECT(x, "ok")
+
+#define ASSERT_MAX_DELTA(expr, desired, delta) \
+ do { \
+ EXPECT_MAX_DELTA(expr, desired, delta); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT(expr, val) \
+ do { \
+ EXPECT(expr, val); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT_NOT(expr, val) \
+ do { \
+ EXPECT_NOT(expr, val); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT_VECTOR2D(expr, val) \
+ do { \
+ EXPECT_VECTOR2D(expr, val); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT_CONTAINS(haystack, needle) \
+ do { \
+ EXPECT_CONTAINS(haystack, needle); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT_NOT_CONTAINS(haystack, needle) \
+ do { \
+ EXPECT_NOT_CONTAINS(haystack, needle); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT_STARTS_WITH(str, what) \
+ do { \
+ EXPECT_STARTS_WITH(str, what); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define ASSERT_COUNT_STRING(str, what, no) \
+ do { \
+ EXPECT_COUNT_STRING(str, what, no); \
+ if (this->failed) \
+ return; \
+ } while (0)
+
+#define OK(x) ASSERT(x, "ok")
diff --git a/hyprtester/src/tests/clients/child-window.cpp b/hyprtester/src/tests/clients/child-window.cpp
index 40118c7c..f97ffde1 100644
--- a/hyprtester/src/tests/clients/child-window.cpp
+++ b/hyprtester/src/tests/clients/child-window.cpp
@@ -1,4 +1,3 @@
-#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include "../shared.hpp"
#include "tests.hpp"
@@ -7,6 +6,7 @@
#include <hyprutils/os/FileDescriptor.hpp>
#include <hyprutils/os/Process.hpp>
+#include <optional>
#include <sys/poll.h>
#include <unistd.h>
#include <csignal>
@@ -17,15 +17,6 @@ using namespace Hyprutils::Memory;
#define SP CSharedPointer
-struct SClient {
- SP<CProcess> proc;
- std::array<char, 1024> readBuf;
- CFileDescriptor readFd, writeFd;
- struct pollfd fds;
-};
-
-static int ret = 0;
-
static bool waitForWindow(SP<CProcess> proc, int windowsBefore) {
int counter = 0;
while (Tests::processAlive(proc->pid()) && Tests::windowCount() == windowsBefore) {
@@ -40,56 +31,69 @@ static bool waitForWindow(SP<CProcess> proc, int windowsBefore) {
return Tests::processAlive(proc->pid());
}
-static bool startClient(SClient& client) {
+namespace {
+ class CClient {
+ SP<CProcess> proc;
+ std::array<char, 1024> readBuf;
+ CFileDescriptor readFd, writeFd;
+ struct pollfd fds;
+
+ public:
+ CClient();
+ ~CClient();
+ bool createChild();
+ };
+}
+
+CClient::CClient() {
NLog::log("{}Attempting to start child-window client", Colors::YELLOW);
- client.proc = makeShared<CProcess>(binaryDir + "/child-window", std::vector<std::string>{});
+ this->proc = makeShared<CProcess>(binaryDir + "/child-window", std::vector<std::string>{});
- client.proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
+ this->proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
int procInPipeFd[2], procOutPipeFd[2];
if (pipe(procInPipeFd) != 0 || pipe(procOutPipeFd) != 0) {
NLog::log("{}Unable to open pipe to client", Colors::RED);
- return false;
+ throw std::exception();
}
- client.writeFd = CFileDescriptor(procInPipeFd[1]);
- client.proc->setStdinFD(procInPipeFd[0]);
+ this->writeFd = CFileDescriptor(procInPipeFd[1]);
+ this->proc->setStdinFD(procInPipeFd[0]);
- client.readFd = CFileDescriptor(procOutPipeFd[0]);
- client.proc->setStdoutFD(procOutPipeFd[1]);
+ this->readFd = CFileDescriptor(procOutPipeFd[0]);
+ this->proc->setStdoutFD(procOutPipeFd[1]);
- if (!client.proc->runAsync()) {
+ if (!this->proc->runAsync()) {
NLog::log("{}Failed to run client", Colors::RED);
- return false;
+ throw std::exception();
}
close(procInPipeFd[0]);
close(procOutPipeFd[1]);
- if (!waitForWindow(client.proc, Tests::windowCount())) {
+ if (!waitForWindow(this->proc, Tests::windowCount())) {
NLog::log("{}Window took too long to open", Colors::RED);
- return false;
+ throw std::exception();
}
NLog::log("{}Started child-window client", Colors::YELLOW);
- return true;
}
-static void stopClient(SClient& client) {
+CClient::~CClient() {
std::string cmd = "exit\n";
- write(client.writeFd.get(), cmd.c_str(), cmd.length());
+ write(this->writeFd.get(), cmd.c_str(), cmd.length());
- kill(client.proc->pid(), SIGKILL);
- client.proc.reset();
+ kill(this->proc->pid(), SIGKILL);
+ this->proc.reset();
}
-static bool createChild(SClient& client) {
+bool CClient::createChild() {
std::string cmd = "toplevel\n";
- if ((size_t)write(client.writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length())
+ if ((size_t)write(this->writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length())
return false;
- if (!waitForWindow(client.proc, Tests::windowCount()))
+ if (!waitForWindow(this->proc, Tests::windowCount()))
NLog::log("{}Child window took too long to open", Colors::RED);
if (getFromSocket("/dispatch hl.dsp.focus({ window = 'class:child-test-child' })") != "ok") {
@@ -100,19 +104,21 @@ static bool createChild(SClient& client) {
return true;
}
-static bool test() {
- SClient client;
+TEST_CASE(childWindow) {
+ {
+ std::optional<CClient> client;
+ try {
+ client.emplace();
+ } catch (...) { FAIL_TEST("Couldn't start the client"); }
- if (!startClient(client))
- return false;
- OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set', window = 'class:child-test-parent' })"));
- OK(getFromSocket("/dispatch hl.dsp.window.pin({ action = 'set', window = 'class:child-test-parent' })"));
+ OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set', window = 'class:child-test-parent' })"));
+ OK(getFromSocket("/dispatch hl.dsp.window.pin({ action = 'set', window = 'class:child-test-parent' })"));
- createChild(client);
- EXPECT(Tests::windowCount(), 2)
- EXPECT_COUNT_STRING(getFromSocket("/clients"), "pinned: 1", 2);
+ client->createChild();
+ EXPECT(Tests::windowCount(), 2);
+ EXPECT_COUNT_STRING(getFromSocket("/clients"), "pinned: 1", 2);
+ }
- stopClient(client);
NLog::log("{}Reloading config", Colors::YELLOW);
OK(getFromSocket("/reload"));
Tests::killAllWindows();
@@ -122,30 +128,27 @@ static bool test() {
NLog::log("{}Test child windows are not auto-grouped", Colors::GREEN);
auto kitty = Tests::spawnKitty();
if (!kitty) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Couldn't spawn kitty");
}
// create group and enable auto-grouping
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
OK(getFromSocket("/eval hl.config({ group = { auto_group = true } })"));
- SClient client2;
- if (!startClient(client2))
- return false;
+ {
+ std::optional<CClient> client2;
+ try {
+ client2.emplace();
+ } catch (...) { FAIL_TEST("Couldn't start the client"); }
- EXPECT(Tests::windowCount(), 2);
- createChild(client2);
- EXPECT(Tests::windowCount(), 3);
+ EXPECT(Tests::windowCount(), 2);
+ client2->createChild();
+ EXPECT(Tests::windowCount(), 3);
- // child has set_parent so shouldBeFloated returns true, it should not be auto-grouped
- EXPECT_COUNT_STRING(getFromSocket("/clients"), "grouped: 0", 1);
+ // child has set_parent so shouldBeFloated returns true, it should not be auto-grouped
+ EXPECT_COUNT_STRING(getFromSocket("/clients"), "grouped: 0", 1);
+ }
- stopClient(client2);
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
-
- return !ret;
}
-
-REGISTER_CLIENT_TEST_FN(test);
diff --git a/hyprtester/src/tests/clients/pointer-scroll.cpp b/hyprtester/src/tests/clients/pointer-scroll.cpp
index 86ce55f0..c468deb3 100644
--- a/hyprtester/src/tests/clients/pointer-scroll.cpp
+++ b/hyprtester/src/tests/clients/pointer-scroll.cpp
@@ -1,4 +1,3 @@
-#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include "../shared.hpp"
#include "tests.hpp"
@@ -7,6 +6,7 @@
#include <hyprutils/os/FileDescriptor.hpp>
#include <hyprutils/os/Process.hpp>
+#include <optional>
#include <sys/poll.h>
#include <unistd.h>
#include <csignal>
@@ -17,100 +17,103 @@ using namespace Hyprutils::Memory;
#define SP CSharedPointer
-struct SClient {
- SP<CProcess> proc;
- std::array<char, 1024> readBuf;
- CFileDescriptor readFd, writeFd;
- struct pollfd fds;
-};
-
-static int ret = 0;
+namespace {
+ class CClient {
+ SP<CProcess> proc;
+ std::array<char, 1024> readBuf;
+ CFileDescriptor readFd, writeFd;
+ struct pollfd fds;
+
+ public:
+ CClient();
+ ~CClient();
+ int getLastDelta();
+ };
+}
-static bool startClient(SClient& client) {
- client.proc = makeShared<CProcess>(binaryDir + "/pointer-scroll", std::vector<std::string>{});
+CClient::CClient() {
+ this->proc = makeShared<CProcess>(binaryDir + "/pointer-scroll", std::vector<std::string>{});
- client.proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
+ this->proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
int pipeFds1[2], pipeFds2[2];
if (pipe(pipeFds1) != 0 || pipe(pipeFds2) != 0) {
NLog::log("{}Unable to open pipe to client", Colors::RED);
- return false;
+ throw std::exception();
}
- client.writeFd = CFileDescriptor(pipeFds1[1]);
- client.proc->setStdinFD(pipeFds1[0]);
+ this->writeFd = CFileDescriptor(pipeFds1[1]);
+ this->proc->setStdinFD(pipeFds1[0]);
- client.readFd = CFileDescriptor(pipeFds2[0]);
- client.proc->setStdoutFD(pipeFds2[1]);
+ this->readFd = CFileDescriptor(pipeFds2[0]);
+ this->proc->setStdoutFD(pipeFds2[1]);
const int COUNT_BEFORE = Tests::windowCount();
- client.proc->runAsync();
+ this->proc->runAsync();
close(pipeFds1[0]);
close(pipeFds2[1]);
- client.fds = {.fd = client.readFd.get(), .events = POLLIN};
- if (poll(&client.fds, 1, 1000) != 1 || !(client.fds.revents & POLLIN))
- return false;
+ this->fds = {.fd = this->readFd.get(), .events = POLLIN};
+ if (poll(&this->fds, 1, 1000) != 1 || !(this->fds.revents & POLLIN))
+ throw std::exception();
- client.readBuf.fill(0);
- if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1)
- return false;
+ this->readBuf.fill(0);
+ if (read(this->readFd.get(), this->readBuf.data(), this->readBuf.size() - 1) == -1)
+ throw std::exception();
- std::string ret = std::string{client.readBuf.data()};
+ std::string ret = std::string{this->readBuf.data()};
if (ret.find("started") == std::string::npos) {
NLog::log("{}Failed to start pointer-scroll client, read {}", Colors::RED, ret);
- return false;
+ throw std::exception();
}
// wait for window to appear
int counter = 0;
- while (Tests::processAlive(client.proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
+ while (Tests::processAlive(this->proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
counter++;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (counter > 50) {
NLog::log("{}pointer-scroll client took too long to open", Colors::RED);
- return false;
+ throw std::exception();
}
}
- if (getFromSocket(std::format("/dispatch hl.dsp.window.set_prop({{ window = 'pid:{}', prop = 'no_anim', value = '1' }})", client.proc->pid())) != "ok") {
+ if (getFromSocket(std::format("/dispatch hl.dsp.window.set_prop({{ window = 'pid:{}', prop = 'no_anim', value = '1' }})", this->proc->pid())) != "ok") {
NLog::log("{}Failed to disable animations for client window", Colors::RED, ret);
- return false;
+ throw std::exception();
}
- if (getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", client.proc->pid())) != "ok") {
+ if (getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", this->proc->pid())) != "ok") {
NLog::log("{}Failed to focus pointer-scroll client", Colors::RED, ret);
- return false;
+ throw std::exception();
}
NLog::log("{}Started pointer-scroll client", Colors::YELLOW);
-
- return true;
}
-static void stopClient(SClient& client) {
+CClient::~CClient() {
std::string cmd = "exit\n";
- write(client.writeFd.get(), cmd.c_str(), cmd.length());
+ write(this->writeFd.get(), cmd.c_str(), cmd.length());
- kill(client.proc->pid(), SIGKILL);
- client.proc.reset();
+ kill(this->proc->pid(), SIGKILL);
+ this->proc.reset();
}
-static int getLastDelta(SClient& client) {
+int CClient::getLastDelta() {
std::string cmd = "hypr";
- if ((size_t)write(client.writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length())
+ if ((size_t)write(this->writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length())
return false;
- if (poll(&client.fds, 1, 1500) != 1 || !(client.fds.revents & POLLIN))
+ if (poll(&this->fds, 1, 1500) != 1 || !(this->fds.revents & POLLIN))
return false;
- ssize_t bytesRead = read(client.fds.fd, client.readBuf.data(), 1023);
+ ssize_t bytesRead = read(this->fds.fd, this->readBuf.data(), 1023);
if (bytesRead == -1)
return false;
- client.readBuf[bytesRead] = 0;
- std::string received = std::string{client.readBuf.data()};
+ this->readBuf[bytesRead] = 0;
+ std::string received = std::string{this->readBuf.data()};
received.pop_back();
try {
@@ -122,35 +125,29 @@ static bool sendScroll(int delta) {
return getFromSocket(std::format("/eval hl.plugin.test.scroll({})", delta)) == "ok";
}
-static bool test() {
- SClient client;
-
- if (!startClient(client))
- return false;
+TEST_CASE(pointerScroll) {
+ std::optional<CClient> client;
+ try {
+ client.emplace();
+ } catch (...) { FAIL_TEST("Couldn't start the client"); }
EXPECT(getFromSocket("r/eval hl.config({ input = { emulate_discrete_scroll = 0 } })"), "ok");
EXPECT(sendScroll(10), true);
- EXPECT(getLastDelta(client), 10);
+ EXPECT(client->getLastDelta(), 10);
EXPECT(getFromSocket("r/eval hl.config({ input = { scroll_factor = 2 } })"), "ok");
EXPECT(sendScroll(10), true);
- EXPECT(getLastDelta(client), 20);
+ EXPECT(client->getLastDelta(), 20);
EXPECT(getFromSocket("r/eval hl.device({ name = 'test-mouse-1', scroll_factor = 3 })"), "ok");
EXPECT(sendScroll(10), true);
- EXPECT(getLastDelta(client), 30);
+ EXPECT(client->getLastDelta(), 30);
EXPECT(getFromSocket("r/dispatch hl.dsp.window.set_prop({ window = 'active', prop = 'scroll_mouse', value = '4' })"), "ok");
EXPECT(sendScroll(10), true);
- EXPECT(getLastDelta(client), 40);
-
- stopClient(client);
+ EXPECT(client->getLastDelta(), 40);
NLog::log("{}Reloading the config", Colors::YELLOW);
OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_CLIENT_TEST_FN(test);
diff --git a/hyprtester/src/tests/clients/pointer-warp.cpp b/hyprtester/src/tests/clients/pointer-warp.cpp
index fa6334d3..e13e03f6 100644
--- a/hyprtester/src/tests/clients/pointer-warp.cpp
+++ b/hyprtester/src/tests/clients/pointer-warp.cpp
@@ -1,4 +1,3 @@
-#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include "../shared.hpp"
#include "tests.hpp"
@@ -7,6 +6,7 @@
#include <hyprutils/os/FileDescriptor.hpp>
#include <hyprutils/os/Process.hpp>
+#include <optional>
#include <sys/poll.h>
#include <unistd.h>
#include <csignal>
@@ -17,102 +17,105 @@ using namespace Hyprutils::Memory;
#define SP CSharedPointer
-struct SClient {
- SP<CProcess> proc;
- std::array<char, 1024> readBuf;
- CFileDescriptor readFd, writeFd;
- struct pollfd fds;
-};
-
-static int ret = 0;
+namespace {
+ class CClient {
+ SP<CProcess> proc;
+ std::array<char, 1024> readBuf;
+ CFileDescriptor readFd, writeFd;
+ struct pollfd fds;
+
+ public:
+ CClient();
+ ~CClient();
+ bool sendWarp(int x, int y);
+ };
+}
-static bool startClient(SClient& client) {
- client.proc = makeShared<CProcess>(binaryDir + "/pointer-warp", std::vector<std::string>{});
+CClient::CClient() {
+ this->proc = makeShared<CProcess>(binaryDir + "/pointer-warp", std::vector<std::string>{});
- client.proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
+ this->proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
int pipeFds1[2], pipeFds2[2];
if (pipe(pipeFds1) != 0 || pipe(pipeFds2) != 0) {
NLog::log("{}Unable to open pipe to client", Colors::RED);
- return false;
+ throw std::exception();
}
- client.writeFd = CFileDescriptor(pipeFds1[1]);
- client.proc->setStdinFD(pipeFds1[0]);
+ this->writeFd = CFileDescriptor(pipeFds1[1]);
+ this->proc->setStdinFD(pipeFds1[0]);
- client.readFd = CFileDescriptor(pipeFds2[0]);
- client.proc->setStdoutFD(pipeFds2[1]);
+ this->readFd = CFileDescriptor(pipeFds2[0]);
+ this->proc->setStdoutFD(pipeFds2[1]);
const int COUNT_BEFORE = Tests::windowCount();
- client.proc->runAsync();
+ this->proc->runAsync();
close(pipeFds1[0]);
close(pipeFds2[1]);
- client.fds = {.fd = client.readFd.get(), .events = POLLIN};
- if (poll(&client.fds, 1, 1000) != 1 || !(client.fds.revents & POLLIN))
- return false;
+ this->fds = {.fd = this->readFd.get(), .events = POLLIN};
+ if (poll(&this->fds, 1, 1000) != 1 || !(this->fds.revents & POLLIN))
+ throw std::exception();
- client.readBuf.fill(0);
- if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1)
- return false;
+ this->readBuf.fill(0);
+ if (read(this->readFd.get(), this->readBuf.data(), this->readBuf.size() - 1) == -1)
+ throw std::exception();
- std::string ret = std::string{client.readBuf.data()};
+ std::string ret = std::string{this->readBuf.data()};
if (ret.find("started") == std::string::npos) {
NLog::log("{}Failed to start pointer-warp client, read {}", Colors::RED, ret);
- return false;
+ throw std::exception();
}
// wait for window to appear
int counter = 0;
- while (Tests::processAlive(client.proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
+ while (Tests::processAlive(this->proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
counter++;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (counter > 100) {
NLog::log("{}pointer-warp client took too long to open, continuing", Colors::YELLOW);
- break;
+ throw std::exception();
}
}
- if (getFromSocket(std::format("/dispatch hl.dsp.window.set_prop({{ window = 'pid:{}', prop = 'no_anim', value = '1' }})", client.proc->pid())) != "ok") {
+ if (getFromSocket(std::format("/dispatch hl.dsp.window.set_prop({{ window = 'pid:{}', prop = 'no_anim', value = '1' }})", this->proc->pid())) != "ok") {
NLog::log("{}Failed to disable animations for client window", Colors::RED, ret);
- return false;
+ throw std::exception();
}
- if (getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", client.proc->pid())) != "ok") {
+ if (getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", this->proc->pid())) != "ok") {
NLog::log("{}Failed to focus pointer-warp client", Colors::RED, ret);
- return false;
+ throw std::exception();
}
NLog::log("{}Started pointer-warp client", Colors::YELLOW);
-
- return true;
}
-static void stopClient(SClient& client) {
+CClient::~CClient() {
std::string cmd = "exit\n";
- write(client.writeFd.get(), cmd.c_str(), cmd.length());
+ write(this->writeFd.get(), cmd.c_str(), cmd.length());
- kill(client.proc->pid(), SIGKILL);
- client.proc.reset();
+ kill(this->proc->pid(), SIGKILL);
+ this->proc.reset();
}
// format is like below
// "warp 20 20\n" would ask to warp cursor to x=20,y=20 in surface local coords
-static bool sendWarp(SClient& client, int x, int y) {
+bool CClient::sendWarp(int x, int y) {
std::string cmd = std::format("warp {} {}\n", x, y);
- if ((size_t)write(client.writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length())
+ if ((size_t)write(this->writeFd.get(), cmd.c_str(), cmd.length()) != cmd.length())
return false;
- if (poll(&client.fds, 1, 1500) != 1 || !(client.fds.revents & POLLIN))
+ if (poll(&this->fds, 1, 1500) != 1 || !(this->fds.revents & POLLIN))
return false;
- ssize_t bytesRead = read(client.fds.fd, client.readBuf.data(), 1023);
+ ssize_t bytesRead = read(this->fds.fd, this->readBuf.data(), 1023);
if (bytesRead == -1)
return false;
- client.readBuf[bytesRead] = 0;
- std::string recieved = std::string{client.readBuf.data()};
+ this->readBuf[bytesRead] = 0;
+ std::string recieved = std::string{this->readBuf.data()};
recieved.pop_back();
return true;
@@ -147,48 +150,40 @@ static bool isCursorPos(int x, int y) {
return clientX == x && clientY == y;
}
-static bool test() {
- SClient client;
+TEST_CASE(pointerWarp) {
+ std::optional<CClient> client;
- if (!startClient(client))
- return false;
+ try {
+ client.emplace();
+ } catch (...) { FAIL_TEST("Couldn't start the client"); }
- EXPECT(sendWarp(client, 100, 100), true);
+ EXPECT(client->sendWarp(100, 100), true);
EXPECT(isCursorPos(100, 100), true);
- EXPECT(sendWarp(client, 0, 0), true);
+ EXPECT(client->sendWarp(0, 0), true);
EXPECT(isCursorPos(0, 0), true);
- EXPECT(sendWarp(client, 200, 200), true);
+ EXPECT(client->sendWarp(200, 200), true);
EXPECT(isCursorPos(200, 200), true);
- EXPECT(sendWarp(client, 100, -100), true);
+ EXPECT(client->sendWarp(100, -100), true);
EXPECT(isCursorPos(200, 200), true);
- EXPECT(sendWarp(client, 234, 345), true);
+ EXPECT(client->sendWarp(234, 345), true);
EXPECT(isCursorPos(234, 345), true);
- EXPECT(sendWarp(client, -1, -1), true);
+ EXPECT(client->sendWarp(-1, -1), true);
EXPECT(isCursorPos(234, 345), true);
- EXPECT(sendWarp(client, 1, -1), true);
+ EXPECT(client->sendWarp(1, -1), true);
EXPECT(isCursorPos(234, 345), true);
- EXPECT(sendWarp(client, 13, 37), true);
+ EXPECT(client->sendWarp(13, 37), true);
EXPECT(isCursorPos(13, 37), true);
- EXPECT(sendWarp(client, -100, 100), true);
+ EXPECT(client->sendWarp(-100, 100), true);
EXPECT(isCursorPos(13, 37), true);
- EXPECT(sendWarp(client, -1, 1), true);
+ EXPECT(client->sendWarp(-1, 1), true);
EXPECT(isCursorPos(13, 37), true);
-
- stopClient(client);
-
- NLog::log("{}Reloading the config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_CLIENT_TEST_FN(test);
diff --git a/hyprtester/src/tests/clients/shortcut-inhibitor.cpp b/hyprtester/src/tests/clients/shortcut-inhibitor.cpp
index 1039916a..491b6f47 100644
--- a/hyprtester/src/tests/clients/shortcut-inhibitor.cpp
+++ b/hyprtester/src/tests/clients/shortcut-inhibitor.cpp
@@ -1,4 +1,3 @@
-#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include "../shared.hpp"
#include "tests.hpp"
@@ -7,6 +6,7 @@
#include <hyprutils/os/FileDescriptor.hpp>
#include <hyprutils/os/Process.hpp>
+#include <optional>
#include <sys/poll.h>
#include <csignal>
#include <thread>
@@ -17,106 +17,109 @@ using namespace Hyprutils::Memory;
#define SP CSharedPointer
-struct SClient {
- SP<CProcess> proc;
- std::array<char, 1024> readBuf;
- CFileDescriptor readFd, writeFd;
- struct pollfd fds;
-};
+namespace {
-static int ret = 0;
+ class CClient {
+ SP<CProcess> proc;
+ std::array<char, 1024> readBuf;
+ CFileDescriptor readFd, writeFd;
+ struct pollfd fds;
-static bool startClient(SClient& client) {
+ public:
+ CClient();
+ ~CClient();
+ };
+}
+
+CClient::CClient() {
Tests::killAllWindows();
- client.proc = makeShared<CProcess>(binaryDir + "/shortcut-inhibitor", std::vector<std::string>{});
+ this->proc = makeShared<CProcess>(binaryDir + "/shortcut-inhibitor", std::vector<std::string>{});
- client.proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
+ this->proc->addEnv("WAYLAND_DISPLAY", WLDISPLAY);
int pipeFds1[2], pipeFds2[2];
if (pipe(pipeFds1) != 0 || pipe(pipeFds2) != 0) {
NLog::log("{}Unable to open pipe to client", Colors::RED);
- return false;
+ throw std::exception();
}
- client.writeFd = CFileDescriptor(pipeFds1[1]);
- client.proc->setStdinFD(pipeFds1[0]);
+ this->writeFd = CFileDescriptor(pipeFds1[1]);
+ this->proc->setStdinFD(pipeFds1[0]);
- client.readFd = CFileDescriptor(pipeFds2[0]);
- client.proc->setStdoutFD(pipeFds2[1]);
+ this->readFd = CFileDescriptor(pipeFds2[0]);
+ this->proc->setStdoutFD(pipeFds2[1]);
const int COUNT_BEFORE = Tests::windowCount();
- client.proc->runAsync();
+ this->proc->runAsync();
close(pipeFds1[0]);
close(pipeFds2[1]);
- client.fds = {.fd = client.readFd.get(), .events = POLLIN};
- if (poll(&client.fds, 1, 1000) != 1 || !(client.fds.revents & POLLIN)) {
+ this->fds = {.fd = this->readFd.get(), .events = POLLIN};
+ if (poll(&this->fds, 1, 1000) != 1 || !(this->fds.revents & POLLIN)) {
NLog::log("{}shortcut-inhibitor client failed poll", Colors::RED);
- return false;
+ throw std::exception();
}
- client.readBuf.fill(0);
- if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1) {
+ this->readBuf.fill(0);
+ if (read(this->readFd.get(), this->readBuf.data(), this->readBuf.size() - 1) == -1) {
NLog::log("{}shortcut-inhibitor client read failed", Colors::RED);
- return false;
+ throw std::exception();
}
- std::string ret = std::string{client.readBuf.data()};
+ std::string ret = std::string{this->readBuf.data()};
if (ret.find("started") == std::string::npos) {
NLog::log("{}Failed to start shortcut-inhibitor client, read {}", Colors::RED, ret);
- return false;
+ throw std::exception();
}
// wait for window to appear
int counter = 0;
- while (Tests::processAlive(client.proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
+ while (Tests::processAlive(this->proc->pid()) && Tests::windowCount() == COUNT_BEFORE) {
counter++;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (counter > 50) {
NLog::log("{}shortcut-inhibitor client took too long to open", Colors::RED);
- return false;
+ throw std::exception();
}
}
- if (!Tests::processAlive(client.proc->pid())) {
+ if (!Tests::processAlive(this->proc->pid())) {
NLog::log("{}shortcut-inhibitor client not alive", Colors::RED);
- return false;
+ throw std::exception();
}
- if (getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", client.proc->pid())) != "ok") {
+ if (getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", this->proc->pid())) != "ok") {
NLog::log("{}Failed to focus shortcut-inhibitor client", Colors::RED, ret);
- return false;
+ throw std::exception();
}
std::string command = "on\n";
- if (write(client.writeFd.get(), command.c_str(), command.length()) == -1) {
+ if (write(this->writeFd.get(), command.c_str(), command.length()) == -1) {
NLog::log("{}shortcut-inhibitor client write failed", Colors::RED);
- return false;
+ throw std::exception();
}
- client.readBuf.fill(0);
- if (read(client.readFd.get(), client.readBuf.data(), client.readBuf.size() - 1) == -1)
- return false;
+ this->readBuf.fill(0);
+ if (read(this->readFd.get(), this->readBuf.data(), this->readBuf.size() - 1) == -1)
+ throw std::exception();
- ret = std::string{client.readBuf.data()};
+ ret = std::string{this->readBuf.data()};
if (ret.find("inhibiting") == std::string::npos) {
NLog::log("{}shortcut-inhibitor client didn't return inhibiting", Colors::RED);
- return false;
+ throw std::exception();
}
NLog::log("{}Started shortcut-inhibitor client", Colors::YELLOW);
-
- return true;
}
-static void stopClient(SClient& client) {
+CClient::~CClient() {
std::string cmd = "off\n";
- write(client.writeFd.get(), cmd.c_str(), cmd.length());
+ write(this->writeFd.get(), cmd.c_str(), cmd.length());
- kill(client.proc->pid(), SIGKILL);
- client.proc.reset();
+ kill(this->proc->pid(), SIGKILL);
+ this->proc.reset();
}
static std::string flagFile = "/tmp/hyprtester-keybinds.txt";
@@ -138,10 +141,12 @@ static bool attemptCheckFlag(int attempts, int intervalMs) {
return false;
}
-static bool test() {
- SClient client;
- if (!startClient(client))
- return false;
+TEST_CASE(shortcutInhibitor) {
+ std::optional<CClient> client;
+
+ try {
+ client.emplace();
+ } catch (...) { FAIL_TEST("Couldn't start the client"); }
NLog::log("{}Testing keybinds", Colors::GREEN);
//basic keybind test
@@ -168,13 +173,4 @@ static bool test() {
//gesture bypass flag test
OK(getFromSocket("/eval hl.plugin.test.gesture('right', 2)"));
EXPECT_CONTAINS(getFromSocket("/activewindow"), "floating: 1");
-
- stopClient(client);
-
- NLog::log("{}Reloading the config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_CLIENT_TEST_FN(test);
diff --git a/hyprtester/src/tests/clients/tests.hpp b/hyprtester/src/tests/clients/tests.hpp
index 31746fe5..7f10fba7 100644
--- a/hyprtester/src/tests/clients/tests.hpp
+++ b/hyprtester/src/tests/clients/tests.hpp
@@ -1,12 +1,9 @@
#pragma once
+#include <map>
-#include <vector>
-#include <functional>
+#include "../../shared.hpp"
-inline std::vector<std::function<bool()>> clientTestFns;
+inline std::map<const char*, CTestCase&> clientTestCases;
-#define REGISTER_CLIENT_TEST_FN(fn) \
- static auto _register_fn = [] { \
- clientTestFns.emplace_back(fn); \
- return 1; \
- }();
+// Where `TEST_CASE` macros will store generated test cases:
+#define TEST_CASES_STORAGE clientTestCases
diff --git a/hyprtester/src/tests/main/animations.cpp b/hyprtester/src/tests/main/animations.cpp
index e464dcbd..2f918d2b 100644
--- a/hyprtester/src/tests/main/animations.cpp
+++ b/hyprtester/src/tests/main/animations.cpp
@@ -5,18 +5,11 @@
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
-static bool test() {
- NLog::log("{}Testing animations", Colors::GREEN);
-
+TEST_CASE(animationsTrivial) {
auto str = getFromSocket("/animations");
NLog::log("{}Testing bezier curve output from `hyprctl animations`", Colors::YELLOW);
- {EXPECT_CONTAINS(str, std::format("beziers:\n\n\tname: quick\n\t\tX0: 0.15\n\t\tY0: 0.00\n\t\tX1: 0.10\n\t\tY1: 1.00"))};
- return !ret;
+ ASSERT_CONTAINS(str, std::format("beziers:\n\n\tname: quick\n\t\tX0: 0.15\n\t\tY0: 0.00\n\t\tX1: 0.10\n\t\tY1: 1.00"));
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/colors.cpp b/hyprtester/src/tests/main/colors.cpp
index ee80f24f..93dcbb65 100644
--- a/hyprtester/src/tests/main/colors.cpp
+++ b/hyprtester/src/tests/main/colors.cpp
@@ -6,32 +6,24 @@
#include <chrono>
#include <thread>
-static int ret = 0;
-
-static bool test() {
- NLog::log("{}Testing hyprctl monitors", Colors::GREEN);
-
+TEST_CASE(monitorsColorManagement) {
std::string monitorsSpec = getFromSocket("j/monitors");
- EXPECT_CONTAINS(monitorsSpec, R"("colorManagementPreset")");
+ ASSERT_CONTAINS(monitorsSpec, R"("colorManagementPreset")");
- EXPECT_CONTAINS(getFromSocket("/eval hl.monitor({ output = 'HEADLESS-2', bitdepth = 10, cm = 'wide' })"), "ok")
+ ASSERT_CONTAINS(getFromSocket("/eval hl.monitor({ output = 'HEADLESS-2', bitdepth = 10, cm = 'wide' })"), "ok");
// monitor settings are applied after a frame is pushed.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
monitorsSpec = getFromSocket("j/monitors");
- EXPECT_CONTAINS(monitorsSpec, R"("colorManagementPreset": "wide")");
+ ASSERT_CONTAINS(monitorsSpec, R"("colorManagementPreset": "wide")");
- EXPECT_CONTAINS(getFromSocket("/eval hl.monitor({ output = 'HEADLESS-2', bitdepth = 10, cm = 'srgb', sdrbrightness = 1.2, sdrsaturation = 0.98 })"), "ok")
+ ASSERT_CONTAINS(getFromSocket("/eval hl.monitor({ output = 'HEADLESS-2', bitdepth = 10, cm = 'srgb', sdrbrightness = 1.2, sdrsaturation = 0.98 })"), "ok");
monitorsSpec = getFromSocket("j/monitors");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
- EXPECT_CONTAINS(monitorsSpec, "colorManagementPreset");
- EXPECT_CONTAINS(monitorsSpec, "sdrBrightness");
- EXPECT_CONTAINS(monitorsSpec, "sdrSaturation");
-
- return !ret;
+ ASSERT_CONTAINS(monitorsSpec, "colorManagementPreset");
+ ASSERT_CONTAINS(monitorsSpec, "sdrBrightness");
+ ASSERT_CONTAINS(monitorsSpec, "sdrSaturation");
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/dwindle.cpp b/hyprtester/src/tests/main/dwindle.cpp
index b0bbe9a9..5641f8ac 100644
--- a/hyprtester/src/tests/main/dwindle.cpp
+++ b/hyprtester/src/tests/main/dwindle.cpp
@@ -3,15 +3,10 @@
#include "../../hyprctlCompat.hpp"
#include "tests.hpp"
-static int ret = 0;
-
-static void testFloatClamp() {
+TEST_CASE(dwindleFloatClamp) {
for (auto const& win : {"a", "b", "c"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -30,25 +25,16 @@ static void testFloatClamp() {
}
OK(getFromSocket("/eval hl.config({ dwindle = { force_split = 0 } })"));
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- OK(getFromSocket("/reload"));
}
-static void test13349() {
+TEST_CASE(dwindleIssue13349) {
// Test if dwindle properly uses a focal point to place a new window.
// exposed by #13349 as a regression from #12890
for (auto const& win : {"a", "b", "c"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -75,13 +61,9 @@ static void test13349() {
EXPECT_CONTAINS(str, "at: 967,547");
EXPECT_CONTAINS(str, "size: 931,511");
}
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
-static void testSplit() {
+TEST_CASE(dwindleSplit) {
// Test various split methods
Tests::spawnKitty("a");
@@ -130,22 +112,16 @@ static void testSplit() {
EXPECT_CONTAINS(str, "at: 22,859");
EXPECT_CONTAINS(str, "size: 1876,199");
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
-static void testRotatesplit() {
+TEST_CASE(dwindleRotateSplit) {
OK(getFromSocket("r/eval hl.config({ general = { gaps_in = 0 } })"));
OK(getFromSocket("r/eval hl.config({ general = { gaps_out = 0 } })"));
OK(getFromSocket("r/eval hl.config({ general = { border_size = 0 } })"));
for (auto const& win : {"a", "b"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -220,19 +196,14 @@ static void testRotatesplit() {
EXPECT_CONTAINS(str, "at: 960,0");
EXPECT_CONTAINS(str, "size: 960,1080");
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- OK(getFromSocket("/reload"));
}
-static void testForceSplitOnMoveToWorkspace() {
+TEST_CASE(dwindleForceSplitOnMoveToWorkspace) {
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '2' })"));
- EXPECT(!!Tests::spawnKitty("kitty"), true);
+ ASSERT(!!Tests::spawnKitty("kitty"), true);
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
- EXPECT(!!Tests::spawnKitty("kitty"), true);
+ ASSERT(!!Tests::spawnKitty("kitty"), true);
std::string posBefore = Tests::getWindowAttribute(getFromSocket("/activewindow"), "at:");
OK(getFromSocket("/eval hl.config({ dwindle = { force_split = 2 } })"));
@@ -242,38 +213,4 @@ static void testForceSplitOnMoveToWorkspace() {
// Should be moved to the right, so the position should change
std::string activeWindow = getFromSocket("/activewindow");
EXPECT(activeWindow.contains(posBefore), false);
-
- // clean up
- OK(getFromSocket("/reload"));
- Tests::killAllWindows();
- Tests::waitUntilWindowsN(0);
-}
-
-static bool test() {
- NLog::log("{}Testing Dwindle layout", Colors::GREEN);
-
- // test
- NLog::log("{}Testing float clamp", Colors::GREEN);
- testFloatClamp();
-
- NLog::log("{}Testing #13349", Colors::GREEN);
- test13349();
-
- NLog::log("{}Testing splits", Colors::GREEN);
- testSplit();
-
- NLog::log("{}Testing rotatesplit", Colors::GREEN);
- testRotatesplit();
-
- NLog::log("{}Testing force_split on move to workspace", Colors::GREEN);
- testForceSplitOnMoveToWorkspace();
-
- // clean up
- NLog::log("Cleaning up", Colors::YELLOW);
- getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })");
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_TEST_FN(test);
diff --git a/hyprtester/src/tests/main/exec.cpp b/hyprtester/src/tests/main/exec.cpp
index 099f2cbc..ff19edfe 100644
--- a/hyprtester/src/tests/main/exec.cpp
+++ b/hyprtester/src/tests/main/exec.cpp
@@ -8,8 +8,6 @@
#include <hyprutils/memory/WeakPtr.hpp>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
@@ -18,9 +16,7 @@ using namespace Hyprutils::Memory;
const static auto SLEEP_DURATIONS = std::array{1, 10};
-static bool test() {
- NLog::log("{}Testing process spawning", Colors::GREEN);
-
+TEST_CASE(processSpawning) {
for (const auto duration : SLEEP_DURATIONS) {
// Note: POSIX sleep does not support fractional seconds, so
// can't sleep for less than 1 second.
@@ -45,17 +41,9 @@ static bool test() {
// Ensure that sleep did not become a zombie
EXPECT(Tests::processAlive(sleepPid), false);
- // kill all
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return !ret;
+ // Test succeeded
+ return;
}
- return false;
+ FAIL_TEST_SILENT();
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/follow_mouse_shrink.cpp b/hyprtester/src/tests/main/follow_mouse_shrink.cpp
index b41e9fd6..0e12915b 100644
--- a/hyprtester/src/tests/main/follow_mouse_shrink.cpp
+++ b/hyprtester/src/tests/main/follow_mouse_shrink.cpp
@@ -7,17 +7,6 @@
#include "../shared.hpp"
#include "tests.hpp"
-static int ret = 0;
-
-static bool spawnKitty(const std::string& class_) {
- NLog::log("{}Spawning {}", Colors::YELLOW, class_);
- if (!Tests::spawnKitty(class_)) {
- NLog::log("{}Error: {} did not spawn", Colors::RED, class_);
- return false;
- }
- return true;
-}
-
static bool isActiveWindow(const std::string& class_, char fullscreen = '0', bool log = true) {
std::string activeWin = getFromSocket("/activewindow");
auto winClass = Tests::getWindowAttribute(activeWin, "class:");
@@ -43,7 +32,8 @@ static bool waitForActiveWindow(const std::string& class_, char fullscreen = '0'
return true;
}
-static bool test() {
+// TODO: split this into multiple test cases
+TEST_CASE(followMouseShrink) {
NLog::log("{}Testing follow_mouse_shrink", Colors::GREEN);
getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:follow_mouse_shrink' })");
@@ -56,15 +46,15 @@ static bool test() {
// Spawn two floating windows with a 20px gap
// fms_a: position (100,100), size 400x400 -> hitbox [100,499] x [100,499]
- if (!spawnKitty("fms_a"))
- return false;
+ if (!Tests::spawnKitty("fms_a"))
+ FAIL_TEST("Couldn't spawn kitty");
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set' })"));
OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 400, y = 400 })"));
OK(getFromSocket("/dispatch hl.dsp.window.move({ x = 100, y = 100 })"));
// fms_b: position (520,100), size 400x400 -> hitbox [520,919] x [100,499]
- if (!spawnKitty("fms_b"))
- return false;
+ if (!Tests::spawnKitty("fms_b"))
+ FAIL_TEST("Couldn't spawn kitty");
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set' })"));
OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 400, y = 400 })"));
OK(getFromSocket("/dispatch hl.dsp.window.move({ x = 520, y = 100 })"));
@@ -74,58 +64,50 @@ static bool test() {
OK(getFromSocket("/eval hl.config({ input = { follow_mouse_shrink = 0 } })"));
// Focus A explicitly, then move cursor inside A so follow_mouse tracks it
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:fms_a' })"));
- EXPECT(waitForActiveWindow("fms_a"), true);
+ ASSERT(waitForActiveWindow("fms_a"), true);
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 300, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// Move to just inside B's left edge
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 521, y = 300 })"));
- EXPECT(waitForActiveWindow("fms_b"), true);
+ ASSERT(waitForActiveWindow("fms_b"), true);
// --- Test 2: Shrink=20, cursor in dead zone does NOT change focus ---
NLog::log("{}Test 2: shrink=20, cursor in B's dead zone stays on A", Colors::GREEN);
OK(getFromSocket("/eval hl.config({ input = { follow_mouse_shrink = 20 } })"));
// Focus A explicitly
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:fms_a' })"));
- EXPECT(waitForActiveWindow("fms_a"), true);
+ ASSERT(waitForActiveWindow("fms_a"), true);
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 300, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// Move to 530,300 -- 10px inside B, within 20px shrink zone (B's shrunk hitbox starts at 540)
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 530, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
- EXPECT(isActiveWindow("fms_a"), true);
+ ASSERT(isActiveWindow("fms_a"), true);
// --- Test 3: Shrink=20, cursor well inside inactive window DOES focus it ---
NLog::log("{}Test 3: shrink=20, cursor at B's center focuses B", Colors::GREEN);
// Still focused on A from test 2
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 720, y = 300 })"));
- EXPECT(waitForActiveWindow("fms_b"), true);
+ ASSERT(waitForActiveWindow("fms_b"), true);
// --- Test 4: Focused window's hitbox is NOT shrunk ---
NLog::log("{}Test 4a: focused window hitbox is not shrunk", Colors::GREEN);
// Focus A explicitly, move cursor inside A, then move near A's right edge
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:fms_a' })"));
- EXPECT(waitForActiveWindow("fms_a"), true);
+ ASSERT(waitForActiveWindow("fms_a"), true);
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 300, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 490, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
- EXPECT(isActiveWindow("fms_a"), true);
+ ASSERT(isActiveWindow("fms_a"), true);
NLog::log("{}Test 4b: inactive window hitbox IS shrunk at same position", Colors::GREEN);
// Focus B explicitly, then move to (490,300). Now A is inactive with shrunk box ending at 479, so 490 is outside A.
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:fms_b' })"));
- EXPECT(waitForActiveWindow("fms_b"), true);
+ ASSERT(waitForActiveWindow("fms_b"), true);
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 720, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 490, y = 300 })"));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
- EXPECT(isActiveWindow("fms_b"), true);
-
- // Cleanup
- OK(getFromSocket("/reload"));
- Tests::killAllWindows();
-
- return ret == 0;
+ ASSERT(isActiveWindow("fms_b"), true);
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/gestures.cpp b/hyprtester/src/tests/main/gestures.cpp
index 131061c4..f8324712 100644
--- a/hyprtester/src/tests/main/gestures.cpp
+++ b/hyprtester/src/tests/main/gestures.cpp
@@ -10,14 +10,13 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define UP CUniquePointer
#define SP CSharedPointer
+// TODO: refactor and reuse `Tests::waitUntilWindowsN`
static bool waitForWindowCount(int expectedWindowCnt, std::string_view expectation, int waitMillis = 100, int maxWaitCnt = 50) {
int counter = 0;
while (Tests::windowCount() != expectedWindowCnt) {
@@ -32,17 +31,10 @@ static bool waitForWindowCount(int expectedWindowCnt, std::string_view expectati
return true;
}
-static bool test() {
- NLog::log("{}Testing gestures", Colors::GREEN);
-
- EXPECT(Tests::windowCount(), 0);
-
- // test on workspace "window"
- NLog::log("{}Switching to workspace 1", Colors::YELLOW);
- getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"); // no OK: we might be on 1 already
-
+// TODO: decompose this into multiple test cases
+TEST_CASE(gestures) {
Tests::spawnKitty();
- EXPECT(Tests::windowCount(), 1);
+ ASSERT(Tests::windowCount(), 1);
// Give the shell a moment to initialize
std::this_thread::sleep_for(std::chrono::milliseconds(500));
@@ -148,7 +140,7 @@ static bool test() {
EXPECT(waitForWindowCount(0, "Gesture closed kitty"), true);
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
// This test ensures that `movecursortocorner`, which expects
// a single-character direction argument, is parsed correctly.
@@ -186,18 +178,4 @@ static bool test() {
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
}
-
- // kill all
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- // reload cfg
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/groups.cpp b/hyprtester/src/tests/main/groups.cpp
index 71b5cf18..7e1c63b6 100644
--- a/hyprtester/src/tests/main/groups.cpp
+++ b/hyprtester/src/tests/main/groups.cpp
@@ -10,17 +10,14 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define UP CUniquePointer
#define SP CSharedPointer
-static bool test() {
- NLog::log("{}Testing groups", Colors::GREEN);
-
+// TODO: decompose this into multiple test cases
+TEST_CASE(groups) {
// test on workspace "window"
NLog::log("{}Dispatching workspace `groups`", Colors::YELLOW);
getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:groups' })");
@@ -28,8 +25,7 @@ static bool test() {
NLog::log("{}Testing movewindoworgroup from group to group", Colors::YELLOW);
auto kittyA = Tests::spawnKitty("kittyA");
if (!kittyA) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
// check kitty properties. One kitty should take the entire screen, minus the gaps.
@@ -43,8 +39,7 @@ static bool test() {
auto kittyB = Tests::spawnKitty("kittyB");
if (!kittyB) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kittyB' })"));
@@ -61,8 +56,7 @@ static bool test() {
auto kittyC = Tests::spawnKitty("kittyC");
if (!kittyC) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Check kittyC dimensions", Colors::YELLOW);
@@ -87,12 +81,11 @@ static bool test() {
NLog::log("{}Spawning kittyProcA", Colors::YELLOW);
auto kittyProcA = Tests::spawnKitty();
if (!kittyProcA) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Expecting 1 window", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 1);
+ ASSERT(Tests::windowCount(), 1);
// check kitty properties. One kitty should take the entire screen, minus the gaps.
NLog::log("{}Check kitty dimensions", Colors::YELLOW);
@@ -127,8 +120,7 @@ static bool test() {
NLog::log("{}Spawn kitty again", Colors::YELLOW);
kittyProcA = Tests::spawnKitty();
if (!kittyProcA) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Group kitty", Colors::YELLOW);
@@ -145,12 +137,11 @@ static bool test() {
NLog::log("{}Spawn kittyProcB", Colors::YELLOW);
auto kittyProcB = Tests::spawnKitty();
if (!kittyProcB) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Expecting 2 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
size_t lastActiveKittyIdx = 0;
@@ -158,10 +149,7 @@ static bool test() {
try {
auto str = getFromSocket("/activewindow");
lastActiveKittyIdx = std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16);
- } catch (...) {
- NLog::log("{}Fail at getting prop", Colors::RED);
- ret = 1;
- }
+ } catch (...) { FAIL_TEST("Could not extract the active window id"); }
// test cycling through
@@ -170,21 +158,15 @@ static bool test() {
try {
auto str = getFromSocket("/activewindow");
- EXPECT(lastActiveKittyIdx != std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16), true);
- } catch (...) {
- NLog::log("{}Fail at getting prop", Colors::RED);
- ret = 1;
- }
+ ASSERT(lastActiveKittyIdx != std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16), true);
+ } catch (...) { FAIL_TEST("Could not extract the active window id"); }
getFromSocket("/dispatch hl.dsp.group.next()");
try {
auto str = getFromSocket("/activewindow");
- EXPECT(lastActiveKittyIdx, std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16));
- } catch (...) {
- NLog::log("{}Fail at getting prop", Colors::RED);
- ret = 1;
- }
+ ASSERT(lastActiveKittyIdx, std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16));
+ } catch (...) { FAIL_TEST("Could not extract the active window id"); }
// test movegroupwindow: focus should follow the moved window
NLog::log("{}Test movegroupwindow focus follows window", Colors::YELLOW);
@@ -195,10 +177,7 @@ static bool test() {
str = getFromSocket("/activewindow");
auto activeAfterMove = std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16);
EXPECT(activeAfterMove, activeBeforeMove);
- } catch (...) {
- NLog::log("{}Fail at getting prop", Colors::RED);
- ret = 1;
- }
+ } catch (...) { FAIL_TEST("Could not extract the active window id"); }
// and backwards
NLog::log("{}Test movegroupwindow backwards", Colors::YELLOW);
@@ -209,10 +188,7 @@ static bool test() {
str = getFromSocket("/activewindow");
auto activeAfterMove = std::stoull(str.substr(7, str.find(" -> ") - 7), nullptr, 16);
EXPECT(activeAfterMove, activeBeforeMove);
- } catch (...) {
- NLog::log("{}Fail at getting prop", Colors::RED);
- ret = 1;
- }
+ } catch (...) { FAIL_TEST("Could not extract the active window id"); }
NLog::log("{}Disable autogrouping", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ group = { auto_group = false } })"));
@@ -220,12 +196,11 @@ static bool test() {
NLog::log("{}Spawn kittyProcC", Colors::YELLOW);
auto kittyProcC = Tests::spawnKitty();
if (!kittyProcC) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Expecting 3 windows 2", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 3);
+ ASSERT(Tests::windowCount(), 3);
{
auto str = getFromSocket("/clients");
EXPECT_COUNT_STRING(str, "at: 22,22", 2);
@@ -239,12 +214,11 @@ static bool test() {
NLog::log("{}Spawn kittyProcD", Colors::YELLOW);
auto kittyProcD = Tests::spawnKitty();
if (!kittyProcD) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Expecting 4 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 4);
+ ASSERT(Tests::windowCount(), 4);
OK(getFromSocket("/dispatch hl.dsp.group.active({ index = 3 })"));
@@ -258,7 +232,7 @@ static bool test() {
Tests::killAllWindows();
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
// test movewindoworgroup: direction should be respected when extracting from group
NLog::log("{}Test movewindoworgroup respects direction out of group", Colors::YELLOW);
@@ -266,8 +240,7 @@ static bool test() {
{
auto kittyE = Tests::spawnKitty();
if (!kittyE) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
// group kitty, and new windows should be auto-grouped
@@ -275,10 +248,9 @@ static bool test() {
auto kittyF = Tests::spawnKitty();
if (!kittyF) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
// both windows should be grouped at the same position
{
@@ -310,7 +282,7 @@ static bool test() {
}
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
}
// test that we deny a floated window getting auto-grouped into a tiled group.
@@ -320,8 +292,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'kitty-tiled', tile = true })"));
auto kittyProcE = Tests::spawnKitty("kitty_tiled");
if (!kittyProcE) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
@@ -329,18 +300,16 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'kitty-floated', float = true })"));
auto kittyProcF = Tests::spawnKitty("kitty_floated");
if (!kittyProcF) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
{
auto clients = getFromSocket("/clients");
auto classPos = clients.find("class: kitty_floated");
if (classPos == std::string::npos) {
- NLog::log("{}Could not find kitty_floated in clients output", Colors::RED);
- ret = 1;
+ FAIL_TEST("Could not find kitty_floated in clients output");
} else {
auto entryStart = clients.rfind("Window ", classPos);
auto entryEnd = clients.find("\n\n", classPos);
@@ -351,27 +320,25 @@ static bool test() {
}
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
// Tests for grouping/merging logic
NLog::log("{}Testing locked groups w/ invade", Colors::GREEN);
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
// Test normal, unlocked groups
{
auto winA = Tests::spawnKitty("unlocked");
if (!winA) {
- NLog::log("{}Error: unlocked kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn unlocked kitty");
}
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
auto winB = Tests::spawnKitty("top");
if (!winB) {
- NLog::log("{}Error: top kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn top kitty");
}
// Verify it DID merge into a group
@@ -382,14 +349,13 @@ static bool test() {
}
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
// Test locked groups
{
auto lockedWin = Tests::spawnKitty("locked");
if (!lockedWin) {
- NLog::log("{}Error: locked kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn locked kitty");
}
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
OK(getFromSocket(std::format("/dispatch hl.dsp.focus({{ window = 'pid:{}' }})", lockedWin->pid())));
@@ -397,8 +363,7 @@ static bool test() {
auto winB = Tests::spawnKitty("top");
if (!winB) {
- NLog::log("{}Error: top kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn top kitty");
}
// Verify it did NOT merge into the locked group
@@ -409,7 +374,7 @@ static bool test() {
}
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
// Test locked groups WITH invade rule
{
@@ -418,14 +383,12 @@ static bool test() {
auto lockedWin = Tests::spawnKitty("locked");
if (!lockedWin) {
- NLog::log("{}Error: locked kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn locked kitty");
}
auto invadingWin = Tests::spawnKitty("invade");
if (!invadingWin) {
- NLog::log("{}Error: invading kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn invading kitty");
}
// Verify it DID merge into the locked group
@@ -434,9 +397,5 @@ static bool test() {
}
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
-
- return !ret;
+ ASSERT(Tests::windowCount(), 0);
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/hyprctl.cpp b/hyprtester/src/tests/main/hyprctl.cpp
index c6d6a9bf..c67c8af9 100644
--- a/hyprtester/src/tests/main/hyprctl.cpp
+++ b/hyprtester/src/tests/main/hyprctl.cpp
@@ -12,8 +12,6 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
@@ -35,9 +33,7 @@ static void setWindowProp(const std::string& selector, const std::string& prop,
getFromSocket("/dispatch hl.dsp.window.set_prop({ window = '" + selector + "', prop = '" + prop + "', value = '" + value + "' })");
}
-static bool testDevicesActiveLayoutIndex() {
- NLog::log("{}Testing hyprctl devices active_layout_index", Colors::GREEN);
-
+TEST_CASE(hyprctlDevicesActiveLayoutIndex) {
// configure layouts
OK(getFromSocket("r/eval hl.config({ input = { kb_layout = \"us,pl,ua\" } })"));
@@ -49,15 +45,11 @@ static bool testDevicesActiveLayoutIndex() {
// check layout index
EXPECT_CONTAINS(devicesJson, expected);
}
-
- return true;
}
-static bool testGetprop() {
- NLog::log("{}Testing hyprctl getprop", Colors::GREEN);
+TEST_CASE(hyprctlGetprop) {
if (!Tests::spawnKitty()) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
// animation
@@ -166,41 +158,16 @@ static bool testGetprop() {
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");
-
- // kill all
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return true;
}
-static void testSubmap() {
- NLog::log("{}Testing hyprctl submap", Colors::GREEN);
-
+TEST_CASE(hyprctlSubmap) {
EXPECT(getCommandStdOut("hyprctl submap"), "default\n");
EXPECT(getCommandStdOut("hyprctl submap -j | jq -r \".\""), "default");
}
-static bool test() {
- NLog::log("{}Testing hyprctl", Colors::GREEN);
-
- {
- NLog::log("{}Testing hyprctl descriptions for any json errors", Colors::GREEN);
- CProcess jqProc("bash", {"-c", "hyprctl descriptions | jq"});
- jqProc.addEnv("HYPRLAND_INSTANCE_SIGNATURE", HIS);
- jqProc.runSync();
- EXPECT(jqProc.exitCode(), 0);
- }
-
- testGetprop();
- testDevicesActiveLayoutIndex();
- testSubmap();
- getFromSocket("/reload");
-
- return !ret;
+TEST_CASE(hyprctlJsonErrors) {
+ CProcess jqProc("bash", {"-c", "hyprctl descriptions | jq"});
+ jqProc.addEnv("HYPRLAND_INSTANCE_SIGNATURE", HIS);
+ jqProc.runSync();
+ EXPECT(jqProc.exitCode(), 0);
}
-
-REGISTER_TEST_FN(test);
diff --git a/hyprtester/src/tests/main/keybinds.cpp b/hyprtester/src/tests/main/keybinds.cpp
index c9a7786c..a1b5288c 100644
--- a/hyprtester/src/tests/main/keybinds.cpp
+++ b/hyprtester/src/tests/main/keybinds.cpp
@@ -8,8 +8,6 @@
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
-
-static int ret = 0;
static std::string flagFile = "/tmp/hyprtester-keybinds.txt";
static std::string pluginKeybindCmd(bool pressed, uint32_t modifier, uint32_t key) {
@@ -88,7 +86,11 @@ static CUniquePointer<CProcess> spawnRemoteControlKitty() {
return kittyProc;
}
-static void testBind() {
+// All the `SUBTEST`s below are supposed to be independent `TEST_CASE`s.
+// But if isolated trivially, some of them fail.
+// TODO: investigate and isolate tests by turning `SUBTEST`s into `TEST_CASE`s.
+
+SUBTEST(bind) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.exec_cmd('touch " + flagFile + "'))"), "ok");
// press keybind
@@ -100,7 +102,7 @@ static void testBind() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static void testBindKey() {
+SUBTEST(bindKey) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('Y', hl.dsp.exec_cmd('touch " + flagFile + "'))"), "ok");
// press keybind
@@ -112,7 +114,7 @@ static void testBindKey() {
EXPECT(getFromSocket("/eval hl.unbind('', 'Y')"), "ok");
}
-static void testLongPress() {
+SUBTEST(longPress) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { long_press = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -128,8 +130,7 @@ static void testLongPress() {
OK(getFromSocket(pluginKeybindCmd(false, 0, 29)));
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-
-static void testKeyLongPress() {
+SUBTEST(keyLongPress) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { long_press = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -146,7 +147,7 @@ static void testKeyLongPress() {
EXPECT(getFromSocket("/eval hl.unbind('', 'Y')"), "ok");
}
-static void testLongPressRelease() {
+SUBTEST(longPressRelease) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { long_press = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -162,8 +163,7 @@ static void testLongPressRelease() {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-
-static void testLongPressOnlyKeyRelease() {
+SUBTEST(longPressOnlyKeyRelease) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { long_press = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -181,7 +181,7 @@ static void testLongPressOnlyKeyRelease() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static void testRepeat() {
+SUBTEST(repeat) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { repeating = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -201,7 +201,7 @@ static void testRepeat() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static void testKeyRepeat() {
+SUBTEST(keyRepeat) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { repeating = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -221,7 +221,7 @@ static void testKeyRepeat() {
EXPECT(getFromSocket("/eval hl.unbind('', 'Y')"), "ok");
}
-static void testRepeatRelease() {
+SUBTEST(repeatRelease) {
// wait until flag becomes false (CI timing can vary)
bool ok = false;
for (int i = 0; i < 20; ++i) {
@@ -253,7 +253,7 @@ static void testRepeatRelease() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static void testRepeatOnlyKeyRelease() {
+SUBTEST(repeatOnlyKeyRelease) {
EXPECT(checkFlag(), false);
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.exec_cmd('touch " + flagFile + "'), { repeating = true })"), "ok");
EXPECT(getFromSocket("r/eval hl.config({ input = { repeat_delay = 100 } })"), "ok");
@@ -276,12 +276,10 @@ static void testRepeatOnlyKeyRelease() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static void testShortcutBind() {
+SUBTEST(shortcutBind) {
auto kittyProc = spawnRemoteControlKitty();
if (!kittyProc) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
EXPECT(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:keybinds_test' })"), "ok");
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.send_shortcut({ mods = '', key = 'q', window = 'activewindow' }))"), "ok");
@@ -298,12 +296,10 @@ static void testShortcutBind() {
Tests::killAllWindows();
}
-static void testShortcutBindKey() {
+SUBTEST(shortcutBindKey) {
auto kittyProc = spawnRemoteControlKitty();
if (!kittyProc) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
EXPECT(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:keybinds_test' })"), "ok");
EXPECT(getFromSocket("/eval hl.bind('Y', hl.dsp.send_shortcut({ mods = '', key = 'q', window = 'activewindow' }))"), "ok");
@@ -321,12 +317,10 @@ static void testShortcutBindKey() {
Tests::killAllWindows();
}
-static void testShortcutLongPress() {
+SUBTEST(shortcutLongPress) {
auto kittyProc = spawnRemoteControlKitty();
if (!kittyProc) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
EXPECT(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:keybinds_test' })"), "ok");
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.send_shortcut({ mods = '', key = 'q', window = 'activewindow' }), { long_press = true })"), "ok");
@@ -350,12 +344,10 @@ static void testShortcutLongPress() {
Tests::killAllWindows();
}
-static void testShortcutLongPressKeyRelease() {
+SUBTEST(shortcutLongPressKeyRelease) {
auto kittyProc = spawnRemoteControlKitty();
if (!kittyProc) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
EXPECT(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:keybinds_test' })"), "ok");
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.send_shortcut({ mods = '', key = 'q', window = 'activewindow' }), { long_press = true })"), "ok");
@@ -377,12 +369,10 @@ static void testShortcutLongPressKeyRelease() {
Tests::killAllWindows();
}
-static void testShortcutRepeat() {
+SUBTEST(shortcutRepeat) {
auto kittyProc = spawnRemoteControlKitty();
if (!kittyProc) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
EXPECT(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:keybinds_test' })"), "ok");
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.send_shortcut({ mods = '', key = 'q', window = 'activewindow' }), { repeating = true })"), "ok");
@@ -407,12 +397,10 @@ static void testShortcutRepeat() {
Tests::killAllWindows();
}
-static void testShortcutRepeatKeyRelease() {
+SUBTEST(shortcutRepeatKeyRelease) {
auto kittyProc = spawnRemoteControlKitty();
if (!kittyProc) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
EXPECT(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:keybinds_test' })"), "ok");
EXPECT(getFromSocket("/eval hl.bind('SUPER + Y', hl.dsp.send_shortcut({ mods = '', key = 'q', window = 'activewindow' }), { repeating = true })"), "ok");
@@ -439,7 +427,7 @@ static void testShortcutRepeatKeyRelease() {
Tests::killAllWindows();
}
-static void testSubmap() {
+SUBTEST(submap) {
const auto press = [](const uint32_t key, const uint32_t mod = 0) {
// +8 because udev -> XKB keycode.
getFromSocket(pluginKeybindCmd(true, mod, key + 8));
@@ -474,7 +462,7 @@ static void testSubmap() {
Tests::killAllWindows();
}
-static void testBindsAfterScroll() {
+SUBTEST(bindsAfterScroll) {
NLog::log("{}Testing binds after scroll", Colors::GREEN);
clearFlag();
@@ -503,7 +491,7 @@ static void testBindsAfterScroll() {
OK(getFromSocket("/eval hl.unbind('ALT', 'w')"));
}
-static void testSubmapUniversal() {
+SUBTEST(submapUniversal) {
NLog::log("{}Testing submap universal", Colors::GREEN);
EXPECT(checkFlag(), false);
@@ -531,7 +519,7 @@ static void testSubmapUniversal() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static void testPerDeviceKeybind() {
+SUBTEST(perDeviceKeybind) {
NLog::log("{}Testing per-device binds", Colors::GREEN);
// Inclusive
@@ -561,34 +549,26 @@ static void testPerDeviceKeybind() {
EXPECT(getFromSocket("/eval hl.unbind('SUPER', 'Y')"), "ok");
}
-static bool test() {
- NLog::log("{}Testing keybinds", Colors::GREEN);
-
- clearFlag();
-
- testBind();
- testBindKey();
- testLongPress();
- testKeyLongPress();
- testLongPressRelease();
- testLongPressOnlyKeyRelease();
- testRepeat();
- testKeyRepeat();
- testRepeatRelease();
- testRepeatOnlyKeyRelease();
- testShortcutBind();
- testShortcutBindKey();
- testShortcutLongPress();
- testShortcutLongPressKeyRelease();
- testShortcutRepeat();
- testShortcutRepeatKeyRelease();
- testSubmap();
- testSubmapUniversal();
- testBindsAfterScroll();
- testPerDeviceKeybind();
-
- clearFlag();
- return !ret;
+// TODO: remove this test after subtests above are properly isolated into independent tests
+TEST_CASE(keybinds) {
+ CALL_SUBTEST(bind);
+ CALL_SUBTEST(bindKey);
+ CALL_SUBTEST(longPress);
+ CALL_SUBTEST(keyLongPress);
+ CALL_SUBTEST(longPressRelease);
+ CALL_SUBTEST(longPressOnlyKeyRelease);
+ CALL_SUBTEST(repeat);
+ CALL_SUBTEST(keyRepeat);
+ CALL_SUBTEST(repeatRelease);
+ CALL_SUBTEST(repeatOnlyKeyRelease);
+ CALL_SUBTEST(shortcutBind);
+ CALL_SUBTEST(shortcutBindKey);
+ CALL_SUBTEST(shortcutLongPress);
+ CALL_SUBTEST(shortcutLongPressKeyRelease);
+ CALL_SUBTEST(shortcutRepeat);
+ CALL_SUBTEST(shortcutRepeatKeyRelease);
+ CALL_SUBTEST(submap);
+ CALL_SUBTEST(submapUniversal);
+ CALL_SUBTEST(bindsAfterScroll);
+ CALL_SUBTEST(perDeviceKeybind);
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/layer.cpp b/hyprtester/src/tests/main/layer.cpp
index df74f8b7..f39c007c 100644
--- a/hyprtester/src/tests/main/layer.cpp
+++ b/hyprtester/src/tests/main/layer.cpp
@@ -6,8 +6,6 @@
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
@@ -20,34 +18,18 @@ static bool spawnLayer(const std::string& namespace_) {
return true;
}
-static bool test() {
- NLog::log("{}Testing plugin layerrules", Colors::GREEN);
+TEST_CASE(plugin_layerrules) {
- if (!spawnLayer("rule-layer"))
- return false;
+ EXPECT(spawnLayer("rule-layer"), true);
OK(getFromSocket("/eval hl.plugin.test.add_layer_rule()"));
OK(getFromSocket("/reload"));
OK(getFromSocket("/eval hl.layer_rule({ match = { namespace = 'rule-layer' }, plugin_rule = 'effect' })"));
- if (!spawnLayer("rule-layer"))
- return false;
+ EXPECT(spawnLayer("rule-layer"), true);
- if (!spawnLayer("norule-layer"))
- return false;
+ EXPECT(spawnLayer("norule-layer"), true);
OK(getFromSocket("/eval hl.plugin.test.check_layer_rule()"));
-
- OK(getFromSocket("/reload"));
-
- NLog::log("{}Killing all layers", Colors::YELLOW);
- Tests::killAllLayers();
-
- NLog::log("{}Expecting 0 layers", Colors::YELLOW);
- EXPECT(Tests::layerCount(), 0);
-
- return !ret;
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/layout.cpp b/hyprtester/src/tests/main/layout.cpp
index e2336add..4d604fa4 100644
--- a/hyprtester/src/tests/main/layout.cpp
+++ b/hyprtester/src/tests/main/layout.cpp
@@ -3,9 +3,7 @@
#include "../../hyprctlCompat.hpp"
#include "tests.hpp"
-static int ret = 0;
-
-static void swar() {
+TEST_CASE(single_window_aspect_ratio) {
OK(getFromSocket("/eval hl.config({ layout = { single_window_aspect_ratio = '1 1' } })"));
Tests::spawnKitty();
@@ -36,14 +34,10 @@ static void swar() {
EXPECT_CONTAINS(str, "at: 22,22");
EXPECT_CONTAINS(str, "size: 1876,1036");
}
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
// Don't crash when focus after global geometry changes
-static void testCrashOnGeomUpdate() {
+TEST_CASE(crashOnGeomUpdate) {
Tests::spawnKitty();
Tests::spawnKitty();
Tests::spawnKitty();
@@ -53,15 +47,10 @@ static void testCrashOnGeomUpdate() {
// shouldnt crash
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'right' })"));
-
- OK(getFromSocket("/reload"));
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
// Test if size + pos is preserved after fs cycle
-static void testPosPreserve() {
+TEST_CASE(posPreserve) {
Tests::spawnKitty();
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set', window = 'class:kitty' })"));
@@ -98,21 +87,18 @@ static void testPosPreserve() {
EXPECT_CONTAINS(str, "at: 581,420");
EXPECT_CONTAINS(str, "size: 1337,69");
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
-static bool testFocusMRUAfterClose() {
+TEST_CASE(focusMRUAfterClose) {
NLog::log("{}Testing focus after close (MRU order)", Colors::GREEN);
OK(getFromSocket("/reload"));
OK(getFromSocket("/eval hl.config({ dwindle = { default_split_ratio = 1.25 } })"));
OK(getFromSocket("/eval hl.config({ input = { focus_on_close = 2 } })"));
- EXPECT(!!Tests::spawnKitty("kitty_A"), true);
- EXPECT(!!Tests::spawnKitty("kitty_B"), true);
- EXPECT(!!Tests::spawnKitty("kitty_C"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_A"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_B"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_C"), true);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_A' })"));
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_B' })"));
@@ -133,22 +119,15 @@ static bool testFocusMRUAfterClose() {
auto str = getFromSocket("/activewindow");
EXPECT(str.contains("class: kitty_A"), true);
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
- return true;
}
-static bool testFocusPreservedLayoutChange() {
- NLog::log("{}Testing focus is preserved on layout change", Colors::GREEN);
-
+TEST_CASE(focusPreservedLayoutChange) {
OK(getFromSocket("r/eval hl.config({ general = { layout = 'master' } })"));
- EXPECT(!!Tests::spawnKitty("kitty_A"), true);
- EXPECT(!!Tests::spawnKitty("kitty_B"), true);
- EXPECT(!!Tests::spawnKitty("kitty_C"), true);
- EXPECT(!!Tests::spawnKitty("kitty_D"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_A"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_B"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_C"), true);
+ ASSERT(!!Tests::spawnKitty("kitty_D"), true);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_C' })"));
@@ -158,34 +137,4 @@ static bool testFocusPreservedLayoutChange() {
auto str = getFromSocket("/activewindow");
EXPECT(str.contains("class: kitty_C"), true);
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
- return true;
}
-
-static bool test() {
- NLog::log("{}Testing layout generic", Colors::GREEN);
-
- // setup
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '10' })"));
-
- // test
- NLog::log("{}Testing `single_window_aspect_ratio`", Colors::GREEN);
- swar();
-
- testCrashOnGeomUpdate();
- testPosPreserve();
- testFocusMRUAfterClose();
- testFocusPreservedLayoutChange();
-
- // clean up
- NLog::log("Cleaning up", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
- OK(getFromSocket("/reload"));
-
- return !ret;
-}
-
-REGISTER_TEST_FN(test);
diff --git a/hyprtester/src/tests/main/master.cpp b/hyprtester/src/tests/main/master.cpp
index 02792631..b9364c45 100644
--- a/hyprtester/src/tests/main/master.cpp
+++ b/hyprtester/src/tests/main/master.cpp
@@ -3,10 +3,44 @@
#include "../../hyprctlCompat.hpp"
#include "tests.hpp"
-static int ret = 0;
+TEST_CASE(focusMasterPrevious) {
+ OK(getFromSocket("r/eval hl.config({ general = { layout = 'master' } })"));
+
+ // setup
+ NLog::log("{}Spawning 1 master and 3 slave windows", Colors::YELLOW);
+ // order of windows set according to new_status = master (set in test.lua)
+ for (auto const& win : {"slave1", "slave2", "slave3", "master"}) {
+ if (!Tests::spawnKitty(win)) {
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
+ }
+ }
+ NLog::log("{}Ensuring focus is on master before testing", Colors::YELLOW);
+ OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster master')"));
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: master");
+
+ // test
+ NLog::log("{}Testing fallback to focusmaster auto", Colors::YELLOW);
+
+ OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: slave1");
+
+ NLog::log("{}Testing focusing from slave to master", Colors::YELLOW);
+
+ OK(getFromSocket("/dispatch hl.dsp.layout('cyclenext noloop')"));
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: slave2");
+ OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: master");
+
+ NLog::log("{}Testing focusing on previous window", Colors::YELLOW);
+
+ OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: slave2");
+
+ NLog::log("{}Testing focusing back to master", Colors::YELLOW);
+
+ OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: master");
-// reqs 1 master 3 slaves
-static void testOrientations() {
OK(getFromSocket("r/eval hl.config({ master = { orientation = 'top' } })"));
// top
@@ -51,62 +85,15 @@ static void testOrientations() {
}
}
-static void focusMasterPrevious() {
- // setup
- NLog::log("{}Spawning 1 master and 3 slave windows", Colors::YELLOW);
- // order of windows set according to new_status = master (set in test.lua)
- for (auto const& win : {"slave1", "slave2", "slave3", "master"}) {
- if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
- }
- }
- NLog::log("{}Ensuring focus is on master before testing", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster master')"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: master");
-
- // test
- NLog::log("{}Testing fallback to focusmaster auto", Colors::YELLOW);
-
- OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: slave1");
-
- NLog::log("{}Testing focusing from slave to master", Colors::YELLOW);
-
- OK(getFromSocket("/dispatch hl.dsp.layout('cyclenext noloop')"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: slave2");
- OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: master");
-
- NLog::log("{}Testing focusing on previous window", Colors::YELLOW);
-
- OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: slave2");
-
- NLog::log("{}Testing focusing back to master", Colors::YELLOW);
-
- OK(getFromSocket("/dispatch hl.dsp.layout('focusmaster previous')"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: master");
-
- testOrientations();
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-}
-
-static void testFsBehavior() {
+TEST_CASE(fsBehavior) {
// Master will re-send data to fullscreen / maximized windows, which can interfere with misc:on_focus_under_fullscreen
// check that it doesn't.
+ OK(getFromSocket("r/eval hl.config({ general = { layout = 'master' } })"));
+
for (auto const& win : {"master", "slave1", "slave2"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -153,31 +140,4 @@ static void testFsBehavior() {
EXPECT_CONTAINS(str, "class: vaxwashere");
EXPECT_CONTAINS(str, "fullscreen: 0");
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-}
-
-static bool test() {
- NLog::log("{}Testing Master layout", Colors::GREEN);
-
- // setup
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:master' })"));
- OK(getFromSocket("r/eval hl.config({ general = { layout = 'master' } })"));
-
- // test
- NLog::log("{}Testing `focusmaster previous` layoutmsg", Colors::GREEN);
- focusMasterPrevious();
-
- NLog::log("{}Testing fs behavior", Colors::GREEN);
- testFsBehavior();
-
- // clean up
- NLog::log("Cleaning up", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_TEST_FN(test);
diff --git a/hyprtester/src/tests/main/misc.cpp b/hyprtester/src/tests/main/misc.cpp
index 704ba9d1..24cc4097 100644
--- a/hyprtester/src/tests/main/misc.cpp
+++ b/hyprtester/src/tests/main/misc.cpp
@@ -10,8 +10,6 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
@@ -38,7 +36,7 @@ using namespace Hyprutils::Memory;
//
// {
// auto str = getFromSocket("/activewindow");
-// EXPECT_CONTAINS(str, "workspace: 2");
+// ASSERT_CONTAINS(str, "workspace: 2");
// }
//
// OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
@@ -48,13 +46,13 @@ using namespace Hyprutils::Memory;
//
// {
// auto str = getFromSocket("/activeworkspace");
-// EXPECT_CONTAINS(str, "windows: 0");
+// ASSERT_CONTAINS(str, "windows: 0");
// }
//
// {
// OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:hyprland-dialog' })"))
// auto str = getFromSocket("/activewindow");
-// EXPECT_CONTAINS(str, "workspace: 2");
+// ASSERT_CONTAINS(str, "workspace: 2");
// }
// }
//
@@ -73,7 +71,7 @@ using namespace Hyprutils::Memory;
//
// {
// auto str = getFromSocket("/activewindow");
-// EXPECT_CONTAINS(str, "yummy");
+// ASSERT_CONTAINS(str, "yummy");
// }
//
// OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
@@ -83,13 +81,13 @@ using namespace Hyprutils::Memory;
//
// {
// auto str = getFromSocket("/activeworkspace");
-// EXPECT_CONTAINS(str, "windows: 0");
+// ASSERT_CONTAINS(str, "windows: 0");
// }
//
// {
// OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:hyprland-dialog' })"))
// auto str = getFromSocket("/activewindow");
-// EXPECT_CONTAINS(str, "yummy");
+// ASSERT_CONTAINS(str, "yummy");
// }
// }
//
@@ -108,7 +106,7 @@ using namespace Hyprutils::Memory;
//
// {
// auto str = getFromSocket("/activewindow");
-// EXPECT_CONTAINS(str, "special:apple");
+// ASSERT_CONTAINS(str, "special:apple");
// }
//
// OK(getFromSocket("/dispatch hl.dsp.workspace.toggle_special('apple')"));
@@ -119,13 +117,13 @@ using namespace Hyprutils::Memory;
//
// {
// auto str = getFromSocket("/activeworkspace");
-// EXPECT_CONTAINS(str, "windows: 0");
+// ASSERT_CONTAINS(str, "windows: 0");
// }
//
// {
// OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:hyprland-dialog' })"))
// auto str = getFromSocket("/activewindow");
-// EXPECT_CONTAINS(str, "special:apple");
+// ASSERT_CONTAINS(str, "special:apple");
// }
// }
//
@@ -133,9 +131,8 @@ using namespace Hyprutils::Memory;
// Tests::killAllWindows();
// }
-static bool test() {
- NLog::log("{}Testing config: misc:", Colors::GREEN);
-
+// TODO: decompose this into multiple test cases
+TEST_CASE(misc) {
NLog::log("{}Testing close_special_on_empty", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ misc = { close_special_on_empty = false } })"));
@@ -145,14 +142,14 @@ static bool test() {
{
auto str = getFromSocket("/monitors");
- EXPECT_CONTAINS(str, "special workspace: -");
+ ASSERT_CONTAINS(str, "special workspace: -");
}
Tests::killAllWindows();
{
auto str = getFromSocket("/monitors");
- EXPECT_CONTAINS(str, "special workspace: -");
+ ASSERT_CONTAINS(str, "special workspace: -");
}
Tests::spawnKitty();
@@ -163,7 +160,7 @@ static bool test() {
{
auto str = getFromSocket("/monitors");
- EXPECT_NOT_CONTAINS(str, "special workspace: -");
+ ASSERT_NOT_CONTAINS(str, "special workspace: -");
}
NLog::log("{}Testing new_window_takes_over_fullscreen", Colors::YELLOW);
@@ -350,19 +347,10 @@ static bool test() {
EXPECT_CONTAINS(str, "fullscreen: 2");
EXPECT_CONTAINS(str, "fullscreenClient: 2");
}
+}
+TEST_CASE(processesThatDieEarlyAreReaped) {
// Ensure that the process autostarted in the config does not
// become a zombie even if it terminates very quickly.
- EXPECT(Tests::execAndGet("pgrep -f 'sleep 0'").empty(), true);
-
- // kill all
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return !ret;
+ ASSERT(Tests::execAndGet("pgrep -f 'sleep 0'").empty(), true);
}
-
-REGISTER_TEST_FN(test);
diff --git a/hyprtester/src/tests/main/moveintoorcreategroup.cpp b/hyprtester/src/tests/main/moveintoorcreategroup.cpp
index 2d47661b..8c2f3aae 100644
--- a/hyprtester/src/tests/main/moveintoorcreategroup.cpp
+++ b/hyprtester/src/tests/main/moveintoorcreategroup.cpp
@@ -10,17 +10,13 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define UP CUniquePointer
#define SP CSharedPointer
-static bool test() {
- NLog::log("{}Testing moveintoorcreategroup", Colors::GREEN);
-
+TEST_CASE(moveIntoOrCreateGroup) {
NLog::log("{}Dispatching workspace `moveintoorcreategroup`", Colors::YELLOW);
getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:moveintoorcreategroup' })");
@@ -29,19 +25,17 @@ static bool test() {
NLog::log("{}Spawning kittyA", Colors::YELLOW);
auto kittyA = Tests::spawnKitty("kitty_A");
if (!kittyA) {
- NLog::log("{}Error: kittyA did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty_A");
}
NLog::log("{}Spawning kittyB", Colors::YELLOW);
auto kittyB = Tests::spawnKitty("kitty_B");
if (!kittyB) {
- NLog::log("{}Error: kittyB did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty_B");
}
NLog::log("{}Expecting 2 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
{
auto str = getFromSocket("/clients");
@@ -68,7 +62,7 @@ static bool test() {
Tests::killAllWindows();
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
NLog::log("{}Testing moveintoorcreategroup into existing group", Colors::YELLOW);
@@ -80,7 +74,7 @@ static bool test() {
auto kittyE = Tests::spawnKitty("kitty_E");
NLog::log("{}Expecting 3 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 3);
+ ASSERT(Tests::windowCount(), 3);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_D' })"));
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
@@ -100,12 +94,4 @@ static bool test() {
auto str = getFromSocket("/activewindow");
EXPECT_CONTAINS(str, "kitty_E");
}
-
- NLog::log("{}Kill windows", Colors::YELLOW);
- Tests::killAllWindows();
- OK(getFromSocket("/eval hl.config({ group = { auto_group = true } })"));
-
- return !ret;
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/persistent.cpp b/hyprtester/src/tests/main/persistent.cpp
index 0a2a7f2e..a203b1f2 100644
--- a/hyprtester/src/tests/main/persistent.cpp
+++ b/hyprtester/src/tests/main/persistent.cpp
@@ -10,19 +10,13 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define UP CUniquePointer
#define SP CSharedPointer
-static bool test() {
- NLog::log("{}Testing persistent workspaces", Colors::GREEN);
-
- EXPECT(Tests::windowCount(), 0);
-
+TEST_CASE(persistentWorkspaces) {
// test on workspace "window"
NLog::log("{}Switching to workspace 1", Colors::YELLOW);
getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"); // no OK: we might be on 1 already
@@ -42,7 +36,7 @@ static bool test() {
{
auto str = getFromSocket("/monitors");
- EXPECT_CONTAINS(str, "HEADLESS-PERSISTENT-TEST");
+ ASSERT_CONTAINS(str, "HEADLESS-PERSISTENT-TEST");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-PERSISTENT-TEST' })"));
@@ -68,18 +62,4 @@ static bool test() {
}
OK(getFromSocket("/output remove HEADLESS-PERSISTENT-TEST"));
-
- // kill all
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- // reload cfg
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/scroll.cpp b/hyprtester/src/tests/main/scroll.cpp
index 3b73b906..bd33e345 100644
--- a/hyprtester/src/tests/main/scroll.cpp
+++ b/hyprtester/src/tests/main/scroll.cpp
@@ -3,15 +3,12 @@
#include "../../hyprctlCompat.hpp"
#include "tests.hpp"
-static int ret = 0;
+TEST_CASE(scrollFocusCycling) {
+ OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
-static void testFocusCycling() {
for (auto const& win : {"a", "b", "c", "d"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -21,49 +18,44 @@ static void testFocusCycling() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: b");
+ ASSERT_CONTAINS(str, "class: b");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'right' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: c");
+ ASSERT_CONTAINS(str, "class: c");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'right' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: d");
+ ASSERT_CONTAINS(str, "class: d");
}
OK(getFromSocket("/dispatch hl.dsp.window.move({ direction = 'left' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: d");
+ ASSERT_CONTAINS(str, "class: d");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'up' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: c");
+ ASSERT_CONTAINS(str, "class: c");
}
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
-static void testFocusWrapping() {
+TEST_CASE(scrollFocusWrapping) {
+ OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
+
for (auto const& win : {"a", "b", "c", "d"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -76,14 +68,14 @@ static void testFocusWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: d");
+ ASSERT_CONTAINS(str, "class: d");
}
OK(getFromSocket("/dispatch hl.dsp.layout('focus r')"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: a");
+ ASSERT_CONTAINS(str, "class: a");
}
// set wrap_focus to false
@@ -95,7 +87,7 @@ static void testFocusWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: a");
+ ASSERT_CONTAINS(str, "class: a");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:d' })"));
@@ -104,21 +96,16 @@ static void testFocusWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: d");
+ ASSERT_CONTAINS(str, "class: d");
}
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
-static void testSwapcolWrapping() {
+TEST_CASE(scrollSwapcolWrapping) {
+ OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
+
for (auto const& win : {"a", "b", "c", "d"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -132,7 +119,7 @@ static void testSwapcolWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: c");
+ ASSERT_CONTAINS(str, "class: c");
}
// clean up
@@ -141,10 +128,7 @@ static void testSwapcolWrapping() {
for (auto const& win : {"a", "b", "c", "d"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -154,7 +138,7 @@ static void testSwapcolWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: b");
+ ASSERT_CONTAINS(str, "class: b");
}
// clean up
@@ -163,10 +147,7 @@ static void testSwapcolWrapping() {
for (auto const& win : {"a", "b", "c", "d"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -180,7 +161,7 @@ static void testSwapcolWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: b");
+ ASSERT_CONTAINS(str, "class: b");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:d' })"));
@@ -190,15 +171,13 @@ static void testSwapcolWrapping() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: c");
+ ASSERT_CONTAINS(str, "class: c");
}
-
- // clean up
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
}
-static bool testWindowRule() {
+TEST_CASE(scrollWindowRule) {
+ OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
+
NLog::log("{}Testing Scrolling Width", Colors::GREEN);
// inject a new rule.
@@ -206,53 +185,15 @@ static bool testWindowRule() {
OK(getFromSocket("/eval hl.window_rule({ name = 'scrolling-width', scrolling_width = 0.1 })"));
if (!Tests::spawnKitty("kitty_scroll")) {
- NLog::log("{}Failed to spawn kitty with win class `kitty_scroll`", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty with win class `kitty_scroll`");
}
if (!Tests::spawnKitty("kitty_scroll")) {
- NLog::log("{}Failed to spawn kitty with win class `kitty_scroll`", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty with win class `kitty_scroll`");
}
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
// not the greatest test, but as long as res and gaps don't change, we good.
EXPECT_CONTAINS(getFromSocket("/activewindow"), "size: 174,1036");
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
- return true;
}
-
-static bool test() {
- NLog::log("{}Testing Scroll layout", Colors::GREEN);
-
- // setup
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:scroll' })"));
- OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
-
- // test
- NLog::log("{}Testing focus cycling", Colors::GREEN);
- testFocusCycling();
-
- // test
- NLog::log("{}Testing focus wrap", Colors::GREEN);
- testFocusWrapping();
-
- // test
- NLog::log("{}Testing swapcol wrap", Colors::GREEN);
- testSwapcolWrapping();
-
- testWindowRule();
-
- // clean up
- NLog::log("Cleaning up", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
- OK(getFromSocket("/reload"));
-
- return !ret;
-}
-
-REGISTER_TEST_FN(test);
diff --git a/hyprtester/src/tests/main/snap.cpp b/hyprtester/src/tests/main/snap.cpp
index ca103fa0..0e0c4604 100644
--- a/hyprtester/src/tests/main/snap.cpp
+++ b/hyprtester/src/tests/main/snap.cpp
@@ -9,43 +9,35 @@
using Hyprutils::Math::Vector2D;
-static int ret = 0;
-
static bool spawnFloatingKitty() {
if (!Tests::spawnKitty()) {
NLog::log("{}Error: kitty did not spawn", Colors::RED);
return false;
}
- OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set' })"));
- OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 100, y = 100 })"));
- return true;
-}
-
-static void expectSocket(const std::string& CMD) {
- if (const auto RESULT = getFromSocket(CMD); RESULT != "ok") {
- NLog::log("{}Failed: {}getFromSocket({}), expected ok, got {}. Source: {}@{}.", Colors::RED, Colors::RESET, CMD, RESULT, __FILE__, __LINE__);
- ret = 1;
- TESTS_FAILED++;
- } else {
- NLog::log("{}Passed: {}getFromSocket({}). Got ok", Colors::GREEN, Colors::RESET, CMD);
- TESTS_PASSED++;
- }
+ bool ok = true;
+ ok &= getFromSocket("/dispatch hl.dsp.window.float({ action = 'set' })") == "ok";
+ ok &= getFromSocket("/dispatch hl.dsp.window.resize({ x = 100, y = 100 })") == "ok";
+ return ok;
}
-static void expectSnapMove(const Vector2D FROM, const Vector2D* TO) {
- const Vector2D& A = FROM;
- const Vector2D& B = TO ? *TO : FROM;
- if (TO)
- NLog::log("{}Expecting snap to ({},{}) when window is moved to ({},{})", Colors::YELLOW, B.x, B.y, A.x, A.y);
+SUBTEST(expectSnapMove, double fromX, double fromY, double toX, double toY) {
+ const Vector2D FROM = {fromX, fromY};
+ const Vector2D TO = {toX, toY};
+ if (FROM == TO)
+ NLog::log("{}Expecting no snap when window is moved to ({},{})", Colors::YELLOW, FROM.x, FROM.y);
else
- NLog::log("{}Expecting no snap when window is moved to ({},{})", Colors::YELLOW, A.x, A.y);
+ NLog::log("{}Expecting snap to ({},{}) when window is moved to ({},{})", Colors::YELLOW, TO.x, TO.y, FROM.x, FROM.y);
- expectSocket(std::format("/dispatch hl.dsp.window.move({{ x = {}, y = {} }})", A.x, A.y));
- expectSocket("/eval hl.plugin.test.snapmove()");
- EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("at: {},{}", B.x, B.y));
+ OK(getFromSocket(std::format("/dispatch hl.dsp.window.move({{ x = {}, y = {} }})", FROM.x, FROM.y)));
+ OK(getFromSocket("/eval hl.plugin.test.snapmove()"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("at: {},{}", TO.x, TO.y));
}
-static void testWindowSnap(const bool RESPECTGAPS) {
+SUBTEST(expectNoSnapMove, double x, double y) {
+ CALL_SUBTEST(expectSnapMove, x, y, x, y);
+}
+
+SUBTEST(testWindowSnap, const bool RESPECTGAPS) {
const int BORDERSIZE = 2;
const int WINDOWSIZE = 100;
@@ -55,22 +47,19 @@ static void testWindowSnap(const bool RESPECTGAPS) {
const int GAP = (RESPECTGAPS ? 2 * GAPSIN : 0) + (2 * BORDERSIZE);
const int END = GAP + WINDOWSIZE;
- int x;
- Vector2D predict;
-
- x = WINDOWGAP + END;
- expectSnapMove({OTHER + x, OTHER}, nullptr);
- expectSnapMove({OTHER - x, OTHER}, nullptr);
- expectSnapMove({OTHER, OTHER + x}, nullptr);
- expectSnapMove({OTHER, OTHER - x}, nullptr);
+ int x = WINDOWGAP + END;
+ CALL_SUBTEST(expectNoSnapMove, OTHER + x, OTHER);
+ CALL_SUBTEST(expectNoSnapMove, OTHER - x, OTHER);
+ CALL_SUBTEST(expectNoSnapMove, OTHER, OTHER + x);
+ CALL_SUBTEST(expectNoSnapMove, OTHER, OTHER - x);
x -= 1;
- expectSnapMove({OTHER + x, OTHER}, &(predict = {OTHER + END, OTHER}));
- expectSnapMove({OTHER - x, OTHER}, &(predict = {OTHER - END, OTHER}));
- expectSnapMove({OTHER, OTHER + x}, &(predict = {OTHER, OTHER + END}));
- expectSnapMove({OTHER, OTHER - x}, &(predict = {OTHER, OTHER - END}));
+ CALL_SUBTEST(expectSnapMove, OTHER + x, OTHER, OTHER + END, OTHER);
+ CALL_SUBTEST(expectSnapMove, OTHER - x, OTHER, OTHER - END, OTHER);
+ CALL_SUBTEST(expectSnapMove, OTHER, OTHER + x, OTHER, OTHER + END);
+ CALL_SUBTEST(expectSnapMove, OTHER, OTHER - x, OTHER, OTHER - END);
}
-static void testMonitorSnap(const bool RESPECTGAPS, const bool OVERLAP) {
+SUBTEST(testMonitorSnap, const bool RESPECTGAPS, const bool OVERLAP) {
const int BORDERSIZE = 2;
const int WINDOWSIZE = 100;
@@ -84,14 +73,14 @@ static void testMonitorSnap(const bool RESPECTGAPS, const bool OVERLAP) {
Vector2D predict;
x = MONITORGAP + GAP;
- expectSnapMove({x, x}, nullptr);
+ CALL_SUBTEST(expectNoSnapMove, x, x);
x -= 1;
- expectSnapMove({x, x}, &(predict = {GAP, GAP}));
+ CALL_SUBTEST(expectSnapMove, x, x, GAP, GAP);
x = MONITORGAP + END;
- expectSnapMove({1920 - x, 1080 - x}, nullptr);
+ CALL_SUBTEST(expectNoSnapMove, 1920 - x, 1080 - x);
x -= 1;
- expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - END, 1080 - END}));
+ CALL_SUBTEST(expectSnapMove, 1920 - x, 1080 - x, 1920 - END, 1080 - END);
// test reserved area
const int RESERVED = 200;
@@ -99,17 +88,18 @@ static void testMonitorSnap(const bool RESPECTGAPS, const bool OVERLAP) {
const int REND = RGAP + WINDOWSIZE;
x = MONITORGAP + RGAP;
- expectSnapMove({x, x}, nullptr);
+ CALL_SUBTEST(expectNoSnapMove, x, x);
x -= 1;
- expectSnapMove({x, x}, &(predict = {RGAP, RGAP}));
+ CALL_SUBTEST(expectSnapMove, x, x, RGAP, RGAP);
x = MONITORGAP + REND;
- expectSnapMove({1920 - x, 1080 - x}, nullptr);
+ CALL_SUBTEST(expectNoSnapMove, 1920 - x, 1080 - x);
x -= 1;
- expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - REND, 1080 - REND}));
+ CALL_SUBTEST(expectSnapMove, 1920 - x, 1080 - x, 1920 - REND, 1080 - REND);
}
-static bool test() {
+// TODO: decompose this into multiple test cases
+TEST_CASE(snap) {
NLog::log("{}Testing snap", Colors::GREEN);
// move to monitor HEADLESS-2
@@ -125,10 +115,10 @@ static bool test() {
// spawn a kitty terminal and move to (500,500)
NLog::log("{}Spawning kittyProcA", Colors::YELLOW);
if (!spawnFloatingKitty())
- return false;
+ FAIL_TEST("Could not spawn kitty");
NLog::log("{}Expecting 1 window", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 1);
+ ASSERT(Tests::windowCount(), 1);
NLog::log("{}Move the kitty window to (500,500)", Colors::YELLOW);
OK(getFromSocket("/dispatch hl.dsp.window.move({ x = 500, y = 500 })"));
@@ -136,41 +126,26 @@ static bool test() {
// spawn a second kitty terminal
NLog::log("{}Spawning kittyProcB", Colors::YELLOW);
if (!spawnFloatingKitty())
- return false;
+ FAIL_TEST("Could not spawn kitty");
NLog::log("{}Expecting 2 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
NLog::log("");
- testWindowSnap(false);
- testMonitorSnap(false, false);
+ CALL_SUBTEST(testWindowSnap, false);
+ CALL_SUBTEST(testMonitorSnap, false, false);
NLog::log("\n{}Turning on respect_gaps", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ general = { snap = { respect_gaps = true } } })"));
- testWindowSnap(true);
- testMonitorSnap(true, false);
+ CALL_SUBTEST(testWindowSnap, true);
+ CALL_SUBTEST(testMonitorSnap, true, false);
NLog::log("\n{}Turning on border_overlap", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ general = { snap = { respect_gaps = false } } })"));
OK(getFromSocket("/eval hl.config({ general = { snap = { border_overlap = true } } })"));
- testMonitorSnap(false, true);
+ CALL_SUBTEST(testMonitorSnap, false, true);
NLog::log("\n{}Turning on both border_overlap and respect_gaps", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ general = { snap = { respect_gaps = true } } })"));
- testMonitorSnap(true, true);
-
- // kill all
- NLog::log("\n{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- NLog::log("{}Reloading the config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
-
- return !ret;
+ CALL_SUBTEST(testMonitorSnap, true, true);
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/solitary.cpp b/hyprtester/src/tests/main/solitary.cpp
index b89c1090..3e124a1e 100644
--- a/hyprtester/src/tests/main/solitary.cpp
+++ b/hyprtester/src/tests/main/solitary.cpp
@@ -7,17 +7,13 @@
#include <hyprutils/memory/WeakPtr.hpp>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define UP CUniquePointer
#define SP CSharedPointer
-static bool test() {
- NLog::log("{}Testing solitary clients", Colors::GREEN);
-
+TEST_CASE(solitaryClients) {
OK(getFromSocket("/eval hl.config({ general = { allow_tearing = false } })"));
OK(getFromSocket("/eval hl.config({ render = { direct_scanout = 0 } })"));
OK(getFromSocket("/eval hl.config({ cursor = { no_hardware_cursors = 1 } })"));
@@ -50,27 +46,16 @@ static bool test() {
// NLog::log("{}Expecting kitty to almost pass for solitary/DS/tearing", Colors::YELLOW);
// {
// auto str = getFromSocket("/monitors");
- // EXPECT_NOT_CONTAINS(str, "solitary: 0\n");
- // EXPECT_CONTAINS(str, "solitaryBlockedBy: null");
- // EXPECT_CONTAINS(str, "activelyTearing: false");
- // EXPECT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,not supported by monitor,window settings");
+ // ASSERT_NOT_CONTAINS(str, "solitary: 0\n");
+ // ASSERT_CONTAINS(str, "solitaryBlockedBy: null");
+ // ASSERT_CONTAINS(str, "activelyTearing: false");
+ // ASSERT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,not supported by monitor,window settings");
// }
// OK(getFromSocket("/dispatch hl.dsp.window.set_prop({ window = 'active', prop = 'immediate', value = '1' })"));
// NLog::log("{}Expecting kitty to almost pass for tearing", Colors::YELLOW);
// {
// auto str = getFromSocket("/monitors");
- // EXPECT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,not supported by monitor\n");
+ // ASSERT_CONTAINS(str, "tearingBlockedBy: next frame is not torn,not supported by monitor\n");
// }
-
- // // kill all
- // NLog::log("{}Killing all windows", Colors::YELLOW);
- // Tests::killAllWindows();
-
- NLog::log("{}Reloading the config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- return !ret;
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/tags.cpp b/hyprtester/src/tests/main/tags.cpp
index 45ee4088..d83f00fa 100644
--- a/hyprtester/src/tests/main/tags.cpp
+++ b/hyprtester/src/tests/main/tags.cpp
@@ -3,20 +3,13 @@
#include "../shared.hpp"
#include "tests.hpp"
-static int ret = 0;
-
-static bool testTags() {
- NLog::log("{}Testing tags", Colors::GREEN);
-
- EXPECT(Tests::windowCount(), 0);
-
+TEST_CASE(tags) {
NLog::log("{}Spawning kittyProcA&B on ws 1", Colors::YELLOW);
auto kittyProcA = Tests::spawnKitty("tagged");
auto kittyProcB = Tests::spawnKitty("untagged");
if (!kittyProcA || !kittyProcB) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Testing testTag tags", Colors::YELLOW);
@@ -28,7 +21,7 @@ static bool testTags() {
OK(getFromSocket("/eval hl.window_rule({ name = 'tag-test-3', match = { tag = 'testTag' } })"));
OK(getFromSocket("/eval hl.window_rule({ name = 'tag-test-3', no_dim = true })"));
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:tagged' })"));
NLog::log("{}Testing tagged window for no_dim 0 & no_shadow", Colors::YELLOW);
EXPECT_CONTAINS(getFromSocket("/activewindow"), "testTag");
@@ -39,13 +32,4 @@ static bool testTags() {
EXPECT_NOT_CONTAINS(getFromSocket("/activewindow"), "testTag");
EXPECT_CONTAINS(getFromSocket("/getprop activewindow no_shadow"), "true");
EXPECT_CONTAINS(getFromSocket("/getprop activewindow no_dim"), "false");
-
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
-
- OK(getFromSocket("/reload"));
-
- return ret == 0;
}
-
-REGISTER_TEST_FN(testTags)
diff --git a/hyprtester/src/tests/main/tests.hpp b/hyprtester/src/tests/main/tests.hpp
index 757052b6..7ee4fd4a 100644
--- a/hyprtester/src/tests/main/tests.hpp
+++ b/hyprtester/src/tests/main/tests.hpp
@@ -1,12 +1,9 @@
#pragma once
+#include <map>
-#include <vector>
-#include <functional>
+#include "../shared.hpp"
-inline std::vector<std::function<bool()>> testFns;
+inline std::map<const char*, CTestCase&> mainTestCases;
-#define REGISTER_TEST_FN(fn) \
- static auto _register_fn = [] { \
- testFns.emplace_back(fn); \
- return 1; \
- }();
+// Where `TEST_CASE` macros will store generated test cases:
+#define TEST_CASES_STORAGE mainTestCases
diff --git a/hyprtester/src/tests/main/window.cpp b/hyprtester/src/tests/main/window.cpp
index f8e7c499..730c51be 100644
--- a/hyprtester/src/tests/main/window.cpp
+++ b/hyprtester/src/tests/main/window.cpp
@@ -14,8 +14,7 @@
#include "../shared.hpp"
#include "tests.hpp"
-static int ret = 0;
-
+// TODO: seems redundant, can just use `Tests::spawnKitty`?
static bool spawnKitty(const std::string& class_, const std::vector<std::string>& args = {}) {
NLog::log("{}Spawning {}", Colors::YELLOW, class_);
if (!Tests::spawnKitty(class_, args)) {
@@ -52,31 +51,26 @@ static std::string getWindowAddress(const std::string& winInfo) {
auto pos2 = winInfo.find(" -> ");
if (pos == std::string::npos || pos2 == std::string::npos) {
NLog::log("{}Wrong window info", Colors::RED);
- ret = 1;
return "Wrong window info";
}
return winInfo.substr(pos + 7, pos2 - pos - 7);
}
-static void testSwapWindow() {
- NLog::log("{}Testing swapwindow", Colors::GREEN);
-
+TEST_CASE(swapWindow) {
// test on workspace "swapwindow"
NLog::log("{}Switching to workspace \"swapwindow\"", Colors::YELLOW);
getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:swapwindow' })");
if (!Tests::spawnKitty("kitty_A")) {
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
if (!Tests::spawnKitty("kitty_B")) {
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
NLog::log("{}Expecting 2 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 2);
+ ASSERT(Tests::windowCount(), 2);
// Test swapwindow by direction
{
@@ -138,18 +132,9 @@ static void testSwapWindow() {
getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_B' })");
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("{}", ws));
}
-
- // kill all
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
}
-static void testGroupRules() {
- NLog::log("{}Testing group window rules", Colors::YELLOW);
-
+TEST_CASE(windowGroupRules) {
OK(getFromSocket("/eval hl.config({ general = { border_size = 8 } })"));
OK(getFromSocket("/eval hl.workspace_rule({ workspace = 'w[tv1]', border_size = 0 })"));
OK(getFromSocket("/eval hl.workspace_rule({ workspace = 'f[1]', border_size = 0 })"));
@@ -157,8 +142,7 @@ static void testGroupRules() {
OK(getFromSocket("/eval hl.window_rule({ match = { workspace = 'f[1]' }, border_size = 0 })"));
if (!Tests::spawnKitty("kitty_A")) {
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
{
@@ -167,8 +151,7 @@ static void testGroupRules() {
}
if (!Tests::spawnKitty("kitty_B")) {
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
{
@@ -194,8 +177,7 @@ static void testGroupRules() {
}
if (!Tests::spawnKitty("kitty_C")) {
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty");
}
OK(getFromSocket("/dispatch hl.dsp.window.move({ out_of_group = 'right' })"));
@@ -204,9 +186,6 @@ static void testGroupRules() {
auto str = getFromSocket("/getprop active border_size");
EXPECT_CONTAINS(str, "8");
}
-
- OK(getFromSocket("/reload"));
- Tests::killAllWindows();
}
static bool isActiveWindow(const std::string& class_, char fullscreen = '0', bool log = true) {
@@ -236,11 +215,11 @@ static bool waitForActiveWindow(const std::string& class_, char fullscreen = '0'
/// Tests behavior of a window being focused when on that window's workspace
/// another fullscreen window exists.
-static bool testWindowFocusOnFullscreenConflict() {
+TEST_CASE(windowFocusOnFullscreenConflict) {
if (!spawnKitty("kitty_A"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
if (!spawnKitty("kitty_B"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/eval hl.config({ misc = { focus_on_activate = true } })"));
@@ -263,7 +242,7 @@ static bool testWindowFocusOnFullscreenConflict() {
// Make a window that will request focus
const std::string removeToActivate = spawnKittyActivating();
if (removeToActivate.empty())
- return false;
+ FAIL_TEST("Could not spawn kitty_activating");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_A' })"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({ mode = 'fullscreen', action = 'set' })"));
EXPECT(isActiveWindow("kitty_A", '2'), true);
@@ -293,7 +272,7 @@ static bool testWindowFocusOnFullscreenConflict() {
// Make a window that will request focus
const std::string removeToActivate = spawnKittyActivating();
if (removeToActivate.empty())
- return false;
+ FAIL_TEST("Could not spawn kitty_activating");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_A' })"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({ mode = 'fullscreen', action = 'set' })"));
EXPECT(isActiveWindow("kitty_A", '2'), true);
@@ -318,30 +297,17 @@ static bool testWindowFocusOnFullscreenConflict() {
// Make a window that will request focus - the setting is treated normally
const std::string removeToActivate = spawnKittyActivating();
if (removeToActivate.empty())
- return false;
+ FAIL_TEST("Could not spawn kitty_activating");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_A' })"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({ mode = 'fullscreen', action = 'set' })"));
EXPECT(isActiveWindow("kitty_A", '2'), true);
std::filesystem::remove(removeToActivate);
EXPECT(waitForActiveWindow("kitty_A", '2'), true);
}
-
- NLog::log("{}Reloading config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return true;
}
-static void testMaximizeSize() {
- NLog::log("{}Testing maximize size", Colors::GREEN);
-
- EXPECT(spawnKitty("kitty_A"), true);
+TEST_CASE(windowMaximizeSize) {
+ ASSERT(spawnKitty("kitty_A"), true);
// check kitty properties. Maximizing shouldnt change its size
{
@@ -359,44 +325,28 @@ static void testMaximizeSize() {
EXPECT(str.contains("size: 1876,1036"), true);
EXPECT(str.contains("fullscreen: 1"), true);
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
}
-static void testFloatingFocusOnFullscreen() {
- NLog::log("{}Testing floating focus on fullscreen", Colors::GREEN);
-
- EXPECT(spawnKitty("kitty_A"), true);
+TEST_CASE(floatingFocusOnFullscreen) {
+ ASSERT(spawnKitty("kitty_A"), true);
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'toggle' })"));
- EXPECT(spawnKitty("kitty_B"), true);
+ ASSERT(spawnKitty("kitty_B"), true);
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({ mode = 'maximized' })"));
OK(getFromSocket("/dispatch hl.dsp.window.cycle_next()"));
OK(getFromSocket("/eval hl.plugin.test.floating_focus_on_fullscreen()"));
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
}
-static void testGroupFallbackFocus() {
- NLog::log("{}Testing group fallback focus", Colors::GREEN);
-
- EXPECT(spawnKitty("kitty_A"), true);
+TEST_CASE(groupFallbackFocus) {
+ ASSERT(spawnKitty("kitty_A"), true);
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
- EXPECT(spawnKitty("kitty_B"), true);
- EXPECT(spawnKitty("kitty_C"), true);
- EXPECT(spawnKitty("kitty_D"), true);
+ ASSERT(spawnKitty("kitty_B"), true);
+ ASSERT(spawnKitty("kitty_C"), true);
+ ASSERT(spawnKitty("kitty_D"), true);
{
auto str = getFromSocket("/activewindow");
@@ -414,27 +364,18 @@ static void testGroupFallbackFocus() {
auto str = getFromSocket("/activewindow");
EXPECT(str.contains("class: kitty_B"), true);
}
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
}
-static void testBringActiveToTopMouseMovement() {
- NLog::log("{}Testing bringactivetotop mouse movement", Colors::GREEN);
-
- Tests::killAllWindows();
+TEST_CASE(bringActiveToTopMouseMovement) {
OK(getFromSocket("/eval hl.config({ input = { follow_mouse = 2 } })"));
OK(getFromSocket("/eval hl.config({ input = { float_switch_override_focus = 0 } })"));
- EXPECT(spawnKitty("a"), true);
+ ASSERT(spawnKitty("a"), true);
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set' })"));
OK(getFromSocket("/dispatch hl.dsp.window.move({ x = 500, y = 300 })"));
OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 400, y = 400 })"));
- EXPECT(spawnKitty("b"), true);
+ ASSERT(spawnKitty("b"), true);
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set' })"));
OK(getFromSocket("/dispatch hl.dsp.window.move({ x = 500, y = 300 })"));
OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 400, y = 400 })"));
@@ -444,31 +385,26 @@ static void testBringActiveToTopMouseMovement() {
return (clients.rfind("class: a") > clients.rfind("class: b")) ? "a" : "b";
};
- EXPECT(getTopWindow(), std::string("b"));
+ ASSERT(getTopWindow(), std::string("b"));
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 700, y = 500 })"));
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:a' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "class: a");
+ ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: a");
OK(getFromSocket("/dispatch hl.dsp.window.bring_to_top()"));
- EXPECT(getTopWindow(), std::string("a"));
+ ASSERT(getTopWindow(), std::string("a"));
OK(getFromSocket("/eval hl.plugin.test.click(272, 1)"));
OK(getFromSocket("/eval hl.plugin.test.click(272, 0)"));
- EXPECT(getTopWindow(), std::string("a"));
-
- Tests::killAllWindows();
+ ASSERT(getTopWindow(), std::string("a"));
}
-static void testInitialFloatSize() {
- NLog::log("{}Testing initial float size", Colors::GREEN);
-
- Tests::killAllWindows();
+TEST_CASE(initialFloatSize) {
OK(getFromSocket("/eval hl.window_rule({ match = { class = 'kitty' }, float = true })"));
OK(getFromSocket("/eval hl.config({ input = { float_switch_override_focus = 0 } })"));
- EXPECT(spawnKitty("kitty"), true);
+ ASSERT(spawnKitty("kitty"), true);
{
// Kitty by default opens as 640x400, if this changes this test will break
@@ -490,21 +426,17 @@ static void testInitialFloatSize() {
EXPECT(str.contains("size: 640,400"), true);
EXPECT(str.contains("floating: 1"), true);
}
-
- Tests::killAllWindows();
}
/// Tests that the `focus_on_activate` effect of window rules always overrides
/// the `misc:focus_on_activate` variable.
-static bool testWindowRuleFocusOnActivate() {
- OK(getFromSocket("/reload"));
-
+TEST_CASE(windowRuleFocusOnActivate) {
if (!spawnKitty("kitty_default")) {
- NLog::log("{}Error: failed to spawn kitty", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
// Do not focus anyone automatically
+ // TODO: this looks like a bug: the following line should not be commented out
///////////OK(getFromSocket("/eval hl.window_rule({ match = { class = '.*' }, no_initial_focus = true })"));
// `focus_on_activate off` takes over
@@ -514,15 +446,15 @@ static bool testWindowRuleFocusOnActivate() {
const std::string removeToActivate = spawnKittyActivating("kitty_antifocus");
if (removeToActivate.empty()) {
- return false;
+ FAIL_TEST("Could not spawn kitty_antifocus");
}
- EXPECT(waitForActiveWindow("kitty_antifocus"), true);
+ ASSERT(waitForActiveWindow("kitty_antifocus"), true);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_default' })"));
- EXPECT(isActiveWindow("kitty_default"), true);
+ ASSERT(isActiveWindow("kitty_default"), true);
std::filesystem::remove(removeToActivate);
// The focus should NOT transition, since the window rule explicitly forbids that
- EXPECT(waitForActiveWindow("kitty_antifocus", '0', false), false);
+ ASSERT(waitForActiveWindow("kitty_antifocus", '0', false), false);
}
// `focus_on_activate on` takes over
@@ -532,37 +464,24 @@ static bool testWindowRuleFocusOnActivate() {
const std::string removeToActivate = spawnKittyActivating("kitty_superfocus");
if (removeToActivate.empty()) {
- return false;
+ FAIL_TEST("Could not spawn kitty_superfocus");
}
- EXPECT(waitForActiveWindow("kitty_superfocus"), true);
+ ASSERT(waitForActiveWindow("kitty_superfocus"), true);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_default' })"));
- EXPECT(isActiveWindow("kitty_default"), true);
+ ASSERT(isActiveWindow("kitty_default"), true);
std::filesystem::remove(removeToActivate);
// Now that we requested activation, the focus SHOULD transition to kitty_superfocus, according to the window rule
- EXPECT(waitForActiveWindow("kitty_superfocus"), true);
+ ASSERT(waitForActiveWindow("kitty_superfocus"), true);
}
-
- NLog::log("{}Reloading config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return true;
}
// tests if a pinned window contains the valid workspace after change
-static bool testPinnedWorkspacesValid() {
- OK(getFromSocket("/reload"));
+TEST_CASE(pinnedWorkspacesValid) {
getFromSocket("/dispatch hl.dsp.focus({ workspace = '1337' })");
if (!spawnKitty("kitty")) {
- NLog::log("{}Error: failed to spawn kitty", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set', window = 'class:kitty' })"));
@@ -582,38 +501,23 @@ static bool testPinnedWorkspacesValid() {
EXPECT(str.contains("pinned: 1"), true);
}
- OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'unset', window = 'class:kitty' })"))
+ OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'unset', window = 'class:kitty' })"));
{
auto str = getFromSocket("/activewindow");
EXPECT(str.contains("workspace: 1338"), true);
EXPECT(str.contains("pinned: 0"), true);
}
-
- NLog::log("{}Reloading config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return true;
}
-static bool testWindowRuleWorkspaceEmpty() {
- NLog::log("{}Testing windowrule workspace empty", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
+TEST_CASE(windowruleWorkspaceEmpty) {
OK(getFromSocket("/eval hl.window_rule({ match = { class = 'kitty_A' }, workspace = 'empty' })"));
OK(getFromSocket("/eval hl.window_rule({ match = { class = 'kitty_B' }, workspace = 'emptyn' })"));
getFromSocket("/dispatch hl.dsp.focus({ workspace = '3' })");
if (!spawnKitty("kitty")) {
- NLog::log("{}Error: failed to spawn kitty", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
{
@@ -622,8 +526,7 @@ static bool testWindowRuleWorkspaceEmpty() {
}
if (!spawnKitty("kitty_A")) {
- NLog::log("{}Error: failed to spawn kitty", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
{
@@ -633,23 +536,16 @@ static bool testWindowRuleWorkspaceEmpty() {
getFromSocket("/dispatch hl.dsp.focus({ workspace = '3' })");
if (!spawnKitty("kitty_B")) {
- NLog::log("{}Error: failed to spawn kitty", Colors::RED);
- return false;
+ FAIL_TEST("Could not spawn kitty");
}
{
auto str = getFromSocket("/activewindow");
EXPECT(str.contains("workspace: 4"), true);
}
-
- Tests::killAllWindows();
-
- return true;
}
-static bool testContentRules() {
- NLog::log("{}Testing content window rules", Colors::YELLOW);
-
+TEST_CASE(contentWindowRules) {
// kill me PLEASE
OK(getFromSocket("/eval hl.window_rule({ match = { class = 'kitty_content_string' }, content = 'game' })"));
@@ -657,33 +553,32 @@ static bool testContentRules() {
OK(getFromSocket("/eval hl.window_rule({ match = { content = 'game' }, border_size = 10 })"));
OK(getFromSocket("/eval hl.window_rule({ match = { content = '3' }, opacity = '0.5' })"));
- const auto testProps = []() {
- EXPECT_CONTAINS(getFromSocket("/getprop active border_size"), "10");
- EXPECT_CONTAINS(getFromSocket("/getprop active opacity"), "0.5");
- };
+#define TEST_PROPS() \
+ EXPECT_CONTAINS(getFromSocket("/getprop active border_size"), "10"); \
+ EXPECT_CONTAINS(getFromSocket("/getprop active opacity"), "0.5");
+
if (!spawnKitty("kitty_content_string"))
- return false;
+ FAIL_TEST("Could not spawn kitty_content_string");
waitForActiveWindow("kitty_content_string");
- testProps();
+ TEST_PROPS();
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
if (!spawnKitty("kitty_content_numbers"))
- return false;
+ FAIL_TEST("Could not spawn kitty_content_numbers");
waitForActiveWindow("kitty_content_numbers");
- testProps();
+ TEST_PROPS();
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
- return true;
-}
+ ASSERT(Tests::windowCount(), 0);
-static bool test14038() {
- NLog::log("{}Testing #14038 crash", Colors::YELLOW);
+#undef TEST_PROPS
+}
+TEST_CASE(issue14038) {
if (!spawnKitty("kitty_14038"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/dispatch hl.dsp.window.move({ workspace = 'special:a', follow = false, window = 'class:kitty_14038' })"));
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'toggle', window = 'class:kitty_14038' })"));
@@ -691,21 +586,16 @@ static bool test14038() {
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'toggle', window = 'class:kitty_14038' })"));
// this should not crash hyprland. If we are alive, we good.
-
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
- return true;
}
-static bool test() {
- NLog::log("{}Testing windows", Colors::GREEN);
-
+// TODO: decompose this into multiple test cases
+TEST_CASE(windows) {
// test on workspace "window"
NLog::log("{}Switching to workspace `window`", Colors::YELLOW);
getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:window' })");
if (!spawnKitty("kitty_A"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
// check kitty properties. One kitty should take the entire screen, as this is smart gaps
NLog::log("{}Expecting kitty_A to take up the whole screen", Colors::YELLOW);
@@ -749,7 +639,7 @@ static bool test() {
OK(getFromSocket("/eval hl.config({ dwindle = { default_split_ratio = 1.25 } })"));
if (!spawnKitty("kitty_B"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
NLog::log("{}Expecting kitty_B size: {},{}", Colors::YELLOW, WIDTH1, HEIGHT);
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
@@ -761,7 +651,7 @@ static bool test() {
OK(getFromSocket("/eval hl.config({ dwindle = { default_split_ratio = 0.75 } })"));
if (!spawnKitty("kitty_B"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
try {
NLog::log("{}Expecting kitty_B size: {},{}", Colors::YELLOW, WIDTH2, HEIGHT);
@@ -791,10 +681,7 @@ static bool test() {
EXPECT_MAX_DELTA(std::stoi(std::string{sizes[1]}), HEIGHT, 2);
}
- } catch (...) {
- NLog::log("{}Exception thrown", Colors::RED);
- EXPECT(false, true);
- }
+ } catch (...) { FAIL_TEST("Exception thrown"); }
OK(getFromSocket("/eval hl.config({ dwindle = { default_split_ratio = 1 } })"));
}
@@ -807,7 +694,7 @@ static bool test() {
Tests::waitUntilWindowsN(3);
NLog::log("{}Expecting 3 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 3);
+ ASSERT(Tests::windowCount(), 3);
NLog::log("{}Checking props of xeyes", Colors::YELLOW);
// check some window props of xeyes, try to float it
@@ -825,23 +712,16 @@ static bool test() {
Tests::killAllWindows();
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- testSwapWindow();
+ ASSERT(Tests::windowCount(), 0);
getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })");
- if (!testWindowFocusOnFullscreenConflict()) {
- ret = 1;
- return false;
- }
-
NLog::log("{}Testing spawning a floating window over a fullscreen window", Colors::YELLOW);
{
if (!spawnKitty("kitty_A"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({ mode = 'fullscreen', action = 'set' })"));
- EXPECT(Tests::windowCount(), 1);
+ ASSERT(Tests::windowCount(), 1);
OK(getFromSocket("/dispatch hl.dsp.exec_cmd('kitty', { float = true })"));
Tests::waitUntilWindowsN(2);
@@ -869,7 +749,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'kitty-max-rule', max_size = '1500 500' })"));
OK(getFromSocket("r/eval hl.window_rule({ name = 'kitty-max-rule', min_size = '1200 500' })"));
if (!spawnKitty("kitty_maxsize"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
auto dwindle = getFromSocket("/activewindow");
EXPECT_CONTAINS(dwindle, "size: 1500,500");
@@ -881,19 +761,19 @@ static bool test() {
// EXPECT_CONTAINS(getFromSocket("/activewindow"), "size: 1200,500");
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'master' } })"));
if (!spawnKitty("kitty_maxsize"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
auto master = getFromSocket("/activewindow");
EXPECT_CONTAINS(master, "size: 1500,500");
EXPECT_CONTAINS(master, "at: 210,290");
if (!spawnKitty("kitty_maxsize"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
// FIXME: I can't be arsed.
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_maxsize' })"));
@@ -902,7 +782,7 @@ static bool test() {
NLog::log("{}Reloading config", Colors::YELLOW);
OK(getFromSocket("/reload"));
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
}
NLog::log("{}Testing minsize/maxsize rules", Colors::YELLOW);
@@ -913,7 +793,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'kitty-max-rule', max_size = '1500 500' })"));
OK(getFromSocket("r/eval hl.window_rule({ name = 'kitty-max-rule', min_size = '1200 500' })"));
if (!spawnKitty("kitty_maxsize"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto res = getFromSocket("/getprop active max_size");
@@ -930,7 +810,7 @@ static bool test() {
NLog::log("{}Reloading config", Colors::YELLOW);
OK(getFromSocket("/reload"));
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
}
{
@@ -940,7 +820,7 @@ static bool test() {
OK(getFromSocket("r/eval hl.window_rule({ name = 'kitty-max-rule', min_size = '1200 500' })"));
OK(getFromSocket("r/eval hl.window_rule({ name = 'kitty-max-rule', float = true })"));
if (!spawnKitty("kitty_maxsize"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto res = getFromSocket("/getprop active max_size");
@@ -962,12 +842,12 @@ static bool test() {
NLog::log("{}Reloading config", Colors::YELLOW);
OK(getFromSocket("/reload"));
Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
}
NLog::log("{}Testing window rules", Colors::YELLOW);
if (!spawnKitty("wr_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/activewindow");
const int SIZE = 200;
@@ -987,7 +867,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'special-magic-kitty', workspace = 'special:magic' })"));
if (!spawnKitty("magic_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/activewindow");
@@ -1005,7 +885,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'border-magic-kitty', border_color = 'rgba(c6ff00ff) rgba(ff0000ee) 45deg' })"));
if (!spawnKitty("border_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:border_kitty' })"));
@@ -1019,7 +899,7 @@ static bool test() {
Tests::killAllWindows();
if (!spawnKitty("tag_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/activewindow");
@@ -1034,7 +914,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ match = { fullscreen = false }, border_size = 10 })"));
if (!spawnKitty("overlap_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/getprop active border_size");
@@ -1048,9 +928,9 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ match = { class = 'persistent_size_kitty' }, persistent_size = true, float = true })"));
if (!spawnKitty("persistent_size_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
- OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 600, y = 400 })"))
+ OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 600, y = 400 })"));
{
auto str = getFromSocket("/activewindow");
@@ -1061,7 +941,7 @@ static bool test() {
Tests::killAllWindows();
if (!spawnKitty("persistent_size_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/activewindow");
@@ -1076,7 +956,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ match = { float = true }, border_size = 10 })"));
if (!spawnKitty("border_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/getprop active border_size");
@@ -1105,7 +985,7 @@ static bool test() {
"max_size = 'monitor_w*0.75 monitor_h*0.75', move = '20+(monitor_w*0.1) monitor_h*0.5' })"));
if (!spawnKitty("expr_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/activewindow");
@@ -1131,7 +1011,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ match = { class = 'plugin_kitty' }, plugin_rule = 'effect' })"));
if (!spawnKitty("plugin_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/eval hl.plugin.test.check_window_rule()"));
@@ -1145,35 +1025,7 @@ static bool test() {
OK(getFromSocket("/eval hl.window_rule({ name = 'test-plugin-rule', plugin_rule = 'effect' })"));
if (!spawnKitty("plugin_kitty"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/eval hl.plugin.test.check_window_rule()"));
-
- OK(getFromSocket("/reload"));
- Tests::killAllWindows();
-
- testGroupRules();
- testMaximizeSize();
- testFloatingFocusOnFullscreen();
- testBringActiveToTopMouseMovement();
- testGroupFallbackFocus();
- testInitialFloatSize();
- testWindowRuleFocusOnActivate();
- testPinnedWorkspacesValid();
- testWindowRuleWorkspaceEmpty();
- testContentRules();
- test14038();
-
- NLog::log("{}Reloading config", Colors::YELLOW);
- OK(getFromSocket("/reload"));
-
- NLog::log("{}Killing all windows", Colors::YELLOW);
- Tests::killAllWindows();
-
- NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return !ret;
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/main/workspaces.cpp b/hyprtester/src/tests/main/workspaces.cpp
index 2975b568..8cde4914 100644
--- a/hyprtester/src/tests/main/workspaces.cpp
+++ b/hyprtester/src/tests/main/workspaces.cpp
@@ -11,8 +11,6 @@
#include <cerrno>
#include "../shared.hpp"
-static int ret = 0;
-
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
using namespace Hyprutils::Utils;
@@ -20,7 +18,11 @@ using namespace Hyprutils::Utils;
#define UP CUniquePointer
#define SP CSharedPointer
-static bool testSpecialWorkspaceFullscreen() {
+// All the `SUBTEST`s below are supposed to be independent `TEST_CASE`s.
+// But if isolated trivially, some of them fail.
+// TODO: investigate and isolate tests by turning `SUBTEST`s into `TEST_CASE`s.
+
+SUBTEST(specialWorkspaceFullscreen) {
NLog::log("{}Testing special workspace fullscreen detection", Colors::YELLOW);
CScopeGuard guard = {[&]() {
@@ -34,14 +36,14 @@ static bool testSpecialWorkspaceFullscreen() {
}};
getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })");
- EXPECT(Tests::windowCount(), 0);
+ ASSERT(Tests::windowCount(), 0);
NLog::log("{}Test 1: Fullscreen detection on special workspace", Colors::YELLOW);
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'special:test_fs_special' })"));
if (!Tests::spawnKitty("kitty_special"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
{
auto str = getFromSocket("/activewindow");
@@ -68,7 +70,7 @@ static bool testSpecialWorkspaceFullscreen() {
getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })");
if (!Tests::spawnKitty("kitty_regular"))
- return false;
+ FAIL_TEST("Could not spawn kitty");
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({ mode = 'fullscreen' })"));
@@ -101,99 +103,91 @@ static bool testSpecialWorkspaceFullscreen() {
auto str = getFromSocket("/monitors");
EXPECT_CONTAINS(str, "special workspace: 0 ()");
}
-
- return true;
}
-static bool testAsymmetricGaps() {
+SUBTEST(asymmetricGaps) {
NLog::log("{}Testing asymmetric gap splits", Colors::YELLOW);
- {
- CScopeGuard guard = {[&]() {
- NLog::log("{}Cleaning up asymmetric gap test", Colors::YELLOW);
- Tests::killAllWindows();
- OK(getFromSocket("/reload"));
- }};
+ ASSERT(Tests::windowCount(), 0);
+ getFromSocket("/dispatch workspace 1");
+ getFromSocket("/reload");
- OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:gap_split_test' })"));
- OK(getFromSocket("r/eval hl.config({ general = { gaps_in = 0 } })"));
- OK(getFromSocket("r/eval hl.config({ general = { border_size = 0 } })"));
- OK(getFromSocket("r/eval hl.config({ dwindle = { split_width_multiplier = 1.0 } })"));
- OK(getFromSocket("r/eval hl.workspace_rule({ workspace = 'name:gap_split_test', gaps_out = { top = 0, right = 1000, bottom = 0, left = 0 } })"));
+ OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'name:gap_split_test' })"));
+ OK(getFromSocket("r/eval hl.config({ general = { gaps_in = 0 } })"));
+ OK(getFromSocket("r/eval hl.config({ general = { border_size = 0 } })"));
+ OK(getFromSocket("r/eval hl.config({ dwindle = { split_width_multiplier = 1.0 } })"));
+ OK(getFromSocket("r/eval hl.workspace_rule({ workspace = 'name:gap_split_test', gaps_out = { top = 0, right = 1000, bottom = 0, left = 0 } })"));
- NLog::log("{}Testing default split (force_split = 0)", Colors::YELLOW);
- OK(getFromSocket("r/eval hl.config({ dwindle = { force_split = 0 } })"));
+ NLog::log("{}Testing default split (force_split = 0)", Colors::YELLOW);
+ OK(getFromSocket("r/eval hl.config({ dwindle = { force_split = 0 } })"));
- if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
- return false;
+ if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
+ FAIL_TEST("Could not spawn kitty");
- NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
+ NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ Tests::killAllWindows();
+ ASSERT(Tests::windowCount(), 0);
- NLog::log("{}Testing force_split = 1", Colors::YELLOW);
- OK(getFromSocket("r/eval hl.config({ dwindle = { force_split = 1 } })"));
+ NLog::log("{}Testing force_split = 1", Colors::YELLOW);
+ OK(getFromSocket("r/eval hl.config({ dwindle = { force_split = 1 } })"));
- if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
- return false;
+ if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
+ FAIL_TEST("Could not spawn kitty");
- NLog::log("{}Expecting vertical split (B above A)", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
+ NLog::log("{}Expecting vertical split (B above A)", Colors::YELLOW);
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
- NLog::log("{}Expecting horizontal split (C left of B)", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
+ NLog::log("{}Expecting horizontal split (C left of B)", Colors::YELLOW);
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
- if (!Tests::spawnKitty("gaps_kitty_C"))
- return false;
+ if (!Tests::spawnKitty("gaps_kitty_C"))
+ FAIL_TEST("Could not spawn kitty");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_C' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_C' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
- Tests::killAllWindows();
- EXPECT(Tests::windowCount(), 0);
+ Tests::killAllWindows();
+ ASSERT(Tests::windowCount(), 0);
- NLog::log("{}Testing force_split = 2", Colors::YELLOW);
- OK(getFromSocket("r/eval hl.config({ dwindle = { force_split = 2 } })"));
+ NLog::log("{}Testing force_split = 2", Colors::YELLOW);
+ OK(getFromSocket("r/eval hl.config({ dwindle = { force_split = 2 } })"));
- if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
- return false;
+ if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
+ FAIL_TEST("Could not spawn kitty");
- NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
+ NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_B' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
- NLog::log("{}Expecting horizontal split (C right of A)", Colors::YELLOW);
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
+ NLog::log("{}Expecting horizontal split (C right of A)", Colors::YELLOW);
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
- if (!Tests::spawnKitty("gaps_kitty_C"))
- return false;
+ if (!Tests::spawnKitty("gaps_kitty_C"))
+ FAIL_TEST("Could not spawn kitty");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
- OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_C' })"));
- EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
- }
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_A' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
+ OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:gaps_kitty_C' })"));
+ EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
// kill all
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
-
- return true;
}
-static void testWorkspaceHistoryMultiMon() {
+SUBTEST(workspaceHistoryMultiMon) {
NLog::log("{}Testing multimon workspace history tracker", Colors::YELLOW);
// Initial state:
@@ -222,7 +216,7 @@ static void testWorkspaceHistoryMultiMon() {
Tests::killAllWindows();
}
-static void testMultimonBAF() {
+SUBTEST(multimonBAF) {
NLog::log("{}Testing multimon back and forth", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ binds = { workspace_back_and_forth = 1 } })"));
@@ -284,7 +278,7 @@ static void testMultimonBAF() {
Tests::killAllWindows();
}
-static void testMultimonFocus() {
+SUBTEST(multimonFocus) {
NLog::log("{}Testing multimon focus and move", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ input = { follow_mouse = 0 } })"));
@@ -295,10 +289,7 @@ static void testMultimonFocus() {
for (auto const& win : {"a", "b"}) {
if (!Tests::spawnKitty(win)) {
- NLog::log("{}Failed to spawn kitty with win class `{}`", Colors::RED, win);
- ++TESTS_FAILED;
- ret = 1;
- return;
+ FAIL_TEST("Could not spawn kitty with win class `{}`", win);
}
}
@@ -350,24 +341,24 @@ static void testMultimonFocus() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: b");
+ ASSERT_CONTAINS(str, "class: b");
}
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_CONTAINS(str, "workspace ID 8 ");
+ ASSERT_CONTAINS(str, "workspace ID 8 ");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'right' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: c");
+ ASSERT_CONTAINS(str, "class: c");
}
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_CONTAINS(str, "workspace ID 8 ");
+ ASSERT_CONTAINS(str, "workspace ID 8 ");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'left' })"));
@@ -375,28 +366,28 @@ static void testMultimonFocus() {
OK(getFromSocket("/eval hl.config({ general = { no_focus_fallback = true } })"));
OK(getFromSocket("/eval hl.config({ binds = { window_direction_monitor_fallback = false } })"));
- EXPECT_NOT(getFromSocket("/dispatch hl.dsp.focus({ direction = 'left' })"), "ok");
+ ASSERT_NOT(getFromSocket("/dispatch hl.dsp.focus({ direction = 'left' })"), "ok");
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: b");
+ ASSERT_CONTAINS(str, "class: b");
}
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_CONTAINS(str, "workspace ID 8 ");
+ ASSERT_CONTAINS(str, "workspace ID 8 ");
}
OK(getFromSocket("/dispatch hl.dsp.window.move({ direction = 'left' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: b");
+ ASSERT_CONTAINS(str, "class: b");
}
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_CONTAINS(str, "workspace ID 8 ");
+ ASSERT_CONTAINS(str, "workspace ID 8 ");
}
OK(getFromSocket("/reload"));
@@ -404,7 +395,7 @@ static void testMultimonFocus() {
Tests::killAllWindows();
}
-static void testDynamicWsEffects() {
+SUBTEST(dynamicWsEffects) {
// test dynamic workspace effects, they shouldn't lag
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '69' })"));
@@ -414,29 +405,22 @@ static void testDynamicWsEffects() {
OK(getFromSocket("r/eval hl.workspace_rule({ workspace = '69', border_size = 20 })"));
OK(getFromSocket("r/eval hl.workspace_rule({ workspace = '69', no_rounding = true })"));
- EXPECT(getFromSocket("/getprop class:bitch border_size"), "20");
- EXPECT(getFromSocket("/getprop class:bitch rounding"), "0");
+ ASSERT(getFromSocket("/getprop class:bitch border_size"), "20");
+ ASSERT(getFromSocket("/getprop class:bitch rounding"), "0");
OK(getFromSocket("/reload"));
Tests::killAllWindows();
}
-static bool test() {
- NLog::log("{}Testing workspaces", Colors::GREEN);
-
- EXPECT(Tests::windowCount(), 0);
-
- // test on workspace "window"
- NLog::log("{}Switching to workspace 1", Colors::YELLOW);
- getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })");
-
+// TODO: decompose this into multiple test cases
+TEST_CASE(workspacesCombined) {
NLog::log("{}Checking persistent no-mon", Colors::YELLOW);
OK(getFromSocket("r/eval hl.workspace_rule({ workspace = '966', persistent = true })"));
{
auto str = getFromSocket("/workspaces");
- EXPECT_CONTAINS(str, "workspace ID 966 (966)");
+ ASSERT_CONTAINS(str, "workspace ID 966 (966)");
}
OK(getFromSocket("/reload"));
@@ -444,10 +428,8 @@ static bool test() {
NLog::log("{}Spawning kittyProc on ws 1", Colors::YELLOW);
auto kittyProcA = Tests::spawnKitty();
- if (!kittyProcA) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
- }
+ if (!kittyProcA)
+ FAIL_TEST("Could not spawn kitty");
NLog::log("{}Switching to workspace 3", Colors::YELLOW);
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '3' })"));
@@ -455,10 +437,8 @@ static bool test() {
NLog::log("{}Spawning kittyProc on ws 3", Colors::YELLOW);
auto kittyProcB = Tests::spawnKitty();
- if (!kittyProcB) {
- NLog::log("{}Error: kitty did not spawn", Colors::RED);
- return false;
- }
+ if (!kittyProcB)
+ FAIL_TEST("Could not spawn kitty");
NLog::log("{}Switching to workspace 1", Colors::YELLOW);
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
@@ -468,14 +448,14 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 2 (2)");
+ ASSERT_STARTS_WITH(str, "workspace ID 2 (2)");
}
// check if the other workspaces are alive
{
auto str = getFromSocket("/workspaces");
- EXPECT_CONTAINS(str, "workspace ID 3 (3)");
- EXPECT_CONTAINS(str, "workspace ID 1 (1)");
+ ASSERT_CONTAINS(str, "workspace ID 3 (3)");
+ ASSERT_CONTAINS(str, "workspace ID 1 (1)");
}
NLog::log("{}Switching to workspace 1", Colors::YELLOW);
@@ -483,7 +463,7 @@ static bool test() {
{
auto str = getFromSocket("/workspaces");
- EXPECT_NOT_CONTAINS(str, "workspace ID 2 (2)");
+ ASSERT_NOT_CONTAINS(str, "workspace ID 2 (2)");
}
NLog::log("{}Switching to workspace m+1", Colors::YELLOW);
@@ -491,7 +471,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
NLog::log("{}Switching to workspace -1", Colors::YELLOW);
@@ -499,7 +479,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 2 (2)");
+ ASSERT_STARTS_WITH(str, "workspace ID 2 (2)");
}
NLog::log("{}Switching to workspace 1", Colors::YELLOW);
@@ -510,7 +490,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 2 (2)");
+ ASSERT_STARTS_WITH(str, "workspace ID 2 (2)");
}
NLog::log("{}Switching to workspace r+1", Colors::YELLOW);
@@ -518,7 +498,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
NLog::log("{}Switching to workspace r~1", Colors::YELLOW);
@@ -526,7 +506,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 1 (1)");
+ ASSERT_STARTS_WITH(str, "workspace ID 1 (1)");
}
NLog::log("{}Switching to workspace empty", Colors::YELLOW);
@@ -534,7 +514,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 2 (2)");
+ ASSERT_STARTS_WITH(str, "workspace ID 2 (2)");
}
NLog::log("{}Switching to workspace previous", Colors::YELLOW);
@@ -542,7 +522,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 1 (1)");
+ ASSERT_STARTS_WITH(str, "workspace ID 1 (1)");
}
NLog::log("{}Switching to workspace name:TEST_WORKSPACE_NULL", Colors::YELLOW);
@@ -550,7 +530,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID -1337 (TEST_WORKSPACE_NULL)");
+ ASSERT_STARTS_WITH(str, "workspace ID -1337 (TEST_WORKSPACE_NULL)");
}
NLog::log("{}Switching to workspace 1", Colors::YELLOW);
@@ -558,14 +538,14 @@ static bool test() {
// add a new monitor
NLog::log("{}Adding a new monitor", Colors::YELLOW);
- EXPECT(getFromSocket("/output create headless"), "ok")
+ ASSERT(getFromSocket("/output create headless"), "ok");
// should take workspace 2
{
auto str = getFromSocket("/monitors");
- EXPECT_CONTAINS(str, "active workspace: 2 (2)");
- EXPECT_CONTAINS(str, "active workspace: 1 (1)");
- EXPECT_CONTAINS(str, "HEADLESS-3");
+ ASSERT_CONTAINS(str, "active workspace: 2 (2)");
+ ASSERT_CONTAINS(str, "active workspace: 1 (1)");
+ ASSERT_CONTAINS(str, "HEADLESS-3");
}
// focus the first monitor
@@ -573,7 +553,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 1 (1)");
+ ASSERT_STARTS_WITH(str, "workspace ID 1 (1)");
}
NLog::log("{}Switching to workspace r+1", Colors::YELLOW);
@@ -581,7 +561,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
NLog::log("{}Switching to workspace r~2", Colors::YELLOW);
@@ -590,7 +570,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
NLog::log("{}Switching to workspace m+1", Colors::YELLOW);
@@ -598,7 +578,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 1 (1)");
+ ASSERT_STARTS_WITH(str, "workspace ID 1 (1)");
}
NLog::log("{}Switching to workspace 1", Colors::YELLOW);
@@ -607,7 +587,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 1 (1)");
+ ASSERT_STARTS_WITH(str, "workspace ID 1 (1)");
}
NLog::log("{}Testing back_and_forth", Colors::YELLOW);
@@ -616,7 +596,7 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
OK(getFromSocket("/eval hl.config({ binds = { workspace_back_and_forth = false } })"));
@@ -627,8 +607,8 @@ static bool test() {
{
auto str = getFromSocket("/monitors");
- EXPECT_CONTAINS(str, "special workspace: -");
- EXPECT_CONTAINS(str, "special:HELLO");
+ ASSERT_CONTAINS(str, "special workspace: -");
+ ASSERT_CONTAINS(str, "special:HELLO");
}
// no OK: will err (it shouldn't prolly but oh well)
@@ -636,7 +616,7 @@ static bool test() {
{
auto str = getFromSocket("/monitors");
- EXPECT_COUNT_STRING(str, "special workspace: 0 ()", 2);
+ ASSERT_COUNT_STRING(str, "special workspace: 0 ()", 2);
}
OK(getFromSocket("/eval hl.config({ binds = { hide_special_on_workspace_change = false } })"));
@@ -652,21 +632,21 @@ static bool test() {
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'previous' })"));
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 1 (1)");
+ ASSERT_STARTS_WITH(str, "workspace ID 1 (1)");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 'previous' })"));
{
auto str = getFromSocket("/activeworkspace");
- EXPECT_STARTS_WITH(str, "workspace ID 3 (3)");
+ ASSERT_STARTS_WITH(str, "workspace ID 3 (3)");
}
OK(getFromSocket("/eval hl.config({ binds = { allow_workspace_cycles = false } })"));
@@ -700,7 +680,7 @@ static bool test() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_C");
+ ASSERT_CONTAINS(str, "class: kitty_C");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_A' })"));
@@ -711,7 +691,7 @@ static bool test() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_B");
+ ASSERT_CONTAINS(str, "class: kitty_B");
}
NLog::log("{}Testing movefocus_cycles_fullscreen", Colors::YELLOW);
@@ -720,14 +700,14 @@ static bool test() {
Tests::spawnKitty("kitty_D");
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_D");
+ ASSERT_CONTAINS(str, "class: kitty_D");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'l' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_A");
+ ASSERT_CONTAINS(str, "class: kitty_A");
}
OK(getFromSocket("/eval hl.config({ binds = { movefocus_cycles_fullscreen = false } })"));
@@ -737,14 +717,14 @@ static bool test() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_D");
+ ASSERT_CONTAINS(str, "class: kitty_D");
}
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'l' })"));
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_A");
+ ASSERT_CONTAINS(str, "class: kitty_A");
}
OK(getFromSocket("/eval hl.config({ binds = { movefocus_cycles_fullscreen = true } })"));
@@ -753,28 +733,24 @@ static bool test() {
{
auto str = getFromSocket("/activewindow");
- EXPECT_CONTAINS(str, "class: kitty_B");
+ ASSERT_CONTAINS(str, "class: kitty_B");
}
// kill all
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
- testMultimonBAF();
- testMultimonFocus();
- testWorkspaceHistoryMultiMon();
+ CALL_SUBTEST(multimonBAF);
+ CALL_SUBTEST(multimonFocus);
+ CALL_SUBTEST(workspaceHistoryMultiMon);
// destroy the headless output
OK(getFromSocket("/output remove HEADLESS-3"));
- testSpecialWorkspaceFullscreen();
- testAsymmetricGaps();
- testDynamicWsEffects();
+ CALL_SUBTEST(specialWorkspaceFullscreen);
+ CALL_SUBTEST(asymmetricGaps);
+ CALL_SUBTEST(dynamicWsEffects);
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
- EXPECT(Tests::windowCount(), 0);
-
- return !ret;
+ ASSERT(Tests::windowCount(), 0);
}
-
-REGISTER_TEST_FN(test)
diff --git a/hyprtester/src/tests/shared.cpp b/hyprtester/src/tests/shared.cpp
index fd158a3e..03a64751 100644
--- a/hyprtester/src/tests/shared.cpp
+++ b/hyprtester/src/tests/shared.cpp
@@ -10,6 +10,10 @@
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
+// Almost everywhere `Tests::spawnKitty` is used, the return value is immediately tested against `nullptr`
+// and the test fails if it is.
+// TODO: add a test macro for that.
+
CUniquePointer<CProcess> Tests::spawnKitty(const std::string& class_, const std::vector<std::string> args) {
const auto COUNT_BEFORE = windowCount();