runa/vscode/test/debugHarness.ts

51 lines
1.7 KiB
TypeScript
Raw Permalink Normal View History

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<T = unknown>(command: string, args?: Record<string, unknown>): Promise<T> {
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<DebugMessage> {
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<void> {
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");
}
}