Files
whetstone_DSL/editor/tests/step1932_test.cpp
Bill bbac434b16 Sprint 280: Cross-language step + breakpoints (steps 1928–1932)
CrossLanguageStepOverHandler, CrossLanguageStepIntoHandler,
ASTNodeBreakpointMapper, BreakpointSyncOrchestrator — 26/26 tests pass.
Integration step 1932: Go+TypeScript poly-API round-trip verified.
Metrics: 7 whetstone calls, 5587 tokens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 21:31:05 -07:00

123 lines
4.5 KiB
C++

// Step 1932: Sprint 280 Integration — Poly-API cross-language step + breakpoint round-trip
//
// Scenario: a Go+TypeScript polyglot service.
// - HandleRequest is implemented in both Go and TypeScript.
// - A breakpoint is set on the HandleRequest AST node in both languages.
// - A polyglot stack trace shows the call crossing from TypeScript into Go.
// - Step-into at the boundary switches the active adapter to Go.
// - Removing the breakpoint clears both languages.
//
// t1: breakpoint fires in both languages after addToAll
// t2: step-into at TypeScript→Go boundary switches router to Go
// t3: step-over at boundary stays in TypeScript (caller side)
// t4: removeFromAll clears both Go and TypeScript breakpoints
// t5: Sprint280IntegrationSummary reports 5 steps completed
#include "BreakpointSyncOrchestrator.h"
#include "CrossLanguageStepIntoHandler.h"
#include "CrossLanguageStepOverHandler.h"
#include "DebugAdapterRouter.h"
#include "PolyglotStackTraceDecoder.h"
#include "Sprint280IntegrationSummary.h"
#include <iostream>
namespace ws = whetstone;
static int p=0,f=0;
#define T(n) { std::cout<<" "<<#n<<"... "; }
#define P() { std::cout<<"PASS\n"; ++p; }
#define F(m) { std::cout<<"FAIL: "<<m<<"\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
static ws::DebugAdapterRouter makeRouter() {
ws::DebugAdapterRouter r;
r.registerAdapter("TypeScript", {"stackTrace","stepIn","stepOver"});
r.registerAdapter("Go", {"stackTrace","stepIn","stepOver"});
r.setActiveLanguage("TypeScript");
return r;
}
static std::vector<ws::StackFrame> makeStack() {
ws::PolyglotStackTraceDecoder dec;
return dec.decode({
{1, "apiHandler", "api.ts", 30}, // TypeScript, boundary (next is Go)
{2, "HandleRequest", "server.go", 42}, // Go, boundary (prev is TypeScript)
{3, "processQuery", "server.go", 88}, // Go, non-boundary
});
}
void t1(){
T(breakpoint_fires_in_both_languages);
ws::BreakpointSyncOrchestrator o;
o.addToAll("HandleRequest", {
{"Go", {"server.go", 42}},
{"TypeScript", {"api.ts", 30}}
});
C(o.totalActiveBreakpoints() == 2, "two active");
auto langs = o.activeLanguages("HandleRequest");
bool hasGo = false, hasTs = false;
for (auto& l : langs) {
if (l == "Go") hasGo = true;
if (l == "TypeScript") hasTs = true;
}
C(hasGo && hasTs, "both Go and TypeScript active");
P();
}
void t2(){
T(stepInto_TypeScript_Go_boundary_switches_router);
auto router = makeRouter();
auto frames = makeStack();
ws::CrossLanguageStepIntoHandler h;
// frames[0] is TypeScript boundary; frames[1] is Go
auto r = h.stepInto(frames[0], router, frames, 0);
C( r.switched, "switched");
C( r.previousLanguage == "TypeScript", "previous TypeScript");
C( r.newLanguage == "Go", "new Go");
C( router.getActiveLanguage() == "Go", "router now Go");
C( r.targetFrameId == frames[1].id, "targetFrameId correct");
P();
}
void t3(){
T(stepOver_boundary_stays_in_TypeScript);
auto router = makeRouter();
auto frames = makeStack();
ws::CrossLanguageStepOverHandler h;
// frames[0] is TypeScript boundary — step-over stays in TypeScript
auto r = h.stepOver(frames[0], router);
C( r.crossed, "crossed");
C( r.newLanguage == "TypeScript", "stays TypeScript");
C( router.getActiveLanguage() == "TypeScript", "router still TypeScript");
P();
}
void t4(){
T(removeFromAll_clears_both_languages);
ws::BreakpointSyncOrchestrator o;
o.addToAll("HandleRequest", {
{"Go", {"server.go", 42}},
{"TypeScript", {"api.ts", 30}}
});
C(o.totalActiveBreakpoints() == 2, "two before remove");
o.removeFromAll("HandleRequest");
C(o.totalActiveBreakpoints() == 0, "zero after remove");
C(o.activeLanguages("HandleRequest").empty(), "no active languages");
P();
}
void t5(){
T(sprint280_integration_summary);
ws::Sprint280IntegrationSummary s;
C(s.stepsCompleted == 5, "5 steps");
C(s.success, "success");
C(s.sprintName() == "Sprint 280: Cross-Language Step + Breakpoints", "name");
P();
}
int main(){
std::cout << "Step 1932: Sprint 280 Integration\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
return f > 0 ? 1 : 0;
}