diff --git a/tests/test_utils_duo.py b/tests/test_utils_duo.py index dcaa25aa..c1653a8b 100644 --- a/tests/test_utils_duo.py +++ b/tests/test_utils_duo.py @@ -1,80 +1,69 @@ import os import pickle import pytest -from tempfile import NamedTemporaryFile +from tempfile import NamedTemporaryFile, TemporaryDirectory from unittest.mock import patch from getpass import getpass from pathlib import Path -from slic.utils.duo import * +from slic.utils import DotDir +from slic.utils.duo import PickledDict, Secrets class TestPickledDictReal: """Tests réels de PickledDict avec manipulation de fichiers""" def test_set_get(self): - # Crée un fichier temporaire qui sera automatiquement supprimé + # Crée et initialise un fichier pickle temporaire with NamedTemporaryFile(delete=False) as tmp_file: tmp_path = tmp_file.name + pickle.dump({}, tmp_file) # Initialise avec dict vide try: - # 1. Test avec fichier vide au départ pd = PickledDict(tmp_path) - # 2. Premier set() - doit créer le fichier + # 1. Test set() et création fichier pd.set("test_key", "test_value") - assert os.path.exists(tmp_path) # Le fichier doit exister + assert os.path.exists(tmp_path) - # 3. Vérifie que les données sont bien persistées - pd2 = PickledDict(tmp_path) - assert pd2.get("test_key") == "test_value" + # 2. Vérification get() + assert pd.get("test_key") == "test_value" - # 4. Test avec plusieurs valeurs + # 3. Test multi-valeurs pd.set("key2", 42) pd.set("key3", [1, 2, 3]) - # 5. Vérifie l'intégrité des données - pd3 = PickledDict(tmp_path) - assert pd3.get("test_key") == "test_value" - assert pd3.get("key2") == 42 - assert pd3.get("key3") == [1, 2, 3] + # 4. Persistance + pd2 = PickledDict(tmp_path) + assert pd2.get("test_key") == "test_value" + assert pd2.get("key2") == 42 + assert pd2.get("key3") == [1, 2, 3] - # 6. Test KeyError + # 5. Test clé manquante with pytest.raises(KeyError): - pd3.get("non_existent_key") + pd2.get("missing_key") finally: - # Nettoyage if os.path.exists(tmp_path): os.unlink(tmp_path) - def test_load(self): - """Test complet du workflow avec vérification de _load()""" + """Test de la méthode _load()""" with NamedTemporaryFile(delete=False) as tmp_file: tmp_path = tmp_file.name + pickle.dump({"initial": "data"}, tmp_file) # Données initiales try: pd = PickledDict(tmp_path) - # Vérifie que _load() retourne bien un dict vide au début - assert pd._load() == {} + # 1. Vérifie chargement initial + assert pd._load() == {"initial": "data"} - # Premier set - pd.set("test_key", "test_value") + # 2. Mise à jour + pd.set("new_key", "new_value") + assert pd._load() == {"initial": "data", "new_key": "new_value"} - # Vérifie le contenu via _load() - assert pd._load() == {"test_key": "test_value"} - - # Ajout de données complexes - pd.set("key2", {"nested": True}) - - # Vérification via _load() - loaded_data = pd._load() - assert loaded_data["test_key"] == "test_value" - assert loaded_data["key2"] == {"nested": True} - - # Test avec une nouvelle instance + # 3. Vérification intégrité pd2 = PickledDict(tmp_path) - assert pd2._load() == loaded_data # Doit être identique + assert pd2._load() == pd._load() finally: if os.path.exists(tmp_path): @@ -82,72 +71,58 @@ class TestPickledDictReal: class TestSecrets: - """Tests réels de Secrets avec le nom de fichier par défaut""" + """Tests réels de Secrets avec isolation du home directory""" @pytest.fixture - def secrets_dir(self, tmp_path): - """Crée un répertoire temporaire avec une structure .dir""" - dot_dir = tmp_path / ".dir" - dot_dir.mkdir() - return dot_dir + def temp_home(self, monkeypatch): + """Crée un home temporaire et mock Path.home()""" + with TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + monkeypatch.setattr(Path, "home", lambda: temp_path) + yield temp_path - def test_default_filename(self, secrets_dir, monkeypatch): - """Test que le fichier par défaut 'secrets' est bien utilisé""" - # 1. On mock DotDir pour utiliser notre répertoire temporaire - monkeypatch.setattr("mon_module.DotDir", lambda: lambda _: str(secrets_dir / "secrets")) - - # 2. Test avec le nom par défaut - secrets = Secrets() # Utilise fname="secrets" par défaut - - with patch("getpass.getpass", return_value="default_secret"): - secrets.set("default_key") - - # 3. Vérifie que le fichier a bien été créé avec le bon nom - expected_file = secrets_dir / "secrets" - assert expected_file.exists() - - # 4. Vérifie la persistance - secrets2 = Secrets() - assert secrets2.get("default_key") == "default_secret" - - def test_secret_workflow(self, secrets_dir, monkeypatch): - """Test complet du workflow avec le nom par défaut""" - monkeypatch.setattr("mon_module.DotDir", lambda: lambda _: str(secrets_dir / "secrets")) - - # 1. Premier secret + def test_default_filename(self, temp_home): + """Test le stockage dans ~/.slic/secrets""" secrets = Secrets() - with patch("getpass.getpass", return_value="first_value"): - secrets.set("first_key") - # 2. Deuxième secret - with patch("getpass.getpass", return_value="second_value"): - secrets.set("second_key") + with patch("getpass.getpass", return_value="secret123"): + secrets.set("api_key") - # 3. Vérification + # Vérifie le fichier + secret_file = temp_home / ".slic" / "secrets" + assert secret_file.exists() + + # Vérifie la persistance secrets2 = Secrets() - assert secrets2.get("first_key") == "first_value" - assert secrets2.get("second_key") == "second_value" + assert secrets2.get("api_key") == "secret123" + + def test_secret_workflow(self, temp_home): + """Test complet du workflow Secrets""" + secrets = Secrets() - # 4. Vérifie le contenu du fichier - with open(secrets_dir / "secrets", "rb") as f: + # Ajout de deux secrets + with patch("getpass.getpass", side_effect=["pass1", "pass2"]): + secrets.set("db_user") + secrets.set("db_pass") + + # Vérification + secrets2 = Secrets() + assert secrets2.get("db_user") == "pass1" + assert secrets2.get("db_pass") == "pass2" + + # Vérifie le contenu pickle + with open(temp_home / ".slic" / "secrets", "rb") as f: data = pickle.load(f) - assert data == { - "first_key": "first_value", - "second_key": "second_value" - } + assert data == {"db_user": "pass1", "db_pass": "pass2"} - def test_keyboard_interrupt(self, secrets_dir, monkeypatch, capsys): - """Test l'annulation avec Ctrl+C""" - monkeypatch.setattr("mon_module.DotDir", lambda: lambda _: str(secrets_dir / "secrets")) - + def test_keyboard_interrupt(self, temp_home, capsys): + """Test l'annulation par Ctrl+C""" secrets = Secrets() - # Simule Ctrl+C with patch("getpass.getpass", side_effect=KeyboardInterrupt): secrets.set("canceled_key") - # Vérifie qu'aucun fichier n'a été créé pour cette annulation - assert not (secrets_dir / "secrets").exists() + # Vérifie qu'aucun fichier n'a été créé + assert not (temp_home / ".slic" / "secrets").exists() captured = capsys.readouterr() - assert captured.out == "\n" - + assert captured.out == "\n" # Saut de ligne du print() \ No newline at end of file