Skip to content

Commit 8022d2c

Browse files
committed
tests(asyncio): strengthen pane typing
1 parent 3e8ff92 commit 8022d2c

File tree

1 file changed

+91
-38
lines changed

1 file changed

+91
-38
lines changed

tests/asyncio/test_pane.py

Lines changed: 91 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,41 @@
88

99
import asyncio
1010
import logging
11+
from dataclasses import dataclass
1112
from typing import TYPE_CHECKING
1213

1314
import pytest
1415

1516
if TYPE_CHECKING:
1617
from libtmux.session import Session
1718

19+
20+
@dataclass(slots=True)
21+
class PaneSetupConfig:
22+
"""Pane command and expected output snippet for setup tests."""
23+
24+
cmd: str
25+
check: str
26+
27+
28+
@dataclass(slots=True)
29+
class PaneSetupResult:
30+
"""Outcome of pane setup verification."""
31+
32+
pane_id: str
33+
command: str
34+
success: bool
35+
36+
37+
@dataclass(slots=True)
38+
class PaneMonitorResult:
39+
"""Result of monitoring command execution per pane."""
40+
41+
pane_id: str
42+
service: str
43+
running: bool
44+
45+
1846
logger = logging.getLogger(__name__)
1947

2048

@@ -31,10 +59,12 @@ async def test_pane_acmd_basic(session: Session) -> None:
3159
"""
3260
pane = session.active_pane
3361
assert pane is not None
62+
pane_id = pane.pane_id
63+
assert pane_id is not None
3464

3565
# Display pane ID
3666
result = await pane.acmd("display-message", "-p", "#{pane_id}")
37-
assert result.stdout[0] == pane.pane_id
67+
assert result.stdout[0] == pane_id
3868

3969

4070
@pytest.mark.asyncio
@@ -78,8 +108,13 @@ async def test_concurrent_send_keys_multiple_panes(session: Session) -> None:
78108
result1 = await window.acmd("split-window", "-h", "-P", "-F#{pane_id}")
79109
result2 = await window.acmd("split-window", "-v", "-P", "-F#{pane_id}")
80110

81-
pane_ids = [
82-
session.active_pane.pane_id,
111+
active_pane = session.active_pane
112+
assert active_pane is not None
113+
active_pane_id = active_pane.pane_id
114+
assert active_pane_id is not None
115+
116+
pane_ids: list[str] = [
117+
active_pane_id,
83118
result1.stdout[0],
84119
result2.stdout[0],
85120
]
@@ -130,38 +165,39 @@ async def test_batch_pane_setup_automation(session: Session) -> None:
130165
assert window is not None
131166

132167
# Define pane setup: command and check string
133-
pane_configs = [
134-
{"cmd": "echo 'Frontend: localhost:3000'", "check": "Frontend"},
135-
{"cmd": "echo 'Backend: localhost:8000'", "check": "Backend"},
136-
{"cmd": "echo 'Database: localhost:5432'", "check": "Database"},
168+
pane_configs: list[PaneSetupConfig] = [
169+
PaneSetupConfig(cmd="echo 'Frontend: localhost:3000'", check="Frontend"),
170+
PaneSetupConfig(cmd="echo 'Backend: localhost:8000'", check="Backend"),
171+
PaneSetupConfig(cmd="echo 'Database: localhost:5432'", check="Database"),
137172
]
138173

139174
# Create panes
140-
pane_ids = [session.active_pane.pane_id]
175+
active_pane = session.active_pane
176+
assert active_pane is not None
177+
first_pane_id = active_pane.pane_id
178+
assert first_pane_id is not None
179+
180+
pane_ids: list[str] = [first_pane_id]
141181
for _ in range(2):
142-
result = await window.acmd("split-window", "-h", "-P", "-F#{pane_id}")
143-
pane_ids.append(result.stdout[0])
182+
split_result = await window.acmd("split-window", "-h", "-P", "-F#{pane_id}")
183+
pane_ids.append(split_result.stdout[0])
144184

145-
async def setup_pane(pane_id: str, config: dict[str, str]) -> dict[str, str | bool]:
185+
async def setup_pane(pane_id: str, config: PaneSetupConfig) -> PaneSetupResult:
146186
"""Set up a pane with command and verify output."""
147187
pane = Pane.from_pane_id(pane_id=pane_id, server=session.server)
148188

149189
# Send command
150-
await pane.acmd("send-keys", config["cmd"], "Enter")
190+
await pane.acmd("send-keys", config.cmd, "Enter")
151191
await asyncio.sleep(0.2)
152192

153193
# Capture and verify
154194
result = await pane.acmd("capture-pane", "-p")
155-
success = any(config["check"] in line for line in result.stdout)
195+
success = any(config.check in line for line in result.stdout)
156196

157-
return {
158-
"pane_id": pane_id,
159-
"command": config["cmd"],
160-
"success": success,
161-
}
197+
return PaneSetupResult(pane_id=pane_id, command=config.cmd, success=success)
162198

163199
# Set up all panes concurrently
164-
results = await asyncio.gather(
200+
results: list[PaneSetupResult] = await asyncio.gather(
165201
*[
166202
setup_pane(pid, config)
167203
for pid, config in zip(pane_ids, pane_configs, strict=False)
@@ -170,8 +206,8 @@ async def setup_pane(pane_id: str, config: dict[str, str]) -> dict[str, str | bo
170206

171207
# Verify all setups succeeded
172208
assert len(results) == 3
173-
for result in results:
174-
assert result["success"], f"Pane {result['pane_id']} setup failed"
209+
for pane_result in results:
210+
assert pane_result.success, f"Pane {pane_result.pane_id} setup failed"
175211

176212

177213
@pytest.mark.asyncio
@@ -190,13 +226,18 @@ async def test_parallel_pane_monitoring(session: Session) -> None:
190226
result1 = await window.acmd("split-window", "-h", "-P", "-F#{pane_id}")
191227
result2 = await window.acmd("split-window", "-v", "-P", "-F#{pane_id}")
192228

193-
pane_ids = [
194-
session.active_pane.pane_id,
229+
active_pane = session.active_pane
230+
assert active_pane is not None
231+
active_pane_id = active_pane.pane_id
232+
assert active_pane_id is not None
233+
234+
pane_ids: list[str] = [
235+
active_pane_id,
195236
result1.stdout[0],
196237
result2.stdout[0],
197238
]
198239

199-
async def send_and_verify(pane_id: str, service_num: int) -> dict[str, str | bool]:
240+
async def send_and_verify(pane_id: str, service_num: int) -> PaneMonitorResult:
200241
"""Send command to pane and verify output."""
201242
pane = Pane.from_pane_id(pane_id=pane_id, server=session.server)
202243

@@ -208,21 +249,21 @@ async def send_and_verify(pane_id: str, service_num: int) -> dict[str, str | boo
208249
result = await pane.acmd("capture-pane", "-p")
209250
found = any(f"service_{service_num}_running" in line for line in result.stdout)
210251

211-
return {
212-
"pane_id": pane_id,
213-
"service": f"service_{service_num}",
214-
"running": found,
215-
}
252+
return PaneMonitorResult(
253+
pane_id=pane_id,
254+
service=f"service_{service_num}",
255+
running=found,
256+
)
216257

217258
# Send commands and monitor all panes concurrently
218-
monitor_results = await asyncio.gather(
259+
monitor_results: list[PaneMonitorResult] = await asyncio.gather(
219260
*[send_and_verify(pid, i) for i, pid in enumerate(pane_ids)]
220261
)
221262

222263
# Verify all services detected
223264
assert len(monitor_results) == 3
224-
for result in monitor_results:
225-
assert result["running"], f"Service {result['service']} not detected"
265+
for monitor_result in monitor_results:
266+
assert monitor_result.running, f"Service {monitor_result.service} not detected"
226267

227268

228269
# ============================================================================
@@ -283,7 +324,7 @@ async def test_asend_keys_literal_mode(session: Session) -> None:
283324
assert pane is not None
284325

285326
# Send literal special character (not a signal)
286-
await pane.asend_keys('C-c', literal=True, enter=False)
327+
await pane.asend_keys("C-c", literal=True, enter=False)
287328

288329
# Wait briefly
289330
await asyncio.sleep(0.1)
@@ -326,6 +367,7 @@ async def test_asend_keys_concurrent_multiple_panes(session: Session) -> None:
326367

327368
# Create 3 panes
328369
pane1 = window.active_pane
370+
assert pane1 is not None
329371
pane2 = window.split()
330372
pane3 = window.split()
331373

@@ -455,6 +497,7 @@ async def test_acapture_pane_concurrent_multiple_panes(session: Session) -> None
455497

456498
# Create 3 panes
457499
pane1 = window.active_pane
500+
assert pane1 is not None
458501
pane2 = window.split()
459502
pane3 = window.split()
460503

@@ -494,6 +537,9 @@ async def test_asplit_default_below(session: Session) -> None:
494537
window = session.active_window
495538
assert window is not None
496539
pane = window.active_pane
540+
assert pane is not None
541+
original_pane_id = pane.pane_id
542+
assert original_pane_id is not None
497543

498544
initial_pane_count = len(window.panes)
499545

@@ -503,7 +549,7 @@ async def test_asplit_default_below(session: Session) -> None:
503549
# Verify new pane created
504550
assert len(window.panes) == initial_pane_count + 1
505551
assert new_pane is not None
506-
assert new_pane.pane_id != pane.pane_id
552+
assert new_pane.pane_id != original_pane_id
507553

508554

509555
@pytest.mark.asyncio
@@ -517,6 +563,9 @@ async def test_asplit_direction_right(session: Session) -> None:
517563
window = session.active_window
518564
assert window is not None
519565
pane = window.active_pane
566+
assert pane is not None
567+
source_pane_id = pane.pane_id
568+
assert source_pane_id is not None
520569

521570
initial_pane_count = len(window.panes)
522571

@@ -526,7 +575,7 @@ async def test_asplit_direction_right(session: Session) -> None:
526575
# Verify new pane created
527576
assert len(window.panes) == initial_pane_count + 1
528577
assert new_pane is not None
529-
assert new_pane.pane_id != pane.pane_id
578+
assert new_pane.pane_id != source_pane_id
530579

531580

532581
@pytest.mark.asyncio
@@ -538,21 +587,22 @@ async def test_asplit_with_start_directory(session: Session) -> None:
538587
window = session.active_window
539588
assert window is not None
540589
pane = window.active_pane
590+
assert pane is not None
541591

542592
# Split with custom directory
543-
new_pane = await pane.asplit(start_directory='/tmp')
593+
new_pane = await pane.asplit(start_directory="/tmp")
544594

545595
# Verify pane created
546596
assert new_pane is not None
547597

548598
# Send pwd command to verify directory
549-
await new_pane.asend_keys('pwd')
599+
await new_pane.asend_keys("pwd")
550600
await asyncio.sleep(0.3)
551601

552602
# Check output
553603
output = new_pane.capture_pane()
554604
# Verify /tmp appears in output (pwd result)
555-
has_tmp = any('/tmp' in line for line in output)
605+
has_tmp = any("/tmp" in line for line in output)
556606
assert has_tmp, f"Expected /tmp in output, got: {output}"
557607

558608

@@ -565,6 +615,7 @@ async def test_asplit_with_size(session: Session) -> None:
565615
window = session.active_window
566616
assert window is not None
567617
pane = window.active_pane
618+
assert pane is not None
568619

569620
initial_pane_count = len(window.panes)
570621

@@ -587,6 +638,7 @@ async def test_asplit_with_shell_command(session: Session) -> None:
587638
window = session.active_window
588639
assert window is not None
589640
pane = window.active_pane
641+
assert pane is not None
590642

591643
initial_pane_count = len(window.panes)
592644

@@ -620,6 +672,7 @@ async def test_asplit_concurrent_multiple_splits(session: Session) -> None:
620672
window = session.active_window
621673
assert window is not None
622674
base_pane = window.active_pane
675+
assert base_pane is not None
623676

624677
initial_pane_count = len(window.panes)
625678

0 commit comments

Comments
 (0)