test-fix: kill all layers before killing all windows in layers test. prevents internal post test cleanup function failing to kill all layers

test-fix: maximized and fullscreen swapped between their tests

test-fix: testScrollingViewBehaviourMoveFocusInGroupFollowFocusTrue missing layout initialization

test-fix: testScrollingViewBehaviourWorkspaceChange, testScrollingViewBehaviourCloseWindowInGroup have stale window class in a comment

clang-format
This commit is contained in:
erstarr 2026-05-01 03:34:17 +02:00
parent 42c3057cc2
commit b645dd2d4d
4 changed files with 35 additions and 105 deletions

View file

@ -198,19 +198,15 @@ TEST_CASE(scrollWindowRule) {
ASSERT_CONTAINS(getFromSocket("/activewindow"), "size: 174,1036");
}
TEST_CASE(testScrollingViewBehaviourDispatchFocusWindowFollowFocusFalse) {
/*
focuswindow DOES NOT move the scrolling view when follow_focus = false
---------------------------------------------------------------------------------
*/
NLog::log("{}Testing scrolling view behaviour: focuswindow dispatch SHOULD NOT move scrolling view when follow_focus = false", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
@ -222,7 +218,6 @@ TEST_CASE(testScrollingViewBehaviourDispatchFocusWindowFollowFocusFalse) {
OK(getFromSocket("/dispatch hl.dsp.layout('colresize 0.8')"));
if (!Tests::spawnKitty("b")) {
FAIL_TEST("Could not spawn kitty with win class `b`");
}
@ -249,19 +244,16 @@ TEST_CASE(testScrollingViewBehaviourDispatchFocusWindowFollowFocusFalse) {
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourDispatchFocusWindowFollowFocustrue) {
/*
focuswindow DOES move the view when follow_focus = true
--------------------------------------------------------------------
*/
NLog::log("{}Testing scrolling view behaviour: focuswindow dispatch SHOULD move scrolling view when follow_focus = true", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
NLog::log("{}Testing scrolling view behaviour: focuswindow dispatch SHOULD move scrolling view when follow_focus = true", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
if (!Tests::spawnKitty("a")) {
FAIL_TEST("Could not spawn kitty with win class `a`");
@ -269,14 +261,12 @@ TEST_CASE(testScrollingViewBehaviourDispatchFocusWindowFollowFocustrue) {
OK(getFromSocket("/dispatch hl.dsp.layout('colresize 0.8')"));
if (!Tests::spawnKitty("b")) {
FAIL_TEST("Could not spawn kitty with win class `b`");
}
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
// If the view does not move, we expect the x coordinate of the window of class "a" to be negative, as it would be to the left of the viewport.
// If it is not, the view moved, which is what we expect to happen.
const std::string posA = Tests::getWindowAttribute(getFromSocket("/activewindow"), "at:");
@ -289,14 +279,12 @@ TEST_CASE(testScrollingViewBehaviourDispatchFocusWindowFollowFocustrue) {
// clean up
// kill all windows
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourFocusFallback) {
/*
@ -306,21 +294,17 @@ TEST_CASE(testScrollingViewBehaviourFocusFallback) {
NLog::log("{}Testing scrolling view behaviour: focus fallback from floating window to a tiled window should not move scrolling view", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
if (!Tests::spawnKitty("a")) {
FAIL_TEST("{}Failed to spawn kitty with win class `a`", Colors::RED);
}
OK(getFromSocket("/dispatch hl.dsp.layout('colresize 0.8')"));
if (!Tests::spawnKitty("b")) {
FAIL_TEST("{}Failed to spawn kitty with class `b`", Colors::RED);
}
@ -337,8 +321,6 @@ TEST_CASE(testScrollingViewBehaviourFocusFallback) {
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:c'})"));
// kill the floating window
// Expect the focus to fall back to the left tiled window
OK(getFromSocket("/dispatch hl.dsp.window.kill({window = 'class:c'})"));
@ -367,16 +349,13 @@ TEST_CASE(testScrollingViewBehaviourFocusFallback) {
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourFocusFallbackWithGroups) {
// same idea as testScrollingViewBehaviourFocusFallback, but with window of class "a" being grouped.
NLog::log("{}Testing scrolling view behaviour: focus fallback from floating window to a grouped tiled should not move scrolling view", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
NLog::log("{}Testing scrolling view behaviour: focus fallback from floating window to a grouped tiled should not move scrolling view", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
@ -435,7 +414,6 @@ TEST_CASE(testScrollingViewBehaviourFocusFallbackWithGroups) {
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourWorkspaceChange) {
@ -452,11 +430,9 @@ TEST_CASE(testScrollingViewBehaviourWorkspaceChange) {
// ensure variables are correctly set for the test - this is to avoid unwanted view shifts when setting up the windows
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
// switch to workspace 1 for this test
OK(getFromSocket("/dispatch hl.dsp.focus({workspace = '1'})"));
if (!Tests::spawnKitty("a")) {
FAIL_TEST("{}Failed to spawn kitty with win class `a`", Colors::RED);
}
@ -470,12 +446,11 @@ TEST_CASE(testScrollingViewBehaviourWorkspaceChange) {
// does not move view when follow_focus = 0
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
// change to workspace 2, then back to workspace 1 again
// change to workspace 2, then back to workspace 1 again
OK(getFromSocket("/dispatch hl.dsp.focus({workspace = '2'})"));
OK(getFromSocket("/dispatch hl.dsp.focus({workspace = '1'})"));
// If the scrolling view did not move, the x value for `at:` of the currently focused windows, class:c, must be <0 (must be left of the viewport)
// If the scrolling view did not move, the x value for `at:` of the currently focused window, class:a, must be <0 (must be left of the viewport)
const std::string currentWindowPos = Tests::getWindowAttribute(getFromSocket("/activewindow"), "at:");
const std::string currentWindowPosX = currentWindowPos.substr(4, currentWindowPos.find(',') - 4);
@ -494,12 +469,8 @@ TEST_CASE(testScrollingViewBehaviourWorkspaceChange) {
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourSpecialWorkspaceChange) {
/*
@ -509,10 +480,8 @@ TEST_CASE(testScrollingViewBehaviourSpecialWorkspaceChange) {
NLog::log("{}Testing scrolling view behaviour: changing to a special scrolling workspace from a normal workspace should not move scrolling view", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test - this is to avoid unwanted view shifts when setting up the windows
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
@ -531,8 +500,6 @@ TEST_CASE(testScrollingViewBehaviourSpecialWorkspaceChange) {
// does not move view when follow_focus = 0
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
// change to workspace 2, then back to special "scroll_S" workspace again
OK(getFromSocket("/dispatch hl.dsp.focus({workspace = '2'})"));
@ -561,11 +528,8 @@ TEST_CASE(testScrollingViewBehaviourSpecialWorkspaceChange) {
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourSpecialToSpecialWorkspaceChange) {
/*
We also test switching between 2 special workspaces
This follows the same idea and dependencies as the test testScrollingViewBehaviourSpecialWorkspaceChange()
@ -575,16 +539,12 @@ TEST_CASE(testScrollingViewBehaviourSpecialToSpecialWorkspaceChange) {
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test - this is to avoid unwanted view shifts when setting up the windows
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
// We'll test in this special workspace
OK(getFromSocket("/dispatch hl.dsp.workspace.toggle_special('name:scroll_S')"));
if (!Tests::spawnKitty("a")) {
FAIL_TEST("{}Failed to spawn kitty with win class `a`", Colors::RED);
}
@ -624,24 +584,19 @@ TEST_CASE(testScrollingViewBehaviourSpecialToSpecialWorkspaceChange) {
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourCloseWindowInGroup) {
/*
When you change close a window inside a group (NOT destroying the group!), it should not cause scrolling view to shift to pull that group into view, regardless of follow_focus
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
NLog::log("{}Testing scrolling view behaviour: closing a window in a group (> 1 window in group) should not move scrolling view", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
// this is to avoid unwanted view shifts when setting up the windows
@ -660,10 +615,7 @@ TEST_CASE(testScrollingViewBehaviourCloseWindowInGroup) {
FAIL_TEST("{}Failed to spawn kitty with win class `b`", Colors::RED);
}
OK(getFromSocket("/dispatch hl.dsp.window.move({ into_group = 'left' })"));
if (!Tests::spawnKitty("c")) {
FAIL_TEST("{}Failed to spawn kitty with win class `c`", Colors::RED);
@ -676,7 +628,7 @@ TEST_CASE(testScrollingViewBehaviourCloseWindowInGroup) {
OK(getFromSocket("/dispatch hl.dsp.window.kill({window = 'class:b'})"));
Tests::waitUntilWindowsN(2);
// If the scrolling view did not move, the x value for `at:` of the currently focused windows, class:c, must be <0 (must be left of the viewport)
// If the scrolling view did not move, the x value for `at:` of the currently focused windows, class:a, must be <0 (must be left of the viewport)
const std::string currentWindowPos = Tests::getWindowAttribute(getFromSocket("/activewindow"), "at:");
const std::string currentWindowPosX = currentWindowPos.substr(4, currentWindowPos.find(',') - 4);
@ -695,10 +647,8 @@ TEST_CASE(testScrollingViewBehaviourCloseWindowInGroup) {
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourMoveWindowIntoGroupFollowFocusFalse) {
/*
@ -754,23 +704,19 @@ TEST_CASE(testScrollingViewBehaviourMoveWindowIntoGroupFollowFocusFalse) {
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourMoveWindowInGroupFollowFocusTrue) {
/*
when a window is moved inside a group, scrolling view should move to fit that group when follow_focus = true
------------------------------------------------------------------------------------------------------------
*/
NLog::log("{}Testing scrolling view behaviour: moving a window in a group SHOULD move scrolling view if follow_focus = true", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
OK(getFromSocket("/eval hl.config({group = {auto_group = false}})"));
@ -810,14 +756,12 @@ TEST_CASE(testScrollingViewBehaviourMoveWindowInGroupFollowFocusTrue) {
// clean up
// kill all windows
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourNewLayer) {
/*
@ -829,7 +773,6 @@ TEST_CASE(testScrollingViewBehaviourNewLayer) {
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test - this is to avoid unwanted view shifts when setting up the windows
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
@ -845,7 +788,6 @@ TEST_CASE(testScrollingViewBehaviourNewLayer) {
// focus class:a - this does not move scrolling view when follow_focus = 0
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
NLog::log("{}Spawning kitty layer {}", Colors::YELLOW, "myLayer");
if (!Tests::spawnLayerKitty("myLayer")) {
@ -867,19 +809,17 @@ TEST_CASE(testScrollingViewBehaviourNewLayer) {
// clean up
// kill all layers
NLog::log("{}Killing all layers", Colors::YELLOW);
Tests::killAllLayers();
ASSERT(Tests::layerCount(), 0);
// kill all windows
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
EXPECT(Tests::windowCount(), 0);
// kill all layers
NLog::log("{}Killing all layers", Colors::YELLOW);
Tests::killAllLayers();
ASSERT(Tests::layerCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourMaximise) {
/*
@ -908,10 +848,10 @@ TEST_CASE(testScrollingViewBehaviourMaximise) {
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
// fullscreen class:a window
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'fullscreen', action = 'set', window = 'class:a'})"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'maximized', action = 'set', window = 'class:a'})"));
// unfullscreen class:a window
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'fullscreen', action = 'unset', window = 'class:a'})"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'maximized', action = 'unset', window = 'class:a'})"));
// If the scrolling view did not move, class:a window's x coordinate for its `at:` value should be <0
@ -926,15 +866,12 @@ TEST_CASE(testScrollingViewBehaviourMaximise) {
FAIL_TEST("{}Failed: {}window of class 'a' does not have negative x coordinates for its position: {}", Colors::RED, Colors::RESET, currentWindowPosX);
}
// clean up
// kill all windows
NLog::log("{}Killing all windows", Colors::YELLOW);
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourFullscreen) {
@ -944,16 +881,14 @@ TEST_CASE(testScrollingViewBehaviourFullscreen) {
fullscreening and then unfullscreening a window shouldn't move scrolling view, regardless of follow_focus
*/
NLog::log("{}Testing scrolling view behaviour: fullscreening and then unfullscreening a window shouldn't move scrolling view", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test - this is to avoid unwanted view shifts when setting up the windows
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
if (!Tests::spawnKitty("a")) {
FAIL_TEST("{}Failed to spawn kitty with win class `a`", Colors::RED);
}
@ -968,10 +903,10 @@ TEST_CASE(testScrollingViewBehaviourFullscreen) {
OK(getFromSocket("/dispatch hl.dsp.focus({window = 'class:a'})"));
// maximise class:a window
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'maximized', action = 'set', window = 'class:a'})"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'fullscreen', action = 'set', window = 'class:a'})"));
// unmaximise class:a window
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'maximized', action = 'unset', window = 'class:a'})"));
OK(getFromSocket("/dispatch hl.dsp.window.fullscreen({mode = 'fullscreen', action = 'unset', window = 'class:a'})"));
// If the scrolling view did not move, class:a window's x coordinate for its `at:` value should be <0
const std::string currentWindowPos = Tests::getWindowAttribute(getFromSocket("/activewindow"), "at:");
@ -995,7 +930,6 @@ TEST_CASE(testScrollingViewBehaviourFullscreen) {
TEST_CASE(testScrollingViewBehaviourMoveFocusFollowFocusFalse) {
/*
dispatching movefocus when follow_focus = false should not cause scrolling view to move
---------------------------------------------------------------------------------------
@ -1052,7 +986,6 @@ TEST_CASE(testScrollingViewBehaviourMoveFocusFollowFocusTrue) {
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
if (!Tests::spawnKitty("a")) {
FAIL_TEST("{}Failed to spawn kitty with win class `a`", Colors::RED);
}
@ -1087,7 +1020,6 @@ TEST_CASE(testScrollingViewBehaviourMoveFocusFollowFocusTrue) {
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourMoveFocusInGroupFollowFocusFalse) {
/*
@ -1097,14 +1029,13 @@ TEST_CASE(testScrollingViewBehaviourMoveFocusInGroupFollowFocusFalse) {
NLog::log("{}Testing scrolling view behaviour: movefocus within groups does not cause scrolling view to move if follow_focus = false", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
// necessary to make sure movefocus first cycles through tabs in a group
OK(getFromSocket("/eval hl.config({ binds = {movefocus_cycles_groupfirst = true}})"));
OK(getFromSocket("/eval hl.config({group = {auto_group = false}})"));
OK(getFromSocket("/eval hl.config({group = {auto_group = false}})"));
OK(getFromSocket("/eval hl.config({scrolling = {follow_focus = false}})"));
if (!Tests::spawnKitty("a")) {
@ -1152,8 +1083,6 @@ TEST_CASE(testScrollingViewBehaviourMoveFocusInGroupFollowFocusFalse) {
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(testScrollingViewBehaviourMoveFocusInGroupFollowFocusTrue) {
/*
@ -1161,9 +1090,10 @@ TEST_CASE(testScrollingViewBehaviourMoveFocusInGroupFollowFocusTrue) {
------------------------------------------------------------------------------------------------------------------------------------------
*/
NLog::log("{}Testing scrolling view behaviour: movefocus within groups does causes scrolling view to move if follow_focus = true", Colors::GREEN);
OK(getFromSocket("r/eval hl.config({ general = { layout = 'scrolling' } })"));
// ensure variables are correctly set for the test
// necessary to make sure movefocus first cycles through tabs in a group

View file

@ -30,12 +30,12 @@ namespace Layout::Tiled {
CDwindleAlgorithm() = default;
virtual ~CDwindleAlgorithm() = default;
virtual void newTarget(SP<ITarget> target);
virtual void movedTarget(SP<ITarget> target, std::optional<Vector2D> focalPoint = std::nullopt);
virtual void removeTarget(SP<ITarget> target);
virtual void newTarget(SP<ITarget> target);
virtual void movedTarget(SP<ITarget> target, std::optional<Vector2D> focalPoint = std::nullopt);
virtual void removeTarget(SP<ITarget> target);
virtual void resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner = CORNER_NONE);
virtual void recalculate(eRecalculateReason reason = RECALCULATE_REASON_UNKNOWN);
virtual void resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner = CORNER_NONE);
virtual void recalculate(eRecalculateReason reason = RECALCULATE_REASON_UNKNOWN);
virtual SP<ITarget> getNextCandidate(SP<ITarget> old);

View file

@ -48,12 +48,12 @@ namespace Layout::Tiled {
CMasterAlgorithm() = default;
virtual ~CMasterAlgorithm() = default;
virtual void newTarget(SP<ITarget> target);
virtual void movedTarget(SP<ITarget> target, std::optional<Vector2D> focalPoint = std::nullopt);
virtual void removeTarget(SP<ITarget> target);
virtual void newTarget(SP<ITarget> target);
virtual void movedTarget(SP<ITarget> target, std::optional<Vector2D> focalPoint = std::nullopt);
virtual void removeTarget(SP<ITarget> target);
virtual void resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner = CORNER_NONE);
virtual void recalculate(eRecalculateReason reason = RECALCULATE_REASON_UNKNOWN);
virtual void resizeTarget(const Vector2D& Δ, SP<ITarget> target, eRectCorner corner = CORNER_NONE);
virtual void recalculate(eRecalculateReason reason = RECALCULATE_REASON_UNKNOWN);
virtual SP<ITarget> getNextCandidate(SP<ITarget> old);

View file

@ -203,8 +203,8 @@ SP<ITarget> CSpace::getNextCandidate(SP<ITarget> old) {
}
bool Layout::isHardRecalculateReason(eRecalculateReason reason) {
return reason != RECALCULATE_REASON_WORKSPACE_CHANGE && reason != RECALCULATE_REASON_SPECIAL_WORKSPACE_TOGGLE &&
reason != RECALCULATE_REASON_TOGGLE_FULLSCREEN && reason != RECALCULATE_REASON_INVALIDATE_MONITOR_GEOMETRIES && reason != RECALCULATE_REASON_RENDER_MOINTOR;
return reason != RECALCULATE_REASON_WORKSPACE_CHANGE && reason != RECALCULATE_REASON_SPECIAL_WORKSPACE_TOGGLE && reason != RECALCULATE_REASON_TOGGLE_FULLSCREEN &&
reason != RECALCULATE_REASON_INVALIDATE_MONITOR_GEOMETRIES && reason != RECALCULATE_REASON_RENDER_MOINTOR;
}
const std::vector<WP<ITarget>>& CSpace::targets() const {