- Updated test cases in test_manager.py to improve readability and consistency. - Simplified assertions and mock setups in tests for PermissionManager. - Enhanced test coverage for HostsManager, including edit mode and entry manipulation tests. - Improved test structure in test_models.py for HostEntry and HostsFile, ensuring clarity in test cases. - Refined test cases in test_parser.py for better organization and readability. - Adjusted test_save_confirmation_modal.py to maintain consistency in mocking and assertions.
305 lines
11 KiB
Python
305 lines
11 KiB
Python
"""
|
|
Tests for the configuration management module.
|
|
|
|
This module contains unit tests for the Config class,
|
|
validating configuration loading, saving, and management functionality.
|
|
"""
|
|
|
|
import tempfile
|
|
import json
|
|
from pathlib import Path
|
|
from unittest.mock import patch, mock_open
|
|
|
|
from hosts.core.config import Config
|
|
|
|
|
|
class TestConfig:
|
|
"""Test cases for the Config class."""
|
|
|
|
def test_config_initialization(self):
|
|
"""Test basic config initialization with defaults."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
# Check default settings
|
|
assert config.get("show_default_entries") is False
|
|
assert len(config.get("default_entries", [])) == 3
|
|
assert config.get("window_settings", {}).get("last_sort_column") == ""
|
|
assert config.get("window_settings", {}).get("last_sort_ascending") is True
|
|
|
|
def test_default_settings_structure(self):
|
|
"""Test that default settings have the expected structure."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
default_entries = config.get("default_entries", [])
|
|
assert len(default_entries) == 3
|
|
|
|
# Check localhost entries
|
|
localhost_entries = [
|
|
e for e in default_entries if e["hostname"] == "localhost"
|
|
]
|
|
assert len(localhost_entries) == 2 # IPv4 and IPv6
|
|
|
|
# Check broadcasthost entry
|
|
broadcast_entries = [
|
|
e for e in default_entries if e["hostname"] == "broadcasthost"
|
|
]
|
|
assert len(broadcast_entries) == 1
|
|
assert broadcast_entries[0]["ip"] == "255.255.255.255"
|
|
|
|
def test_config_paths(self):
|
|
"""Test that config paths are set correctly."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
expected_dir = Path.home() / ".config" / "hosts-manager"
|
|
expected_file = expected_dir / "config.json"
|
|
|
|
assert config.config_dir == expected_dir
|
|
assert config.config_file == expected_file
|
|
|
|
def test_get_existing_key(self):
|
|
"""Test getting an existing configuration key."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
result = config.get("show_default_entries")
|
|
assert result is False
|
|
|
|
def test_get_nonexistent_key_with_default(self):
|
|
"""Test getting a nonexistent key with default value."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
result = config.get("nonexistent_key", "default_value")
|
|
assert result == "default_value"
|
|
|
|
def test_get_nonexistent_key_without_default(self):
|
|
"""Test getting a nonexistent key without default value."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
result = config.get("nonexistent_key")
|
|
assert result is None
|
|
|
|
def test_set_configuration_value(self):
|
|
"""Test setting a configuration value."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
config.set("test_key", "test_value")
|
|
assert config.get("test_key") == "test_value"
|
|
|
|
def test_set_overwrites_existing_value(self):
|
|
"""Test that setting overwrites existing values."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
# Set initial value
|
|
config.set("show_default_entries", True)
|
|
assert config.get("show_default_entries") is True
|
|
|
|
# Overwrite with new value
|
|
config.set("show_default_entries", False)
|
|
assert config.get("show_default_entries") is False
|
|
|
|
def test_is_default_entry_true(self):
|
|
"""Test identifying default entries correctly."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
# Test localhost IPv4
|
|
assert config.is_default_entry("127.0.0.1", "localhost") is True
|
|
|
|
# Test localhost IPv6
|
|
assert config.is_default_entry("::1", "localhost") is True
|
|
|
|
# Test broadcasthost
|
|
assert config.is_default_entry("255.255.255.255", "broadcasthost") is True
|
|
|
|
def test_is_default_entry_false(self):
|
|
"""Test that non-default entries are not identified as default."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
# Test custom entries
|
|
assert config.is_default_entry("192.168.1.1", "router") is False
|
|
assert config.is_default_entry("10.0.0.1", "test.local") is False
|
|
assert config.is_default_entry("127.0.0.1", "custom") is False
|
|
|
|
def test_should_show_default_entries_default(self):
|
|
"""Test default value for show_default_entries."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
|
|
assert config.should_show_default_entries() is False
|
|
|
|
def test_should_show_default_entries_configured(self):
|
|
"""Test configured value for show_default_entries."""
|
|
with patch.object(Config, "load"):
|
|
config = Config()
|
|
config.set("show_default_entries", True)
|
|
|
|
assert config.should_show_default_entries() is True
|
|
|
|
def test_toggle_show_default_entries(self):
|
|
"""Test toggling the show_default_entries setting."""
|
|
with patch.object(Config, "load"), patch.object(Config, "save") as mock_save:
|
|
config = Config()
|
|
|
|
# Initial state should be False
|
|
assert config.should_show_default_entries() is False
|
|
|
|
# Toggle to True
|
|
config.toggle_show_default_entries()
|
|
assert config.should_show_default_entries() is True
|
|
mock_save.assert_called_once()
|
|
|
|
# Toggle back to False
|
|
mock_save.reset_mock()
|
|
config.toggle_show_default_entries()
|
|
assert config.should_show_default_entries() is False
|
|
mock_save.assert_called_once()
|
|
|
|
def test_load_nonexistent_file(self):
|
|
"""Test loading config when file doesn't exist."""
|
|
with patch("pathlib.Path.exists", return_value=False):
|
|
config = Config()
|
|
|
|
# Should use defaults when file doesn't exist
|
|
assert config.get("show_default_entries") is False
|
|
|
|
def test_load_existing_file(self):
|
|
"""Test loading config from existing file."""
|
|
test_config = {"show_default_entries": True, "custom_setting": "custom_value"}
|
|
|
|
with (
|
|
patch("pathlib.Path.exists", return_value=True),
|
|
patch("builtins.open", mock_open(read_data=json.dumps(test_config))),
|
|
):
|
|
config = Config()
|
|
|
|
# Should load values from file
|
|
assert config.get("show_default_entries") is True
|
|
assert config.get("custom_setting") == "custom_value"
|
|
|
|
# Should still have defaults for missing keys
|
|
assert len(config.get("default_entries", [])) == 3
|
|
|
|
def test_load_invalid_json(self):
|
|
"""Test loading config with invalid JSON falls back to defaults."""
|
|
with (
|
|
patch("pathlib.Path.exists", return_value=True),
|
|
patch("builtins.open", mock_open(read_data="invalid json")),
|
|
):
|
|
config = Config()
|
|
|
|
# Should use defaults when JSON is invalid
|
|
assert config.get("show_default_entries") is False
|
|
|
|
def test_load_file_io_error(self):
|
|
"""Test loading config with file I/O error falls back to defaults."""
|
|
with (
|
|
patch("pathlib.Path.exists", return_value=True),
|
|
patch("builtins.open", side_effect=IOError("File error")),
|
|
):
|
|
config = Config()
|
|
|
|
# Should use defaults when file can't be read
|
|
assert config.get("show_default_entries") is False
|
|
|
|
def test_save_creates_directory(self):
|
|
"""Test that save creates config directory if it doesn't exist."""
|
|
with (
|
|
patch.object(Config, "load"),
|
|
patch("pathlib.Path.mkdir") as mock_mkdir,
|
|
patch("builtins.open", mock_open()) as mock_file,
|
|
):
|
|
config = Config()
|
|
config.save()
|
|
|
|
# Should create directory with parents=True, exist_ok=True
|
|
mock_mkdir.assert_called_once_with(parents=True, exist_ok=True)
|
|
mock_file.assert_called_once()
|
|
|
|
def test_save_writes_json(self):
|
|
"""Test that save writes configuration as JSON."""
|
|
with (
|
|
patch.object(Config, "load"),
|
|
patch("pathlib.Path.mkdir"),
|
|
patch("builtins.open", mock_open()) as mock_file,
|
|
):
|
|
config = Config()
|
|
config.set("test_key", "test_value")
|
|
config.save()
|
|
|
|
# Check that file was opened for writing
|
|
mock_file.assert_called_once_with(config.config_file, "w")
|
|
|
|
# Check that JSON was written
|
|
handle = mock_file()
|
|
written_data = "".join(call.args[0] for call in handle.write.call_args_list)
|
|
|
|
# Should be valid JSON containing our test data
|
|
parsed_data = json.loads(written_data)
|
|
assert parsed_data["test_key"] == "test_value"
|
|
|
|
def test_save_io_error_silent_fail(self):
|
|
"""Test that save silently fails on I/O error."""
|
|
with (
|
|
patch.object(Config, "load"),
|
|
patch("pathlib.Path.mkdir"),
|
|
patch("builtins.open", side_effect=IOError("Write error")),
|
|
):
|
|
config = Config()
|
|
|
|
# Should not raise exception
|
|
config.save()
|
|
|
|
def test_save_directory_creation_error_silent_fail(self):
|
|
"""Test that save silently fails on directory creation error."""
|
|
with (
|
|
patch.object(Config, "load"),
|
|
patch("pathlib.Path.mkdir", side_effect=OSError("Permission denied")),
|
|
):
|
|
config = Config()
|
|
|
|
# Should not raise exception
|
|
config.save()
|
|
|
|
def test_integration_load_save_roundtrip(self):
|
|
"""Test complete load/save cycle with temporary file."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
config_dir = Path(temp_dir) / "hosts-manager"
|
|
config_file = config_dir / "config.json"
|
|
|
|
with patch.object(Config, "__init__", lambda self: None):
|
|
config = Config()
|
|
config.config_dir = config_dir
|
|
config.config_file = config_file
|
|
config._settings = config._load_default_settings()
|
|
|
|
# Modify some settings
|
|
config.set("show_default_entries", True)
|
|
config.set("custom_setting", "test_value")
|
|
|
|
# Save configuration
|
|
config.save()
|
|
|
|
# Verify file was created
|
|
assert config_file.exists()
|
|
|
|
# Create new config instance and load
|
|
config2 = Config()
|
|
config2.config_dir = config_dir
|
|
config2.config_file = config_file
|
|
config2._settings = config2._load_default_settings()
|
|
config2.load()
|
|
|
|
# Verify settings were loaded correctly
|
|
assert config2.get("show_default_entries") is True
|
|
assert config2.get("custom_setting") == "test_value"
|
|
|
|
# Verify defaults are still present
|
|
assert len(config2.get("default_entries", [])) == 3
|