From 67376e00ab953fad168e04e4b7ce1e2d762d8f4b Mon Sep 17 00:00:00 2001 From: raymondginger Date: Sun, 20 Sep 2026 18:04:23 +0800 Subject: [PATCH] tests: fix two TUI cases that only fail on Windows The whole suite runs on ubuntu-24.04; the Windows job runs a hand-picked file list that does not include `tests/test_tui.py`. These two failures therefore never show up in CI, and only bite anyone running the suite on Windows. Measured on 2b223c13: `tests/test_tui.py` -> 2 failed, 57 passed. After this change: 59 passed. `test_resume_scoped_to_directory` asserted on the raw `tmp_path`. The session picker names an origin directory with `short_path()`, which `~`-folds anything under the home directory. pytest's `tmp_path` lives under `$HOME` on Windows and under `/tmp` on POSIX, so comparing against the unfolded path only held on POSIX. Compare against the folded form the picker actually prints. `test_interactive_ctrl_c_becomes_a_turn_interrupt_request` reached `patch_stdout` through `InputReader.read()`. It builds a prompt_toolkit output, which needs a real console, so under pytest on Windows it raised `NoConsoleScreenBufferError: Found xterm-256color` before anything under test ran. Patching stdout is unrelated to the interrupt mapping under test; stub it. Both cases keep `async def` + `@pytest.mark.asyncio`: `pytest-asyncio` is declared in `setup.py`'s `test` extra and pinned in `scripts/ci/requirements.lock`. --- tests/test_tui.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/test_tui.py b/tests/test_tui.py index 78e1469b..4c1413c7 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -9,6 +9,7 @@ from __future__ import annotations import asyncio +import contextlib import io import json import sys @@ -32,6 +33,7 @@ from cli.tui import text as text_fitting from cli.tui.input import InputInterrupted, InputReader, expand_file_refs from cli.tui.renderer import EventRenderer +from cli.tui.text import short_path from core import agent_setup from core.events import ( AgentMessage, @@ -1528,7 +1530,10 @@ def test_resume_scoped_to_directory(monkeypatch, tmp_path, capsys): out = capsys.readouterr().out assert "no sessions for this directory" in out assert "task in A" in out # shown in the `all` view - assert str(tmp_path / "A") in out # origin directory annotated + # Origin directory annotated, exactly as the picker names it: a path under + # the home directory is `~`-folded (pytest's tmp dir lives under $HOME on + # Windows, and does not on POSIX, so compare against the folded form). + assert short_path(str(tmp_path / "A")) in out def test_cross_directory_resume_hints_origin(monkeypatch, tmp_path, capsys): @@ -1582,7 +1587,19 @@ def test_file_refs_fenced_to_workspace(tmp_path): @pytest.mark.asyncio -async def test_interactive_ctrl_c_becomes_a_turn_interrupt_request() -> None: +async def test_interactive_ctrl_c_becomes_a_turn_interrupt_request(monkeypatch) -> None: + """Ctrl-C at the prompt interrupts the turn; it must not end the session. + + ``patch_stdout`` is stubbed out: it builds a prompt_toolkit output, which + wants a real console (on Windows pytest gets + ``NoConsoleScreenBufferError: Found xterm-256color``), and the stdout + patching has nothing to do with the interrupt mapping under test. + """ + + monkeypatch.setattr( + "cli.tui.input.patch_stdout", lambda **_kwargs: contextlib.nullcontext() + ) + class InterruptingPrompt: async def prompt_async(self, _prompt: str) -> str: raise KeyboardInterrupt