diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index b315e8c..9497987 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -39,7 +39,8 @@ jobs: # Étape 4 : Lancer les tests unitaires - name: Lancer les tests unitaires run: | - pytest tests/ --basetemp=resultats_pytest --verbose --cov=app --cov-report=term-missing --cov-report=xml:resultats_pytest/tests-couverture.xml --junitxml=resultats_pytest/tests-rapport.xml + cd tests + pytest --basetemp=resultats_pytest --verbose --cov=../app --cov-report=term-missing --cov-report=xml:resultats_pytest/tests-couverture.xml --junitxml=resultats_pytest/tests-rapport.xml # Étape 5 : Sauvegarder les artefacts - name: Sauvegarder les résultats de test @@ -48,4 +49,4 @@ jobs: with: if-no-files-found: error name: tests-resultats-python-${{ matrix.python-version }} # Nom de l'artefact - path: resultats_pytest # Eléments à sauvegarder + path: tests/resultats_pytest # Eléments à sauvegarder diff --git a/analyse-log-apache.json b/analyse-log-apache.json new file mode 100644 index 0000000..e1d5c52 --- /dev/null +++ b/analyse-log-apache.json @@ -0,0 +1,77 @@ +{ + "chemin": "C:\\Users\\Work\\App\\Xampp\\apache\\logs\\access.log", + "statistiques": { + "total_entrees": 17594, + "requetes": { + "top_urls": [ + { + "url": "/assets/icons/muted.png", + "total": 665, + "taux": 3.7796976241900646 + }, + { + "url": "/style/Header.css", + "total": 616, + "taux": 3.501193588723429 + }, + { + "url": "/assets/icon.ico", + "total": 595, + "taux": 3.381834716380584 + } + ], + "repartition_code_statut_http": [ + { + "code": 200, + "total": 14996, + "taux": 85.23360236444243 + }, + { + "code": 304, + "total": 1494, + "taux": 8.491531203819484 + }, + { + "code": 206, + "total": 604, + "taux": 3.432988518813232 + }, + { + "code": 404, + "total": 230, + "taux": 1.307263839945436 + }, + { + "code": 302, + "total": 188, + "taux": 1.0685460952597476 + }, + { + "code": 403, + "total": 40, + "taux": 0.22735023303398885 + }, + { + "code": 500, + "total": 20, + "taux": 0.11367511651699443 + }, + { + "code": 301, + "total": 13, + "taux": 0.07388882573604638 + }, + { + "code": 400, + "total": 6, + "taux": 0.03410253495509833 + }, + { + "code": 408, + "total": 3, + "taux": 0.017051267477549165 + } + ] + } + } +} \ No newline at end of file diff --git a/app/cli/afficheur_cli.py b/app/cli/afficheur_cli.py new file mode 100644 index 0000000..5083b13 --- /dev/null +++ b/app/cli/afficheur_cli.py @@ -0,0 +1,210 @@ +""" +Module pour les intéractions avec la ligne de commande. +""" + +import sys +from pathlib import Path +from json import load +from time import sleep +from random import choice +import colorama +import threading + +class AfficheurCLI: + """ + Représente une classe pour afficher des informations dans la ligne de commande. + + Attributes: + _thread_chargement (Union[None,Thread]): Le thread de l'animation de chargement. + _thread_chargement_termine (Event): L'évènement pour demander au thread de + l'animation de chargement de s'arrêter lorsque le chargement est terminé. + _thread_chargement_erreur (Event): L'évènement pour demander au thread de + l'animation de chargement de s'arrêter lorsque une erreur s'est produite. + _animations_actuelles (dict): Les éléments visuels pour l'animation de chargement. + + Class-level variables: + :cvar COULEUR_MESSAGE_NORMAL (str): La couleur pour les messages normaux en CLI. + :cvar COULEUR_MESSAGE_ERREUR (str): La couleur pour les messages d'erreur en CLI. + """ + COULEUR_MESSAGE_NORMAL = colorama.Fore.WHITE + COULEUR_MESSAGE_ERREUR = colorama.Fore.RED + + def __init__(self): + """ + Initialise un objet pour afficher des informations dans la ligne de commande. + """ + # Normalise les codes couleurs pour fonctionner partout + colorama.init() + # Initialise les variables pour le chargement + self._thread_chargement = None + self._thread_chargement_termine = threading.Event() + self._thread_chargement_erreur = threading.Event() + # Récupère les animations + chemin_racine = Path(__file__).parent.parent.parent.resolve() + chemin_animations = chemin_racine / "assets" / "animations.json" + with open(chemin_animations, "r", encoding="utf-8") as animations: + elements_animations = load(animations) + # Choisis une animation au hasard parmi chaque catégorie d'animation + self._animations_actuelles = { + "chasseur": choice(elements_animations["chasseurs"]), + "fantome": choice(elements_animations["fantomes"]), + "rayon_laser": elements_animations["rayons_laser"] + } + + def reecrire_ligne(self, message: str): + """ + Permet d'écrire des caractères par dessus la dernière ligne dans la + ligne de commande. + + Args: + message (str): Les caractères à afficher. + + Returns: + None + + Raises: + TypeError: Le paramètre ``message`` n'est pas une chaîne de caractères. + """ + # Validation du paramètre + if not isinstance(message, str): + raise TypeError("Le message pour la réécriture doit être une chaîne de caractères.") + # Ecriture du message + sys.stdout.write("\r" + self.COULEUR_MESSAGE_NORMAL + message) + sys.stdout.flush() + + def affiche_message(self, message: str): + """ + Permet d'écrire un message commun dans la ligne de commande avec la bonne + couleur. + + Args: + message (str): Le message à afficher. + + Returns: + None + + Raises: + TypeError: Le paramètre ``message`` n'est pas une chaîne de caractères. + """ + # Validation du paramètre + if not isinstance(message, str): + raise TypeError("Le message doit être une chaîne de caractères.") + # Ecriture du message + print(self.COULEUR_MESSAGE_NORMAL + message, flush=True) + + def affiche_erreur(self, message: str, exception: Exception): + """ + Permet d'écrire un message d'erreur dans la ligne de commande avec la bonne + couleur. + + Args: + message (str): Le message à afficher. + exception (Exception): L'exception à afficher. + + Returns: + None + + Raises: + TypeError: Le paramètre ``message`` n'est pas une chaîne de caractères ou + le paramètre ``exception`` n'est pas une instance de la classe :class:`Exception`. + """ + # Validation des paramètres + if not isinstance(message, str): + raise TypeError("Le message d'erreur doit être une chaîne de caractères.") + if not isinstance(exception, Exception): + raise TypeError("L'exception à afficher doit être une instance de Exception.") + # Ecriture du message + print(self.COULEUR_MESSAGE_ERREUR + f"{message}\n{exception}", flush=True) + + def lance_animation_chargement(self): + """ + Lance une animation de chargement dans la ligne de commande via un thread non bloquant. + Si l'animation de chargement est déjà en cours, cette méthode ne fait rien. + + Returns: + None + """ + # Si le thread est déjà lancé, annulation de l'animation + if self._thread_chargement is None: + # On réinitialise les demandes d'arrêt + self._thread_chargement_termine.clear() + self._thread_chargement_erreur.clear() + # Initialisation du thread pour le chargement + self._thread_chargement = threading.Thread(target=self._animation_chargement, daemon=True) + # Lancement du thread pour le chargement + self._thread_chargement.start() + + def _animation_chargement(self): + """ + Lance l'animation de chargement en boucle jusqu'à la demande d'arrêt via + l'attribut :attr:`_thread_chargement_demande_arret`. + + Returns: + None + """ + # Eléments de l'animation de chargement + chasseur_chargement = self._animations_actuelles["chasseur"][0] + fantome_chargement = self._animations_actuelles["fantome"][0] + signes_rayon_laser = self._animations_actuelles["rayon_laser"] + couleurs = ["\033[91m", "\033[93m", "\033[94m", "\033[95m"] # Rouge, Jaune, Bleu, Magenta + + # Eléments de l'animation de fin de chargement en cas de succès + chasseur_gagne = self._animations_actuelles["chasseur"][2] + fantome_perd = self._animations_actuelles["fantome"][1] + + # Eléments de l'animation de fin de chargement en cas d'erreur + chasseur_perd = self._animations_actuelles["chasseur"][1] + fantome_gagne = self._animations_actuelles["fantome"][2] + + # Variables pour l'animation de chargement + index_boucle = 0 + rayon_laser = "" + + # Début de l'animation (jusqu'à la demande d'arrêt) + while not (self._thread_chargement_termine.is_set() + or self._thread_chargement_erreur.is_set()): + # Arrête d'ajouter des caractères lorsque la chaîne est trop longue + if (index_boucle < 40): + # Récupération de la prochaine couleur + couleur_courante = couleurs[(index_boucle % len(couleurs))] + # Récupération du prochain signe du rayon + signe_courant = signes_rayon_laser[(index_boucle % len(signes_rayon_laser))] + # Ajout du dernier signe avec la nouvelle couleur au rayon + rayon_laser += couleur_courante + signe_courant + # Réactualisation de l'animation de chargement + self.reecrire_ligne(f"{chasseur_chargement}{rayon_laser}\033[0m{fantome_chargement}") + index_boucle += 1 + sleep(0.05) + + # Suppression de la ligne de chargement + self.reecrire_ligne("\033[K") + espace_rayon_laser = " " * index_boucle + if (self._thread_chargement_termine.is_set()): + # Message d'animation terminée + self.reecrire_ligne(f"{chasseur_gagne}{espace_rayon_laser}\033[0m{fantome_perd}\n") + self.affiche_message(f"Analyse terminée! We came, we saw, we logged it.") + else: + # Message d'animation erreur + self.reecrire_ligne(f"{chasseur_perd}{espace_rayon_laser}\033[0m{fantome_gagne}\n") + + def stop_animation_chargement(self, erreur: bool = False): + """ + Lance une demande d'arrêt au thread qui gère l'animation de chargement + en cours. Si aucune animation n'est en cours, cette méthode ne fait rien. + + Args: + erreur (bool): Indique si la demande d'arrêt est dûe à une erreur ou non. + + Returns: + None + """ + # Si le thread de chargement existe et est lancé + if self._thread_chargement and self._thread_chargement.is_alive(): + # Lancement de la demade d'arrêt + if not erreur: + self._thread_chargement_termine.set() + else: + self._thread_chargement_erreur.set() + # Attente de l'arrêt depuis le thread principal + self._thread_chargement.join() + self._thread_chargement = None diff --git a/app/main.py b/app/main.py index 4833dc2..3b1c5d1 100644 --- a/app/main.py +++ b/app/main.py @@ -1,8 +1,9 @@ """ Point d'entrée de l'application LogBuster ! """ - +from time import sleep import colorama +from cli.afficheur_cli import AfficheurCLI from cli.parseur_arguments_cli import ParseurArgumentsCLI, ArgumentCLIException from parse.parseur_log_apache import ParseurLogApache, FormatLogApacheInvalideException from analyse.analyseur_log_apache import AnalyseurLogApache @@ -13,20 +14,10 @@ def main(): """ Point d'entrée de l'application. """ - colorama.init() - print(colorama.Style.DIM + r""" - .-. .-') .-') .-') _ ('-. _ .-') ,---. - \ ( OO ) ( OO ). ( OO) ) _( OO)( \( -O ) | | - ,--. .-'),-----. ,----. ;-----.\ ,--. ,--. (_)---\_)/ '._(,------.,------. | | - | |.-') ( OO' .-. ' ' .-./-') | .-. | | | | | / _ | |'--...__)| .---'| /`. '| | - | | OO )/ | | | | | |_( O- )| '-' /_) | | | .-') \ :` `. '--. .--'| | | / | || | - | |`-' |\_) | |\| | | | .--, \| .-. `. | |_|( OO ) '..`''.) | | (| '--. | |_.' || .' -(| '---.' \ | | | |(| | '. (_/| | \ | | | | `-' /.-._) \ | | | .--' | . '.'`--' - | | `' '-' ' | '--' | | '--' /(' '-'(_.-' \ / | | | `---.| |\ \ .--. - `------' `-----' `------' `------' `-----' `-----' `--' `------'`--' '--''--' - - """) + afficheur_cli = AfficheurCLI() + afficheur_cli.affiche_message("Who ya gonna call? LogBuster!") try: + afficheur_cli.lance_animation_chargement() # Récupération des arguments parseur_cli = ParseurArgumentsCLI() arguments_cli = parseur_cli.parse_args() @@ -39,17 +30,33 @@ def main(): # Exportation de l'analyse exporteur = Exporteur(arguments_cli.sortie) exporteur.export_vers_json(analyse) - except ArgumentCLIException as ex: - print(f"Erreur dans les arguments fournis !\n {ex}") - except FileNotFoundError as ex: - print(f"Erreur dans la recherche du log Apache !\n{ex}") - except FormatLogApacheInvalideException as ex: - print(f"Erreur dans l'analyse du log Apache !\n{ex}") - except ExportationException as ex: - print(f"Erreur dans l'exportation de l'analyse !\n{ex}") + afficheur_cli.stop_animation_chargement() except Exception as ex: - print(f"Erreur interne !\n{ex}") + gestion_exception(afficheur_cli, ex) + +def gestion_exception(afficheur_cli, exception): + """ + Gère les erreurs qui demandent une fin du programme. + Affiche également un message d'erreur personnalisé en fonction + de l'exception. + Args: + afficheur_cli (AfficheurCLI): L'objet permettant d'intéragir avec la ligne + de commande. + exception (Exception): L'exception qui s'est produite. + + Returns: + None + """ + erreurs = { + ArgumentCLIException: "Erreur dans les arguments fournis !", + FileNotFoundError: "Erreur dans la recherche du log Apache !", + FormatLogApacheInvalideException: "Erreur dans l'analyse du log Apache !", + ExportationException: "Erreur dans l'exportation de l'analyse !" + } + message = erreurs.get(type(exception), "Erreur interne !") + afficheur_cli.stop_animation_chargement(True) + afficheur_cli.affiche_erreur(message, exception) if __name__ == "__main__": main() diff --git a/assets/animations.json b/assets/animations.json new file mode 100644 index 0000000..eb38a6f --- /dev/null +++ b/assets/animations.json @@ -0,0 +1,18 @@ +{ + "chasseurs": [ + ["(҂-_•)⊃═O", "(҂x_x)", "d(•᎑-҂)"], + ["(⌐■_■)⊃═O", "(⌐x_x)", "d(■᎑■⌐)"], + ["(∩•_•)⊃═O", "(∩x_x)", "d(•᎑•∩)"], + ["(ò_ó)⊃═O", "(x_x)", "d(ò᎑ó)"] + ], + + "fantomes": [ + ["ε=(( ꐑº-° )ꐑ", "(( x-x)", "ε=(( ꐑº᎑° )ꐑ"], + ["ε=(¬ ´ཀ` )¬", "( xཀx)", "ε=(¬ ´᎑` )¬"], + ["ε=༼ つ ╹ ╹ ༽つ", "༼ x x ༽", "ε=༼ つ ╹᎑╹ ༽つ"], + ["ε=( >_<)", "( x_x)", "ε=( >᎑<)"], + ["ε=(ง'̀-'́)ง", "('x-x)", "ε=(ง'̀᎑'́)ง"] + ], + + "rayons_laser": ["-", "=", "~", "*", "~", "=", "-"] +} \ No newline at end of file diff --git a/docs/source/modules/cli/afficheur_cli.rst b/docs/source/modules/cli/afficheur_cli.rst new file mode 100644 index 0000000..ff28b66 --- /dev/null +++ b/docs/source/modules/cli/afficheur_cli.rst @@ -0,0 +1,7 @@ +AfficheurCLI +====================== + +.. automodule:: cli.afficheur_cli + :members: + :show-inheritance: + :undoc-members: diff --git a/docs/source/modules/cli/index_cli.rst b/docs/source/modules/cli/index_cli.rst index 5494b23..3f644e3 100644 --- a/docs/source/modules/cli/index_cli.rst +++ b/docs/source/modules/cli/index_cli.rst @@ -5,3 +5,4 @@ CLI :maxdepth: 4 parseur_arguments_cli.rst + afficheur_cli.rst diff --git a/tests/.coveragerc b/tests/.coveragerc new file mode 100644 index 0000000..7d5cb5a --- /dev/null +++ b/tests/.coveragerc @@ -0,0 +1,3 @@ +[report] +exclude_lines = + if __name__ == "__main__": \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 550738c..861d5e2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ """ import pytest +from cli.afficheur_cli import AfficheurCLI from cli.parseur_arguments_cli import ParseurArgumentsCLI from parse.parseur_log_apache import ParseurLogApache from analyse.analyseur_log_apache import AnalyseurLogApache @@ -47,6 +48,10 @@ # Fixtures générales # ------------------ +@pytest.fixture +def afficheur_cli(): + return AfficheurCLI() + @pytest.fixture def parseur_arguments_cli(): """ diff --git a/tests/test_afficheur_cli.py b/tests/test_afficheur_cli.py new file mode 100644 index 0000000..c68ec51 --- /dev/null +++ b/tests/test_afficheur_cli.py @@ -0,0 +1,211 @@ +""" +Modules des tests unitaires pour l'affichage d'informations dans la CLI. +""" + +import pytest +from time import sleep +from io import StringIO +from cli.afficheur_cli import AfficheurCLI + +# Données +messages = [ + "Un message normal", + "Test\r avec des \ncaractères\t spéciaux", + "Test d'un message très long" * 1000, + "\033[31mTest avec couleur\033[0m", + "🎉 Test avec des unicodes 🎉" +] + +# Tests unitaires + +@pytest.mark.parametrize("message", messages) +def test_afficheur_cli_affiche_message(mocker, afficheur_cli, message): + """ + Vérifie que la méthode affiche_message affiche correctement les messages avec la bonne + couleur dans le terminal. + + Scénarios testés: + - Passage d'un message à la méthode. + + Asserts: + - Le message est le même que celui fourni avec la bonne couleur. + + Args: + mocker (MockerFixture): Fixture qui permet de modifier le stdout. + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + message (str): Message à afficher. + """ + # Remplacement de la sortie standard par un StringIO (nommé sortie_cli) + with mocker.patch("sys.stdout", new_callable=StringIO) as sortie_cli: + afficheur_cli.affiche_message(message) + assert sortie_cli.getvalue() == afficheur_cli.COULEUR_MESSAGE_NORMAL + message + "\n" + +def test_afficheur_cli_exception_affiche_message_type(afficheur_cli): + """ + Vérifie que la méthode affiche_message lève une exception TypeError + lorsque l'argument fourni n'est pas une chaîne de caractères. + + Scénarios testés: + - Passage d'un entier à la méthode. + + Asserts: + - Vérifie que l'exception TypeError est levée. + + Args: + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + """ + with pytest.raises(TypeError): + afficheur_cli.affiche_message(123) + +@pytest.mark.parametrize("message, exception", [ + ("Un message d'erreur !", Exception("Erreur générale !")), + ("Erreur de typage !", TypeError("Une variable str était attendue !")), + ("Erreur dans la recherche !", FileNotFoundError("Fichier non trouvé !")) +]) +def test_afficheur_cli_affiche_erreur(mocker, afficheur_cli, message, exception): + """ + Vérifie que la méthode affiche_erreur affiche correctement les messages d'erreur + dans le terminal avec la couleur adéquate. + + Scénarios testés: + - Affichage d'erreurs avec différents types d'exceptions. + + Asserts: + - Vérifie que le message d'erreur et l'exception sont bien affichés. + + Args: + mocker (MockerFixture): Fixture pour modifier le stdout. + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + message (str): Message d'erreur à afficher. + exception (Exception): Exception associée à l'erreur. + """ + # Remplacement de la sortie standard par un StringIO (nommé sortie_cli) + with mocker.patch("sys.stdout", new_callable=StringIO) as sortie_cli: + afficheur_cli.affiche_erreur(message, exception) + assert sortie_cli.getvalue() == (afficheur_cli.COULEUR_MESSAGE_ERREUR + + message + "\n" + str(exception) + "\n") + +@pytest.mark.parametrize("message, exception", [ + (False, Exception("Erreur générale !")), + ("Erreur de typage !", False) +]) +def test_afficheur_cli_exception_affiche_erreur_type(afficheur_cli, message, exception): + """ + Vérifie que la méthode affiche_erreur lève une exception TypeError + lorsque les arguments ne sont pas du bon type. + + Scénarios testés: + - Passage d'un mauvais type pour le paramètre ``message``. + - Passage d'un mauvais type pour le paramètre ``exception``. + + Asserts: + - Vérifie que l'exception TypeError est levée. + + Args: + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + message (Any): Valeur incorrecte à tester. + exception (Any): Valeur incorrecte à tester. + """ + with pytest.raises(TypeError): + afficheur_cli.affiche_erreur(message, exception) + +@pytest.mark.parametrize("message", messages) +def test_afficheur_cli_reecrire_ligne(mocker, afficheur_cli, message): + """ + Vérifie que la méthode reecrire_ligne affiche correctement un message + sur la même ligne du terminal. + + Scénarios testés: + - Affichage de plusieurs messages. + + Asserts: + - Vérifie que la sortie standard contient le message formaté. + + Args: + mocker (MockerFixture): Fixture pour modifier le stdout. + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + message (str): Message à afficher. + """ + # Remplacement de la sortie standard par un StringIO (nommé sortie_cli) + with mocker.patch("sys.stdout", new_callable=StringIO) as sortie_cli: + afficheur_cli.reecrire_ligne(message) + assert sortie_cli.getvalue() == "\r" + afficheur_cli.COULEUR_MESSAGE_NORMAL + message + +def test_afficheur_cli_exception_reecrire_ligne_type(afficheur_cli): + """ + Vérifie que la méthode reecrire_ligne lève une exception TypeError + lorsqu'un argument de type incorrect est fourni. + + Scénarios testés: + - Passage d'un entier au lieu d'une chaîne de caractères. + + Asserts: + - Vérifie que l'exception TypeError est levée. + + Args: + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + """ + with pytest.raises(TypeError): + afficheur_cli.reecrire_ligne(123) + +def test_afficheur_cli_lance_animation_chargement(mocker, afficheur_cli): + """ + Vérifie que la méthode lance_animation_chargement démarre bien un thread + pour l'animation de chargement. + + Scénarios testés: + - Lancement de l'animation de chargement. + + Asserts: + - Vérifie que le thread est bien initialisé et actif. + + Args: + mocker (MockerFixture): Fixture pour modifier les méthodes internes. + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + """ + mocker.patch.object(afficheur_cli, "_animation_chargement", side_effect=lambda: sleep(10)) + assert afficheur_cli._thread_chargement is None + afficheur_cli.lance_animation_chargement() + assert afficheur_cli._thread_chargement is not None + assert afficheur_cli._thread_chargement.is_alive() + +def test_afficheur_cli_stop_animation_chargement_terminee(afficheur_cli): + """ + Vérifie que la méthode stop_animation_chargement arrête correctement l'animation en + cas de demande d'arrêt suite à une fin de chargement normale. + + Scénarios testés: + - Arrêt normal de l'animation de chargement. + + Asserts: + - Vérifie que le thread est bien arrêté. + - Vérifie que le flag d'arrêt normale est activé. + + Args: + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + """ + afficheur_cli.lance_animation_chargement() + afficheur_cli.stop_animation_chargement() + assert afficheur_cli._thread_chargement is None + assert afficheur_cli._thread_chargement is None + assert afficheur_cli._thread_chargement_termine.is_set() + +def test_afficheur_cli_stop_animation_chargement_erreur(afficheur_cli): + """ + Vérifie que la méthode stop_animation_chargement arrête correctement l'animation en + cas de demande d'arrêt suite à une erreur. + + Scénarios testés: + - Arrêt normal de l'animation de chargement. + + Asserts: + - Vérifie que le thread est bien arrêté. + - Vérifie que le flag d'arrêt d'erreur est activé. + + Args: + afficheur_cli (AfficheurCLI): Fixture pour l'instance de la classe ``AfficheurCLI``. + """ + afficheur_cli.lance_animation_chargement() + afficheur_cli.stop_animation_chargement(True) + assert afficheur_cli._thread_chargement is None + assert afficheur_cli._thread_chargement_erreur.is_set() \ No newline at end of file diff --git a/tests/test_main.py b/tests/test_main.py index c2fb6e1..a92fba9 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -24,7 +24,7 @@ def test_main_gestion_exception(mocker, exception): - Vérification que les exceptions n'arrête pas le programme. Args: - mocker (any): Une fixture pour simuler des exceptions. + mocker (MockerFixture): Une fixture pour simuler des exceptions. exception (any): L'exception à simuler. """ mocker.patch("main.ParseurArgumentsCLI", side_effect=exception) @@ -40,7 +40,7 @@ def test_main_succes(mocker): d'un déroulement normal. Args: - mocker (any): Une fixture pour simuler des retours pour les classes + mocker (MockerFixture): Une fixture pour simuler des retours pour les classes et méthodes dans main. """ # Mock des classes pour simuler un fonctionnement correct