Module isolé qui choisit l'écran cible avec stratégie en cascade : 1. action.monitor_index (session source) → cible explicite 2. session.last_focused_monitor → fallback focus actif 3. composite (offset 0,0) → backward compat (comportement actuel) Backward 100% : actions sans monitor_index → fallback composite identique au comportement mss.monitors[0] actuel. Tests : 4 cas (cible OK, fallback focus, fallback composite, index invalide). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
# tests/unit/test_monitor_router.py
|
|
"""Tests unitaires pour MonitorRouter (QW1)."""
|
|
import pytest
|
|
|
|
from agent_v0.server_v1.monitor_router import resolve_target_monitor, MonitorTarget
|
|
|
|
|
|
# Geometry de référence pour les 3 tests : 2 écrans côte à côte
|
|
TWO_MONITORS = [
|
|
{"idx": 0, "x": 0, "y": 0, "w": 1920, "h": 1080, "primary": True},
|
|
{"idx": 1, "x": 1920, "y": 0, "w": 1920, "h": 1080, "primary": False},
|
|
]
|
|
|
|
|
|
def test_resolve_uses_action_monitor_index_when_present():
|
|
"""Si action.monitor_index présent et valide → cible cet écran."""
|
|
action = {"monitor_index": 1}
|
|
session_state = {"monitors_geometry": TWO_MONITORS, "last_focused_monitor": 0}
|
|
result = resolve_target_monitor(action, session_state)
|
|
assert result.idx == 1
|
|
assert result.offset_x == 1920
|
|
assert result.offset_y == 0
|
|
assert result.source == "action"
|
|
|
|
|
|
def test_resolve_falls_back_to_focused_monitor_when_action_missing():
|
|
"""Si action.monitor_index absent → fallback focus actif."""
|
|
action = {} # pas de monitor_index
|
|
session_state = {"monitors_geometry": TWO_MONITORS, "last_focused_monitor": 1}
|
|
result = resolve_target_monitor(action, session_state)
|
|
assert result.idx == 1
|
|
assert result.source == "focus"
|
|
|
|
|
|
def test_resolve_falls_back_to_composite_when_geometry_empty():
|
|
"""Si geometry vide (vieux Agent V1) → fallback composite (idx=-1, offset=0)."""
|
|
action = {}
|
|
session_state = {"monitors_geometry": [], "last_focused_monitor": None}
|
|
result = resolve_target_monitor(action, session_state)
|
|
assert result.source == "composite_fallback"
|
|
assert result.offset_x == 0
|
|
assert result.offset_y == 0
|
|
|
|
|
|
def test_resolve_falls_back_when_action_index_out_of_range():
|
|
"""Si action.monitor_index hors limites (écran débranché) → fallback focus."""
|
|
action = {"monitor_index": 5} # n'existe pas
|
|
session_state = {"monitors_geometry": TWO_MONITORS, "last_focused_monitor": 0}
|
|
result = resolve_target_monitor(action, session_state)
|
|
assert result.idx == 0
|
|
assert result.source == "focus"
|