import { ActorDebugAdapter, DebugMessage } from "../src/debugger"; export class DebugHarness { readonly adapter: ActorDebugAdapter; readonly messages: DebugMessage[] = []; private seq = 0; private readonly listeners = new Set<() => void>(); constructor(create: (send: (message: DebugMessage) => void) => ActorDebugAdapter) { this.adapter = create((message) => { this.messages.push(message); for (const listener of this.listeners) listener(); }); } async request(command: string, args?: Record): Promise { const seq = ++this.seq; const response = this.wait((message) => message.request_seq === seq); this.adapter.handleMessage({ seq, type: "request", command, arguments: args }); const message = await response; if (!message.success) throw new Error(message.message); return message.body as T; } wait(predicate: (message: DebugMessage) => boolean, since = 0): Promise { return new Promise((resolve, reject) => { const check = () => { const found = this.messages.slice(since).find(predicate); if (!found) return; clearTimeout(timer); this.listeners.delete(check); resolve(found); }; const timer = setTimeout(() => { this.listeners.delete(check); reject(new Error("Timed out waiting for DAP message")); }, 5000); this.listeners.add(check); check(); }); } async attach(): Promise { await this.request("initialize"); await this.request("attach"); await this.wait((message) => message.event === "initialized"); await this.request("configurationDone"); await this.wait((message) => message.event === "stopped"); } }