"""Smoke tests for the foreground tracker. The OS-specific probe code is hard to mock end-to-end inside a CI container, so these tests focus on the platform-agnostic surface: the dataclass shape, TTL caching, and graceful fallback when the platform probe raises. The Windows/Linux/macOS probes themselves are exercised through manual runs. """ from __future__ import annotations from media_server.services import foreground_service as fg def setup_function(_): fg.reset_cache() def test_unavailable_default_shape(): info = fg.ForegroundInfo(available=False) d = info.to_dict() assert d["available"] is False assert d["pid"] is None assert d["process_name"] is None assert d["is_fullscreen"] is False assert "platform" in d def test_cache_returns_same_instance(monkeypatch): calls = {"n": 0} def fake_probe(): calls["n"] += 1 return fg.ForegroundInfo(available=True, pid=42, process_name="x.exe") monkeypatch.setattr(fg, "_probe", fake_probe) a = fg.get_foreground_info() b = fg.get_foreground_info() assert a is b assert calls["n"] == 1 def test_cache_force_refresh(monkeypatch): calls = {"n": 0} def fake_probe(): calls["n"] += 1 return fg.ForegroundInfo(available=True, pid=calls["n"]) monkeypatch.setattr(fg, "_probe", fake_probe) fg.get_foreground_info() fg.get_foreground_info(force_refresh=True) assert calls["n"] == 2 def test_cache_ttl_expiry(monkeypatch): calls = {"n": 0} def fake_probe(): calls["n"] += 1 return fg.ForegroundInfo(available=True, pid=calls["n"]) monkeypatch.setattr(fg, "_probe", fake_probe) monkeypatch.setattr(fg, "_CACHE_TTL", 0.0) # Re-bind the cache's TTL by exercising it twice with TTL 0. fg.get_foreground_info() fg.get_foreground_info() assert calls["n"] == 2 def test_probe_crash_returns_unavailable(monkeypatch): def boom(): raise RuntimeError("kaboom") # Force every platform branch to call our crashing probe. monkeypatch.setattr(fg, "_probe_windows", boom) monkeypatch.setattr(fg, "_probe_linux", boom) monkeypatch.setattr(fg, "_probe_macos", boom) info = fg._probe() assert info.available is False assert info.error and "kaboom" in info.error