test_merge_daily_noms_nettoyes.py
Rama main · réplica de lectura del repositorio original.
"""Backlog « journalières sans distinction si deux caméras se nettoient pareil » :
« Garage » et « Garage! » donnent le même dossier par safe_name, et leurs
journalières s'écrivaient au même chemin, l'une écrasant l'autre. Elles
reçoivent maintenant des clés distinctes, comme les homonymes de deux réseaux
(test_merge_daily_homonymes.py), sans toucher aux caméras qui n'entrent pas en
collision."""
from __future__ import annotations
import json
import tempfile
import unittest
from pathlib import Path
try:
from zoneinfo import ZoneInfo
except ImportError: # Python 3.8, édition Windows 7
from backports.zoneinfo import ZoneInfo
import merge_daily
from test_merge_daily_homonymes import mp4_structurel
class NomsQuiSeNettoientPareil(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.input_dir = Path(self.tmp.name)
self.tz = ZoneInfo("Europe/Paris")
def _registre(self, cameras, reseau=""):
clips = {}
for numero, camera in enumerate(cameras):
chemin = f"c{numero}.mp4"
(self.input_dir / chemin).write_bytes(mp4_structurel())
clips[f"k{numero}"] = {
"camera": camera, "network_id": reseau, "device_id": "",
"created_at": f"2026-09-01T1{numero}:00:00+00:00", "path": chemin,
}
(self.input_dir / merge_daily.DOWNLOAD_STATE).write_text(
json.dumps({"version": 2, "clips": clips}), encoding="utf-8")
def _cles(self):
groupes = merge_daily.load_groups(self.input_dir, self.tz)
return {camera for camera, _ in groupes}
def _dossiers_distincts(self, cles):
self.assertEqual(len({merge_daily.safe_name(c).casefold() for c in cles}), len(cles), cles)
def test_garage_et_garage_point_d_exclamation_ne_partagent_plus_un_dossier(self):
self._registre(["Garage", "Garage!"])
cles = self._cles()
self.assertEqual(len(cles), 2)
self._dossiers_distincts(cles)
# Le nom déjà propre garde son dossier : l'historique déjà assemblé reste.
self.assertIn("Garage", cles)
def test_le_choix_ne_depend_pas_de_l_ordre_du_registre(self):
self._registre(["Garage!", "Garage"])
premiere = self._cles()
self._registre(["Garage", "Garage!"])
self.assertEqual(premiere, self._cles())
def test_trois_noms_qui_se_nettoient_pareil(self):
self._registre(["Garage", "Garage!", "Garage?"])
cles = self._cles()
self.assertEqual(len(cles), 3)
self._dossiers_distincts(cles)
self.assertIn("Garage", cles)
def test_la_casse_seule_distingue_deux_dossiers(self):
# Windows et macOS confondent « Salon » et « salon » : même dossier.
self._registre(["Salon", "salon"])
cles = self._cles()
self.assertEqual(len(cles), 2)
self._dossiers_distincts(cles)
def test_un_suffixe_qui_existe_deja_n_est_pas_reutilise(self):
self._registre(["Garage", "Garage!", "Garage! (2)"])
cles = self._cles()
self.assertEqual(len(cles), 3)
self._dossiers_distincts(cles)
def test_noms_sans_collision_inchanges(self):
self._registre(["Salon", "jardin", "Bureau", "Portail", "Terrasse1"])
self.assertEqual(self._cles(), {"Salon", "jardin", "Bureau", "Portail", "Terrasse1"})
def test_meme_nom_a_espace_final_reste_une_seule_camera(self):
# La forme réelle de production : « jardin » et « jardin » + espace.
self._registre(["jardin", "jardin "])
self.assertEqual(self._cles(), {"jardin"})
def test_deux_reseaux_et_un_nom_voisin_restent_distincts(self):
entrees = {
"a": {"camera": "jardin", "network_id": "1", "created_at": "2026-09-01T10:00:00+00:00"},
"b": {"camera": "jardin", "network_id": "2", "created_at": "2026-09-01T11:00:00+00:00"},
"c": {"camera": "jardin!", "network_id": "1", "created_at": "2026-09-01T12:00:00+00:00"},
}
cles = merge_daily._cles_camera_par_collision(entrees)
finales = {merge_daily._camera_key(cles, e, e["camera"]) for e in entrees.values()}
self.assertEqual(len(finales), 3, finales)
self._dossiers_distincts(finales)
def test_les_clips_se_repartissent_entre_les_deux_cles(self):
self._registre(["Garage", "Garage!"])
groupes = merge_daily.load_groups(self.input_dir, self.tz)
self.assertEqual(sorted(len(v) for v in groupes.values()), [1, 1])
def test_les_journees_indisponibles_utilisent_les_memes_cles(self):
self._registre(["Garage", "Garage!"])
(self.input_dir / "c0.mp4").unlink()
(self.input_dir / "c1.mp4").unlink()
jours, _ = merge_daily.journees_a_source_indisponible(self.input_dir, self.tz)
cles_groupes = self._cles()
self.assertEqual({camera for camera, _ in jours}, cles_groupes)
if __name__ == "__main__":
unittest.main()