Le formateur de ce dépôt est ruff depuis qu'il remplace black, qui ne connaît aucune cible au-delà de py313 ; ce passage applique sa norme à l'arbre entier, d'un coup, pour qu'aucun commit de fond n'ait à porter du style. L'écart tient presque entièrement aux chaînes coupées à la main que ruff recolle quand elles tiennent sur une ligne, et aux « with » multiples qu'il regroupe : aucune valeur ne change, et les clés de traduction non plus. Vérifié : la suite unitaire reste verte après le passage, et le contrôle de syntaxe ne signale rien. --- EN --- This repository's formatter is ruff since it replaced black, which knows no target beyond py313; this pass applies its standard to the whole tree at once, so that no substantive commit has to carry style. The difference is almost entirely the hand-split strings ruff joins back when they fit on one line, and the multiple "with" it merges: no value changes, nor do the translation keys. Checked: the unit suite stays green after the pass, and the syntax check reports nothing. Assisted-by: Claude Opus 5
106 lines
4.2 KiB
Python
106 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
"""La langue du binaire du cache, vue du menu.
|
|
|
|
Le binaire traduit ses messages humains selon --lang. Le menu doit donc dire
|
|
laquelle il veut, et la bonne : la langue de todo.py pour ce qu'il AFFICHE,
|
|
le français pour ce qu'il LIT — il ne connaît les libellés que dans cette
|
|
langue. Et ce qu'il lit dans un journal écrit par le service, dont la langue
|
|
est fixée à l'installation, il doit le reconnaître dans les deux.
|
|
"""
|
|
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
RACINE = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(RACINE))
|
|
|
|
from script.todo import qemu_cache_menu as menu # noqa: E402
|
|
|
|
CATALOGUE = RACINE / "script" / "qemu_cache" / "catalogue_en.go"
|
|
|
|
|
|
class TestLOptionDeLangue(unittest.TestCase):
|
|
def test_une_sortie_lue_est_demandee_en_francais(self):
|
|
with mock.patch.object(menu, "get_lang", return_value="en"):
|
|
self.assertEqual(menu.option_langue(lue=True), "--lang fr")
|
|
|
|
def test_une_sortie_affichee_suit_la_langue_de_todo(self):
|
|
for langue in ("fr", "en"):
|
|
with mock.patch.object(menu, "get_lang", return_value=langue):
|
|
self.assertEqual(menu.option_langue(), f"--lang {langue}")
|
|
|
|
def test_le_pre_remplissage_parle_la_langue_de_todo(self):
|
|
"""Lancé par sudo -u : EL_LANG n'y arriverait pas, l'option si."""
|
|
with mock.patch.object(menu, "get_lang", return_value="en"):
|
|
cmd = menu.miroir_prefetch_cmd("/tmp/liste", [])
|
|
self.assertIn("--lang en", cmd)
|
|
|
|
def test_le_retrait_d_exception_garde_nft_en_bout_de_tube(self):
|
|
"""Le message humain va à l'erreur standard ; la sortie standard
|
|
porte les règles que nft lit, et ne se traduit jamais."""
|
|
with mock.patch.object(menu, "get_lang", return_value="en"):
|
|
cmd = menu.bypass_retrait_cmd("52:54:00:00:00:04")
|
|
self.assertIn("--lang en", cmd)
|
|
self.assertTrue(cmd.endswith("| sudo nft -f -"))
|
|
|
|
|
|
class TestCeQueLeMenuLit(unittest.TestCase):
|
|
def test_l_occupation_du_miroir_est_lue_en_francais(self):
|
|
vu = {}
|
|
|
|
def faux_lire(cmd, delai=15):
|
|
vu["cmd"] = cmd
|
|
return "objets : 3\ndépôts git : 12 en miroir, 4.2 Gio\n"
|
|
|
|
with (
|
|
mock.patch.object(
|
|
menu.QemuCacheMenuMixin, "_cache_lire", staticmethod(faux_lire)
|
|
),
|
|
mock.patch.object(menu, "get_lang", return_value="en"),
|
|
):
|
|
rendu = menu.QemuCacheMenuMixin._cache_miroir_occupation()
|
|
self.assertIn("--lang fr", vu["cmd"])
|
|
self.assertEqual(rendu, ("12", "4.2 Gio"))
|
|
|
|
def test_le_journal_est_lu_dans_les_deux_langues(self):
|
|
"""La langue du service est celle de son installation, pas celle de
|
|
qui ouvre le menu : un refus appris doit être reconnu dans les deux."""
|
|
journal = (
|
|
"tunnel opaque retenu pour npm.example (3 échec(s)) : EOF\n"
|
|
"opaque tunnel kept for pypi.example (3 failure(s)): EOF\n"
|
|
)
|
|
commandes = []
|
|
|
|
def faux_lire(cmd, delai=15):
|
|
commandes.append(cmd)
|
|
return journal
|
|
|
|
with mock.patch.object(
|
|
menu.QemuCacheMenuMixin, "_cache_lire", staticmethod(faux_lire)
|
|
):
|
|
hotes = menu.QemuCacheMenuMixin._cache_refus_appris()
|
|
self.assertEqual(hotes, ["npm.example", "pypi.example"])
|
|
for motif in menu.REFUS_APPRIS:
|
|
self.assertIn(motif, commandes[0])
|
|
|
|
def test_le_catalogue_porte_ce_que_le_menu_lit(self):
|
|
"""Une traduction qui s'écarte de ces libellés rendrait le menu
|
|
aveugle sans qu'aucun test du binaire ne le voie."""
|
|
texte = CATALOGUE.read_text(encoding="utf-8")
|
|
self.assertIn('"opaque tunnel kept for %s (', texte)
|
|
for libelle in ("authority : %s", "fingerprint : %s"):
|
|
self.assertIn(f'"{libelle}', texte)
|
|
for prefixe in menu.LIBELLES_TUS:
|
|
self.assertTrue(
|
|
prefixe in texte or prefixe in ("autorité", "empreinte"),
|
|
prefixe,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|