Files
whetstone_DSL/editor/tests/step1917_test.cpp

165 lines
6.6 KiB
C++
Raw Normal View History

// Step 1917: Sprint 277 Integration
// poly-api project: Go HTTP server + TypeScript client.
// The orchestrator opens both files, handles cross-language goto-definition
// (TS client calls Go handler), aggregates diagnostics from both servers,
// and merges completions from both LSPs.
//
// t1: poly-api symbol table loads Go+TS boundary
// t2: orchestrator opens Go+TS docs via didOpen messages
// t3: TS→Go cross-language goto-definition resolves through orchestrator
// t4: diagnostics from gopls + tsserver aggregated per URI
// t5: completions merged from gopls + tsserver, deduped; summary accurate
// t6 (bonus): Sprint277IntegrationSummary reports complete
#include "LSPOrchestrator.h"
#include "ABIBoundaryExtractor.h"
#include "CrossLanguageSymbolTable.h"
#include "Sprint277IntegrationSummary.h"
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
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;}
// poly-api: TypeScript client calls Go server via HTTP handler
static ws::CrossLanguageSymbolTable buildPolyApiTable() {
ws::CrossLanguageSymbolTable table;
ws::ABIBoundaryNode n1;
n1.name="HandleRequest"; n1.kind="function";
n1.fromComponent="api-client"; n1.toComponent="api-server";
n1.fromLanguage="TypeScript"; n1.toLanguage="Go";
n1.signature="void HandleRequest(const char* body, int len)";
table.insert(n1);
ws::ABIBoundaryNode n2;
n2.name="HandleHealthCheck"; n2.kind="function";
n2.fromComponent="api-client"; n2.toComponent="api-server";
n2.fromLanguage="TypeScript"; n2.toLanguage="Go";
n2.signature="void HandleHealthCheck()";
table.insert(n2);
return table;
}
static void openDoc(ws::LSPOrchestrator& orc, const std::string& uri,
const std::string& lang, const std::string& text) {
json m = {{"jsonrpc","2.0"},{"method","textDocument/didOpen"},
{"params",{{"textDocument",{{"uri",uri},{"languageId",lang},
{"text",text},{"version",1}}}}}};
orc.handle(m);
}
void t1(){
T(polyapi_symbol_table_loads);
auto table = buildPolyApiTable();
C(table.contains("TypeScript", "HandleRequest"), "TS has HandleRequest");
C(table.contains("Go", "HandleRequest"), "Go has HandleRequest");
C(table.contains("TypeScript", "HandleHealthCheck"), "TS has HandleHealthCheck");
P();
}
void t2(){
T(orchestrator_opens_go_and_ts_docs);
auto table = buildPolyApiTable();
ws::LSPOrchestrator orc(table);
openDoc(orc, "file:///server/main.go", "go", "package main");
openDoc(orc, "file:///client/api.ts", "typescript", "export {}");
C(orc.workspaceIndex().size() == 2, "two docs open");
C(orc.workspaceIndex().getLanguage("file:///server/main.go") == "go", "go lang");
C(orc.workspaceIndex().getLanguage("file:///client/api.ts") == "typescript", "ts lang");
P();
}
void t3(){
T(ts_to_go_definition_resolves_through_orchestrator);
auto table = buildPolyApiTable();
ws::LSPOrchestrator orc(table);
openDoc(orc, "file:///client/api.ts", "typescript", "HandleRequest();");
json req = {{"jsonrpc","2.0"},{"id",1},{"method","textDocument/definition"},
{"params",{{"textDocument",{{"uri","file:///client/api.ts"}}},
{"symbol","HandleRequest"}}}};
auto resp = orc.handle(req);
C(resp.contains("result"), "has result");
C(!resp["result"].is_null(), "result not null");
C(resp["result"]["language"] == "Go", "provider language Go");
C(resp["result"]["provider"] == "api-server", "provider component api-server");
C(resp["result"]["scipSymbol"] == "api-server/HandleRequest.", "scip symbol");
P();
}
void t4(){
T(diagnostics_aggregated_from_gopls_and_tsserver);
auto table = buildPolyApiTable();
ws::LSPOrchestrator orc(table);
openDoc(orc, "file:///server/main.go", "go", "package main");
openDoc(orc, "file:///client/api.ts", "typescript", "");
ws::Diagnostic goErr; goErr.uri="file:///server/main.go"; goErr.severity=1;
goErr.message="undefined: x"; goErr.source="gopls";
ws::Diagnostic tsWarn; tsWarn.uri="file:///client/api.ts"; tsWarn.severity=2;
tsWarn.message="implicit any"; tsWarn.source="tsserver";
ws::Diagnostic tsErr; tsErr.uri="file:///client/api.ts"; tsErr.severity=1;
tsErr.message="type mismatch"; tsErr.source="tsserver";
orc.publishDiagnostics("gopls", "file:///server/main.go", {goErr});
orc.publishDiagnostics("tsserver", "file:///client/api.ts", {tsWarn, tsErr});
auto goDiags = orc.getDiagnostics("file:///server/main.go");
C(goDiags.size() == 1, "one go diagnostic");
C(goDiags[0].severity == 1, "go diagnostic is error");
auto tsDiags = orc.getDiagnostics("file:///client/api.ts");
C(tsDiags.size() == 2, "two ts diagnostics");
P();
}
void t5(){
T(completions_merged_and_summary_accurate);
auto table = buildPolyApiTable();
ws::LSPOrchestrator orc(table);
openDoc(orc, "file:///server/main.go", "go", "package main");
openDoc(orc, "file:///client/api.ts", "typescript", "");
orc.registerCompletions("gopls", { {"fmt.Println",3,"func","gopls"},
{"HandleRequest",2,"func","gopls"} });
orc.registerCompletions("tsserver", { {"console.log",3,"func","tsserver"},
{"HandleRequest",2,"func","tsserver"} }); // dup
auto items = orc.getCompletions();
C(items.size() == 3, "three unique completions");
ws::Diagnostic err; err.uri="file:///server/main.go"; err.severity=1;
err.message="E1"; err.source="gopls";
orc.publishDiagnostics("gopls", "file:///server/main.go", {err});
auto s = orc.summary();
C(s.openDocuments == 2, "two open docs");
C(s.diagnosticUris == 1, "one uri with diagnostics");
C(s.completionItems == 3, "three completion items");
C(s.errorCount == 1, "one error");
P();
}
void t6(){
T(sprint277_integration_summary_complete);
ws::Sprint277IntegrationSummary s;
C(s.stepsCompleted == 5, "5 steps");
C(s.success, "success");
C(s.sprintName().find("277") != std::string::npos,"sprint 277 in name");
P();
}
int main(){
std::cout << "Step 1917: Sprint 277 Integration (poly-api: Go+TypeScript)\n";
t1(); t2(); t3(); t4(); t5(); t6();
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
return f > 0 ? 1 : 0;
}