108 lines
4.0 KiB
C++
108 lines
4.0 KiB
C++
|
|
// Step 1925: PolyglotStackTraceDecoder
|
||
|
|
// Decodes flat raw frames into language-annotated StackFrames.
|
||
|
|
//
|
||
|
|
// t1: languageFromSource infers language from extension
|
||
|
|
// t2: decode sets language and astNodeId per frame
|
||
|
|
// t3: single-language stack: no boundary frames
|
||
|
|
// t4: two-language stack: boundary frames marked at seam
|
||
|
|
// t5: three-language stack: multiple boundary regions
|
||
|
|
|
||
|
|
#include "PolyglotStackTraceDecoder.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::RawFrame rf(int id, const std::string& name, const std::string& src, int line=1){
|
||
|
|
return {id, name, src, line};
|
||
|
|
}
|
||
|
|
|
||
|
|
void t1(){
|
||
|
|
T(languageFromSource);
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("main.py") == "Python", ".py");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("lib.rs") == "Rust", ".rs");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("server.go") == "Go", ".go");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("app.ts") == "TypeScript", ".ts");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("app.js") == "TypeScript", ".js");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("util.cpp") == "C++", ".cpp");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("util.h") == "C++", ".h");
|
||
|
|
C(ws::PolyglotStackTraceDecoder::languageFromSource("noext") == "Unknown", "no ext");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t2(){
|
||
|
|
T(decode_sets_language_and_astNodeId);
|
||
|
|
ws::PolyglotStackTraceDecoder dec;
|
||
|
|
auto frames = dec.decode({rf(1,"main","main.py"), rf(2,"sort_array","lib.rs")});
|
||
|
|
C(frames.size() == 2, "two frames");
|
||
|
|
C(frames[0].language == "Python", "frame0 Python");
|
||
|
|
C(frames[0].astNodeId == "Python:main","frame0 astNodeId");
|
||
|
|
C(frames[1].language == "Rust", "frame1 Rust");
|
||
|
|
C(frames[1].astNodeId == "Rust:sort_array","frame1 astNodeId");
|
||
|
|
C(frames[0].id == 1, "id preserved");
|
||
|
|
C(frames[0].name == "main", "name preserved");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t3(){
|
||
|
|
T(single_language_no_boundaries);
|
||
|
|
ws::PolyglotStackTraceDecoder dec;
|
||
|
|
auto frames = dec.decode({
|
||
|
|
rf(1,"main", "main.py"),
|
||
|
|
rf(2,"process","process.py"),
|
||
|
|
rf(3,"helper", "helper.py")
|
||
|
|
});
|
||
|
|
for (auto& fr : frames)
|
||
|
|
C(!fr.isBoundary, fr.name + " should not be boundary");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t4(){
|
||
|
|
T(two_language_boundary_at_seam);
|
||
|
|
ws::PolyglotStackTraceDecoder dec;
|
||
|
|
// Python frames then Rust frame
|
||
|
|
auto frames = dec.decode({
|
||
|
|
rf(1,"run", "main.py"),
|
||
|
|
rf(2,"generate", "data.py"),
|
||
|
|
rf(3,"sort_array", "sorter.rs"),
|
||
|
|
});
|
||
|
|
C(!frames[0].isBoundary, "run: not boundary (only next differs)");
|
||
|
|
// frame[1] "generate": next is Rust → boundary
|
||
|
|
C( frames[1].isBoundary, "generate: boundary (next is Rust)");
|
||
|
|
// frame[2] "sort_array": prev is Python → boundary
|
||
|
|
C( frames[2].isBoundary, "sort_array: boundary (prev is Python)");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t5(){
|
||
|
|
T(three_language_multiple_boundaries);
|
||
|
|
ws::PolyglotStackTraceDecoder dec;
|
||
|
|
auto frames = dec.decode({
|
||
|
|
rf(1,"py_main", "main.py"), // Python
|
||
|
|
rf(2,"rs_sort", "sort.rs"), // Rust ← seam
|
||
|
|
rf(3,"rs_inner", "inner.rs"), // Rust
|
||
|
|
rf(4,"go_send", "sender.go"), // Go ← seam
|
||
|
|
});
|
||
|
|
// py_main: next=Rust → boundary
|
||
|
|
C( frames[0].isBoundary, "py_main boundary (next is Rust)");
|
||
|
|
// rs_sort: prev=Python, next=Rust → boundary (prev diff only)
|
||
|
|
C( frames[1].isBoundary, "rs_sort boundary (prev Python)");
|
||
|
|
// rs_inner: next=Go → boundary
|
||
|
|
C( frames[2].isBoundary, "rs_inner boundary (next Go)");
|
||
|
|
// go_send: prev=Rust → boundary
|
||
|
|
C( frames[3].isBoundary, "go_send boundary (prev Rust)");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(){
|
||
|
|
std::cout << "Step 1925: PolyglotStackTraceDecoder\n";
|
||
|
|
t1(); t2(); t3(); t4(); t5();
|
||
|
|
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
|
||
|
|
return f > 0 ? 1 : 0;
|
||
|
|
}
|