test_merge_daily_periodes_independantes.py
Rama main · réplica de lectura del repositorio original.
"""Non-régression de --no-weekly / --no-monthly (AUDIT-2026-08-13.md,
section 28.39) : remplace --no-periods, qui coupait hebdomadaire et
mensuel ensemble sans possibilité de choisir l'un sans l'autre - la
journalière, elle, reste toujours construite, les agrégats en dépendant."""
from __future__ import annotations
import argparse
import tempfile
import unittest
from pathlib import Path
from unittest import mock
import merge_daily
class TestsFlagsIndependants(unittest.TestCase):
def test_parse_args_no_weekly_et_no_monthly_existent_separement(self):
# parse_args() lit sys.argv : substitué le temps de l'appel plutôt
# que de dupliquer la construction du parser.
import sys
ancien_argv = sys.argv
try:
sys.argv = ["merge_daily.py", "--no-weekly"]
args = merge_daily.parse_args()
finally:
sys.argv = ancien_argv
self.assertTrue(args.no_weekly)
self.assertFalse(args.no_monthly)
def test_no_periods_n_existe_plus(self):
import sys
ancien_argv = sys.argv
try:
sys.argv = ["merge_daily.py", "--no-periods"]
with self.assertRaises(SystemExit):
merge_daily.parse_args()
finally:
sys.argv = ancien_argv
class TestsExecuterRespecteLesDrapeaux(unittest.TestCase):
"""_executer() construit hebdo puis mensuel dans une même boucle : on
vérifie ici que chacun peut être coupé indépendamment, sans passer par
un vrai ffmpeg (find_ffmpeg et consorts simulés, aucun clip réel)."""
def setUp(self) -> None:
self.temporaire = tempfile.TemporaryDirectory(prefix="blink_periodes_test_")
self.racine = Path(self.temporaire.name)
for nom in ("clips", "normalized", "excluded", "daily", "weekly", "monthly"):
(self.racine / nom).mkdir()
def tearDown(self) -> None:
self.temporaire.cleanup()
def construire_args(self, no_weekly: bool, no_monthly: bool) -> argparse.Namespace:
return argparse.Namespace(
input=self.racine / "clips",
output=self.racine / "daily",
weekly_output=self.racine / "weekly",
monthly_output=self.racine / "monthly",
normalized_output=self.racine / "normalized",
excluded_output=self.racine / "excluded",
no_weekly=no_weekly,
no_monthly=no_monthly,
no_timestamp=True,
exclude=[],
include=[],
timezone="UTC",
date=None,
camera=None,
force=False,
font=None,
font_size=None,
font_color="white",
box_opacity=0.55,
clock="24h",
preset="veryfast",
crf=21,
)
def executer_avec_simulation(self, args):
with mock.patch.object(merge_daily, "find_ffmpeg", return_value="ffmpeg"), \
mock.patch.object(merge_daily, "load_groups", return_value={}), \
mock.patch.object(merge_daily, "build_periods",
return_value=(0, 0, 0)) as periodes_simulees:
merge_daily._executer(args)
return periodes_simulees
def test_les_deux_periodes_construites_par_defaut(self):
periodes_simulees = self.executer_avec_simulation(
self.construire_args(no_weekly=False, no_monthly=False))
appels = [appel.args[4] for appel in periodes_simulees.call_args_list]
self.assertEqual(appels, ["weekly", "monthly"])
def test_no_weekly_ne_construit_que_le_mensuel(self):
periodes_simulees = self.executer_avec_simulation(
self.construire_args(no_weekly=True, no_monthly=False))
appels = [appel.args[4] for appel in periodes_simulees.call_args_list]
self.assertEqual(appels, ["monthly"])
def test_no_monthly_ne_construit_que_lhebdomadaire(self):
periodes_simulees = self.executer_avec_simulation(
self.construire_args(no_weekly=False, no_monthly=True))
appels = [appel.args[4] for appel in periodes_simulees.call_args_list]
self.assertEqual(appels, ["weekly"])
def test_les_deux_drapeaux_ne_construisent_aucune_periode(self):
periodes_simulees = self.executer_avec_simulation(
self.construire_args(no_weekly=True, no_monthly=True))
periodes_simulees.assert_not_called()
if __name__ == "__main__":
unittest.main()