from pathlib import Path from unittest.mock import patch import pytest from syncvito.config_store import ConfigError, ConfigStore from syncvito.models import AppConfig, AppSettings, SyncDirection, SyncTask def test_config_roundtrip(tmp_path: Path) -> None: path = tmp_path / "config.json" config = AppConfig( tasks=[ SyncTask( name="Archiv", source=str(tmp_path / "quelle"), target=str(tmp_path / "ziel"), direction=SyncDirection.BIDIRECTIONAL, selected_paths=["Dokumente"], ) ], settings=AppSettings(font_size=12, ui_scale=110, check_updates_on_start=False), ) ConfigStore(path).save(config) loaded = ConfigStore(path).load() assert loaded.settings.font_size == 12 assert loaded.settings.ui_scale == 110 assert loaded.settings.check_updates_on_start is False assert loaded.tasks[0].name == "Archiv" assert loaded.tasks[0].direction is SyncDirection.BIDIRECTIONAL assert loaded.tasks[0].selected_paths == ["Dokumente"] def test_config_corrupt_json_creates_backup(tmp_path: Path) -> None: path = tmp_path / "config.json" path.write_text("{ unvollstaendiges json...", encoding="utf-8") store = ConfigStore(path) with pytest.raises(ConfigError, match="syntaktisch beschädigt"): store.load() defekt_files = list(tmp_path.glob("config.defekt-*.json")) assert len(defekt_files) == 1 assert not path.exists() def test_config_read_locked_does_not_rename_file(tmp_path: Path) -> None: path = tmp_path / "config.json" path.write_text('{"schema_version": 1, "tasks": [], "settings": {}}', encoding="utf-8") store = ConfigStore(path) with ( patch.object(Path, "read_text", side_effect=PermissionError(13, "Permission denied")), pytest.raises(ConfigError, match="konnte nicht gelesen werden"), ): store.load() # Originaldatei darf bei Lese-/Sperrfehler NICHT umbenannt/gelöscht werden! assert path.exists() assert list(tmp_path.glob("config.defekt-*.json")) == [] def test_config_load_with_invalid_task_keeps_task_disabled() -> None: data = { "schema_version": 1, "tasks": [ { "name": "Ungültig", "source": "C:\\Ordner", "target": "C:\\Ordner", # Gleiche Quelle und Ziel -> ValueError bei validate() "interval_minutes": 30, } ], "settings": {}, } config = AppConfig.from_dict(data) assert len(config.tasks) == 1 assert config.tasks[0].name == "Ungültig" assert config.tasks[0].enabled is False def test_sync_task_safe_resolve_network_oserror(tmp_path: Path) -> None: task = SyncTask( name="Netzwerk-Task", source=str(tmp_path / "lokal"), target=r"\\UnerreichbarerServer\Freigabe\Ordner", ) with patch.object(Path, "resolve", side_effect=OSError("Network unreachable")): task.validate() assert task.source == str((tmp_path / "lokal").resolve()) assert r"\\UnerreichbarerServer\Freigabe\Ordner" in task.target