testsAndMisc/linux_configuration/features/lib/tests/test_dwm_config.sh
Krzysztof kuhy Rudnicki 4f2b0ccdf7 Dissolve linux_configuration/scripts/ and single_use/
Two levels of pure taxonomy carrying no information, and a 2-directory
cap leaves no room for them. Categories now sit directly under
linux_configuration/: features, fixes, utils, misc, fresh-install,
installers, diagnostics, gaming, boot_recovery, periodic_background, lib,
meta, tests. A script's own lib/ and tests/ are exempt from the cap, so
those stay put.

Depth violations 248 -> 139; roughly 40 of the remainder are inside
digital_wellbeing and hosts, deferred until the guard-lib repoint.

The moves are the easy half. What breaks is every path that counted
levels, and three classes of it had to be found by resolving paths rather
than reading diffs:

  - 52 relative `source` lines for lib/common.sh and lib/android.sh. The
    correct prefix differs per file: 40 were ../../ and 12 were ../../../,
    so a blanket replace would have fixed one set and broken the other.
  - REPO_ROOT in 7 fixes/lib/tests harnesses and setup_syncyomi_guard.sh,
    each walking up four levels from a directory now two levels shallower.
    This caused a real regression -- the fixes suite went red with
    "log_warn: command not found" -- caught by running it and comparing
    against the pre-move baseline worktree.
  - conftest.py's sys.path entries, which took the pytest gate down with
    14 collection errors, and the `# shellcheck source=` directives, which
    took shellcheck down with SC1091.

16 symlinks in $HOME broke, including the entire i3blocks bar. All
repointed, and cpu_monitor/memory/disk/time/volume were run to confirm
they emit real output rather than merely resolving.

Verified: 1798 tests pass at 100% coverage, 8 of 9 lib/tests suites pass
(the ninth needs the coverage jail, identically at baseline), pre-commit
is clean, and the two untracked secret configs are still ignored after
their gitignore paths changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
2026-08-23 18:53:30 +02:00

189 lines
7.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Tests for dwm_config.sh — dwm's config install, healing and source patches.
#
# The subject is driven for real: it rewrites dwm.c with perl, appends to
# config.h, compiles with cc and installs to /usr/local/bin. The generated
# CONTENT is what is worth asserting -- a focus-on-click rewrite that silently
# stops matching upstream is precisely the bug a presence check would miss.
#
# Safe only under meta/scripts/shell_coverage_jail.sh: write_session_files and
# build_pointer_confine install into /usr/local/bin, which the jail
# bind-mounts to a throwaway dir. See jail_args beside this file.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=./features_harness.sh
. "$SCRIPT_DIR/features_harness.sh"
# --- Refuse to run outside the jail -----------------------------------------
# /usr/local/bin is bind-mounted to an empty dir inside the jail. Finding the
# host's own binaries there means we are NOT contained, and the installs below
# would overwrite the real ones.
if [[ -e /usr/local/bin/switch-wm ]] && [[ ! -w /usr/local/bin ]]; then
printf 'REFUSING: this suite must run under shell_coverage_jail.sh\n' >&2
exit 1
fi
_t_setup_env
trap _t_teardown EXIT
warn() { printf '[test-warn] %s\n' "$1" >&2; }
# The globals dwm_config.sh inherits from setup_dwm.sh above its source line.
SRC_DIR="$TEST_TMPDIR/src"
REPO_DWM_DIR="$TEST_TMPDIR/repo"
BIN_SESSION="/usr/local/bin/dwm-session"
BIN_STATUS="/usr/local/bin/dwmstatus"
BIN_REBUILD="/usr/local/bin/dwm-rebuild"
BIN_SWITCH="/usr/local/bin/switch-wm"
BIN_CONFINE="/usr/local/bin/pointer-confine"
BIN_CONFINE_AUTO="/usr/local/bin/pconfine-auto"
XSESSION="$TEST_TMPDIR/dwm.desktop"
mkdir -p "$SRC_DIR" "$REPO_DWM_DIR/bin"
# shellcheck source=../dwm_config.sh
. "$FEATURES_LIB_DIR/dwm_config.sh"
# --- install_config ---------------------------------------------------------
printf 'static const int ours = 1;\n' >"$REPO_DWM_DIR/config.h"
install_config
_t_file_has "$SRC_DIR/config.h" 'ours' "install_config copies the repo's config.h onto the clone"
# --- heal_config: no config.def.h is a clean no-op ---------------------------
heal_config
_t_eq "0" "$?" "heal_config returns 0 when config.def.h is absent"
# --- heal_config: merges a knob dwm.c needs and config.h lacks --------------
cat >"$SRC_DIR/config.def.h" <<'DEFH'
static const int refreshrate = 60;
static const int ours = 9;
static const int unused = 3;
DEFH
printf 'int main(void){return refreshrate + ours;}\n' >"$SRC_DIR/dwm.c"
heal_config
_t_file_has "$SRC_DIR/config.h" 'refreshrate' "heal_config merges an upstream knob dwm.c references"
_t_eq "1" "$(grep -c 'ours' "$SRC_DIR/config.h")" "heal_config keeps OUR value and does not duplicate it"
_t_eq "0" "$(grep -c 'unused' "$SRC_DIR/config.h")" "heal_config skips a knob dwm.c never references"
# --- apply_focusonclick: missing dwm.c is a clean no-op ---------------------
rm -f "$SRC_DIR/dwm.c"
apply_focusonclick
_t_eq "0" "$?" "apply_focusonclick returns 0 when dwm.c is absent"
# --- apply_focusonclick: rewrites both handlers ------------------------------
# Shaped like upstream: a column-0 closing brace ends each function body.
cat >"$SRC_DIR/dwm.c" <<'DWMC'
void
enternotify(XEvent *e)
{
Client *c;
if (c)
focus(c);
}
void
motionnotify(XEvent *e)
{
Monitor *m;
if (m)
selmon = m;
}
DWMC
apply_focusonclick
_t_file_has "$SRC_DIR/dwm.c" 'pointer never changes focus' "apply_focusonclick rewrites enternotify"
_t_file_has "$SRC_DIR/dwm.c" 'keep the active monitor fixed' "apply_focusonclick rewrites motionnotify"
_t_eq "0" "$(grep -c 'focus(c);' "$SRC_DIR/dwm.c")" "the original enternotify body is gone"
# --- apply_focusonclick: warns instead of aborting on refactored upstream ---
printf 'void\nsomething_else(void)\n{\n\treturn;\n}\n' >"$SRC_DIR/dwm.c"
focus_out="$(apply_focusonclick 2>&1)"
_t_has "$focus_out" 'did NOT match upstream' "apply_focusonclick warns when the rewrite does not match"
# --- apply_fullscreen_confine_hook: missing dwm.c is a clean no-op -----------
rm -f "$SRC_DIR/dwm.c"
apply_fullscreen_confine_hook
_t_eq "0" "$?" "apply_fullscreen_confine_hook returns 0 when dwm.c is absent"
# --- apply_fullscreen_confine_hook: 1 "on", 2 "off" --------------------------
cat >"$SRC_DIR/dwm.c" <<'DWMC'
void
setfullscreen(Client *c, int fullscreen)
{
if (fullscreen && !c->isfullscreen) {
c->isfullscreen = 1;
} else if (!fullscreen && c->isfullscreen) {
c->isfullscreen = 0;
}
}
void
unmanage(Client *c, int destroyed)
{
Monitor *m = c->mon;
XWindowChanges wc;
detach(c);
}
DWMC
hook_out="$(apply_fullscreen_confine_hook 2>&1)"
_t_eq "1" "$(grep -c 'pconfine-auto on' "$SRC_DIR/dwm.c")" "the hook adds exactly one 'on' call"
_t_eq "2" "$(grep -c 'pconfine-auto off' "$SRC_DIR/dwm.c")" "the hook adds two 'off' calls (leave + unmanage)"
_t_has "$hook_out" 'Applied auto pointer-confinement' "the hook reports success at 1/2"
# --- apply_fullscreen_confine_hook: warns on a partial match ----------------
printf 'void\nsetfullscreen(void)\n{\n\treturn;\n}\n' >"$SRC_DIR/dwm.c"
partial_out="$(apply_fullscreen_confine_hook 2>&1)"
_t_has "$partial_out" 'only partially applied' "the hook warns when setfullscreen was refactored"
# --- build_install ----------------------------------------------------------
_t_stub make
build_install
_t_called 'make' "build_install invokes make"
# --- build_pointer_confine: the compile succeeds ----------------------------
printf 'int main(void){return 0;}\n' >"$REPO_DWM_DIR/pointer-confine.c"
_t_stub cc
confine_out="$(build_pointer_confine 2>&1)"
_t_has "$confine_out" "Installed $BIN_CONFINE" "build_pointer_confine installs the helper on a clean compile"
_t_eq "0" "$([[ -f $BIN_CONFINE ]] && echo 0 || echo 1)" "the pointer-confine binary lands in /usr/local/bin"
# --- build_pointer_confine: a failed compile fails SOFT ---------------------
# The real cc fails on a C file that is not C; dwm itself must still install.
cat >"$TEST_TMPDIR/bin/cc" <<'FAILCC'
#!/usr/bin/env bash
# Mimic a real cc failure: dwm_config redirects our stderr to the build log,
# so writing there is enough -- no need to know which argv slot -o landed in.
printf 'error: broken\n' >&2
exit 1
FAILCC
chmod +x "$TEST_TMPDIR/bin/cc"
soft_out="$(build_pointer_confine 2>&1)"
_t_has "$soft_out" 'fullscreen cursor-lock disabled' "a failed compile warns instead of aborting"
# --- write_session_files ----------------------------------------------------
for helper in dwm-session dwmstatus dwm-rebuild switch-wm pconfine-auto; do
printf '#!/bin/sh\nexit 0\n' >"$REPO_DWM_DIR/bin/$helper"
done
write_session_files
_t_eq "0" "$([[ -x $BIN_SWITCH ]] && echo 0 || echo 1)" "write_session_files installs switch-wm executable"
_t_eq "0" "$([[ -x $BIN_CONFINE_AUTO ]] && echo 0 || echo 1)" "write_session_files installs pconfine-auto executable"
_t_file_has "$XSESSION" 'Exec=/usr/local/bin/dwm-session' "the xsession entry uses an absolute Exec path"
_t_file_has "$XSESSION" 'DesktopNames=dwm' "the xsession entry declares DesktopNames=dwm"
# --- verify -----------------------------------------------------------------
_t_stub dwm
verify_out="$(verify 2>&1)"
_t_has "$verify_out" 'dwm version:' "verify reports the dwm version"
_t_has "$verify_out" 'xsession registered' "verify confirms the xsession is registered"
# --- verify: tolerates a missing dwm binary ---------------------------------
_t_unstub dwm
missing_out="$(verify 2>&1)" || true
_t_has "$missing_out" 'dwm version:' "verify still reports when dwm is absent (dwm -v exits 1)"
# --- print_summary ----------------------------------------------------------
summary_out="$(print_summary)"
_t_has "$summary_out" 'switch-wm dwm' "print_summary documents the switch-wm command"
_t_has "$summary_out" 'Ctrl+Alt+F3' "print_summary documents the TTY recovery path"
_t_report "test_dwm_config.sh"