- 9 nouveaux fichiers de tests (persistance, translations, fiches, indices, IHH) - Enrichissement des tests existants (graph_utils, gitea, widgets, tickets) - 67→448 tests, tous passent Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
298 lines
11 KiB
Python
298 lines
11 KiB
Python
"""Tests unitaires pour le module utils.gitea.
|
|
|
|
Ces tests vérifient les fonctions d'interaction avec l'API Gitea.
|
|
"""
|
|
|
|
import base64
|
|
from datetime import datetime, timezone
|
|
from unittest.mock import Mock, mock_open, patch
|
|
|
|
import pytest
|
|
import requests
|
|
|
|
from utils.gitea import (
|
|
charger_arborescence_fiches,
|
|
charger_instructions_depuis_gitea,
|
|
charger_schema_depuis_gitea,
|
|
lire_fichier_local,
|
|
recuperer_date_dernier_commit,
|
|
)
|
|
|
|
|
|
class TestLireFichierLocal:
|
|
"""Tests pour la fonction lire_fichier_local."""
|
|
|
|
def test_lecture_fichier_utf8(self, tmp_path):
|
|
"""Test la lecture d'un fichier UTF-8 standard."""
|
|
fichier = tmp_path / "test.txt"
|
|
contenu_attendu = "Contenu de test avec caractères spéciaux: éàç"
|
|
fichier.write_text(contenu_attendu, encoding="utf-8")
|
|
|
|
resultat = lire_fichier_local(str(fichier))
|
|
|
|
assert resultat == contenu_attendu
|
|
|
|
def test_lecture_fichier_avec_accents(self, tmp_path):
|
|
"""Test la lecture d'un fichier avec caractères accentués."""
|
|
fichier = tmp_path / "accents.txt"
|
|
contenu = "Voici des accents: é, è, à, ç, ù"
|
|
fichier.write_text(contenu, encoding="utf-8")
|
|
|
|
resultat = lire_fichier_local(str(fichier))
|
|
|
|
assert resultat == contenu
|
|
|
|
def test_lecture_fichier_vide(self, tmp_path):
|
|
"""Test la lecture d'un fichier vide."""
|
|
fichier = tmp_path / "vide.txt"
|
|
fichier.write_text("", encoding="utf-8")
|
|
|
|
resultat = lire_fichier_local(str(fichier))
|
|
|
|
assert resultat == ""
|
|
|
|
def test_fichier_inexistant(self):
|
|
"""Test la gestion d'un fichier inexistant."""
|
|
with pytest.raises(FileNotFoundError):
|
|
lire_fichier_local("fichier_inexistant.txt")
|
|
|
|
|
|
class TestRecupererDateDernierCommit:
|
|
"""Tests pour la fonction recuperer_date_dernier_commit."""
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_recuperation_date_commit(self, mock_get):
|
|
"""Test la récupération de la date du dernier commit."""
|
|
# Mock de la réponse Gitea
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = [
|
|
{
|
|
"commit": {
|
|
"author": {
|
|
"date": "2025-01-15T10:30:00Z"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
mock_get.return_value = mock_response
|
|
|
|
resultat = recuperer_date_dernier_commit("https://gitea.example.com/api/v1/repos/org/repo/commits")
|
|
|
|
assert resultat is not None
|
|
assert isinstance(resultat, datetime)
|
|
assert resultat.year == 2025
|
|
assert resultat.month == 1
|
|
assert resultat.day == 15
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_aucun_commit(self, mock_get):
|
|
"""Test avec un dépôt sans commits."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = []
|
|
mock_get.return_value = mock_response
|
|
|
|
resultat = recuperer_date_dernier_commit("https://gitea.example.com/api/v1/repos/org/repo/commits")
|
|
|
|
assert resultat is None
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_erreur_requete(self, mock_get):
|
|
"""Test la gestion d'une erreur de requête."""
|
|
mock_get.side_effect = requests.RequestException("Network error")
|
|
|
|
resultat = recuperer_date_dernier_commit("https://gitea.example.com/api/v1/repos/org/repo/commits")
|
|
|
|
assert resultat is None
|
|
|
|
|
|
class TestChargerInstructionsDepuisGitea:
|
|
"""Tests pour la fonction charger_instructions_depuis_gitea."""
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
@patch("utils.gitea.recuperer_date_dernier_commit")
|
|
def test_telechargement_fichier_inexistant(self, mock_date_commit, mock_get):
|
|
"""Test le téléchargement quand le fichier local n'existe pas."""
|
|
# Commit distant disponible
|
|
mock_date_commit.return_value = datetime(2025, 1, 15, tzinfo=timezone.utc)
|
|
|
|
# Contenu encodé en base64
|
|
contenu_md = "# Instructions\nCeci est un test"
|
|
contenu_base64 = base64.b64encode(contenu_md.encode("utf-8")).decode("utf-8")
|
|
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {"content": contenu_base64}
|
|
mock_get.return_value = mock_response
|
|
|
|
m_open = mock_open()
|
|
with patch("pathlib.Path.exists", return_value=False), \
|
|
patch("pathlib.Path.open", m_open):
|
|
resultat = charger_instructions_depuis_gitea("Instructions.md")
|
|
|
|
# Vérifie que le fichier a été écrit
|
|
m_open.assert_called_once_with("w", encoding="utf-8")
|
|
assert resultat == contenu_md
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
@patch("utils.gitea.recuperer_date_dernier_commit")
|
|
def test_utilisation_cache_local_recent(self, mock_date_commit, mock_get):
|
|
"""Test l'utilisation du cache local si plus récent."""
|
|
# Date fichier local plus récent
|
|
local_time = datetime(2025, 1, 20, tzinfo=timezone.utc)
|
|
mock_stat = Mock()
|
|
mock_stat.st_mtime = local_time.timestamp()
|
|
|
|
# Date commit distant plus ancien
|
|
mock_date_commit.return_value = datetime(2025, 1, 15, tzinfo=timezone.utc)
|
|
|
|
with patch("pathlib.Path.exists", return_value=True), \
|
|
patch("pathlib.Path.stat", return_value=mock_stat), \
|
|
patch("pathlib.Path.open", mock_open(read_data="# Local Instructions")):
|
|
resultat = charger_instructions_depuis_gitea("Instructions.md")
|
|
|
|
# Doit lire le fichier local sans appeler l'API
|
|
assert mock_get.call_count == 0
|
|
assert resultat == "# Local Instructions"
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
@patch("utils.gitea.recuperer_date_dernier_commit")
|
|
def test_erreur_reseau_avec_cache(self, mock_date_commit, _mock_get):
|
|
"""Test le fallback sur le cache en cas d'erreur réseau."""
|
|
mock_date_commit.side_effect = requests.RequestException("Network error")
|
|
|
|
with patch("pathlib.Path.exists", return_value=True), \
|
|
patch("pathlib.Path.open", mock_open(read_data="# Cached content")):
|
|
resultat = charger_instructions_depuis_gitea("Instructions.md")
|
|
|
|
assert resultat == "# Cached content"
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
@patch("utils.gitea.recuperer_date_dernier_commit")
|
|
def test_erreur_reseau_sans_cache(self, mock_date_commit, _mock_get):
|
|
"""Test le retour None si erreur et pas de cache."""
|
|
mock_date_commit.side_effect = requests.RequestException("Network error")
|
|
|
|
with patch("pathlib.Path.exists", return_value=False):
|
|
resultat = charger_instructions_depuis_gitea("Instructions.md")
|
|
|
|
assert resultat is None
|
|
|
|
|
|
class TestChargerSchemaDepuisGitea:
|
|
"""Tests pour la fonction charger_schema_depuis_gitea."""
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
@patch("utils.gitea.recuperer_date_dernier_commit")
|
|
def test_telechargement_schema_file(self, mock_date_commit, mock_get):
|
|
"""Test le téléchargement d'un fichier schema depuis Gitea."""
|
|
# Commit distant disponible
|
|
mock_date_commit.return_value = datetime(2025, 1, 15, tzinfo=timezone.utc)
|
|
|
|
# Contenu DOT encodé en base64
|
|
contenu_dot = "digraph G { A -> B; }"
|
|
contenu_base64 = base64.b64encode(contenu_dot.encode("utf-8")).decode("utf-8")
|
|
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {"content": contenu_base64}
|
|
mock_get.return_value = mock_response
|
|
|
|
m_open = mock_open()
|
|
with patch("pathlib.Path.exists", return_value=False), \
|
|
patch("pathlib.Path.open", m_open):
|
|
resultat = charger_schema_depuis_gitea("test_schema.txt")
|
|
|
|
# Vérifie que le fichier a été écrit
|
|
assert m_open.called
|
|
assert resultat == "OK"
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
@patch("utils.gitea.recuperer_date_dernier_commit")
|
|
def test_cache_schema_file(self, mock_date_commit, mock_get):
|
|
"""Test l'utilisation du cache pour le fichier schema."""
|
|
# Date fichier local plus récent
|
|
local_time = datetime(2025, 1, 20, tzinfo=timezone.utc)
|
|
mock_stat = Mock()
|
|
mock_stat.st_mtime = local_time.timestamp()
|
|
|
|
# Date commit distant plus ancien
|
|
mock_date_commit.return_value = datetime(2025, 1, 15, tzinfo=timezone.utc)
|
|
|
|
# Mock response pour le premier appel (get file info)
|
|
contenu_base64 = base64.b64encode(b"digraph G { cached }").decode("utf-8")
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {"content": contenu_base64}
|
|
mock_get.return_value = mock_response
|
|
|
|
with patch("pathlib.Path.exists", return_value=True), \
|
|
patch("pathlib.Path.stat", return_value=mock_stat):
|
|
resultat = charger_schema_depuis_gitea("test_schema.txt")
|
|
|
|
# Doit retourner OK sans réécrire (fichier déjà à jour)
|
|
assert resultat == "OK"
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_erreur_chargement_schema(self, mock_get):
|
|
"""Test la gestion d'erreur lors du chargement du schema."""
|
|
mock_get.side_effect = requests.RequestException("Network error")
|
|
|
|
resultat = charger_schema_depuis_gitea("test_schema.txt")
|
|
|
|
assert resultat is None
|
|
|
|
|
|
class TestChargerArborescenceFiches:
|
|
"""Tests pour la fonction charger_arborescence_fiches."""
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_arborescence_vide(self, mock_get):
|
|
"""Test avec un dépôt sans dossiers."""
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = []
|
|
mock_get.return_value = mock_response
|
|
|
|
resultat = charger_arborescence_fiches()
|
|
|
|
assert resultat == {}
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_arborescence_avec_dossiers(self, mock_get):
|
|
"""Test avec des dossiers contenant des fiches."""
|
|
# Mock réponse pour la liste des dossiers
|
|
mock_response_dossiers = Mock()
|
|
mock_response_dossiers.status_code = 200
|
|
mock_response_dossiers.json.return_value = [
|
|
{"name": "Composants", "type": "dir", "url": "https://gitea.example.com/api/v1/repos/org/repo/contents/Documents/Composants"}
|
|
]
|
|
|
|
# Mock réponse pour le contenu du dossier
|
|
mock_response_fichiers = Mock()
|
|
mock_response_fichiers.status_code = 200
|
|
mock_response_fichiers.json.return_value = [
|
|
{"name": "Processeur.md", "download_url": "https://gitea.example.com/download/Processeur.md"},
|
|
{"name": "Memoire.md", "download_url": "https://gitea.example.com/download/Memoire.md"}
|
|
]
|
|
|
|
# Configure les appels successifs
|
|
mock_get.side_effect = [mock_response_dossiers, mock_response_fichiers]
|
|
|
|
resultat = charger_arborescence_fiches()
|
|
|
|
assert "Composants" in resultat
|
|
assert len(resultat["Composants"]) == 2
|
|
assert resultat["Composants"][0]["nom"] == "Memoire.md" # Trié alphabétiquement
|
|
assert resultat["Composants"][1]["nom"] == "Processeur.md"
|
|
|
|
@patch("utils.gitea.requests.get")
|
|
def test_erreur_requete(self, mock_get):
|
|
"""Test la gestion d'erreur lors de la requête."""
|
|
mock_get.side_effect = requests.RequestException("Network error")
|
|
|
|
resultat = charger_arborescence_fiches()
|
|
|
|
assert resultat == {}
|