feat(nix): the manage_rules and state_fidelity scenarios

This commit is contained in:
LGUG2Z committed 2026-10-30 12:29:02 -07:00
1 parent ac3a9853a7
commit 6748528b90
5 files changed
+184 -5

No files matched your search

@@ -0,0 +1,73 @@
"""A manage rule has a window managed that an ignore rule leaves alone, by title, class and exe."""
from typing import Any
from komorebi_vm.core.checks import Checks
from komorebi_vm.core.platform import Client, Platform
# how long a window has to stay unmanaged for it to be left alone
QUIET = 3
def _kinds(platform: Platform) -> list[tuple[str, str, dict[str, Any]]]:
"""For each kind of rule: its name, the id of the rule, and what the window is opened with."""
return [
("title", "e2e-manage-title", {}),
("class", "e2e-manage-class", {"app_id": "e2e-manage-class"}),
("exe", platform.exe_id("e2e-manage-exe"), {"exe": "e2e-manage-exe"}),
]
def run(platform: Platform, checks: Checks) -> None:
"""For each kind of rule, an ignore rule leaves a window alone and a manage rule for the same
application then has the next one managed and tiled.
A window the daemon leaves alone does not make room for itself: the window that is tiled keeps
its frame. The daemon must be running, with no window, and the rules are for names no other
scenario uses, because `ignore-rule` drops a rule whose id an earlier rule has.
"""
base = platform.spawn("manage-base")
platform.wait_for(lambda: platform.state().workspace_of(base.title) == 0, timeout=20)
for kind, rule_id, how in _kinds(platform):
title = rule_id if kind == "title" else f"manage-{kind}"
platform.komorebic("ignore-rule", kind, rule_id)
before = platform.os_window(base)
ignored = platform.spawn(f"{title} ignored", **how)
checks.check(
f"a window an ignore rule by {kind} matches is not managed",
not platform.wait_for(
lambda c=ignored: platform.state().workspace_of(c.title) is not None,
timeout=QUIET,
),
)
after = platform.os_window(base)
checks.check(
f"... and the window that is tiled keeps its place ({kind})",
before is not None and after is not None and before.frame == after.frame,
)
platform.close(ignored)
platform.wait_for(lambda c=ignored: platform.os_window(c) is None, timeout=20)
platform.komorebic("manage-rule", kind, rule_id)
managed: Client = platform.spawn(f"{title} managed", **how)
checks.check(
f"with a manage rule by {kind} too, a window it matches is managed",
platform.wait_for(
lambda c=managed: platform.state().workspace_of(c.title) == 0, timeout=20
),
)
checks.check(
f"... and tiled: {base.title} gives it room ({kind})",
platform.wait_for(
lambda b=before: (
(a := platform.os_window(base)) is not None
and b is not None
and a.frame != b.frame
),
timeout=20,
),
)
platform.close(managed)
platform.wait_for(lambda c=managed: platform.state().workspace_of(c.title) is None)
platform.close(base)
platform.wait_for(lambda: platform.state().managed() == 0, timeout=20)
@@ -0,0 +1,48 @@
"""The daemon's state names each window as it was opened: its title, its program and its class."""
from komorebi_vm.core.checks import Checks
from komorebi_vm.core.platform import Platform
def _window(platform: Platform, title: str): # noqa: ANN202
for workspace in platform.state().workspace().windows():
if workspace.title == title:
return workspace
return None
def run(platform: Platform, checks: Checks) -> None:
"""Opens a window with only a title, one with a class, and one made by a program of its own,
and checks what the state says of each: the title as given, the class that was set, and the
program (through `exe_id`, which is its file name on the platform).
The rules scenarios check that a rule finds a window by these; this checks that what the state
shows of a window is what the window was given. The daemon must be running, with no window.
"""
plain = platform.spawn("fidelity plain")
classed = platform.spawn("fidelity class", app_id="e2e-fidelity-class")
made = platform.spawn("fidelity exe", exe="e2e-fidelity-exe")
platform.wait_for(lambda: platform.state().managed() == 3, timeout=30)
found = _window(platform, plain.title)
checks.check("the state has the title of a window as it was opened", found is not None)
checks.check(
"... and says what program opened it",
found is not None and found.exe != "",
)
found = _window(platform, classed.title)
checks.check(
"the state has the class a window was given",
found is not None and found.window_class == "e2e-fidelity-class",
)
found = _window(platform, made.title)
checks.check(
"the state has the program that opened a window, as its file name",
found is not None and found.exe == platform.exe_id("e2e-fidelity-exe"),
)
for client in (plain, classed, made):
platform.close(client)
checks.check(
"the three windows are closed",
platform.wait_for(lambda: platform.state().managed() == 0, timeout=20),
)
+5 -2
View File
@@ -93,9 +93,12 @@ class KdePlatform:
program = "foot"
if exe:
# the daemon reads the executable from /proc, where a link shows its target: a copy
# of the terminal is what has the name
# of the terminal is what has the name, made once: a copy that is running cannot be
# written over
program = f"{BIN}/{exe}"
self.kde.sh(f"mkdir -p {BIN} && cp -L $(command -v foot) {program}")
self.kde.sh(
f"mkdir -p {BIN} && {{ test -x {program} || cp -L $(command -v foot) {program}; }}"
)
self.kde.spawn(f"{program} {name}-T {shlex.quote(title)} sleep 3000")
self.kde.wait_for(lambda: self.kde.wid(title) != "", timeout=30)
return Client(title)
+17 -3
View File
@@ -87,6 +87,8 @@ class FakePlatform:
self.exe_rules: dict[str, int] = {}
self.ignored_exes: set[str] = set()
self.exes: dict[str, str] = {}
self.classes: dict[str, str] = {}
self.manage: set[tuple[str, str]] = set()
self.names: list[str | None] = [None, None, None]
self.layout_name = "Columns"
self.reloads = reloads
@@ -171,7 +173,17 @@ class FakePlatform:
return [stack[0] for stack in self.containers]
def spawn(self, title: str, app_id: str | None = None, exe: str | None = None) -> Client:
self.exes[title] = exe or ""
self.exes[title] = exe or "foot"
self.classes[title] = app_id or ""
forced = (
("exe", exe) in self.manage
or ("class", app_id) in self.manage
or any(kind == "title" and title.startswith(i) for kind, i in self.manage)
)
if forced:
self.containers.append([title])
self._relayout()
return Client(title)
if exe in self.ignored_exes:
self.unmanaged.append(title)
return Client(title)
@@ -187,7 +199,7 @@ class FakePlatform:
if self.paused:
self.unmanaged.append(title)
return Client(title)
if title in self.ignored:
if any(title.startswith(i) for i in self.ignored):
self.unmanaged.append(title)
elif title in self.initial_rules:
self.spaces[self.initial_rules.pop(title)].append([title])
@@ -451,6 +463,8 @@ class FakePlatform:
self.ignored_classes.add(name)
case ("ignore-rule", "title", title):
self.ignored.add(title)
case ("manage-rule", kind, name):
self.manage.add((kind, name))
case ("move-to-workspace", number):
self.komorebic("send-to-workspace", number)
self.last, self.current = self.current, int(number)
@@ -528,7 +542,7 @@ class FakePlatform:
"details": {
"title": title,
"exe": self.exes.get(title, ""),
"class": "",
"class": self.classes.get(title, ""),
"path": "",
},
}
@@ -16,6 +16,7 @@ from komorebi_vm.core.scenarios import (
lifecycle,
lifecycle_hidden,
locking,
manage_rules,
maximizing,
minimizing,
monocle,
@@ -32,6 +33,7 @@ from komorebi_vm.core.scenarios import (
scrolling,
stacks,
startup_rules,
state_fidelity,
tiling,
tiling_off,
workspace_moves,
@@ -507,6 +509,45 @@ def test_a_daemon_that_does_not_tile_again_on_unlock_fails_locking() -> None:
assert checks.failed > 0
def test_a_daemon_that_is_right_passes_manage_rules() -> None:
platform = FakePlatform()
checks = Checks()
manage_rules.run(platform, checks)
assert checks.failed == 0, checks.failures
assert checks.passed > 8
def test_a_daemon_that_ignores_manage_rules_fails_manage_rules() -> None:
class Deaf(FakePlatform):
def komorebic(self, *args: str) -> str:
return "" if args[0] == "manage-rule" else super().komorebic(*args)
platform = Deaf()
checks = Checks()
manage_rules.run(platform, checks)
assert checks.failed > 0
def test_a_daemon_that_shows_what_a_window_was_given_passes_state_fidelity() -> None:
platform = FakePlatform()
checks = Checks()
state_fidelity.run(platform, checks)
assert checks.failed == 0, checks.failures
assert checks.passed > 4
def test_a_daemon_that_loses_the_class_fails_state_fidelity() -> None:
class Forgetful(FakePlatform):
def spawn(self, title, app_id=None, exe=None): # noqa: ANN001, ANN202
client = super().spawn(title, app_id=None, exe=exe)
return client
platform = Forgetful()
checks = Checks()
state_fidelity.run(platform, checks)
assert checks.failed > 0
def test_a_command_the_port_lacks_is_skipped_by_name() -> None:
platform = FakePlatform()
checks = Checks()