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.
This commit is contained in:
parent
43fa8c871a
commit
1fddff91c8
18 changed files with 1364 additions and 1038 deletions
|
@ -15,49 +15,49 @@ from hosts.core.models import HostEntry, HostsFile
|
|||
|
||||
class TestHostsParser:
|
||||
"""Test cases for the HostsParser class."""
|
||||
|
||||
|
||||
def test_parser_initialization(self):
|
||||
"""Test parser initialization with default and custom paths."""
|
||||
# Default path
|
||||
parser = HostsParser()
|
||||
assert str(parser.file_path) == "/etc/hosts"
|
||||
|
||||
|
||||
# Custom path
|
||||
custom_path = "/tmp/test_hosts"
|
||||
parser = HostsParser(custom_path)
|
||||
assert str(parser.file_path) == custom_path
|
||||
|
||||
|
||||
def test_parse_simple_hosts_file(self):
|
||||
"""Test parsing a simple hosts file."""
|
||||
content = """127.0.0.1 localhost
|
||||
192.168.1.1 router
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
|
||||
|
||||
parser = HostsParser(f.name)
|
||||
hosts_file = parser.parse()
|
||||
|
||||
|
||||
assert len(hosts_file.entries) == 2
|
||||
|
||||
|
||||
# Check first entry
|
||||
entry1 = hosts_file.entries[0]
|
||||
assert entry1.ip_address == "127.0.0.1"
|
||||
assert entry1.hostnames == ["localhost"]
|
||||
assert entry1.is_active is True
|
||||
assert entry1.comment is None
|
||||
|
||||
|
||||
# Check second entry
|
||||
entry2 = hosts_file.entries[1]
|
||||
assert entry2.ip_address == "192.168.1.1"
|
||||
assert entry2.hostnames == ["router"]
|
||||
assert entry2.is_active is True
|
||||
assert entry2.comment is None
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_parse_hosts_file_with_comments(self):
|
||||
"""Test parsing hosts file with comments and inactive entries."""
|
||||
content = """# This is a header comment
|
||||
|
@ -69,93 +69,93 @@ class TestHostsParser:
|
|||
|
||||
# Footer comment
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
|
||||
|
||||
parser = HostsParser(f.name)
|
||||
hosts_file = parser.parse()
|
||||
|
||||
|
||||
# Check header comments
|
||||
assert len(hosts_file.header_comments) == 2
|
||||
assert hosts_file.header_comments[0] == "This is a header comment"
|
||||
assert hosts_file.header_comments[1] == "Another header comment"
|
||||
|
||||
|
||||
# Check entries
|
||||
assert len(hosts_file.entries) == 3
|
||||
|
||||
|
||||
# Active entry with comment
|
||||
entry1 = hosts_file.entries[0]
|
||||
assert entry1.ip_address == "127.0.0.1"
|
||||
assert entry1.hostnames == ["localhost", "loopback"]
|
||||
assert entry1.comment == "Loopback address"
|
||||
assert entry1.is_active is True
|
||||
|
||||
|
||||
# Another active entry
|
||||
entry2 = hosts_file.entries[1]
|
||||
assert entry2.ip_address == "192.168.1.1"
|
||||
assert entry2.hostnames == ["router", "gateway"]
|
||||
assert entry2.comment == "Local router"
|
||||
assert entry2.is_active is True
|
||||
|
||||
|
||||
# Inactive entry
|
||||
entry3 = hosts_file.entries[2]
|
||||
assert entry3.ip_address == "10.0.0.1"
|
||||
assert entry3.hostnames == ["test.local"]
|
||||
assert entry3.comment == "Disabled test entry"
|
||||
assert entry3.is_active is False
|
||||
|
||||
|
||||
# Check footer comments
|
||||
assert len(hosts_file.footer_comments) == 1
|
||||
assert hosts_file.footer_comments[0] == "Footer comment"
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_parse_empty_file(self):
|
||||
"""Test parsing an empty hosts file."""
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write("")
|
||||
f.flush()
|
||||
|
||||
|
||||
parser = HostsParser(f.name)
|
||||
hosts_file = parser.parse()
|
||||
|
||||
|
||||
assert len(hosts_file.entries) == 0
|
||||
assert len(hosts_file.header_comments) == 0
|
||||
assert len(hosts_file.footer_comments) == 0
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_parse_comments_only_file(self):
|
||||
"""Test parsing a file with only comments."""
|
||||
content = """# This is a comment
|
||||
# Another comment
|
||||
# Yet another comment
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
|
||||
|
||||
parser = HostsParser(f.name)
|
||||
hosts_file = parser.parse()
|
||||
|
||||
|
||||
assert len(hosts_file.entries) == 0
|
||||
assert len(hosts_file.header_comments) == 3
|
||||
assert hosts_file.header_comments[0] == "This is a comment"
|
||||
assert hosts_file.header_comments[1] == "Another comment"
|
||||
assert hosts_file.header_comments[2] == "Yet another comment"
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_parse_nonexistent_file(self):
|
||||
"""Test parsing a nonexistent file raises FileNotFoundError."""
|
||||
parser = HostsParser("/nonexistent/path/hosts")
|
||||
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
parser.parse()
|
||||
|
||||
|
||||
def test_serialize_simple_hosts_file(self):
|
||||
"""Test serializing a simple hosts file."""
|
||||
hosts_file = HostsFile()
|
||||
|
@ -177,30 +177,24 @@ class TestHostsParser:
|
|||
192.168.1.1\trouter
|
||||
"""
|
||||
assert content == expected
|
||||
|
||||
|
||||
def test_serialize_hosts_file_with_comments(self):
|
||||
"""Test serializing hosts file with comments."""
|
||||
hosts_file = HostsFile()
|
||||
hosts_file.header_comments = ["Header comment 1", "Header comment 2"]
|
||||
hosts_file.footer_comments = ["Footer comment"]
|
||||
|
||||
|
||||
entry1 = HostEntry(
|
||||
ip_address="127.0.0.1",
|
||||
hostnames=["localhost"],
|
||||
comment="Loopback"
|
||||
ip_address="127.0.0.1", hostnames=["localhost"], comment="Loopback"
|
||||
)
|
||||
entry2 = HostEntry(
|
||||
ip_address="10.0.0.1",
|
||||
hostnames=["test"],
|
||||
is_active=False
|
||||
)
|
||||
|
||||
entry2 = HostEntry(ip_address="10.0.0.1", hostnames=["test"], is_active=False)
|
||||
|
||||
hosts_file.add_entry(entry1)
|
||||
hosts_file.add_entry(entry2)
|
||||
|
||||
|
||||
parser = HostsParser()
|
||||
content = parser.serialize(hosts_file)
|
||||
|
||||
|
||||
expected = """# Header comment 1
|
||||
# Header comment 2
|
||||
# Managed by hosts - https://git.s1q.dev/phg/hosts
|
||||
|
@ -210,13 +204,13 @@ class TestHostsParser:
|
|||
# Footer comment
|
||||
"""
|
||||
assert content == expected
|
||||
|
||||
|
||||
def test_serialize_empty_hosts_file(self):
|
||||
"""Test serializing an empty hosts file."""
|
||||
hosts_file = HostsFile()
|
||||
parser = HostsParser()
|
||||
content = parser.serialize(hosts_file)
|
||||
|
||||
|
||||
expected = """# #
|
||||
# Host Database
|
||||
#
|
||||
|
@ -224,19 +218,19 @@ class TestHostsParser:
|
|||
# #
|
||||
"""
|
||||
assert content == expected
|
||||
|
||||
|
||||
def test_write_hosts_file(self):
|
||||
"""Test writing hosts file to disk."""
|
||||
hosts_file = HostsFile()
|
||||
entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
hosts_file.add_entry(entry)
|
||||
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
parser = HostsParser(f.name)
|
||||
parser.write(hosts_file, backup=False)
|
||||
|
||||
|
||||
# Read back and verify
|
||||
with open(f.name, 'r') as read_file:
|
||||
with open(f.name, "r") as read_file:
|
||||
content = read_file.read()
|
||||
expected = """# #
|
||||
# Host Database
|
||||
|
@ -246,37 +240,37 @@ class TestHostsParser:
|
|||
127.0.0.1\tlocalhost
|
||||
"""
|
||||
assert content == expected
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_write_hosts_file_with_backup(self):
|
||||
"""Test writing hosts file with backup creation."""
|
||||
# Create initial file
|
||||
initial_content = "192.168.1.1 router\n"
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write(initial_content)
|
||||
f.flush()
|
||||
|
||||
|
||||
# Create new hosts file to write
|
||||
hosts_file = HostsFile()
|
||||
entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
hosts_file.add_entry(entry)
|
||||
|
||||
|
||||
parser = HostsParser(f.name)
|
||||
parser.write(hosts_file, backup=True)
|
||||
|
||||
|
||||
# Check that backup was created
|
||||
backup_path = Path(f.name).with_suffix('.bak')
|
||||
backup_path = Path(f.name).with_suffix(".bak")
|
||||
assert backup_path.exists()
|
||||
|
||||
|
||||
# Check backup content
|
||||
with open(backup_path, 'r') as backup_file:
|
||||
with open(backup_path, "r") as backup_file:
|
||||
backup_content = backup_file.read()
|
||||
assert backup_content == initial_content
|
||||
|
||||
|
||||
# Check new content
|
||||
with open(f.name, 'r') as new_file:
|
||||
with open(f.name, "r") as new_file:
|
||||
new_content = new_file.read()
|
||||
expected = """# #
|
||||
# Host Database
|
||||
|
@ -286,61 +280,61 @@ class TestHostsParser:
|
|||
127.0.0.1\tlocalhost
|
||||
"""
|
||||
assert new_content == expected
|
||||
|
||||
|
||||
# Cleanup
|
||||
os.unlink(backup_path)
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_validate_write_permissions(self):
|
||||
"""Test write permission validation."""
|
||||
# Test with a temporary file (should be writable)
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
parser = HostsParser(f.name)
|
||||
assert parser.validate_write_permissions() is True
|
||||
|
||||
|
||||
# Test with a nonexistent file in /tmp (should be writable)
|
||||
parser = HostsParser("/tmp/test_hosts_nonexistent")
|
||||
assert parser.validate_write_permissions() is True
|
||||
|
||||
|
||||
# Test with a path that likely doesn't have write permissions
|
||||
parser = HostsParser("/root/test_hosts")
|
||||
# This might be True if running as root, so we can't assert False
|
||||
result = parser.validate_write_permissions()
|
||||
assert isinstance(result, bool)
|
||||
|
||||
|
||||
def test_get_file_info(self):
|
||||
"""Test getting file information."""
|
||||
content = "127.0.0.1 localhost\n"
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
|
||||
|
||||
parser = HostsParser(f.name)
|
||||
info = parser.get_file_info()
|
||||
|
||||
assert info['path'] == f.name
|
||||
assert info['exists'] is True
|
||||
assert info['readable'] is True
|
||||
assert info['size'] == len(content)
|
||||
assert info['modified'] is not None
|
||||
assert isinstance(info['modified'], float)
|
||||
|
||||
|
||||
assert info["path"] == f.name
|
||||
assert info["exists"] is True
|
||||
assert info["readable"] is True
|
||||
assert info["size"] == len(content)
|
||||
assert info["modified"] is not None
|
||||
assert isinstance(info["modified"], float)
|
||||
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def test_get_file_info_nonexistent(self):
|
||||
"""Test getting file information for nonexistent file."""
|
||||
parser = HostsParser("/nonexistent/path")
|
||||
info = parser.get_file_info()
|
||||
|
||||
assert info['path'] == "/nonexistent/path"
|
||||
assert info['exists'] is False
|
||||
assert info['readable'] is False
|
||||
assert info['writable'] is False
|
||||
assert info['size'] == 0
|
||||
assert info['modified'] is None
|
||||
|
||||
|
||||
assert info["path"] == "/nonexistent/path"
|
||||
assert info["exists"] is False
|
||||
assert info["readable"] is False
|
||||
assert info["writable"] is False
|
||||
assert info["size"] == 0
|
||||
assert info["modified"] is None
|
||||
|
||||
def test_round_trip_parsing(self):
|
||||
"""Test that parsing and serializing preserves content."""
|
||||
original_content = """# System hosts file
|
||||
|
@ -353,26 +347,26 @@ class TestHostsParser:
|
|||
|
||||
# End of file
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
|
||||
f.write(original_content)
|
||||
f.flush()
|
||||
|
||||
|
||||
# Parse and serialize
|
||||
parser = HostsParser(f.name)
|
||||
hosts_file = parser.parse()
|
||||
|
||||
|
||||
# Write back and read
|
||||
parser.write(hosts_file, backup=False)
|
||||
|
||||
with open(f.name, 'r') as read_file:
|
||||
|
||||
with open(f.name, "r") as read_file:
|
||||
final_content = read_file.read()
|
||||
|
||||
|
||||
# The content should be functionally equivalent
|
||||
# (though formatting might differ slightly with tabs)
|
||||
assert "127.0.0.1\tlocalhost\tloopback\t# Local loopback" in final_content
|
||||
assert "::1\t\tlocalhost\t# IPv6 loopback" in final_content
|
||||
assert "192.168.1.1\trouter\t\tgateway\t# Local router" in final_content
|
||||
assert "# 10.0.0.1\ttest.local\t# Test entry (disabled)" in final_content
|
||||
|
||||
|
||||
os.unlink(f.name)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue