diff --git a/confsync/tests/test_detect.py b/confsync/tests/test_detect.py new file mode 100644 index 0000000..72cbc71 --- /dev/null +++ b/confsync/tests/test_detect.py @@ -0,0 +1,232 @@ +"""Tests for configuration detection system.""" + +import pytest +import tempfile +import os +from pathlib import Path +from unittest.mock import patch + +from confsync.detectors.base import BaseDetector, DetectorRegistry +from confsync.detectors.editor import VimDetector +from confsync.detectors.git import GitConfigDetector +from confsync.detectors.shell import BashDetector +from confsync.models.config_models import ConfigCategory + + +class TestBaseDetector: + """Tests for the base detector class.""" + + def test_detector_abstract_methods(self): + """Test that BaseDetector requires abstract method implementation.""" + class TestDetector(BaseDetector): + category = ConfigCategory.EDITOR + tool_name = "test" + + def detect(self): + return [] + + detector = TestDetector() + assert detector.category == ConfigCategory.EDITOR + assert detector.tool_name == "test" + + def test_create_config_file(self): + """Test ConfigFile creation from path.""" + class TestDetector(BaseDetector): + category = ConfigCategory.EDITOR + tool_name = "test" + + def detect(self): + return [] + + detector = TestDetector() + + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + f.write('{"test": true}') + temp_path = f.name + + try: + config = detector._create_config_file(temp_path) + assert config.path == temp_path + assert config.name.endswith('.json') + assert config.category == ConfigCategory.EDITOR + assert config.tool_name == "test" + assert config.content == '{"test": true}' + finally: + os.unlink(temp_path) + + +class TestDetectorRegistry: + """Tests for the detector registry.""" + + def test_register_detector(self): + """Test detector registration.""" + class TestDetector(BaseDetector): + category = ConfigCategory.EDITOR + tool_name = "test_register" + + def detect(self): + return [] + + DetectorRegistry.register(TestDetector) + detector = DetectorRegistry.get_detector("test_register") + assert detector is not None + assert detector.tool_name == "test_register" + + def test_detect_all(self): + """Test running all detectors.""" + with tempfile.TemporaryDirectory() as tmpdir: + home = Path(tmpdir) + vimrc = home / ".vimrc" + vimrc.write_text("set nocompatible") + + with patch('pathlib.Path.home', return_value=home): + DetectorRegistry.detect_all([ConfigCategory.EDITOR]) + + def test_list_tools(self): + """Test listing available tools.""" + tools = DetectorRegistry.list_tools() + assert isinstance(tools, list) + assert len(tools) > 0 + + def test_list_categories(self): + """Test listing available categories.""" + categories = DetectorRegistry.list_categories() + assert ConfigCategory.EDITOR in categories + assert ConfigCategory.TERMINAL in categories + assert ConfigCategory.GIT in categories + + +class TestSpecificDetectors: + """Tests for specific detector implementations.""" + + def test_vim_detector(self): + """Test Vim detector.""" + with tempfile.TemporaryDirectory() as tmpdir: + home = Path(tmpdir) + vimrc = home / ".vimrc" + vimrc.write_text("set nocompatible\nsyntax on") + + with patch('pathlib.Path.home', return_value=home): + detector = VimDetector() + configs = detector.detect() + + assert len(configs) >= 1 + assert any(c.tool_name == "vim" for c in configs) + + def test_git_detector(self): + """Test Git config detector.""" + with tempfile.TemporaryDirectory() as tmpdir: + home = Path(tmpdir) + gitconfig = home / ".gitconfig" + gitconfig.write_text("[user]\n\tname = Test User\n\temail = test@example.com") + + with patch('pathlib.Path.home', return_value=home): + detector = GitConfigDetector() + configs = detector.detect() + + assert len(configs) >= 1 + assert any(c.tool_name == "git" for c in configs) + + def test_bash_detector(self): + """Test Bash detector.""" + with tempfile.TemporaryDirectory() as tmpdir: + home = Path(tmpdir) + bashrc = home / ".bashrc" + bashrc.write_text("export PATH=$PATH:/usr/local/bin") + + with patch('pathlib.Path.home', return_value=home): + detector = BashDetector() + configs = detector.detect() + + assert len(configs) >= 1 + assert any(c.tool_name == "bash" for c in configs) + + +class TestConfigModels: + """Tests for configuration models.""" + + def test_config_file_hash(self): + """Test hash calculation.""" + from confsync.models.config_models import calculate_file_hash + + content = "test content" + hash1 = calculate_file_hash(content) + hash2 = calculate_file_hash(content) + + assert hash1 == hash2 + assert len(hash1) == 64 + + def test_config_file_serialization(self): + """Test ConfigFile serialization and deserialization.""" + from confsync.models.config_models import ConfigFile, ConfigCategory + + config = ConfigFile( + path="/test/path", + name="test.json", + category=ConfigCategory.EDITOR, + tool_name="test", + content='{"key": "value"}', + ) + + data = config.to_dict() + restored = ConfigFile.from_dict(data) + + assert restored.path == config.path + assert restored.name == config.name + assert restored.category == config.category + assert restored.content == config.content + + def test_manifest_operations(self): + """Test manifest add/remove operations.""" + from confsync.models.config_models import Manifest, ManifestEntry, ConfigFile, ConfigCategory + + manifest = Manifest() + config = ConfigFile( + path="/test/.vimrc", + name=".vimrc", + category=ConfigCategory.EDITOR, + tool_name="vim", + ) + entry = ManifestEntry(config_file=config) + + manifest.add_entry(entry) + + assert len(manifest.entries) == 1 + assert config.id in manifest.entries + + manifest.remove_entry(config.id) + assert len(manifest.entries) == 0 + + def test_manifest_by_category(self): + """Test filtering manifest by category.""" + from confsync.models.config_models import Manifest, ManifestEntry, ConfigFile, ConfigCategory + + manifest = Manifest() + + vim_config = ConfigFile( + path="/test/.vimrc", + name=".vimrc", + category=ConfigCategory.EDITOR, + tool_name="vim", + ) + git_config = ConfigFile( + path="/test/.gitconfig", + name=".gitconfig", + category=ConfigCategory.GIT, + tool_name="git", + ) + + manifest.add_entry(ManifestEntry(config_file=vim_config)) + manifest.add_entry(ManifestEntry(config_file=git_config)) + + editors = manifest.get_by_category(ConfigCategory.EDITOR) + assert len(editors) == 1 + assert editors[0].config_file.tool_name == "vim" + + git_entries = manifest.get_by_category(ConfigCategory.GIT) + assert len(git_entries) == 1 + assert git_entries[0].config_file.tool_name == "git" + + +if __name__ == "__main__": + pytest.main([__file__, "-v"])