aboutsummaryrefslogtreecommitdiff
path: root/tests/notify
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-02 12:16:38 -0500
committerCraig Jennings <c@cjennings.net>2026-06-02 12:16:38 -0500
commitb10cba594db836c0747066addad48bda4d30cd02 (patch)
tree063119a623fa3f7139feda4ef302896d8f5f934c /tests/notify
parent49c2ba9c4510bf6e1acd306687473bc8ba9ad8dd (diff)
downloadarchsetup-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/notify')
-rw-r--r--tests/notify/test_notify.py186
1 files changed, 0 insertions, 186 deletions
diff --git a/tests/notify/test_notify.py b/tests/notify/test_notify.py
deleted file mode 100644
index c49af57..0000000
--- a/tests/notify/test_notify.py
+++ /dev/null
@@ -1,186 +0,0 @@
-"""Tests for dotfiles/common/.local/bin/notify.
-
-notify wraps notify-send (the visual popup) and paplay (the sound). The tests
-run the real script with HOME pointed at a temp dir holding fake icon/sound
-assets, and with fake `notify-send` and `paplay` executables on PATH that log
-their arguments. Assertions are made on those logs:
-
- - the popup always fires (notify-send logged)
- - the sound fires only when not --silent, at NOTIFY_VOLUME
- - --persist and --silent compose in any order
- - bad type / too few args / unknown flag fail
-
-No real audio plays and no real notification is sent.
-
-Run from repo root:
- python3 -m unittest tests.notify.test_notify
-"""
-
-import os
-import shutil
-import subprocess
-import tempfile
-import time
-import unittest
-
-
-REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
-SCRIPT = os.path.join(REPO_ROOT, "dotfiles/common/.local/bin/notify")
-
-SOUND_TYPES = ["success", "fail", "alert", "question", "alarm", "info", "security", "bug"]
-
-
-class NotifyHarness(unittest.TestCase):
-
- def setUp(self):
- self.tmp = tempfile.mkdtemp(prefix="notify-test-")
- self.home = os.path.join(self.tmp, "home")
- self.bin = os.path.join(self.tmp, "bin")
- self.sound_dir = os.path.join(self.home, ".local/share/sounds/notify")
- self.icon_dir = os.path.join(self.home, ".local/share/icons/notify")
- os.makedirs(self.bin)
- os.makedirs(self.sound_dir)
- os.makedirs(self.icon_dir)
-
- # Fake assets so the script's existence checks pass.
- for t in SOUND_TYPES:
- open(os.path.join(self.sound_dir, f"{t}.ogg"), "w").close()
- open(os.path.join(self.icon_dir, f"{t}.png"), "w").close()
-
- # Fake binaries that log their argv to a file under tmp.
- self.notify_log = os.path.join(self.tmp, "notify-send.log")
- self.paplay_log = os.path.join(self.tmp, "paplay.log")
- self._make_stub("notify-send", self.notify_log)
- self._make_stub("paplay", self.paplay_log)
-
- def tearDown(self):
- shutil.rmtree(self.tmp, ignore_errors=True)
-
- def _make_stub(self, name, logfile):
- path = os.path.join(self.bin, name)
- with open(path, "w") as f:
- f.write("#!/bin/bash\n")
- f.write('printf "%s\\n" "$*" >> "' + logfile + '"\n')
- os.chmod(path, 0o755)
-
- def run_notify(self, *args, env_extra=None):
- env = os.environ.copy()
- env["HOME"] = self.home
- env["PATH"] = self.bin + os.pathsep + env.get("PATH", "")
- if env_extra:
- env.update(env_extra)
- return subprocess.run(
- [SCRIPT, *args], env=env, capture_output=True, text=True, timeout=10,
- )
-
- def read_log(self, path, wait=False):
- """Return log contents. If wait, poll briefly (the sound is backgrounded)."""
- if wait:
- deadline = time.time() + 2.0
- while time.time() < deadline and not os.path.exists(path):
- time.sleep(0.02)
- if not os.path.exists(path):
- return ""
- with open(path) as f:
- return f.read()
-
- def paplay_called(self):
- # Silent path never spawns paplay, so a short settle is enough to be sure.
- time.sleep(0.3)
- return os.path.exists(self.paplay_log)
-
-
-# -----------------------------------------------------------------------------
-# Normal cases
-# -----------------------------------------------------------------------------
-
-class TestNotifyNormal(NotifyHarness):
-
- def test_default_shows_popup_and_plays_sound(self):
- result = self.run_notify("info", "Title", "Body")
- self.assertEqual(result.returncode, 0, msg=result.stderr)
- self.assertIn("Title", self.read_log(self.notify_log))
- self.assertIn("info.ogg", self.read_log(self.paplay_log, wait=True))
-
- def test_sound_played_at_default_volume(self):
- self.run_notify("success", "T", "B")
- self.assertIn("--volume=65536", self.read_log(self.paplay_log, wait=True))
-
- def test_each_type_selects_its_own_sound(self):
- for t in SOUND_TYPES:
- with self.subTest(type=t):
- # Fresh log per type.
- if os.path.exists(self.paplay_log):
- os.remove(self.paplay_log)
- self.run_notify(t, "T", "B")
- self.assertIn(f"{t}.ogg", self.read_log(self.paplay_log, wait=True))
-
-
-# -----------------------------------------------------------------------------
-# --silent
-# -----------------------------------------------------------------------------
-
-class TestNotifySilent(NotifyHarness):
-
- def test_silent_shows_popup_but_no_sound(self):
- result = self.run_notify("info", "T", "B", "--silent")
- self.assertEqual(result.returncode, 0, msg=result.stderr)
- self.assertIn("T", self.read_log(self.notify_log))
- self.assertFalse(self.paplay_called(), "paplay should not run under --silent")
-
- def test_silent_then_persist_both_apply(self):
- result = self.run_notify("info", "T", "B", "--silent", "--persist")
- self.assertEqual(result.returncode, 0, msg=result.stderr)
- self.assertIn("--expire-time=0", self.read_log(self.notify_log))
- self.assertFalse(self.paplay_called())
-
- def test_persist_then_silent_order_independent(self):
- result = self.run_notify("info", "T", "B", "--persist", "--silent")
- self.assertEqual(result.returncode, 0, msg=result.stderr)
- self.assertIn("--expire-time=0", self.read_log(self.notify_log))
- self.assertFalse(self.paplay_called())
-
-
-# -----------------------------------------------------------------------------
-# Volume knob + persist
-# -----------------------------------------------------------------------------
-
-class TestNotifyVolumeAndPersist(NotifyHarness):
-
- def test_notify_volume_env_overrides_playback_volume(self):
- self.run_notify("info", "T", "B", env_extra={"NOTIFY_VOLUME": "30000"})
- self.assertIn("--volume=30000", self.read_log(self.paplay_log, wait=True))
-
- def test_persist_adds_expire_time_zero(self):
- self.run_notify("info", "T", "B", "--persist")
- self.assertIn("--expire-time=0", self.read_log(self.notify_log))
-
- def test_no_persist_has_no_expire_time(self):
- self.run_notify("info", "T", "B")
- self.assertNotIn("--expire-time", self.read_log(self.notify_log))
-
-
-# -----------------------------------------------------------------------------
-# Error cases
-# -----------------------------------------------------------------------------
-
-class TestNotifyErrors(NotifyHarness):
-
- def test_unknown_type_exits_nonzero(self):
- result = self.run_notify("bogus", "T", "B")
- self.assertNotEqual(result.returncode, 0)
- self.assertIn("Unknown type", result.stderr)
-
- def test_too_few_args_shows_usage(self):
- result = self.run_notify("info", "OnlyTitle")
- self.assertNotEqual(result.returncode, 0)
- self.assertIn("Usage", result.stderr + result.stdout)
-
- def test_unknown_flag_exits_nonzero(self):
- result = self.run_notify("info", "T", "B", "--bogus")
- self.assertNotEqual(result.returncode, 0)
- self.assertIn("Unknown option", result.stderr)
-
-
-if __name__ == "__main__":
- unittest.main()