From 6282091ed42f282060162ab0bc23265b2bd23638 Mon Sep 17 00:00:00 2001 From: Lucas Pirola Date: Mon, 8 Jun 2026 21:50:06 +0400 Subject: [PATCH] test: make collision-warning test robust to basicConfig(force=True) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_handler_logs_warning_on_collision relied on pytest's caplog, but the package calls logging.basicConfig(..., force=True) at import time (the rotating-file logging added in #181). force=True detaches the root handler that caplog reads from, so the emitted warning was routed to the stderr/file handlers but never reached caplog.records — the final assertion failed depending on import/handler ordering. Capture on the "kicad_interface" logger with a test-owned handler instead of relying on caplog, and disable propagation for the duration so the warning no longer leaks to stderr. Logger level and propagation are restored in a finally block. Behaviour under test is unchanged; the assertion is now deterministic. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_move_with_wire_preservation.py | 44 ++++++++++++++++------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/tests/test_move_with_wire_preservation.py b/tests/test_move_with_wire_preservation.py index 4edbd4b..509b285 100644 --- a/tests/test_move_with_wire_preservation.py +++ b/tests/test_move_with_wire_preservation.py @@ -785,38 +785,56 @@ class TestSynthesizeTouchingPinWires: class TestOldToNewCollision: """Verify that coincident pins do not silently overwrite each other in old_to_new.""" - def test_handler_logs_warning_on_collision(self, caplog: Any) -> None: + def test_handler_logs_warning_on_collision(self) -> None: """ When two pins share the same old position, a warning should be logged and the *first* mapping should be kept (not overwritten by the second). """ import logging - # Build a fake pin_positions dict with a deliberate collision - pin_positions = { - "1": ((0.0, 3.81), (10.0, 23.81)), - "2": ((0.0, 3.81), (10.0, 16.19)), # same old_xy as pin "1" - } + # Capture on the "kicad_interface" logger with our own handler rather + # than pytest's ``caplog``: the package calls + # ``logging.basicConfig(..., force=True)`` at import time, which detaches + # the root-level handler ``caplog`` reads from and silently drops records. + records = [] - old_to_new = {} - with caplog.at_level(logging.WARNING, logger="kicad_interface"): + class _Capture(logging.Handler): + def emit(self, record: logging.LogRecord) -> None: + records.append(record) + + kicad_logger = logging.getLogger("kicad_interface") + handler = _Capture(level=logging.WARNING) + prev_level = kicad_logger.level + prev_propagate = kicad_logger.propagate + kicad_logger.addHandler(handler) + kicad_logger.setLevel(logging.WARNING) + kicad_logger.propagate = False # keep the warning out of stderr/file handlers + try: + # Build a fake pin_positions dict with a deliberate collision + pin_positions = { + "1": ((0.0, 3.81), (10.0, 23.81)), + "2": ((0.0, 3.81), (10.0, 16.19)), # same old_xy as pin "1" + } + + old_to_new = {} for _pin, (old_xy, new_xy) in pin_positions.items(): if old_xy in old_to_new: - import logging as _logging - - logger_inner = _logging.getLogger("kicad_interface") - logger_inner.warning( + kicad_logger.warning( f"move_schematic_component: pin {_pin!r} shares old position {old_xy} " f"with another pin; keeping first entry, skipping duplicate" ) continue old_to_new[old_xy] = new_xy + finally: + kicad_logger.removeHandler(handler) + kicad_logger.setLevel(prev_level) + kicad_logger.propagate = prev_propagate # Only one entry should exist, and it should be the first one assert len(old_to_new) == 1 assert old_to_new[(0.0, 3.81)] == (10.0, 23.81) # Warning should have been logged - assert any("skipping duplicate" in r.message for r in caplog.records) + assert any("skipping duplicate" in r.getMessage() for r in records) # ---------------------------------------------------------------------------