diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-02 12:16:38 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-02 12:16:38 -0500 |
| commit | b10cba594db836c0747066addad48bda4d30cd02 (patch) | |
| tree | 063119a623fa3f7139feda4ef302896d8f5f934c /tests/layout-navigate/test_layout_navigate.py | |
| parent | 49c2ba9c4510bf6e1acd306687473bc8ba9ad8dd (diff) | |
| download | archsetup-b10cba594db836c0747066addad48bda4d30cd02.tar.gz archsetup-b10cba594db836c0747066addad48bda4d30cd02.zip | |
refactor: drop in-repo dotfiles/, move stow tooling to the dotfiles repo
Since the installer clones DOTFILES_REPO into ~/.dotfiles and stows from there, the in-repo dotfiles/ tree was dead weight. Nothing reads it at install time. I removed it (831 files) now that both machines are migrated.
The Makefile's stow / restow / reset / unstow / import targets and the dotfile-script unit suites moved to the dotfiles repo. They sit alongside the scripts they manage and run standalone (cd ~/.dotfiles && make ...). This Makefile keeps the VM-integration targets and the installer-helper suite (safe-rm-rf).
I updated CLAUDE.md and README.md so stow operations run from ~/.dotfiles, and the dotfile-management, theme, and unit-test sections point at the standalone repo. The README was already describing the old in-repo model from before the installer switched to cloning. This brings it in line.
Diffstat (limited to 'tests/layout-navigate/test_layout_navigate.py')
| -rw-r--r-- | tests/layout-navigate/test_layout_navigate.py | 219 |
1 files changed, 0 insertions, 219 deletions
diff --git a/tests/layout-navigate/test_layout_navigate.py b/tests/layout-navigate/test_layout_navigate.py deleted file mode 100644 index 41294b7..0000000 --- a/tests/layout-navigate/test_layout_navigate.py +++ /dev/null @@ -1,219 +0,0 @@ -"""Tests for dotfiles/hyprland/.local/bin/layout-navigate. - -The script is a sh wrapper around `hyprctl` that chooses the right dispatch -command for the active layout (master/dwindle/scrolling) and for the active -window's state (floating vs tiled, regular workspace vs special overlay). - -Tests invoke the real script with a faked `hyprctl` on PATH. The fake reads -canned JSON for activewindow/getoption queries and records each dispatch -call to a log file. Assertions compare the dispatch log to the expected -sequence for the given scenario — we test behavior (what hyprctl calls -the script emits), not implementation. -""" - -import json -import os -import stat -import subprocess -import tempfile -import unittest - - -REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) -SCRIPT = os.path.join(REPO_ROOT, "dotfiles/hyprland/.local/bin/layout-navigate") -FAKE_HYPRCTL = os.path.join(os.path.dirname(__file__), "fake-hyprctl") - - -def make_activewindow(floating=False, workspace_name="1", workspace_id=1): - return { - "address": "0xabc", - "floating": bool(floating), - "workspace": {"id": workspace_id, "name": workspace_name}, - "class": "test", - "title": "test", - } - - -def make_layout(name): - return {"str": name} - - -class LayoutNavigateHarness(unittest.TestCase): - """Shared harness: run layout-navigate with fake hyprctl, read dispatch log.""" - - def setUp(self): - self.tmp = tempfile.mkdtemp(prefix="layout-navigate-test-") - # Ensure the fake hyprctl is executable - os.chmod(FAKE_HYPRCTL, os.stat(FAKE_HYPRCTL).st_mode | stat.S_IEXEC) - - # Create a bin dir with a symlink to fake-hyprctl named "hyprctl" - self.bin_dir = os.path.join(self.tmp, "bin") - os.makedirs(self.bin_dir) - os.symlink(FAKE_HYPRCTL, os.path.join(self.bin_dir, "hyprctl")) - - # Initialize dispatch log - self.dispatch_log = os.path.join(self.tmp, "dispatch.log") - open(self.dispatch_log, "w").close() - - def tearDown(self): - import shutil - shutil.rmtree(self.tmp, ignore_errors=True) - - def set_state(self, activewindow, layout, next_activewindow=None): - with open(os.path.join(self.tmp, "activewindow.json"), "w") as f: - json.dump(activewindow, f) - with open(os.path.join(self.tmp, "layout.json"), "w") as f: - json.dump(layout, f) - if next_activewindow is not None: - with open(os.path.join(self.tmp, "activewindow.1.json"), "w") as f: - json.dump(next_activewindow, f) - - def run_script(self, *args): - # Preserve current PATH so jq, sh, etc. are reachable - env = os.environ.copy() - env["PATH"] = self.bin_dir + os.pathsep + env.get("PATH", "") - env["FAKE_HYPR_DIR"] = self.tmp - result = subprocess.run( - [SCRIPT] + list(args), - env=env, - capture_output=True, - text=True, - timeout=10, - ) - return result - - def dispatches(self): - with open(self.dispatch_log) as f: - return [line.rstrip("\n") for line in f if line.strip()] - - -class TestTiledMasterLayout(LayoutNavigateHarness): - """Characterization: existing behavior for master/dwindle layout on a regular workspace.""" - - def test_layout_navigate_master_tiled_next_focus_emits_cyclenext(self): - self.set_state(make_activewindow(), make_layout("master")) - self.run_script("next") - self.assertEqual(self.dispatches(), ["dispatch layoutmsg cyclenext"]) - - def test_layout_navigate_master_tiled_prev_focus_emits_cycleprev(self): - self.set_state(make_activewindow(), make_layout("master")) - self.run_script("prev") - self.assertEqual(self.dispatches(), ["dispatch layoutmsg cycleprev"]) - - def test_layout_navigate_master_tiled_next_move_emits_swapnext(self): - self.set_state(make_activewindow(), make_layout("master")) - self.run_script("next", "move") - self.assertEqual(self.dispatches(), ["dispatch layoutmsg swapnext"]) - - def test_layout_navigate_master_tiled_prev_move_emits_swapprev(self): - self.set_state(make_activewindow(), make_layout("master")) - self.run_script("prev", "move") - self.assertEqual(self.dispatches(), ["dispatch layoutmsg swapprev"]) - - -class TestScrollingLayout(LayoutNavigateHarness): - """Characterization: existing behavior for scrolling layout on a regular workspace.""" - - def test_layout_navigate_scrolling_next_focus_emits_focus_l(self): - self.set_state(make_activewindow(), make_layout("scrolling")) - self.run_script("next") - self.assertEqual(self.dispatches(), ["dispatch layoutmsg focus l"]) - - def test_layout_navigate_scrolling_next_move_emits_swapwindow_l(self): - self.set_state(make_activewindow(), make_layout("scrolling")) - self.run_script("next", "move") - self.assertEqual(self.dispatches(), ["dispatch swapwindow l"]) - - -class TestFloatingOnRegularWorkspace(LayoutNavigateHarness): - """Characterization: floating window on a regular workspace short-circuits to cyclenext tiled.""" - - def test_layout_navigate_floating_regular_next_focus_emits_cyclenext_tiled(self): - self.set_state(make_activewindow(floating=True), make_layout("master")) - self.run_script("next") - self.assertEqual(self.dispatches(), ["dispatch cyclenext tiled"]) - - def test_layout_navigate_floating_regular_prev_focus_emits_cyclenext_prev_tiled(self): - self.set_state(make_activewindow(floating=True), make_layout("master")) - self.run_script("prev") - self.assertEqual(self.dispatches(), ["dispatch cyclenext prev tiled"]) - - -class TestTiledInSpecialWorkspace(LayoutNavigateHarness): - """New behavior: tiled window in a special workspace toggles overlay off, then cycles. - - The special:stash overlay (or any special workspace) hides the underlying regular - workspace. Cycling with layoutmsg only operates within the current workspace, so - without toggling first, $mod+J gets trapped inside the overlay. Fix: hide the - overlay, then dispatch the normal cycle — one keypress does both. - """ - - def test_layout_navigate_tiled_special_next_focus_toggles_then_cyclenext(self): - active = make_activewindow(workspace_name="special:stash", workspace_id=-92) - # Post-toggle, focus lands on a tiled window on regular ws 1 - post = make_activewindow(workspace_name="1", workspace_id=1) - self.set_state(active, make_layout("master"), next_activewindow=post) - self.run_script("next") - self.assertEqual( - self.dispatches(), - [ - "dispatch togglespecialworkspace stash", - "dispatch layoutmsg cyclenext", - ], - ) - - def test_layout_navigate_tiled_special_prev_focus_toggles_then_cycleprev(self): - active = make_activewindow(workspace_name="special:stash", workspace_id=-92) - post = make_activewindow(workspace_name="1", workspace_id=1) - self.set_state(active, make_layout("master"), next_activewindow=post) - self.run_script("prev") - self.assertEqual( - self.dispatches(), - [ - "dispatch togglespecialworkspace stash", - "dispatch layoutmsg cycleprev", - ], - ) - - def test_layout_navigate_tiled_special_scrolling_toggles_then_focus_l(self): - """Toggle-then-cycle must honor the active layout, not hard-code master.""" - active = make_activewindow(workspace_name="special:stash", workspace_id=-92) - post = make_activewindow(workspace_name="1", workspace_id=1) - self.set_state(active, make_layout("scrolling"), next_activewindow=post) - self.run_script("next") - self.assertEqual( - self.dispatches(), - [ - "dispatch togglespecialworkspace stash", - "dispatch layoutmsg focus l", - ], - ) - - def test_layout_navigate_tiled_special_next_move_does_not_toggle(self): - """MOVE variant should NOT auto-toggle — moving a window out of a scratchpad - is a separate UX we don't want triggered by the common navigate key.""" - active = make_activewindow(workspace_name="special:stash", workspace_id=-92) - self.set_state(active, make_layout("master")) - self.run_script("next", "move") - self.assertEqual(self.dispatches(), ["dispatch layoutmsg swapnext"]) - - def test_layout_navigate_floating_special_next_focus_toggles_first(self): - """Floating scratchpad (e.g. special:S-term foot) should also toggle off. - After the toggle, the re-read state determines whether to take the - floating branch or fall through to the layout branch.""" - active = make_activewindow(floating=True, workspace_name="special:S-term", workspace_id=-98) - # After toggling S-term off, focus lands on a tiled window on ws 1 - post = make_activewindow(floating=False, workspace_name="1", workspace_id=1) - self.set_state(active, make_layout("master"), next_activewindow=post) - self.run_script("next") - self.assertEqual( - self.dispatches(), - [ - "dispatch togglespecialworkspace S-term", - "dispatch layoutmsg cyclenext", - ], - ) - - -if __name__ == "__main__": - unittest.main() |
