mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 13:22:19 +01:00
feat(e2e): sync the neutral core from kfde bf5da0e6
This commit is contained in:
1 parent
7c59f3e2c6
commit
8a8674ac9b
5 files changed
+131
-1
No files matched your search
@@ -10,7 +10,7 @@ and takes the shape both platforms can give.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Protocol
|
||||
from typing import Any, Protocol
|
||||
|
||||
from PIL import Image
|
||||
|
||||
@@ -93,6 +93,14 @@ class Platform(Protocol):
|
||||
"""Starts the daemon from a clean state and waits until it answers."""
|
||||
...
|
||||
|
||||
def restart_with(self, config: dict[str, Any]) -> None:
|
||||
"""Stops the daemon if it runs, and starts it from a clean state with `config` as its
|
||||
`komorebi.json`, and waits until it answers.
|
||||
|
||||
Windows that are open stay open, and the new daemon takes up the ones that are in view.
|
||||
"""
|
||||
...
|
||||
|
||||
def komorebic(self, *args: str) -> str:
|
||||
"""Runs `komorebic` with `args` and returns what it printed. Fails if it does."""
|
||||
...
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Where in the layout a window that opens goes, as the placement rules of the config say."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from komorebi_vm.core.checks import Checks
|
||||
from komorebi_vm.core.platform import Client, Platform
|
||||
|
||||
CASES: list[tuple[str, Any, list[str], list[str]]] = [
|
||||
# (what it says, the placement rules, the titles in the order they open, the order they end in)
|
||||
("no rules: after the one in focus", None, ["a", "b", "c"], ["a", "b", "c"]),
|
||||
("every window to the primary tile", "Primary", ["a", "b", "c"], ["c", "b", "a"]),
|
||||
("by the number of the place, counted from 1", 2, ["a", "b", "c"], ["a", "c", "b"]),
|
||||
("text that is a number is the same place", "2", ["a", "b", "c"], ["a", "c", "b"]),
|
||||
(
|
||||
"by the title: first, last, and after the one in focus",
|
||||
{
|
||||
"Primary": {"kind": "Title", "id": "special", "matching_strategy": "Equals"},
|
||||
"Last": [{"kind": "Title", "id": "chat", "matching_strategy": "Contains"}],
|
||||
},
|
||||
["one", "two", "special", "a chat room", "four"],
|
||||
["special", "one", "two", "a chat room", "four"],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _config(rules: Any) -> dict[str, Any]:
|
||||
workspace: dict[str, Any] = {"name": "a", "layout": "BSP"}
|
||||
if rules is not None:
|
||||
workspace["initial_window_placement_rules"] = rules
|
||||
return {
|
||||
"default_workspace_padding": 10,
|
||||
"default_container_padding": 10,
|
||||
"monitors": [{"workspaces": [workspace]}],
|
||||
}
|
||||
|
||||
|
||||
def _order(platform: Platform) -> list[str]:
|
||||
return [titles[0] for titles in platform.state().containers()]
|
||||
|
||||
|
||||
def _settled(platform: Platform, title: str, count: int) -> None:
|
||||
"""Waits until `count` windows are managed and the last one to open has the focus."""
|
||||
platform.wait_for(lambda: platform.state().managed() == count, timeout=20)
|
||||
platform.wait_for(lambda: platform.state().focused_title() == title, timeout=20)
|
||||
|
||||
|
||||
def run(platform: Platform, checks: Checks) -> None:
|
||||
"""Starts the daemon with each case's rules, opens its windows one after the other, and checks
|
||||
the order they are in.
|
||||
|
||||
Nothing else may be open: the daemon takes up every window in view, and the order would
|
||||
count it. The windows of a case are closed before the next one. A window is opened only after
|
||||
the one before is managed and has the focus, because "after the one in focus" depends on it.
|
||||
"""
|
||||
for description, rules, titles, want in CASES:
|
||||
platform.restart_with(_config(rules))
|
||||
clients: list[Client] = []
|
||||
for title in titles:
|
||||
clients.append(platform.spawn(title))
|
||||
_settled(platform, title, len(clients))
|
||||
got = _order(platform)
|
||||
checks.check(f"{description}: {', '.join(want)} ({got})", got == want)
|
||||
for client in clients:
|
||||
platform.close(client)
|
||||
platform.wait_for(lambda: platform.state().managed() == 0, timeout=20)
|
||||
@@ -17,6 +17,11 @@ from komorebi_vm.core.snapshot import Snapshot, parse
|
||||
TILES = [Rect(0, 0, 640, 1080), Rect(640, 0, 640, 1080), Rect(1280, 0, 640, 1080)]
|
||||
|
||||
|
||||
def _place_index(place: str, count: int) -> int:
|
||||
"""The index a placement rule's place stands for: `Primary`, `Last`, or a number from 1."""
|
||||
return int(place) - 1 if place.isdigit() else {"Primary": 0, "Last": count}[place]
|
||||
|
||||
|
||||
class FakePointer:
|
||||
"""A pointer that, dragged from just outside the right edge of a tile, moves that edge."""
|
||||
|
||||
@@ -62,11 +67,13 @@ class FakePlatform:
|
||||
self.initial_rules: dict[str, int] = {}
|
||||
self.rules: dict[str, int] = {}
|
||||
self.ignored: set[str] = set()
|
||||
self.placing = False
|
||||
self.unmanaged: list[str] = []
|
||||
self.display_count = 2
|
||||
self.display_of: dict[str, int] = {}
|
||||
self.forgets_displays = False
|
||||
self.running = True
|
||||
self.placement: Any = None
|
||||
self.moves = moves
|
||||
self.focus_follows_move = focus_follows_move
|
||||
|
||||
@@ -126,12 +133,38 @@ class FakePlatform:
|
||||
self.spaces[self.initial_rules.pop(title)].append([title])
|
||||
elif title in self.rules:
|
||||
self.spaces[self.rules[title]].append([title])
|
||||
elif self.placing:
|
||||
self._place(title)
|
||||
else:
|
||||
self.containers.append([title])
|
||||
if len(self.containers) > len(self.tiles):
|
||||
self._relayout()
|
||||
return Client(title)
|
||||
|
||||
def _place(self, title: str) -> None:
|
||||
"""A window goes where the placement rules say, or after the one in focus, and has the
|
||||
focus."""
|
||||
n = len(self.containers)
|
||||
index = min(self.focus + 1, n) if n else 0
|
||||
rules = self.placement
|
||||
if isinstance(rules, dict):
|
||||
for place, matches in rules.items():
|
||||
for match in matches if isinstance(matches, list) else [matches]:
|
||||
equals = match["matching_strategy"] == "Equals"
|
||||
if (title == match["id"]) if equals else (match["id"] in title):
|
||||
index = _place_index(place, n)
|
||||
elif rules is not None:
|
||||
index = 0 if rules == "Primary" else int(rules) - 1
|
||||
index = max(0, min(index, n))
|
||||
self.containers.insert(index, [title])
|
||||
self.focus = index
|
||||
|
||||
def restart_with(self, config: dict[str, Any]) -> None:
|
||||
self.start_komorebi()
|
||||
workspace = config["monitors"][0]["workspaces"][0]
|
||||
self.placement = workspace.get("initial_window_placement_rules")
|
||||
self.placing = True
|
||||
|
||||
def _find(self, title: str) -> tuple[int, int]:
|
||||
for s, containers in enumerate(self.spaces):
|
||||
for i, stack in enumerate(containers):
|
||||
|
||||
@@ -9,6 +9,7 @@ from komorebi_vm.core.scenarios import (
|
||||
lifecycle,
|
||||
monocle,
|
||||
moving,
|
||||
placement,
|
||||
resize,
|
||||
rules,
|
||||
stacks,
|
||||
@@ -279,3 +280,23 @@ def test_a_known_failure_does_not_fail_the_suite_until_it_is_fixed() -> None:
|
||||
clients = opened(fixed, checks)
|
||||
commands.unknown_monitor(fixed, checks, clients, known_failure=reason)
|
||||
assert checks.failed == 2 and checks.known == []
|
||||
|
||||
|
||||
def test_a_daemon_that_follows_the_placement_rules_passes() -> None:
|
||||
platform = FakePlatform()
|
||||
checks = Checks()
|
||||
placement.run(platform, checks)
|
||||
assert checks.failed == 0, checks.failures
|
||||
assert checks.passed == len(placement.CASES)
|
||||
|
||||
|
||||
def test_a_daemon_that_ignores_the_placement_rules_fails() -> None:
|
||||
class Ignores(FakePlatform):
|
||||
def restart_with(self, config: dict) -> None:
|
||||
super().restart_with(config)
|
||||
self.placement = None
|
||||
|
||||
platform = Ignores()
|
||||
checks = Checks()
|
||||
placement.run(platform, checks)
|
||||
assert checks.failed == len(placement.CASES) - 1, checks.failures
|
||||
@@ -63,6 +63,9 @@ class FakePlatform:
|
||||
def start_komorebi(self) -> None:
|
||||
pass
|
||||
|
||||
def restart_with(self, config: dict) -> None:
|
||||
pass
|
||||
|
||||
def komorebic(self, *args: str) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
Reference in new issue
Block a user