import json
import sys
import os
def log(msg):
print(f"[mock-dap] {msg}", file=sys.stderr, flush=True)
def read_frame():
header = b""
while not header.endswith(b"\r\n\r\n"):
byte = sys.stdin.buffer.read(1)
if not byte:
log("stdin closed")
sys.exit(0)
header += byte
header_str = header.decode("utf-8")
content_length = 0
for line in header_str.split("\r\n"):
if line.lower().startswith("content-length:"):
content_length = int(line.split(":", 1)[1].strip())
if content_length == 0:
log(f"zero-length frame, header was: {header_str!r}")
return None
body = sys.stdin.buffer.read(content_length)
return json.loads(body)
def write_frame(obj):
body = json.dumps(obj, separators=(",", ":")).encode("utf-8")
header = f"Content-Length: {len(body)}\r\n\r\n".encode("utf-8")
sys.stdout.buffer.write(header + body)
sys.stdout.buffer.flush()
def send_response(request_seq, command, body=None, success=True, message=None):
resp = {
"type": "response",
"seq": next_seq(),
"request_seq": request_seq,
"command": command,
"success": success,
}
if body is not None:
resp["body"] = body
if message is not None:
resp["message"] = message
write_frame(resp)
def send_event(event_type, body=None):
evt = {
"type": "event",
"seq": next_seq(),
"event": event_type,
}
if body is not None:
evt["body"] = body
write_frame(evt)
_seq = 0
def next_seq():
global _seq
_seq += 1
return _seq
stopped_thread_id = 1
frame_id_counter = 1000
variable_ref_counter = 2000
def main():
global frame_id_counter, variable_ref_counter
log("mock DAP adapter starting")
msg = read_frame()
assert msg["command"] == "initialize", f"expected initialize, got {msg}"
send_response(
msg["seq"],
"initialize",
body={
"supportsConfigurationDoneRequest": True,
"supportsEvaluateForHovers": True,
"supportsStepInTargetsRequest": True,
"supportsConditionalBreakpoints": True,
"supportsFunctionBreakpoints": True,
"supportsSetVariable": True,
"supportsTerminateRequest": True,
"supportsDisassembleRequest": False,
"supportTerminateDebuggee": True,
},
)
send_event("initialized")
msg = read_frame()
assert msg["command"] == "launch", f"expected launch, got {msg}"
send_response(msg["seq"], "launch")
send_event(
"stopped",
body={"reason": "entry", "threadId": stopped_thread_id, "allThreadsStopped": True},
)
msg = read_frame()
assert msg["command"] == "setBreakpoints", f"expected setBreakpoints, got {msg}"
bps = msg.get("arguments", {}).get("breakpoints", [])
send_response(
msg["seq"],
"setBreakpoints",
body={
"breakpoints": [
{"id": i + 1, "verified": True, "line": bp.get("line", 0)}
for i, bp in enumerate(bps)
]
},
)
msg = read_frame()
assert msg["command"] == "configurationDone", f"expected configurationDone, got {msg}"
send_response(msg["seq"], "configurationDone")
msg = read_frame()
assert msg["command"] == "threads", f"expected threads, got {msg}"
send_response(
msg["seq"],
"threads",
body={"threads": [{"id": stopped_thread_id, "name": "MainThread"}]},
)
msg = read_frame()
assert msg["command"] == "stackTrace", f"expected stackTrace, got {msg}"
frame_id_1 = frame_id_counter
frame_id_counter += 1
send_response(
msg["seq"],
"stackTrace",
body={
"stackFrames": [
{
"id": frame_id_1,
"name": "main",
"source": {"name": "test.py", "path": "/tmp/test.py"},
"line": 10,
"column": 0,
}
],
"totalFrames": 1,
},
)
msg = read_frame()
assert msg["command"] == "scopes", f"expected scopes, got {msg}"
var_ref = variable_ref_counter
variable_ref_counter += 1
send_response(
msg["seq"],
"scopes",
body={
"scopes": [
{
"name": "Locals",
"variablesReference": var_ref,
"expensive": False,
}
]
},
)
msg = read_frame()
assert msg["command"] == "variables", f"expected variables, got {msg}"
send_response(
msg["seq"],
"variables",
body={
"variables": [
{"name": "x", "value": "42", "type": "int", "variablesReference": 0}
]
},
)
msg = read_frame()
assert msg["command"] == "evaluate", f"expected evaluate, got {msg}"
send_response(
msg["seq"],
"evaluate",
body={"result": "2", "type": "int", "variablesReference": 0},
)
msg = read_frame()
assert msg["command"] == "continue", f"expected continue, got {msg}"
send_response(
msg["seq"],
"continue",
body={"allThreadsContinued": True},
)
send_event(
"stopped",
body={"reason": "breakpoint", "threadId": stopped_thread_id, "allThreadsStopped": True},
)
msg = read_frame()
assert msg["command"] == "terminate", f"expected terminate, got {msg}"
send_response(msg["seq"], "terminate")
send_event("terminated")
msg = read_frame()
assert msg["command"] == "disconnect", f"expected disconnect, got {msg}"
send_response(msg["seq"], "disconnect")
send_event("exited", body={"exitCode": 0})
log("mock DAP adapter exiting normally")
if __name__ == "__main__":
try:
main()
except Exception as e:
log(f"FATAL: {e}")
sys.exit(1)