299 lines
11 KiB
Python
299 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 == []
|