- Implement tests for ConfigValidator to ensure proper validation of configuration settings, including valid configurations, required fields, type checks, and error handling. - Create tests for ConfigProfile to verify profile management functionalities such as saving, loading, listing, and deleting profiles. - Add tests for ConfigExporter to validate JSON export and import processes, including error handling for non-existent files and invalid JSON. - Introduce tests for SettingsDialog to confirm proper initialization, tab existence, and configuration data retrieval and application.
302 lines
10 KiB
Python
302 lines
10 KiB
Python
"""Tests for configuration management module."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from webdrop_bridge.config import Config, ConfigurationError
|
|
from webdrop_bridge.core.config_manager import ConfigExporter, ConfigProfile, ConfigValidator
|
|
|
|
|
|
class TestConfigValidator:
|
|
"""Test configuration validation."""
|
|
|
|
def test_validate_valid_config(self):
|
|
"""Test validation passes for valid configuration."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
"log_level": "INFO",
|
|
"log_file": None,
|
|
"allowed_roots": ["/home", "/data"],
|
|
"allowed_urls": ["http://example.com"],
|
|
"webapp_url": "http://localhost:8080",
|
|
"window_width": 800,
|
|
"window_height": 600,
|
|
"enable_logging": True,
|
|
}
|
|
|
|
errors = ConfigValidator.validate(config_dict)
|
|
assert errors == []
|
|
|
|
def test_validate_missing_required_field(self):
|
|
"""Test validation fails for missing required fields."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
}
|
|
|
|
errors = ConfigValidator.validate(config_dict)
|
|
assert len(errors) > 0
|
|
assert any("log_level" in e for e in errors)
|
|
|
|
def test_validate_invalid_type(self):
|
|
"""Test validation fails for invalid type."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
"log_level": "INFO",
|
|
"log_file": None,
|
|
"allowed_roots": ["/home"],
|
|
"allowed_urls": ["http://example.com"],
|
|
"webapp_url": "http://localhost:8080",
|
|
"window_width": "800", # Should be int
|
|
"window_height": 600,
|
|
"enable_logging": True,
|
|
}
|
|
|
|
errors = ConfigValidator.validate(config_dict)
|
|
assert len(errors) > 0
|
|
assert any("window_width" in e for e in errors)
|
|
|
|
def test_validate_invalid_log_level(self):
|
|
"""Test validation fails for invalid log level."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
"log_level": "TRACE", # Invalid
|
|
"log_file": None,
|
|
"allowed_roots": [],
|
|
"allowed_urls": [],
|
|
"webapp_url": "http://localhost:8080",
|
|
"window_width": 800,
|
|
"window_height": 600,
|
|
"enable_logging": True,
|
|
}
|
|
|
|
errors = ConfigValidator.validate(config_dict)
|
|
assert len(errors) > 0
|
|
assert any("log_level" in e for e in errors)
|
|
|
|
def test_validate_invalid_version_format(self):
|
|
"""Test validation fails for invalid version format."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0", # Should be X.Y.Z
|
|
"log_level": "INFO",
|
|
"log_file": None,
|
|
"allowed_roots": [],
|
|
"allowed_urls": [],
|
|
"webapp_url": "http://localhost:8080",
|
|
"window_width": 800,
|
|
"window_height": 600,
|
|
"enable_logging": True,
|
|
}
|
|
|
|
errors = ConfigValidator.validate(config_dict)
|
|
# Note: Current implementation doesn't check regex pattern
|
|
# This test documents the expected behavior for future enhancement
|
|
|
|
def test_validate_out_of_range_value(self):
|
|
"""Test validation fails for values outside allowed range."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
"log_level": "INFO",
|
|
"log_file": None,
|
|
"allowed_roots": [],
|
|
"allowed_urls": [],
|
|
"webapp_url": "http://localhost:8080",
|
|
"window_width": 100, # Below minimum of 400
|
|
"window_height": 600,
|
|
"enable_logging": True,
|
|
}
|
|
|
|
errors = ConfigValidator.validate(config_dict)
|
|
assert len(errors) > 0
|
|
assert any("window_width" in e for e in errors)
|
|
|
|
def test_validate_or_raise_valid(self):
|
|
"""Test validate_or_raise succeeds for valid config."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
"log_level": "INFO",
|
|
"log_file": None,
|
|
"allowed_roots": [],
|
|
"allowed_urls": [],
|
|
"webapp_url": "http://localhost:8080",
|
|
"window_width": 800,
|
|
"window_height": 600,
|
|
"enable_logging": True,
|
|
}
|
|
|
|
# Should not raise
|
|
ConfigValidator.validate_or_raise(config_dict)
|
|
|
|
def test_validate_or_raise_invalid(self):
|
|
"""Test validate_or_raise raises for invalid config."""
|
|
config_dict = {
|
|
"app_name": "WebDrop Bridge",
|
|
"app_version": "1.0.0",
|
|
}
|
|
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
ConfigValidator.validate_or_raise(config_dict)
|
|
|
|
assert "Configuration validation failed" in str(exc_info.value)
|
|
|
|
|
|
class TestConfigProfile:
|
|
"""Test configuration profile management."""
|
|
|
|
@pytest.fixture
|
|
def profile_manager(self, tmp_path, monkeypatch):
|
|
"""Create profile manager with temporary directory."""
|
|
monkeypatch.setattr(ConfigProfile, "PROFILES_DIR", tmp_path / "profiles")
|
|
return ConfigProfile()
|
|
|
|
@pytest.fixture
|
|
def sample_config(self):
|
|
"""Create sample configuration."""
|
|
return Config(
|
|
app_name="WebDrop Bridge",
|
|
app_version="1.0.0",
|
|
log_level="INFO",
|
|
log_file=None,
|
|
allowed_roots=[Path("/home"), Path("/data")],
|
|
allowed_urls=["http://example.com"],
|
|
webapp_url="http://localhost:8080",
|
|
window_width=800,
|
|
window_height=600,
|
|
enable_logging=True,
|
|
)
|
|
|
|
def test_save_profile(self, profile_manager, sample_config):
|
|
"""Test saving a profile."""
|
|
profile_path = profile_manager.save_profile("work", sample_config)
|
|
|
|
assert profile_path.exists()
|
|
assert profile_path.name == "work.json"
|
|
|
|
def test_load_profile(self, profile_manager, sample_config):
|
|
"""Test loading a profile."""
|
|
profile_manager.save_profile("work", sample_config)
|
|
loaded = profile_manager.load_profile("work")
|
|
|
|
assert loaded["app_name"] == "WebDrop Bridge"
|
|
assert loaded["log_level"] == "INFO"
|
|
assert loaded["window_width"] == 800
|
|
|
|
def test_load_nonexistent_profile(self, profile_manager):
|
|
"""Test loading nonexistent profile raises error."""
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
profile_manager.load_profile("nonexistent")
|
|
|
|
assert "Profile not found" in str(exc_info.value)
|
|
|
|
def test_list_profiles(self, profile_manager, sample_config):
|
|
"""Test listing profiles."""
|
|
profile_manager.save_profile("work", sample_config)
|
|
profile_manager.save_profile("personal", sample_config)
|
|
|
|
profiles = profile_manager.list_profiles()
|
|
|
|
assert "work" in profiles
|
|
assert "personal" in profiles
|
|
assert len(profiles) == 2
|
|
|
|
def test_delete_profile(self, profile_manager, sample_config):
|
|
"""Test deleting a profile."""
|
|
profile_manager.save_profile("work", sample_config)
|
|
assert profile_manager.list_profiles() == ["work"]
|
|
|
|
profile_manager.delete_profile("work")
|
|
assert profile_manager.list_profiles() == []
|
|
|
|
def test_delete_nonexistent_profile(self, profile_manager):
|
|
"""Test deleting nonexistent profile raises error."""
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
profile_manager.delete_profile("nonexistent")
|
|
|
|
assert "Profile not found" in str(exc_info.value)
|
|
|
|
def test_invalid_profile_name(self, profile_manager, sample_config):
|
|
"""Test invalid profile names are rejected."""
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
profile_manager.save_profile("work/personal", sample_config)
|
|
|
|
assert "Invalid profile name" in str(exc_info.value)
|
|
|
|
|
|
class TestConfigExporter:
|
|
"""Test configuration export/import."""
|
|
|
|
@pytest.fixture
|
|
def sample_config(self):
|
|
"""Create sample configuration."""
|
|
return Config(
|
|
app_name="WebDrop Bridge",
|
|
app_version="1.0.0",
|
|
log_level="INFO",
|
|
log_file=None,
|
|
allowed_roots=[Path("/home"), Path("/data")],
|
|
allowed_urls=["http://example.com"],
|
|
webapp_url="http://localhost:8080",
|
|
window_width=800,
|
|
window_height=600,
|
|
enable_logging=True,
|
|
)
|
|
|
|
def test_export_to_json(self, tmp_path, sample_config):
|
|
"""Test exporting configuration to JSON."""
|
|
output_file = tmp_path / "config.json"
|
|
|
|
ConfigExporter.export_to_json(sample_config, output_file)
|
|
|
|
assert output_file.exists()
|
|
|
|
data = json.loads(output_file.read_text())
|
|
assert data["app_name"] == "WebDrop Bridge"
|
|
assert data["log_level"] == "INFO"
|
|
|
|
def test_import_from_json(self, tmp_path, sample_config):
|
|
"""Test importing configuration from JSON."""
|
|
# Export first
|
|
output_file = tmp_path / "config.json"
|
|
ConfigExporter.export_to_json(sample_config, output_file)
|
|
|
|
# Import
|
|
imported = ConfigExporter.import_from_json(output_file)
|
|
|
|
assert imported["app_name"] == "WebDrop Bridge"
|
|
assert imported["log_level"] == "INFO"
|
|
assert imported["window_width"] == 800
|
|
|
|
def test_import_nonexistent_file(self):
|
|
"""Test importing nonexistent file raises error."""
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
ConfigExporter.import_from_json(Path("/nonexistent/file.json"))
|
|
|
|
assert "File not found" in str(exc_info.value)
|
|
|
|
def test_import_invalid_json(self, tmp_path):
|
|
"""Test importing invalid JSON raises error."""
|
|
invalid_file = tmp_path / "invalid.json"
|
|
invalid_file.write_text("{ invalid json }")
|
|
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
ConfigExporter.import_from_json(invalid_file)
|
|
|
|
assert "Invalid JSON" in str(exc_info.value)
|
|
|
|
def test_import_invalid_config(self, tmp_path):
|
|
"""Test importing JSON with invalid config raises error."""
|
|
invalid_file = tmp_path / "invalid_config.json"
|
|
invalid_file.write_text('{"app_name": "test"}') # Missing required fields
|
|
|
|
with pytest.raises(ConfigurationError) as exc_info:
|
|
ConfigExporter.import_from_json(invalid_file)
|
|
|
|
assert "Configuration validation failed" in str(exc_info.value)
|