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
|
@ -16,259 +16,277 @@ from hosts.core.config import Config
|
|||
|
||||
class TestHostsManagerApp:
|
||||
"""Test cases for the HostsManagerApp class."""
|
||||
|
||||
|
||||
def test_app_initialization(self):
|
||||
"""Test application initialization."""
|
||||
with patch('hosts.tui.app.HostsParser'), patch('hosts.tui.app.Config'):
|
||||
with patch("hosts.tui.app.HostsParser"), patch("hosts.tui.app.Config"):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
assert app.title == "/etc/hosts Manager"
|
||||
assert app.sub_title == "" # Now set by update_status
|
||||
assert app.edit_mode is False
|
||||
assert app.selected_entry_index == 0
|
||||
assert app.sort_column == ""
|
||||
assert app.sort_ascending is True
|
||||
|
||||
|
||||
def test_app_compose_method_exists(self):
|
||||
"""Test that app has compose method."""
|
||||
with patch('hosts.tui.app.HostsParser'), patch('hosts.tui.app.Config'):
|
||||
with patch("hosts.tui.app.HostsParser"), patch("hosts.tui.app.Config"):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Test that compose method exists and is callable
|
||||
assert hasattr(app, 'compose')
|
||||
assert hasattr(app, "compose")
|
||||
assert callable(app.compose)
|
||||
|
||||
|
||||
def test_load_hosts_file_success(self):
|
||||
"""Test successful hosts file loading."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
|
||||
# Create test hosts file
|
||||
test_hosts = HostsFile()
|
||||
test_entry = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
test_hosts.add_entry(test_entry)
|
||||
|
||||
|
||||
mock_parser.parse.return_value = test_hosts
|
||||
mock_parser.get_file_info.return_value = {
|
||||
'path': '/etc/hosts',
|
||||
'exists': True,
|
||||
'size': 100
|
||||
"path": "/etc/hosts",
|
||||
"exists": True,
|
||||
"size": 100,
|
||||
}
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.populate_entries_table = Mock()
|
||||
app.update_entry_details = Mock()
|
||||
app.set_timer = Mock()
|
||||
|
||||
|
||||
app.load_hosts_file()
|
||||
|
||||
|
||||
# Verify hosts file was loaded
|
||||
assert len(app.hosts_file.entries) == 1
|
||||
assert app.hosts_file.entries[0].ip_address == "127.0.0.1"
|
||||
mock_parser.parse.assert_called_once()
|
||||
|
||||
|
||||
def test_load_hosts_file_not_found(self):
|
||||
"""Test handling of missing hosts file."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
mock_parser.parse.side_effect = FileNotFoundError("Hosts file not found")
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.update_status = Mock()
|
||||
|
||||
|
||||
app.load_hosts_file()
|
||||
|
||||
|
||||
# Should handle error gracefully
|
||||
app.update_status.assert_called_with("❌ Error loading hosts file: Hosts file not found")
|
||||
|
||||
app.update_status.assert_called_with(
|
||||
"❌ Error loading hosts file: Hosts file not found"
|
||||
)
|
||||
|
||||
def test_load_hosts_file_permission_error(self):
|
||||
"""Test handling of permission denied error."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
mock_parser.parse.side_effect = PermissionError("Permission denied")
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.update_status = Mock()
|
||||
|
||||
|
||||
app.load_hosts_file()
|
||||
|
||||
|
||||
# Should handle error gracefully
|
||||
app.update_status.assert_called_with("❌ Error loading hosts file: Permission denied")
|
||||
|
||||
app.update_status.assert_called_with(
|
||||
"❌ Error loading hosts file: Permission denied"
|
||||
)
|
||||
|
||||
def test_populate_entries_table_logic(self):
|
||||
"""Test populating DataTable logic without UI dependencies."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
mock_config.should_show_default_entries.return_value = True
|
||||
mock_config.is_default_entry.return_value = False
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Mock the query_one method to return a mock table
|
||||
mock_table = Mock()
|
||||
app.query_one = Mock(return_value=mock_table)
|
||||
|
||||
|
||||
# Add test entries
|
||||
app.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
|
||||
ip_address="192.168.1.1", hostnames=["router"], is_active=False
|
||||
)
|
||||
app.hosts_file.add_entry(active_entry)
|
||||
app.hosts_file.add_entry(inactive_entry)
|
||||
|
||||
|
||||
app.populate_entries_table()
|
||||
|
||||
|
||||
# Verify table methods were called
|
||||
mock_table.clear.assert_called_once_with(columns=True)
|
||||
mock_table.add_columns.assert_called_once()
|
||||
assert mock_table.add_row.call_count == 2 # Two entries added
|
||||
|
||||
|
||||
def test_update_entry_details_with_entry(self):
|
||||
"""Test updating entry details pane."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
mock_config.should_show_default_entries.return_value = True
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Mock the query_one method to return DataTable mock
|
||||
mock_details_table = Mock()
|
||||
mock_details_table.columns = [] # Mock empty columns list
|
||||
mock_edit_form = Mock()
|
||||
|
||||
|
||||
def mock_query_one(selector, widget_type=None):
|
||||
if selector == "#entry-details-table":
|
||||
return mock_details_table
|
||||
elif selector == "#entry-edit-form":
|
||||
return mock_edit_form
|
||||
return Mock()
|
||||
|
||||
|
||||
app.query_one = mock_query_one
|
||||
|
||||
|
||||
# Add test entry
|
||||
app.hosts_file = HostsFile()
|
||||
test_entry = HostEntry(
|
||||
ip_address="127.0.0.1",
|
||||
hostnames=["localhost", "local"],
|
||||
comment="Test comment"
|
||||
comment="Test comment",
|
||||
)
|
||||
app.hosts_file.add_entry(test_entry)
|
||||
app.selected_entry_index = 0
|
||||
|
||||
|
||||
app.update_entry_details()
|
||||
|
||||
|
||||
# Verify DataTable operations were called
|
||||
mock_details_table.remove_class.assert_called_with("hidden")
|
||||
mock_edit_form.add_class.assert_called_with("hidden")
|
||||
mock_details_table.clear.assert_called_once()
|
||||
mock_details_table.add_column.assert_called()
|
||||
mock_details_table.add_row.assert_called()
|
||||
|
||||
|
||||
def test_update_entry_details_no_entries(self):
|
||||
"""Test updating entry details with no entries."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Mock the query_one method to return DataTable mock
|
||||
mock_details_table = Mock()
|
||||
mock_details_table.columns = [] # Mock empty columns list
|
||||
mock_edit_form = Mock()
|
||||
|
||||
|
||||
def mock_query_one(selector, widget_type=None):
|
||||
if selector == "#entry-details-table":
|
||||
return mock_details_table
|
||||
elif selector == "#entry-edit-form":
|
||||
return mock_edit_form
|
||||
return Mock()
|
||||
|
||||
|
||||
app.query_one = mock_query_one
|
||||
app.hosts_file = HostsFile()
|
||||
|
||||
|
||||
app.update_entry_details()
|
||||
|
||||
|
||||
# Verify DataTable operations were called for empty state
|
||||
mock_details_table.remove_class.assert_called_with("hidden")
|
||||
mock_edit_form.add_class.assert_called_with("hidden")
|
||||
mock_details_table.clear.assert_called_once()
|
||||
mock_details_table.add_column.assert_called_with("Field", key="field")
|
||||
mock_details_table.add_row.assert_called_with("No entries loaded")
|
||||
|
||||
|
||||
def test_update_status_default(self):
|
||||
"""Test status bar update with default information."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
mock_parser.get_file_info.return_value = {
|
||||
'path': '/etc/hosts',
|
||||
'exists': True,
|
||||
'size': 100
|
||||
"path": "/etc/hosts",
|
||||
"exists": True,
|
||||
"size": 100,
|
||||
}
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Add test entries
|
||||
app.hosts_file = HostsFile()
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="127.0.0.1", hostnames=["localhost"]))
|
||||
app.hosts_file.add_entry(HostEntry(
|
||||
ip_address="192.168.1.1",
|
||||
hostnames=["router"],
|
||||
is_active=False
|
||||
))
|
||||
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
)
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(
|
||||
ip_address="192.168.1.1", hostnames=["router"], is_active=False
|
||||
)
|
||||
)
|
||||
|
||||
app.update_status()
|
||||
|
||||
|
||||
# Verify sub_title was set correctly
|
||||
assert "Read-only mode" in app.sub_title
|
||||
assert "2 entries" in app.sub_title
|
||||
assert "1 active" in app.sub_title
|
||||
|
||||
|
||||
def test_update_status_custom_message(self):
|
||||
"""Test status bar update with custom message."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Mock set_timer and query_one to avoid event loop and UI issues
|
||||
app.set_timer = Mock()
|
||||
mock_status_bar = Mock()
|
||||
app.query_one = Mock(return_value=mock_status_bar)
|
||||
|
||||
|
||||
# Add test hosts_file for subtitle generation
|
||||
app.hosts_file = HostsFile()
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="127.0.0.1", hostnames=["localhost"]))
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="192.168.1.1", hostnames=["router"], is_active=False))
|
||||
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
)
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(
|
||||
ip_address="192.168.1.1", hostnames=["router"], is_active=False
|
||||
)
|
||||
)
|
||||
|
||||
app.update_status("Custom status message")
|
||||
|
||||
|
||||
# Verify status bar was updated with custom message
|
||||
mock_status_bar.update.assert_called_with("Custom status message")
|
||||
mock_status_bar.remove_class.assert_called_with("hidden")
|
||||
|
@ -277,225 +295,248 @@ class TestHostsManagerApp:
|
|||
assert "Read-only mode" in app.sub_title
|
||||
# Verify timer was set for auto-clearing
|
||||
app.set_timer.assert_called_once()
|
||||
|
||||
|
||||
def test_action_reload(self):
|
||||
"""Test reload action."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.load_hosts_file = Mock()
|
||||
app.update_status = Mock()
|
||||
|
||||
|
||||
app.action_reload()
|
||||
|
||||
|
||||
app.load_hosts_file.assert_called_once()
|
||||
app.update_status.assert_called_with("Hosts file reloaded")
|
||||
|
||||
|
||||
def test_action_help(self):
|
||||
"""Test help action."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.update_status = Mock()
|
||||
|
||||
|
||||
app.action_help()
|
||||
|
||||
|
||||
# Should update status with help message
|
||||
app.update_status.assert_called_once()
|
||||
call_args = app.update_status.call_args[0][0]
|
||||
assert "Help:" in call_args
|
||||
|
||||
|
||||
def test_action_config(self):
|
||||
"""Test config action opens modal."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.push_screen = Mock()
|
||||
|
||||
|
||||
app.action_config()
|
||||
|
||||
|
||||
# Should push config modal screen
|
||||
app.push_screen.assert_called_once()
|
||||
args = app.push_screen.call_args[0]
|
||||
assert len(args) >= 1 # ConfigModal instance
|
||||
|
||||
|
||||
def test_action_sort_by_ip_ascending(self):
|
||||
"""Test sorting by IP address in ascending order."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Add test entries in reverse order
|
||||
app.hosts_file = HostsFile()
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="192.168.1.1", hostnames=["router"]))
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="127.0.0.1", hostnames=["localhost"]))
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="10.0.0.1", hostnames=["test"]))
|
||||
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="192.168.1.1", hostnames=["router"])
|
||||
)
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
)
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="10.0.0.1", hostnames=["test"])
|
||||
)
|
||||
|
||||
# Mock the table_handler methods to avoid UI queries
|
||||
app.table_handler.populate_entries_table = Mock()
|
||||
app.table_handler.restore_cursor_position = Mock()
|
||||
app.update_status = Mock()
|
||||
|
||||
|
||||
app.action_sort_by_ip()
|
||||
|
||||
|
||||
# Check that entries are sorted by IP address
|
||||
assert app.hosts_file.entries[0].ip_address == "10.0.0.1" # Sorted by IP
|
||||
assert app.hosts_file.entries[0].ip_address == "10.0.0.1" # Sorted by IP
|
||||
assert app.hosts_file.entries[1].ip_address == "127.0.0.1"
|
||||
assert app.hosts_file.entries[2].ip_address == "192.168.1.1"
|
||||
|
||||
|
||||
assert app.sort_column == "ip"
|
||||
assert app.sort_ascending is True
|
||||
app.table_handler.populate_entries_table.assert_called_once()
|
||||
|
||||
|
||||
def test_action_sort_by_hostname_ascending(self):
|
||||
"""Test sorting by hostname in ascending order."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Add test entries in reverse alphabetical order
|
||||
app.hosts_file = HostsFile()
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="127.0.0.1", hostnames=["zebra"]))
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="192.168.1.1", hostnames=["alpha"]))
|
||||
app.hosts_file.add_entry(HostEntry(ip_address="10.0.0.1", hostnames=["beta"]))
|
||||
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="127.0.0.1", hostnames=["zebra"])
|
||||
)
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="192.168.1.1", hostnames=["alpha"])
|
||||
)
|
||||
app.hosts_file.add_entry(
|
||||
HostEntry(ip_address="10.0.0.1", hostnames=["beta"])
|
||||
)
|
||||
|
||||
# Mock the table_handler methods to avoid UI queries
|
||||
app.table_handler.populate_entries_table = Mock()
|
||||
app.table_handler.restore_cursor_position = Mock()
|
||||
app.update_status = Mock()
|
||||
|
||||
|
||||
app.action_sort_by_hostname()
|
||||
|
||||
|
||||
# Check that entries are sorted alphabetically
|
||||
assert app.hosts_file.entries[0].hostnames[0] == "alpha"
|
||||
assert app.hosts_file.entries[1].hostnames[0] == "beta"
|
||||
assert app.hosts_file.entries[2].hostnames[0] == "zebra"
|
||||
|
||||
|
||||
assert app.sort_column == "hostname"
|
||||
assert app.sort_ascending is True
|
||||
app.table_handler.populate_entries_table.assert_called_once()
|
||||
|
||||
|
||||
def test_data_table_row_highlighted_event(self):
|
||||
"""Test DataTable row highlighting event handling."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Mock the details_handler and table_handler methods
|
||||
app.details_handler.update_entry_details = Mock()
|
||||
app.table_handler.display_index_to_actual_index = Mock(return_value=2)
|
||||
|
||||
|
||||
# Create mock event with required parameters
|
||||
mock_table = Mock()
|
||||
mock_table.id = "entries-table"
|
||||
event = Mock()
|
||||
event.data_table = mock_table
|
||||
event.cursor_row = 2
|
||||
|
||||
|
||||
app.on_data_table_row_highlighted(event)
|
||||
|
||||
|
||||
# Should update selected index and details
|
||||
assert app.selected_entry_index == 2
|
||||
app.details_handler.update_entry_details.assert_called_once()
|
||||
app.table_handler.display_index_to_actual_index.assert_called_once_with(2)
|
||||
|
||||
|
||||
def test_data_table_header_selected_ip_column(self):
|
||||
"""Test DataTable header selection for IP column."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
app.action_sort_by_ip = Mock()
|
||||
|
||||
|
||||
# Create mock event for IP column
|
||||
mock_table = Mock()
|
||||
mock_table.id = "entries-table"
|
||||
event = Mock()
|
||||
event.data_table = mock_table
|
||||
event.column_key = "IP Address"
|
||||
|
||||
|
||||
app.on_data_table_header_selected(event)
|
||||
|
||||
|
||||
app.action_sort_by_ip.assert_called_once()
|
||||
|
||||
|
||||
def test_restore_cursor_position_logic(self):
|
||||
"""Test cursor position restoration logic."""
|
||||
mock_parser = Mock(spec=HostsParser)
|
||||
mock_config = Mock(spec=Config)
|
||||
|
||||
with patch('hosts.tui.app.HostsParser', return_value=mock_parser), \
|
||||
patch('hosts.tui.app.Config', return_value=mock_config):
|
||||
|
||||
|
||||
with (
|
||||
patch("hosts.tui.app.HostsParser", return_value=mock_parser),
|
||||
patch("hosts.tui.app.Config", return_value=mock_config),
|
||||
):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Mock the query_one method to avoid UI dependencies
|
||||
mock_table = Mock()
|
||||
app.query_one = Mock(return_value=mock_table)
|
||||
app.update_entry_details = Mock()
|
||||
|
||||
|
||||
# Add test entries
|
||||
app.hosts_file = HostsFile()
|
||||
entry1 = HostEntry(ip_address="127.0.0.1", hostnames=["localhost"])
|
||||
entry2 = HostEntry(ip_address="192.168.1.1", hostnames=["router"])
|
||||
app.hosts_file.add_entry(entry1)
|
||||
app.hosts_file.add_entry(entry2)
|
||||
|
||||
|
||||
# Test the logic without UI dependencies
|
||||
# Find the index of entry2
|
||||
target_index = None
|
||||
for i, entry in enumerate(app.hosts_file.entries):
|
||||
if entry.ip_address == entry2.ip_address and entry.hostnames == entry2.hostnames:
|
||||
if (
|
||||
entry.ip_address == entry2.ip_address
|
||||
and entry.hostnames == entry2.hostnames
|
||||
):
|
||||
target_index = i
|
||||
break
|
||||
|
||||
|
||||
# Should find the matching entry at index 1
|
||||
assert target_index == 1
|
||||
|
||||
|
||||
def test_app_bindings_defined(self):
|
||||
"""Test that application has expected key bindings."""
|
||||
with patch('hosts.tui.app.HostsParser'), patch('hosts.tui.app.Config'):
|
||||
with patch("hosts.tui.app.HostsParser"), patch("hosts.tui.app.Config"):
|
||||
app = HostsManagerApp()
|
||||
|
||||
|
||||
# Check that bindings are defined
|
||||
assert len(app.BINDINGS) >= 6
|
||||
|
||||
|
||||
# Check specific bindings exist (handle both Binding objects and tuples)
|
||||
binding_keys = []
|
||||
for binding in app.BINDINGS:
|
||||
if hasattr(binding, 'key'):
|
||||
if hasattr(binding, "key"):
|
||||
# Binding object
|
||||
binding_keys.append(binding.key)
|
||||
elif isinstance(binding, tuple) and len(binding) >= 1:
|
||||
# Tuple format (key, action, description)
|
||||
binding_keys.append(binding[0])
|
||||
|
||||
|
||||
assert "q" in binding_keys
|
||||
assert "r" in binding_keys
|
||||
assert "h" in binding_keys
|
||||
|
@ -503,16 +544,17 @@ class TestHostsManagerApp:
|
|||
assert "n" in binding_keys
|
||||
assert "c" in binding_keys
|
||||
assert "ctrl+c" in binding_keys
|
||||
|
||||
|
||||
def test_main_function(self):
|
||||
"""Test main entry point function."""
|
||||
with patch('hosts.main.HostsManagerApp') as mock_app_class:
|
||||
with patch("hosts.main.HostsManagerApp") as mock_app_class:
|
||||
mock_app = Mock()
|
||||
mock_app_class.return_value = mock_app
|
||||
|
||||
|
||||
from hosts.main import main
|
||||
|
||||
main()
|
||||
|
||||
|
||||
# Should create and run app
|
||||
mock_app_class.assert_called_once()
|
||||
mock_app.run.assert_called_once()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue