Files
anonymisation/tests/unit/test_gui_v6_result_hint.py
2026-06-29 19:15:28 +02:00

119 lines
3.8 KiB
Python

"""Message d'aide localisant les documents non livrés (P1-5) + ouverture dossier.
Pur : pas de display. ``failure_hint`` formate un texte ; ``open_in_file_manager``
dispatch vers la bonne commande OS (monkeypatchée).
"""
from __future__ import annotations
from pathlib import Path
import pytest
import gui_v6.fsutil as fsutil
from gui_v6.processing_runner import RunSummary
from gui_v6.tabs.tab_usage import failure_hint
def test_no_hint_when_all_ok():
s = RunSummary(total=3, succeeded=3, failed=0)
assert failure_hint(s, Path("/out")) is None
def test_hint_when_failures_mentions_output_dir():
s = RunSummary(total=3, succeeded=2, failed=1)
hint = failure_hint(s, Path("/out/anonymise"))
assert hint is not None
assert "/out/anonymise" in hint
# Honnêteté : préciser que les échecs ne sont PAS anonymisés.
assert "pas" in hint.lower()
def test_hint_when_stopped():
s = RunSummary(total=3, succeeded=1, failed=0, stopped=True)
assert failure_hint(s, Path("/out")) is not None
def test_no_hint_without_output_dir():
s = RunSummary(total=1, succeeded=0, failed=1)
assert failure_hint(s, None) is None
def test_open_in_file_manager_dispatches(monkeypatch):
calls = {}
monkeypatch.setattr(fsutil.sys, "platform", "linux")
monkeypatch.setattr(fsutil.subprocess, "Popen", lambda args, **k: calls.setdefault("args", args))
fsutil.open_in_file_manager(Path("/out"))
assert calls["args"][0] == "xdg-open"
assert calls["args"][1] == "/out"
def test_no_claim_written_when_zero_succeeded():
"""0 succès : ne pas prétendre qu'un dossier contient des documents écrits."""
s = RunSummary(total=2, succeeded=0, failed=2)
hint = failure_hint(s, Path("/out"))
assert hint is not None
assert "écrits dans" not in hint
assert "Aucun document" in hint
def test_hint_with_path_when_some_succeeded():
"""≥1 succès : localiser le dossier de sortie effectif."""
s = RunSummary(total=3, succeeded=2, failed=1)
hint = failure_hint(s, Path("/out"))
assert hint is not None
assert "/out" in hint
assert "écrits dans" in hint
# -- garde anti-régression du bug Critical (empilement de widgets) -----------
@pytest.fixture
def usage_tab():
"""``UsageTab`` headless (Xvfb) — skip propre si pas de display."""
pytest.importorskip("customtkinter")
try:
import customtkinter as ctk
from gui_v6.tabs.tab_usage import UsageTab
root = ctk.CTk()
root.withdraw()
tab = UsageTab(root)
except Exception as exc: # pas de display Tk
pytest.skip(f"display Tk indisponible: {exc}")
try:
yield tab
finally:
try:
root.destroy()
except Exception:
pass
def test_show_failure_hint_does_not_accumulate(usage_tab):
"""Bug Critical : deux runs en échec ne doivent pas empiler de hints sous
``_rsec`` (handle ``_hint_row`` détruit inconditionnellement)."""
usage_tab._last_output_dir = Path("/out")
summary = RunSummary(total=3, succeeded=2, failed=1)
usage_tab._show_failure_hint(summary)
count_after_first = len(usage_tab._rsec.winfo_children())
usage_tab._show_failure_hint(summary)
count_after_second = len(usage_tab._rsec.winfo_children())
assert count_after_second == count_after_first
def test_show_failure_hint_clears_stale_hint(usage_tab):
"""Un run en échec suivi d'un run nominal ne doit pas laisser de hint périmé."""
usage_tab._last_output_dir = Path("/out")
usage_tab._show_failure_hint(RunSummary(total=3, succeeded=2, failed=1))
with_hint = len(usage_tab._rsec.winfo_children())
usage_tab._show_failure_hint(RunSummary(total=3, succeeded=3, failed=0))
without_hint = len(usage_tab._rsec.winfo_children())
assert without_hint == with_hint - 1