From b10cba594db836c0747066addad48bda4d30cd02 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 2 Jun 2026 12:16:38 -0500 Subject: 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. --- tests/layout-navigate/fake-hyprctl | 48 ------ tests/layout-navigate/test_layout_navigate.py | 219 -------------------------- 2 files changed, 267 deletions(-) delete mode 100755 tests/layout-navigate/fake-hyprctl delete mode 100644 tests/layout-navigate/test_layout_navigate.py (limited to 'tests/layout-navigate') diff --git a/tests/layout-navigate/fake-hyprctl b/tests/layout-navigate/fake-hyprctl deleted file mode 100755 index 701f397..0000000 --- a/tests/layout-navigate/fake-hyprctl +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# Fake hyprctl for testing layout-navigate. -# -# State files live in $FAKE_HYPR_DIR: -# activewindow.json - first activewindow call returns this -# activewindow.1.json - second call (after togglespecialworkspace) returns this, if present -# layout.json - getoption general:layout returns this -# dispatch.log - every "dispatch" invocation appended here (one line) -# call-count - internal counter for activewindow calls - -: "${FAKE_HYPR_DIR:?FAKE_HYPR_DIR must be set}" - -cmd="$1" -shift - -case "$cmd" in - activewindow) - # Count calls so tests can provide a post-toggle state - count_file="$FAKE_HYPR_DIR/call-count" - count=$(cat "$count_file" 2>/dev/null || echo 0) - next=$((count + 1)) - echo "$next" > "$count_file" - - if [ "$count" -eq 0 ]; then - cat "$FAKE_HYPR_DIR/activewindow.json" - else - # Try numbered file; fall back to original - numbered="$FAKE_HYPR_DIR/activewindow.$count.json" - if [ -f "$numbered" ]; then - cat "$numbered" - else - cat "$FAKE_HYPR_DIR/activewindow.json" - fi - fi - ;; - getoption) - cat "$FAKE_HYPR_DIR/layout.json" - ;; - dispatch) - # Log the entire dispatch invocation as one line - echo "dispatch $*" >> "$FAKE_HYPR_DIR/dispatch.log" - echo "ok" - ;; - *) - echo "fake-hyprctl: unknown command '$cmd'" >&2 - exit 1 - ;; -esac 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() -- cgit v1.2.3