from __future__ import annotations from unittest.mock import patch from ameba_control_panel.config import Direction from ameba_control_panel.services.log_buffer import LogBuffer, LogLine class TestLogBuffer: def test_append_returns_logline(self): buf = LogBuffer(max_tail=10) line = buf.append("hello", Direction.RX) assert isinstance(line, LogLine) assert line.text == "hello" assert line.direction == Direction.RX def test_tail_bounded(self): buf = LogBuffer(max_tail=5) for i in range(10): buf.append(f"line {i}", Direction.RX) assert len(buf.tail()) == 5 assert buf.tail()[0].text == "line 5" def test_archive_bounded(self): with patch("ameba_control_panel.services.log_buffer.config.LOG_ARCHIVE_MAX", 3): buf = LogBuffer(max_tail=10) for i in range(5): buf.append(f"line {i}", Direction.RX) assert len(buf.archive()) == 3 assert buf.archive()[0].text == "line 2" def test_clear(self): buf = LogBuffer(max_tail=10) buf.append("test", Direction.INFO) buf.clear() assert len(buf.tail()) == 0 assert len(buf.archive()) == 0 def test_as_text(self): buf = LogBuffer(max_tail=10) buf.append("hello", Direction.RX) buf.append("world", Direction.TX) text = buf.as_text() assert "hello" in text assert "world" in text def test_direction_preserved(self): buf = LogBuffer(max_tail=10) buf.append("rx data", Direction.RX) buf.append("tx data", Direction.TX) buf.append("info msg", Direction.INFO) lines = list(buf.tail()) assert lines[0].direction == Direction.RX assert lines[1].direction == Direction.TX assert lines[2].direction == Direction.INFO def test_newline_stripped(self): buf = LogBuffer(max_tail=10) line = buf.append("with newline\n", Direction.RX) assert line.text == "with newline"