// Step 1928: CrossLanguageStepOverHandler // // t1: isAtBoundary delegates to frame.isBoundary // t2: stepOver at non-boundary returns crossed=false, no router change // t3: stepOver at boundary returns crossed=true, sets router to frame language // t4: stepOver records previousLanguage correctly // t5: successive step-overs across multiple boundary frames #include "CrossLanguageStepOverHandler.h" #include "PolyglotStackTraceDecoder.h" #include "DebugAdapterRouter.h" #include 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: "< makeStack() { ws::PolyglotStackTraceDecoder dec; return dec.decode({ {1,"run", "main.py", 10}, {2,"generate", "gen.py", 20}, // boundary (next is Rust) {3,"sort_array","sort.rs", 5}, // boundary (prev is Python) {4,"partition", "sort.rs", 15}, }); } void t1(){ T(isAtBoundary_delegates_to_frame); ws::CrossLanguageStepOverHandler h; auto frames = makeStack(); C(!h.isAtBoundary(frames[0]), "frame0 not boundary"); C( h.isAtBoundary(frames[1]), "frame1 boundary"); C( h.isAtBoundary(frames[2]), "frame2 boundary"); C(!h.isAtBoundary(frames[3]), "frame3 not boundary"); P(); } void t2(){ T(stepOver_non_boundary_returns_not_crossed); ws::CrossLanguageStepOverHandler h; auto router = makeRouter(); auto frames = makeStack(); auto r = h.stepOver(frames[0], router); C(!r.crossed, "not crossed"); C(r.previousLanguage.empty(), "no previous"); C(r.newLanguage.empty(), "no new"); C(router.getActiveLanguage() == "Python", "router unchanged"); P(); } void t3(){ T(stepOver_boundary_sets_router_to_frame_language); ws::CrossLanguageStepOverHandler h; auto router = makeRouter(); auto frames = makeStack(); // frame[1] is Python boundary — step-over stays in Python (caller side) auto r = h.stepOver(frames[1], router); C( r.crossed, "crossed"); C( r.newLanguage == "Python", "stays in Python"); C( router.getActiveLanguage() == "Python", "router set to Python"); P(); } void t4(){ T(stepOver_records_previousLanguage); ws::CrossLanguageStepOverHandler h; auto router = makeRouter(); router.setActiveLanguage("Rust"); auto frames = makeStack(); // frame[2] is Rust, boundary — step-over sets router to Rust auto r = h.stepOver(frames[2], router); C(r.crossed, "crossed"); C(r.previousLanguage == "Rust","previous was Rust"); C(r.newLanguage == "Rust", "new is Rust (frame language)"); P(); } void t5(){ T(successive_stepOvers); ws::CrossLanguageStepOverHandler h; ws::PolyglotStackTraceDecoder dec; auto frames = dec.decode({ {1,"a","a.py",1},{2,"b","b.rs",1},{3,"c","c.go",1} }); auto router = makeRouter(); router.registerAdapter("Go", {"continue"}); router.setActiveLanguage("Python"); // All three frames are boundaries for (auto& fr : frames) C(h.isAtBoundary(fr), fr.name + " is boundary"); // Step-over frame[0] (Python): stays Python auto r0 = h.stepOver(frames[0], router); C(r0.newLanguage == "Python", "step-over0 stays Python"); // Step-over frame[1] (Rust): router goes to Rust auto r1 = h.stepOver(frames[1], router); C(r1.newLanguage == "Rust", "step-over1 to Rust"); P(); } int main(){ std::cout << "Step 1928: CrossLanguageStepOverHandler\n"; t1(); t2(); t3(); t4(); t5(); std::cout << "\n" << p << "/" << (p+f) << " passed\n"; return f > 0 ? 1 : 0; }