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>
This commit is contained in:
122
editor/tests/step1932_test.cpp
Normal file
122
editor/tests/step1932_test.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user