Skip to content

Commit 1dc476e

Browse files
committed
ControlModeEngine(test): Make fakes satisfy _ControlProcess without casts
why: Avoid mypy assignment errors; align test doubles with protocol fields. what: - Type FakeProcess stdin/stdout/stderr as TextIO/Iterable[str] per protocol - Make FakeStdin subclass StringIO and add write/flush stubs - Remove remaining casts to _ControlProcess
1 parent a9245a6 commit 1dc476e

File tree

1 file changed

+29
-26
lines changed

1 file changed

+29
-26
lines changed

tests/test_control_mode_engine.py

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import pathlib
77
import time
88
import typing as t
9-
from typing import cast
109

1110
import pytest
1211

@@ -82,32 +81,32 @@ def __next__(self) -> str: # pragma: no cover - simple block
8281

8382
class FakeProcess:
8483
def __init__(self) -> None:
85-
self.stdin = io.StringIO()
86-
self.stdout = BlockingStdout()
87-
self.stderr = None
88-
self._terminated = False
89-
self.pid = 1234
84+
self.stdin: t.TextIO | None = io.StringIO()
85+
self.stdout: t.Iterable[str] | None = BlockingStdout()
86+
self.stderr: t.Iterable[str] | None = iter([])
87+
self._terminated: bool = False
88+
self.pid: int | None = 1234
9089

9190
def terminate(self) -> None: # pragma: no cover - simple stub
9291
self._terminated = True
9392

9493
def kill(self) -> None: # pragma: no cover - simple stub
9594
self._terminated = True
9695

97-
def wait(self, timeout: float | None = None) -> None: # pragma: no cover
98-
return None
96+
def wait(self, timeout: float | None = None) -> int | None: # pragma: no cover
97+
return 0
9998

10099
def poll(self) -> int | None: # pragma: no cover - simple stub
101100
return 0
102101

103102
engine = ControlModeEngine(command_timeout=0.01)
104103

105-
fake_process = FakeProcess()
104+
fake_process: _ControlProcess = FakeProcess()
106105

107106
def fake_start(server_args: t.Sequence[str | int] | None) -> None:
108107
engine.tmux_bin = "tmux"
109108
engine._server_args = tuple(server_args or ())
110-
engine.process = cast(_ControlProcess, fake_process)
109+
engine.process = fake_process
111110

112111
monkeypatch.setattr(engine, "_start_process", fake_start)
113112

@@ -122,20 +121,20 @@ def test_control_mode_per_command_timeout(monkeypatch: pytest.MonkeyPatch) -> No
122121

123122
class FakeProcess:
124123
def __init__(self) -> None:
125-
self.stdin = io.StringIO()
126-
self.stdout: t.Iterator[str] = iter([]) # no output
127-
self.stderr = None
128-
self._terminated = False
129-
self.pid = 5678
124+
self.stdin: t.TextIO | None = io.StringIO()
125+
self.stdout: t.Iterable[str] | None = iter([]) # no output
126+
self.stderr: t.Iterable[str] | None = iter([])
127+
self._terminated: bool = False
128+
self.pid: int | None = 5678
130129

131130
def terminate(self) -> None:
132131
self._terminated = True
133132

134133
def kill(self) -> None:
135134
self._terminated = True
136135

137-
def wait(self, timeout: float | None = None) -> None:
138-
return None
136+
def wait(self, timeout: float | None = None) -> int | None:
137+
return 0
139138

140139
def poll(self) -> int | None:
141140
return 0
@@ -145,7 +144,8 @@ def poll(self) -> int | None:
145144
def fake_start(server_args: t.Sequence[str | int] | None) -> None:
146145
engine.tmux_bin = "tmux"
147146
engine._server_args = tuple(server_args or ())
148-
engine.process = cast(_ControlProcess, FakeProcess())
147+
fake_proc: _ControlProcess = FakeProcess()
148+
engine.process = fake_proc
149149

150150
monkeypatch.setattr(engine, "_start_process", fake_start)
151151

@@ -240,33 +240,36 @@ def test_write_line_broken_pipe_increments_restart(
240240
) -> None:
241241
"""Broken pipe should raise ControlModeConnectionError and bump restarts."""
242242

243-
class FakeStdin:
244-
def write(self, _: str) -> None:
243+
class FakeStdin(io.StringIO):
244+
def write(self, _: str) -> int: # pragma: no cover - simple stub
245245
raise BrokenPipeError
246246

247247
def flush(self) -> None: # pragma: no cover - not reached
248248
return None
249249

250250
class FakeProcess:
251251
def __init__(self) -> None:
252-
self.stdin = FakeStdin()
253-
self._terminated = False
254-
self.pid = 9999
252+
self.stdin: t.TextIO | None = FakeStdin()
253+
self.stdout: t.Iterable[str] | None = iter([])
254+
self.stderr: t.Iterable[str] | None = iter([])
255+
self._terminated: bool = False
256+
self.pid: int | None = 9999
255257

256258
def terminate(self) -> None:
257259
self._terminated = True
258260

259261
def kill(self) -> None: # pragma: no cover - simple stub
260262
self._terminated = True
261263

262-
def wait(self, timeout: float | None = None) -> None:
263-
return None
264+
def wait(self, timeout: float | None = None) -> int | None:
265+
return 0
264266

265267
def poll(self) -> int | None:
266268
return 0
267269

268270
engine = ControlModeEngine()
269-
engine.process = cast(_ControlProcess, FakeProcess())
271+
fake_proc: _ControlProcess = FakeProcess()
272+
engine.process = fake_proc
270273

271274
with pytest.raises(case.should_raise):
272275
engine._write_line("list-sessions", server_args=())

0 commit comments

Comments
 (0)