"""Tests for settings and session serialization.""" import json import pytest from pathlib import Path from development_hub.settings import Settings class TestSettingsPersistence: """Test settings persistence and round-trips.""" @pytest.fixture def isolated_settings(self, tmp_path, monkeypatch): """Create an isolated Settings instance with temp files.""" # Reset singleton Settings._instance = None # Point to temp directory settings_file = tmp_path / "settings.json" session_file = tmp_path / "session.json" monkeypatch.setattr(Settings, "_settings_file", settings_file) monkeypatch.setattr(Settings, "_session_file", session_file) settings = Settings() yield settings # Clean up singleton Settings._instance = None def test_default_values(self, isolated_settings): """Settings have sensible defaults.""" settings = isolated_settings assert settings.deploy_docs_after_creation == True assert settings.preferred_editor == "auto" assert settings.auto_start_docs_server == True assert isinstance(settings.project_search_paths, list) assert isinstance(settings.project_ignore_folders, list) def test_set_and_get(self, isolated_settings): """Values can be set and retrieved.""" settings = isolated_settings settings.preferred_editor = "pycharm" assert settings.preferred_editor == "pycharm" settings.deploy_docs_after_creation = False assert settings.deploy_docs_after_creation == False def test_persistence_round_trip(self, isolated_settings, tmp_path): """Settings persist across instances.""" settings = isolated_settings # Modify settings settings.preferred_editor = "code" settings.auto_start_docs_server = False settings.set("custom_key", "custom_value") # Reset singleton and create new instance Settings._instance = None new_settings = Settings() assert new_settings.preferred_editor == "code" assert new_settings.auto_start_docs_server == False assert new_settings.get("custom_key") == "custom_value" def test_file_created_on_save(self, isolated_settings, tmp_path): """Settings file is created when saving.""" settings = isolated_settings settings.preferred_editor = "xed" # Check file exists assert Settings._settings_file.exists() def test_invalid_json_handled(self, isolated_settings, tmp_path): """Invalid JSON in settings file doesn't crash.""" # Write invalid JSON Settings._settings_file.parent.mkdir(parents=True, exist_ok=True) Settings._settings_file.write_text("{ invalid json }") # Reset and reload Settings._instance = None settings = Settings() # Should fall back to defaults assert settings.preferred_editor == "auto" class TestSessionSerialization: """Test session state serialization.""" @pytest.fixture def isolated_settings(self, tmp_path, monkeypatch): """Create an isolated Settings instance with temp files.""" Settings._instance = None settings_file = tmp_path / "settings.json" session_file = tmp_path / "session.json" monkeypatch.setattr(Settings, "_settings_file", settings_file) monkeypatch.setattr(Settings, "_session_file", session_file) settings = Settings() yield settings Settings._instance = None def test_save_load_session_round_trip(self, isolated_settings): """Session state round-trips correctly.""" settings = isolated_settings state = { "window_geometry": {"x": 100, "y": 200, "width": 800, "height": 600}, "splitter_sizes": [300, 500], "panes": [ { "tabs": [ {"type": "terminal", "cwd": "/home/user/project", "title": "Terminal 1"}, {"type": "dashboard", "project_key": "my-project"}, ], "active_tab": 0, } ], "active_pane": 0, } settings.save_session(state) loaded = settings.load_session() assert loaded == state def test_save_session_creates_directory(self, isolated_settings, tmp_path): """Session save creates config directory if needed.""" settings = isolated_settings # Ensure parent doesn't exist if Settings._session_file.parent.exists(): import shutil shutil.rmtree(Settings._session_file.parent) state = {"test": True} settings.save_session(state) assert Settings._session_file.exists() def test_load_empty_session(self, isolated_settings): """Loading non-existent session returns empty dict.""" settings = isolated_settings loaded = settings.load_session() assert loaded == {} def test_load_invalid_session(self, isolated_settings): """Invalid JSON in session returns empty dict.""" settings = isolated_settings Settings._session_file.parent.mkdir(parents=True, exist_ok=True) Settings._session_file.write_text("not valid json") loaded = settings.load_session() assert loaded == {} def test_session_preserves_types(self, isolated_settings): """Session preserves various data types.""" settings = isolated_settings state = { "string": "hello", "number": 42, "float": 3.14, "bool": True, "none": None, "list": [1, 2, 3], "nested": {"a": {"b": "c"}}, } settings.save_session(state) loaded = settings.load_session() assert loaded["string"] == "hello" assert loaded["number"] == 42 assert loaded["float"] == 3.14 assert loaded["bool"] == True assert loaded["none"] is None assert loaded["list"] == [1, 2, 3] assert loaded["nested"]["a"]["b"] == "c" def test_session_handles_unicode(self, isolated_settings): """Session handles unicode characters.""" settings = isolated_settings state = { "emoji": "Test", "japanese": "Hello", "symbols": "angle bracket < > quotes \" '", } settings.save_session(state) loaded = settings.load_session() assert loaded == state class TestGitHostSettings: """Test git hosting configuration.""" @pytest.fixture def isolated_settings(self, tmp_path, monkeypatch): """Create an isolated Settings instance.""" Settings._instance = None monkeypatch.setattr(Settings, "_settings_file", tmp_path / "settings.json") monkeypatch.setattr(Settings, "_session_file", tmp_path / "session.json") settings = Settings() yield settings Settings._instance = None def test_git_not_configured_by_default(self, isolated_settings): """Git is not configured initially.""" settings = isolated_settings assert settings.is_git_configured == False def test_git_configured_when_all_set(self, isolated_settings): """Git is configured when all required fields are set.""" settings = isolated_settings settings.git_host_type = "gitea" settings.git_host_url = "https://gitea.example.com" settings.git_host_owner = "myuser" assert settings.is_git_configured == True def test_git_not_configured_if_missing_field(self, isolated_settings): """Git not configured if any required field is missing.""" settings = isolated_settings settings.git_host_type = "github" settings.git_host_url = "https://github.com" # Missing: git_host_owner assert settings.is_git_configured == False if __name__ == "__main__": pytest.main([__file__, "-v"])