"""Unit tests for configuration loading and validation.""" import os import tempfile from pathlib import Path from unittest.mock import patch import pytest from dev_env_sync.core.config import ConfigLoader, ConfigSchema, ConfigParseError class TestConfigLoader: """Tests for ConfigLoader class.""" @pytest.fixture def sample_yaml_content(self): """Sample YAML configuration content.""" return ''' version: "1.0" name: "Test Environment" description: "Test configuration" dotfiles: bashrc: source: ./dotfiles/.bashrc target: ~/.bashrc backup: true vimrc: source: ./dotfiles/.vimrc target: ~/.vimrc shell: shell: bash merge_strategy: replace editors: vscode: settings: settings_file: ./editors/vscode/settings.json extensions: - name: ms-python.python packages: - name: brew packages: - git - neovim backup: enabled: true directory: ~/.dev-env-sync-backups timestamp_format: "%Y%m%d_%H%M%S" ''' def test_load_valid_config(self, sample_yaml_content, temp_dir): """Test loading a valid configuration file.""" config_file = temp_dir / "config.yml" config_file.write_text(sample_yaml_content) loader = ConfigLoader(str(config_file)) config = loader.load() assert config is not None assert config.version == "1.0" assert config.name == "Test Environment" assert len(config.dotfiles) == 2 assert "bashrc" in config.dotfiles assert "vimrc" in config.dotfiles def test_load_minimal_config(self, temp_dir): """Test loading a minimal configuration file.""" config_file = temp_dir / "minimal.yml" config_file.write_text('version: "1.0"\nname: "Minimal"') loader = ConfigLoader(str(config_file)) config = loader.load() assert config is not None assert config.version == "1.0" assert config.name == "Minimal" assert len(config.dotfiles) == 0 def test_dotfiles_parsing(self, sample_yaml_content, temp_dir): """Test parsing dotfiles configuration.""" config_file = temp_dir / "config.yml" config_file.write_text(sample_yaml_content) loader = ConfigLoader(str(config_file)) config = loader.load() assert "bashrc" in config.dotfiles bashrc = config.dotfiles["bashrc"] assert bashrc.source == "./dotfiles/.bashrc" assert bashrc.target == "~/.bashrc" assert bashrc.backup == True def test_packages_parsing(self, sample_yaml_content, temp_dir): """Test parsing packages configuration.""" config_file = temp_dir / "config.yml" config_file.write_text(sample_yaml_content) loader = ConfigLoader(str(config_file)) config = loader.load() assert len(config.packages) == 1 brew_pkg = config.packages[0] assert brew_pkg.name == "brew" assert len(brew_pkg.packages) == 2 assert "git" in brew_pkg.packages assert "neovim" in brew_pkg.packages def test_editors_parsing(self, sample_yaml_content, temp_dir): """Test parsing editors configuration.""" config_file = temp_dir / "config.yml" config_file.write_text(sample_yaml_content) loader = ConfigLoader(str(config_file)) config = loader.load() assert "vscode" in config.editors vscode_config = config.editors["vscode"] assert "extensions" in vscode_config assert len(vscode_config["extensions"]) == 1 def test_backup_config_parsing(self, sample_yaml_content, temp_dir): """Test parsing backup configuration.""" config_file = temp_dir / "config.yml" config_file.write_text(sample_yaml_content) loader = ConfigLoader(str(config_file)) config = loader.load() assert config.backup.enabled == True assert config.backup.directory == "~/.dev-env-sync-backups" assert config.backup.timestamp_format == "%Y%m%d_%H%M%S" def test_invalid_yaml(self, temp_dir): """Test handling of invalid YAML.""" config_file = temp_dir / "invalid.yml" config_file.write_text("invalid: yaml: content: [") loader = ConfigLoader(str(config_file)) with pytest.raises(ConfigParseError): loader.load() def test_nonexistent_file(self): """Test handling of nonexistent configuration file.""" loader = ConfigLoader("/nonexistent/path/config.yml") with pytest.raises(ConfigParseError): loader.load() def test_create_default_config(self): """Test creating default configuration.""" config = ConfigLoader.create_default_config() assert config is not None assert config.version == "1.0" assert config.name == "My Dev Environment" assert len(config.dotfiles) > 0 assert len(config.packages) > 0 def test_config_to_dict(self, temp_dir): """Test converting config to dictionary.""" config_file = temp_dir / "config.yml" config_file.write_text('version: "1.0"\nname: "Test"') loader = ConfigLoader(str(config_file)) config = loader.load() config_dict = config.to_dict() assert isinstance(config_dict, dict) assert config_dict["version"] == "1.0" assert config_dict["name"] == "Test" class TestConfigValidation: """Tests for configuration validation.""" def test_valid_config_schema(self, temp_dir): """Test that valid config matches schema.""" config_file = temp_dir / "valid.yml" config_file.write_text(''' version: "1.0" name: "Valid Test" description: "Testing validation" dotfiles: test: source: ./test target: ~/.test backup: true backup: enabled: true directory: ~/.test-backups ''') loader = ConfigLoader(str(config_file)) config = loader.load() assert config.version == "1.0" assert config.backup.enabled == True def test_string_dotfile_shorthand(self, temp_dir): """Test string shorthand for dotfiles.""" config_file = temp_dir / "shorthand.yml" config_file.write_text(''' version: "1.0" dotfiles: bashrc: ./bashrc ''') loader = ConfigLoader(str(config_file)) config = loader.load() assert "bashrc" in config.dotfiles assert config.dotfiles["bashrc"].source == "./bashrc" assert config.dotfiles["bashrc"].target == "~/.bashrc"