hosts/tests/test_models.py
phg 1fddff91c8 Refactor tests for PermissionManager, HostsManager, HostEntry, HostsFile, and HostsParser
- 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.
2025-08-14 17:32:02 +02:00

293 lines
11 KiB
Python

"""
Tests for the hosts data models.
This module contains unit tests for the HostEntry and HostsFile classes,
validating their functionality and data integrity.
"""
import pytest
from hosts.core.models import HostEntry, HostsFile
class TestHostEntry:
"""Test cases for the HostEntry class."""
def test_host_entry_creation(self):
"""Test basic host entry creation."""
entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
assert entry.ip_address == "127.0.0.1"
assert entry.hostnames == ["localhost"]
assert entry.is_active is True
assert entry.comment is None
assert entry.dns_name is None
def test_host_entry_with_comment(self):
"""Test host entry creation with comment."""
entry = HostEntry(
ip_address="192.168.1.1",
hostnames=["router", "gateway"],
comment="Local router",
)
assert entry.comment == "Local router"
def test_host_entry_inactive(self):
"""Test inactive host entry creation."""
entry = HostEntry(
ip_address="10.0.0.1", hostnames=["test.local"], is_active=False
)
assert entry.is_active is False
def test_invalid_ip_address(self):
"""Test that invalid IP addresses raise ValueError."""
with pytest.raises(ValueError, match="Invalid IP address"):
HostEntry(ip_address="invalid.ip", hostnames=["test"])
def test_empty_hostnames(self):
"""Test that empty hostnames list raises ValueError."""
with pytest.raises(ValueError, match="At least one hostname is required"):
HostEntry(ip_address="127.0.0.1", hostnames=[])
def test_invalid_hostname(self):
"""Test that invalid hostnames raise ValueError."""
with pytest.raises(ValueError, match="Invalid hostname"):
HostEntry(ip_address="127.0.0.1", hostnames=["invalid..hostname"])
def test_ipv6_address(self):
"""Test IPv6 address support."""
entry = HostEntry(ip_address="::1", hostnames=["localhost"])
assert entry.ip_address == "::1"
def test_to_hosts_line_active(self):
"""Test conversion to hosts file line format for active entry."""
entry = HostEntry(
ip_address="127.0.0.1", hostnames=["localhost", "local"], comment="Loopback"
)
line = entry.to_hosts_line()
assert line == "127.0.0.1\tlocalhost\tlocal\t# Loopback"
def test_to_hosts_line_inactive(self):
"""Test conversion to hosts file line format for inactive entry."""
entry = HostEntry(
ip_address="192.168.1.1", hostnames=["router"], is_active=False
)
line = entry.to_hosts_line()
assert line == "# 192.168.1.1\trouter"
def test_from_hosts_line_simple(self):
"""Test parsing simple hosts file line."""
line = "127.0.0.1 localhost"
entry = HostEntry.from_hosts_line(line)
assert entry is not None
assert entry.ip_address == "127.0.0.1"
assert entry.hostnames == ["localhost"]
assert entry.is_active is True
assert entry.comment is None
def test_from_hosts_line_with_comment(self):
"""Test parsing hosts file line with comment."""
line = "192.168.1.1 router gateway # Local network"
entry = HostEntry.from_hosts_line(line)
assert entry is not None
assert entry.ip_address == "192.168.1.1"
assert entry.hostnames == ["router", "gateway"]
assert entry.comment == "Local network"
def test_from_hosts_line_inactive(self):
"""Test parsing inactive hosts file line."""
line = "# 10.0.0.1 test.local"
entry = HostEntry.from_hosts_line(line)
assert entry is not None
assert entry.ip_address == "10.0.0.1"
assert entry.hostnames == ["test.local"]
assert entry.is_active is False
def test_from_hosts_line_empty(self):
"""Test parsing empty line returns None."""
assert HostEntry.from_hosts_line("") is None
assert HostEntry.from_hosts_line(" ") is None
def test_from_hosts_line_comment_only(self):
"""Test parsing comment-only line returns None."""
assert HostEntry.from_hosts_line("# This is just a comment") is None
def test_from_hosts_line_invalid(self):
"""Test parsing invalid line returns None."""
assert HostEntry.from_hosts_line("invalid line") is None
assert HostEntry.from_hosts_line("192.168.1.1") is None # No hostname
class TestHostsFile:
"""Test cases for the HostsFile class."""
def test_hosts_file_creation(self):
"""Test basic hosts file creation."""
hosts_file = HostsFile()
assert len(hosts_file.entries) == 0
assert len(hosts_file.header_comments) == 0
assert len(hosts_file.footer_comments) == 0
def test_add_entry(self):
"""Test adding entries to hosts file."""
hosts_file = HostsFile()
entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
hosts_file.add_entry(entry)
assert len(hosts_file.entries) == 1
assert hosts_file.entries[0] == entry
def test_add_invalid_entry(self):
"""Test that adding invalid entry raises ValueError."""
hosts_file = HostsFile()
with pytest.raises(ValueError):
# This will fail validation in add_entry
invalid_entry = HostEntry.__new__(HostEntry) # Bypass __init__
invalid_entry.ip_address = "invalid"
invalid_entry.hostnames = ["test"]
hosts_file.add_entry(invalid_entry)
def test_remove_entry(self):
"""Test removing entries from hosts file."""
hosts_file = HostsFile()
entry1 = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
entry2 = HostEntry(ip_address="192.168.1.1", hostnames=["router"])
hosts_file.add_entry(entry1)
hosts_file.add_entry(entry2)
hosts_file.remove_entry(0)
assert len(hosts_file.entries) == 1
assert hosts_file.entries[0] == entry2
def test_remove_entry_invalid_index(self):
"""Test removing entry with invalid index does nothing."""
hosts_file = HostsFile()
entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
hosts_file.add_entry(entry)
hosts_file.remove_entry(10) # Invalid index
assert len(hosts_file.entries) == 1
def test_toggle_entry(self):
"""Test toggling entry active state."""
hosts_file = HostsFile()
entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
hosts_file.add_entry(entry)
assert entry.is_active is True
hosts_file.toggle_entry(0)
assert entry.is_active is False
hosts_file.toggle_entry(0)
assert entry.is_active is True
def test_get_active_entries(self):
"""Test getting only active entries."""
hosts_file = HostsFile()
active_entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
inactive_entry = HostEntry(
ip_address="192.168.1.1", hostnames=["router"], is_active=False
)
hosts_file.add_entry(active_entry)
hosts_file.add_entry(inactive_entry)
active_entries = hosts_file.get_active_entries()
assert len(active_entries) == 1
assert active_entries[0] == active_entry
def test_get_inactive_entries(self):
"""Test getting only inactive entries."""
hosts_file = HostsFile()
active_entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
inactive_entry = HostEntry(
ip_address="192.168.1.1", hostnames=["router"], is_active=False
)
hosts_file.add_entry(active_entry)
hosts_file.add_entry(inactive_entry)
inactive_entries = hosts_file.get_inactive_entries()
assert len(inactive_entries) == 1
assert inactive_entries[0] == inactive_entry
def test_sort_by_ip(self):
"""Test sorting entries by IP address with default entries on top."""
hosts_file = HostsFile()
entry1 = HostEntry(ip_address="192.168.1.1", hostnames=["router"])
entry2 = HostEntry(
ip_address="127.0.0.1", hostnames=["localhost"]
) # Default entry
entry3 = HostEntry(ip_address="10.0.0.1", hostnames=["test"])
hosts_file.add_entry(entry1)
hosts_file.add_entry(entry2)
hosts_file.add_entry(entry3)
hosts_file.sort_by_ip()
# Default entries should come first, then sorted non-default entries
assert hosts_file.entries[0].ip_address == "127.0.0.1" # Default entry first
assert (
hosts_file.entries[1].ip_address == "10.0.0.1"
) # Then sorted non-defaults
assert hosts_file.entries[2].ip_address == "192.168.1.1"
def test_sort_by_hostname(self):
"""Test sorting entries by hostname."""
hosts_file = HostsFile()
entry1 = HostEntry(ip_address="127.0.0.1", hostnames=["zebra"])
entry2 = HostEntry(ip_address="192.168.1.1", hostnames=["alpha"])
entry3 = HostEntry(ip_address="10.0.0.1", hostnames=["beta"])
hosts_file.add_entry(entry1)
hosts_file.add_entry(entry2)
hosts_file.add_entry(entry3)
hosts_file.sort_by_hostname()
assert hosts_file.entries[0].hostnames[0] == "alpha"
assert hosts_file.entries[1].hostnames[0] == "beta"
assert hosts_file.entries[2].hostnames[0] == "zebra"
def test_find_entries_by_hostname(self):
"""Test finding entries by hostname."""
hosts_file = HostsFile()
entry1 = HostEntry(ip_address="127.0.0.1", hostnames=["localhost", "local"])
entry2 = HostEntry(ip_address="192.168.1.1", hostnames=["router"])
entry3 = HostEntry(ip_address="10.0.0.1", hostnames=["test", "localhost"])
hosts_file.add_entry(entry1)
hosts_file.add_entry(entry2)
hosts_file.add_entry(entry3)
indices = hosts_file.find_entries_by_hostname("localhost")
assert indices == [0, 2]
indices = hosts_file.find_entries_by_hostname("router")
assert indices == [1]
indices = hosts_file.find_entries_by_hostname("nonexistent")
assert indices == []
def test_find_entries_by_ip(self):
"""Test finding entries by IP address."""
hosts_file = HostsFile()
entry1 = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
entry2 = HostEntry(ip_address="192.168.1.1", hostnames=["router"])
entry3 = HostEntry(ip_address="127.0.0.1", hostnames=["local"])
hosts_file.add_entry(entry1)
hosts_file.add_entry(entry2)
hosts_file.add_entry(entry3)
indices = hosts_file.find_entries_by_ip("127.0.0.1")
assert indices == [0, 2]
indices = hosts_file.find_entries_by_ip("192.168.1.1")
assert indices == [1]
indices = hosts_file.find_entries_by_ip("10.0.0.1")
assert indices == []