11import os
22import time
3- from typing import Optional , Callable , Any , List , Union
3+ from typing import Optional
44import uuid
55
66import dap_server
@@ -67,10 +67,7 @@ def set_source_breakpoints_assembly(
6767 self , source_reference , lines , data = None , wait_for_resolve = True
6868 ):
6969 return self .set_source_breakpoints_from_source (
70- Source .build (source_reference = source_reference ),
71- lines ,
72- data ,
73- wait_for_resolve ,
70+ Source (source_reference = source_reference ), lines , data , wait_for_resolve
7471 )
7572
7673 def set_source_breakpoints_from_source (
@@ -123,19 +120,11 @@ def wait_for_breakpoints_to_resolve(
123120 f"Expected to resolve all breakpoints. Unresolved breakpoint ids: { unresolved_breakpoints } " ,
124121 )
125122
126- def wait_until (
127- self ,
128- predicate : Callable [[], bool ],
129- delay : float = 0.5 ,
130- timeout : float = DEFAULT_TIMEOUT ,
131- ) -> bool :
132- """Repeatedly run the predicate until either the predicate returns True
133- or a timeout has occurred."""
134- deadline = time .monotonic () + timeout
135- while deadline > time .monotonic ():
136- if predicate ():
123+ def waitUntil (self , condition_callback ):
124+ for _ in range (20 ):
125+ if condition_callback ():
137126 return True
138- time .sleep (delay )
127+ time .sleep (0.5 )
139128 return False
140129
141130 def assertCapabilityIsSet (self , key : str , msg : Optional [str ] = None ) -> None :
@@ -148,16 +137,13 @@ def assertCapabilityIsNotSet(self, key: str, msg: Optional[str] = None) -> None:
148137 if key in self .dap_server .capabilities :
149138 self .assertEqual (self .dap_server .capabilities [key ], False , msg )
150139
151- def verify_breakpoint_hit (
152- self , breakpoint_ids : List [Union [int , str ]], timeout : float = DEFAULT_TIMEOUT
153- ):
140+ def verify_breakpoint_hit (self , breakpoint_ids , timeout = DEFAULT_TIMEOUT ):
154141 """Wait for the process we are debugging to stop, and verify we hit
155142 any breakpoint location in the "breakpoint_ids" array.
156143 "breakpoint_ids" should be a list of breakpoint ID strings
157144 (["1", "2"]). The return value from self.set_source_breakpoints()
158145 or self.set_function_breakpoints() can be passed to this function"""
159146 stopped_events = self .dap_server .wait_for_stopped (timeout )
160- normalized_bp_ids = [str (b ) for b in breakpoint_ids ]
161147 for stopped_event in stopped_events :
162148 if "body" in stopped_event :
163149 body = stopped_event ["body" ]
@@ -168,16 +154,22 @@ def verify_breakpoint_hit(
168154 and body ["reason" ] != "instruction breakpoint"
169155 ):
170156 continue
171- if "hitBreakpointIds " not in body :
157+ if "description " not in body :
172158 continue
173- hit_breakpoint_ids = body ["hitBreakpointIds" ]
174- for bp in hit_breakpoint_ids :
175- if str (bp ) in normalized_bp_ids :
159+ # Descriptions for breakpoints will be in the form
160+ # "breakpoint 1.1", so look for any description that matches
161+ # ("breakpoint 1.") in the description field as verification
162+ # that one of the breakpoint locations was hit. DAP doesn't
163+ # allow breakpoints to have multiple locations, but LLDB does.
164+ # So when looking at the description we just want to make sure
165+ # the right breakpoint matches and not worry about the actual
166+ # location.
167+ description = body ["description" ]
168+ for breakpoint_id in breakpoint_ids :
169+ match_desc = f"breakpoint { breakpoint_id } ."
170+ if match_desc in description :
176171 return
177- self .assertTrue (
178- False ,
179- f"breakpoint not hit, wanted breakpoint_ids { breakpoint_ids } in stopped_events { stopped_events } " ,
180- )
172+ self .assertTrue (False , f"breakpoint not hit, stopped_events={ stopped_events } " )
181173
182174 def verify_all_breakpoints_hit (self , breakpoint_ids , timeout = DEFAULT_TIMEOUT ):
183175 """Wait for the process we are debugging to stop, and verify we hit
@@ -221,7 +213,7 @@ def verify_stop_exception_info(self, expected_description, timeout=DEFAULT_TIMEO
221213 return True
222214 return False
223215
224- def verify_commands (self , flavor : str , output : str , commands : list [ str ] ):
216+ def verify_commands (self , flavor , output , commands ):
225217 self .assertTrue (output and len (output ) > 0 , "expect console output" )
226218 lines = output .splitlines ()
227219 prefix = "(lldb) "
@@ -234,11 +226,10 @@ def verify_commands(self, flavor: str, output: str, commands: list[str]):
234226 found = True
235227 break
236228 self .assertTrue (
237- found ,
238- f"Command '{ flavor } ' - '{ cmd } ' not found in output: { output } " ,
229+ found , "verify '%s' found in console output for '%s'" % (cmd , flavor )
239230 )
240231
241- def get_dict_value (self , d : dict , key_path : list [ str ]) -> Any :
232+ def get_dict_value (self , d , key_path ) :
242233 """Verify each key in the key_path array is in contained in each
243234 dictionary within "d". Assert if any key isn't in the
244235 corresponding dictionary. This is handy for grabbing values from VS
@@ -307,34 +298,28 @@ def get_source_and_line(self, threadId=None, frameIndex=0):
307298 return (source ["path" ], stackFrame ["line" ])
308299 return ("" , 0 )
309300
310- def get_stdout (self ):
311- return self .dap_server .get_output ("stdout" )
301+ def get_stdout (self , timeout = 0.0 ):
302+ return self .dap_server .get_output ("stdout" , timeout = timeout )
312303
313- def get_console (self ):
314- return self .dap_server .get_output ("console" )
304+ def get_console (self , timeout = 0.0 ):
305+ return self .dap_server .get_output ("console" , timeout = timeout )
315306
316- def get_important (self ):
317- return self .dap_server .get_output ("important" )
307+ def get_important (self , timeout = 0.0 ):
308+ return self .dap_server .get_output ("important" , timeout = timeout )
318309
319- def collect_stdout (
320- self , timeout : float = DEFAULT_TIMEOUT , pattern : Optional [str ] = None
321- ) -> str :
310+ def collect_stdout (self , timeout_secs , pattern = None ):
322311 return self .dap_server .collect_output (
323- "stdout" , timeout = timeout , pattern = pattern
312+ "stdout" , timeout_secs = timeout_secs , pattern = pattern
324313 )
325314
326- def collect_console (
327- self , timeout : float = DEFAULT_TIMEOUT , pattern : Optional [str ] = None
328- ) -> str :
315+ def collect_console (self , timeout_secs , pattern = None ):
329316 return self .dap_server .collect_output (
330- "console" , timeout = timeout , pattern = pattern
317+ "console" , timeout_secs = timeout_secs , pattern = pattern
331318 )
332319
333- def collect_important (
334- self , timeout : float = DEFAULT_TIMEOUT , pattern : Optional [str ] = None
335- ) -> str :
320+ def collect_important (self , timeout_secs , pattern = None ):
336321 return self .dap_server .collect_output (
337- "important" , timeout = timeout , pattern = pattern
322+ "important" , timeout_secs = timeout_secs , pattern = pattern
338323 )
339324
340325 def get_local_as_int (self , name , threadId = None ):
0 commit comments