Dotfiles_ArchAP/tests/quickshell/test_scratchpad_drawer.py
2026-10-09 17:32:37 +02:00

94 lines
4.3 KiB
Python

"""Contrats du modèle scratchpad Sway, sans toucher au bureau réel."""
import importlib.util
from pathlib import Path
import unittest
from unittest.mock import patch
BACKEND = (Path(__file__).resolve().parents[2] / "quickshell/.config/quickshell"
/ "labfy-sway/scratchpad/backend.py")
spec = importlib.util.spec_from_file_location("drawer_backend", BACKEND)
drawer = importlib.util.module_from_spec(spec)
spec.loader.exec_module(drawer)
def app(cid, name="Application", app_id="demo", state="none"):
return {"id": cid, "type": "con", "name": name, "app_id": app_id,
"scratchpad_state": state, "nodes": [], "floating_nodes": []}
def tree(*nodes):
return {"id": 1, "type": "root", "nodes": [
{"id": 2, "type": "output", "name": "__i3", "nodes": [
{"id": 3, "type": "workspace", "name": "__i3_scratch",
"nodes": [], "floating_nodes": [n for n in nodes if n.get("hidden")]}]},
{"id": 4, "type": "output", "name": "DP-2", "nodes": [
{"id": 5, "type": "workspace", "name": 'Travail ; "A"',
"nodes": [], "floating_nodes": [n for n in nodes if not n.get("hidden")]}]}]}
class DrawerModelTest(unittest.TestCase):
def test_empty_and_duplicate_app_identity(self):
self.assertEqual(drawer.members(tree()), [])
a, b = app(20, "Premier", state="fresh"), app(21, "Second", state="fresh")
a["hidden"] = True
result = drawer.members(tree(a, b))
self.assertEqual([(x["id"], x["shown"]) for x in result], [(20, False), (21, True)])
def test_group_is_blocked_even_when_apps_are_nested(self):
group = {"id": 10, "type": "floating_con", "scratchpad_state": "fresh",
"nodes": [{"id": 11, "type": "con", "nodes": [app(20)],
"floating_nodes": [app(21)]}], "floating_nodes": []}
group["hidden"] = True
self.assertTrue(all(x["group"] for x in drawer.members(tree(group))))
def test_workspace_quoting_and_missing_target(self):
self.assertEqual(drawer.quoted_workspace('Travail ; "A"'), "'Travail ; \"A\"'")
with self.assertRaises(drawer.DrawerError):
drawer.quoted_workspace("A 'B' and \"C\"")
with self.assertRaises(drawer.DrawerError):
drawer.valid_app(tree(), 99)
with patch.object(drawer, "sway", return_value=[{"name": "A", "output": "DP-2", "visible": True}]):
with self.assertRaises(drawer.DrawerError):
drawer.target_workspace("HDMI-A-1")
def test_non_app_container_is_rejected(self):
group = {"id": 30, "type": "con", "nodes": [app(31)], "floating_nodes": []}
with self.assertRaises(drawer.DrawerError):
drawer.valid_app(tree(group), 30)
def test_store_rejects_multi_app_parent(self):
group = {"id": 30, "type": "floating_con", "nodes": [app(31), app(32)],
"floating_nodes": []}
with self.assertRaises(drawer.DrawerError):
drawer.valid_app(tree(group), 31)
def test_repeated_show_only_focuses_and_repeated_hide_sends_nothing(self):
displayed = tree(app(20, state="fresh"))
hidden = app(20, state="fresh")
hidden["hidden"] = True
hidden_tree = tree(hidden)
workspaces = [{"name": 'Travail ; "A"', "output": "DP-2", "visible": True}]
def answer(kind, current):
return current if kind == "get_tree" else workspaces
with patch.object(drawer, "sway", side_effect=lambda kind: answer(kind, displayed)), \
patch.object(drawer, "safe_command") as sent:
self.assertTrue(drawer.operate("show", 20, "DP-2")["shown"])
sent.assert_called_once_with("[con_id=20] focus")
with patch.object(drawer, "sway", side_effect=lambda kind: answer(kind, hidden_tree)), \
patch.object(drawer, "safe_command") as sent:
self.assertFalse(drawer.operate("hide", 20, "DP-2")["shown"])
sent.assert_not_called()
def test_rejected_command_does_not_report_success(self):
with patch.object(drawer, "sway", return_value=tree(app(20))), \
patch.object(drawer, "safe_command", side_effect=drawer.DrawerError("refusée")):
with self.assertRaisesRegex(drawer.DrawerError, "refusée"):
drawer.operate("store", 20, "DP-2")
if __name__ == "__main__":
unittest.main()