Files
webterm/tests/test_poller.py
T
Rui Carmo a0e31d43fd merge
2026-01-21 23:53:57 +00:00

128 lines
3.8 KiB
Python

"""Tests for poller module."""
import asyncio
import contextlib
from unittest.mock import MagicMock, patch
import pytest
from textual_webterm.poller import Poller, Write
class TestWrite:
"""Tests for Write dataclass."""
def test_create_write(self):
"""Test creating a Write object."""
write = Write(data=b"test")
assert write.data == b"test"
assert write.position == 0
assert write.done_event is not None
def test_write_with_position(self):
"""Test Write with custom position."""
write = Write(data=b"test", position=5)
assert write.position == 5
class TestPoller:
"""Tests for Poller class."""
def test_init(self):
"""Test Poller initialization."""
poller = Poller()
assert poller._loop is None
assert poller._read_queues == {}
assert poller._write_queues == {}
assert not poller._exit_event.is_set()
def test_set_loop(self):
"""Test setting the asyncio loop."""
poller = Poller()
mock_loop = MagicMock()
poller.set_loop(mock_loop)
assert poller._loop == mock_loop
def test_add_file(self):
"""Test adding a file descriptor."""
poller = Poller()
# Use a mock file descriptor
with patch.object(poller._selector, "register"):
queue = poller.add_file(42)
assert 42 in poller._read_queues
assert isinstance(queue, asyncio.Queue)
def test_remove_file(self):
"""Test removing a file descriptor."""
poller = Poller()
# Add first
with patch.object(poller._selector, "register"):
poller.add_file(42)
# Remove
with patch.object(poller._selector, "unregister"):
poller.remove_file(42)
assert 42 not in poller._read_queues
def test_remove_nonexistent_file(self):
"""Test removing a non-existent file descriptor."""
poller = Poller()
with patch.object(poller._selector, "unregister"):
# Should not raise
poller.remove_file(999)
@pytest.mark.asyncio
async def test_write_creates_queue(self):
"""Test that write creates a write queue if needed."""
poller = Poller()
poller._loop = asyncio.get_event_loop()
# Mock selector
with patch.object(poller._selector, "register"):
poller.add_file(42)
with patch.object(poller._selector, "modify"):
# Start write in background (won't complete without poller running)
task = asyncio.create_task(poller.write(42, b"test"))
# Give it time to set up
await asyncio.sleep(0.01)
assert 42 in poller._write_queues
assert len(poller._write_queues[42]) == 1
# Cancel to clean up
task.cancel()
with contextlib.suppress(asyncio.CancelledError):
await task
def test_exit_sets_event(self):
"""Test that exit sets the exit event."""
poller = Poller()
poller._exit_event.clear()
# Mock join to avoid blocking
with patch.object(poller, "join"):
poller.exit()
assert poller._exit_event.is_set()
assert poller._read_queues == {}
assert poller._write_queues == {}
def test_exit_puts_none_in_queues(self):
"""Test that exit puts None in all read queues."""
poller = Poller()
# Add some queues
with patch.object(poller._selector, "register"):
q1 = poller.add_file(1)
q2 = poller.add_file(2)
# Mock join
with patch.object(poller, "join"):
poller.exit()
# Queues should have None
assert q1.get_nowait() is None
assert q2.get_nowait() is None