Skip to content

Commit b445651

Browse files
committed
implement hit_condition and hit log_message for breakpoints
1 parent bf985f7 commit b445651

File tree

1 file changed

+61
-20
lines changed

1 file changed

+61
-20
lines changed

robotcode/debug_adapter/launcher/debugger.py

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ def global_id(self) -> int:
104104
return id(self._global_marker)
105105

106106

107+
class HitCountEntry(NamedTuple):
108+
source: str
109+
line: int
110+
type: str
111+
112+
107113
class Debugger:
108114
__instance = None
109115
__lock = threading.RLock()
@@ -147,6 +153,7 @@ def __init__(self) -> None:
147153
self.output_messages: bool = False
148154
self.output_log: bool = False
149155
self.group_output: bool = False
156+
self.hit_counts: Dict[HitCountEntry, int] = {}
150157

151158
@property
152159
def robot_report_file(self) -> Optional[str]:
@@ -294,7 +301,7 @@ def set_breakpoints(
294301

295302
return []
296303

297-
def process_state(self, source: Optional[str], line_no: Optional[int], type: Optional[str]) -> None:
304+
def process_state(self, source: str, line_no: int, type: str) -> None:
298305
from robot.running.context import EXECUTION_CONTEXTS
299306
from robot.variables.evaluation import evaluate_expression
300307

@@ -359,6 +366,7 @@ def process_state(self, source: Optional[str], line_no: Optional[int], type: Opt
359366
if len(breakpoints) > 0:
360367
for point in breakpoints:
361368
if point.condition is not None:
369+
hit = False
362370
try:
363371
vars = EXECUTION_CONTEXTS.current.variables.current
364372
hit = bool(evaluate_expression(vars.replace_string(point.condition), vars.store))
@@ -367,18 +375,48 @@ def process_state(self, source: Optional[str], line_no: Optional[int], type: Opt
367375

368376
if not hit:
369377
return
370-
371-
self.state = State.Paused
372-
self.send_event(
373-
self,
374-
StoppedEvent(
375-
body=StoppedEventBody(
376-
reason=StoppedReason.BREAKPOINT,
377-
thread_id=threading.current_thread().ident,
378-
hit_breakpoint_ids=[id(v) for v in breakpoints],
378+
if point.hit_condition is not None:
379+
hit = False
380+
entry = HitCountEntry(source, line_no, type)
381+
if entry not in self.hit_counts:
382+
self.hit_counts[entry] = 0
383+
self.hit_counts[entry] += 1
384+
try:
385+
hit = self.hit_counts[entry] != int(point.hit_condition)
386+
except BaseException:
387+
hit = False
388+
if not hit:
389+
return
390+
if point.log_message:
391+
vars = EXECUTION_CONTEXTS.current.variables.current
392+
try:
393+
message = vars.replace_string(point.log_message)
394+
except BaseException as e:
395+
message = f"{point.log_message}\nError: {e}"
396+
self.send_event(
397+
self,
398+
OutputEvent(
399+
body=OutputEventBody(
400+
output=message,
401+
category=OutputCategory.CONSOLE,
402+
source=Source(path=source) if source else None,
403+
line=line_no,
404+
)
405+
),
406+
)
407+
return
408+
else:
409+
self.state = State.Paused
410+
self.send_event(
411+
self,
412+
StoppedEvent(
413+
body=StoppedEventBody(
414+
reason=StoppedReason.BREAKPOINT,
415+
thread_id=threading.current_thread().ident,
416+
hit_breakpoint_ids=[id(v) for v in breakpoints],
417+
)
418+
),
379419
)
380-
),
381-
)
382420

383421
@_logger.call
384422
def wait_for_running(self) -> None:
@@ -398,7 +436,7 @@ def start_output_group(self, name: str, attributes: Dict[str, Any], type: Option
398436
# category=OutputCategory.CONSOLE,
399437
category="log",
400438
group=OutputGroup.STARTCOLLAPSED,
401-
source=Source(name=name, path=source) if source else None,
439+
source=Source(path=source) if source else None,
402440
line=line_no,
403441
)
404442
),
@@ -417,7 +455,7 @@ def end_output_group(self, name: str, attributes: Dict[str, Any]) -> None:
417455
# category=OutputCategory.CONSOLE,
418456
category="log",
419457
group=OutputGroup.END,
420-
source=Source(name=name, path=source) if source else None,
458+
source=Source(path=source) if source else None,
421459
line=line_no,
422460
)
423461
),
@@ -459,9 +497,10 @@ def start_suite(self, name: str, attributes: Dict[str, Any]) -> None:
459497

460498
entry = self.add_stackframe_entry(longname, type, source, line_no)
461499

462-
self.process_state(entry.source, entry.line, entry.type)
500+
if entry.source:
501+
self.process_state(entry.source, entry.line, entry.type)
463502

464-
self.wait_for_running()
503+
self.wait_for_running()
465504

466505
def end_suite(self, name: str, attributes: Dict[str, Any]) -> None:
467506
if self.stack_frames:
@@ -475,9 +514,10 @@ def start_test(self, name: str, attributes: Dict[str, Any]) -> None:
475514

476515
entry = self.add_stackframe_entry(longname, type, source, line_no)
477516

478-
self.process_state(entry.source, entry.line, entry.type)
517+
if entry.source:
518+
self.process_state(entry.source, entry.line, entry.type)
479519

480-
self.wait_for_running()
520+
self.wait_for_running()
481521

482522
def end_test(self, name: str, attributes: Dict[str, Any]) -> None:
483523
if self.stack_frames:
@@ -496,9 +536,10 @@ def start_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
496536

497537
entry = self.add_stackframe_entry(kwname, type, source, line_no)
498538

499-
self.process_state(entry.source, entry.line, entry.type)
539+
if entry.source:
540+
self.process_state(entry.source, entry.line, entry.type)
500541

501-
self.wait_for_running()
542+
self.wait_for_running()
502543

503544
def end_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
504545
status = attributes.get("status", "")

0 commit comments

Comments
 (0)