88
99import asyncio
1010import logging
11+ from dataclasses import dataclass
1112from typing import TYPE_CHECKING
1213
1314import pytest
1415
1516if 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+
1846logger = 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