Files
whetstone_DSL/editor/tests/step1916_test.cpp

141 lines
5.6 KiB
C++
Raw Normal View History

// Step 1916: LSPOrchestrator
// Top-level coordinator: workspace index + cross-lang definition routing +
// diagnostics aggregation + completion merging.
//
// t1: didOpen/didChange/didClose update workspace index via handle()
// t2: textDocument/definition routes cross-language via proxy
// t3: publishDiagnostics and getDiagnostics
// t4: registerCompletions and getCompletions (merged, deduped)
// t5: summary() reflects current state
#include "LSPOrchestrator.h"
#include "ABIBoundaryExtractor.h"
#include "CrossLanguageSymbolTable.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;}
static ws::CrossLanguageSymbolTable buildTable() {
ws::CrossLanguageSymbolTable t;
ws::ABIBoundaryNode n;
n.name="HandleRequest"; n.kind="function";
n.fromComponent="api-client"; n.toComponent="api-server";
n.fromLanguage="TypeScript"; n.toLanguage="Go";
n.signature="void HandleRequest(const char* body)";
t.insert(n);
return t;
}
void t1(){
T(didOpen_didChange_didClose_via_handle);
auto table = buildTable();
ws::LSPOrchestrator orc(table);
// didOpen
json openMsg = {{"jsonrpc","2.0"},{"method","textDocument/didOpen"},
{"params",{{"textDocument",{{"uri","file:///api.go"},{"languageId","go"},
{"text","package main"},{"version",1}}}}}};
orc.handle(openMsg);
C(orc.workspaceIndex().contains("file:///api.go"), "doc opened");
C(orc.workspaceIndex().getLanguage("file:///api.go") == "go", "language go");
// didChange
json changeMsg = {{"jsonrpc","2.0"},{"method","textDocument/didChange"},
{"params",{{"textDocument",{{"uri","file:///api.go"},{"version",2}}},
{"contentChanges",json::array({json{{"text","package api"}}})}}}};
orc.handle(changeMsg);
C(orc.workspaceIndex().getDocument("file:///api.go").content == "package api", "content updated");
C(orc.workspaceIndex().getDocument("file:///api.go").version == 2, "version updated");
// didClose
json closeMsg = {{"jsonrpc","2.0"},{"method","textDocument/didClose"},
{"params",{{"textDocument",{{"uri","file:///api.go"}}}}}};
orc.handle(closeMsg);
C(!orc.workspaceIndex().contains("file:///api.go"), "doc closed");
P();
}
void t2(){
T(definition_routes_cross_language);
auto table = buildTable();
ws::LSPOrchestrator orc(table);
json req = {{"jsonrpc","2.0"},{"id",1},{"method","textDocument/definition"},
{"params",{{"textDocument",{{"uri","file:///client.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");
P();
}
void t3(){
T(publishDiagnostics_and_getDiagnostics);
auto table = buildTable();
ws::LSPOrchestrator orc(table);
ws::Diagnostic d1; d1.uri="file:///a.go"; d1.severity=1; d1.message="E1"; d1.source="gopls";
ws::Diagnostic d2; d2.uri="file:///a.go"; d2.severity=2; d2.message="W1"; d2.source="staticcheck";
orc.publishDiagnostics("gopls", "file:///a.go", {d1});
orc.publishDiagnostics("staticcheck", "file:///a.go", {d2});
auto diags = orc.getDiagnostics("file:///a.go");
C(diags.size() == 2, "two diagnostics");
int errors = 0;
for (auto& d : diags) if (d.severity == 1) ++errors;
C(errors == 1, "one error");
P();
}
void t4(){
T(registerCompletions_merged_deduped);
auto table = buildTable();
ws::LSPOrchestrator orc(table);
orc.registerCompletions("gopls", { {"fmt.Println",3,"func","gopls"},
{"fmt.Printf", 3,"func","gopls"} });
orc.registerCompletions("tsserver", { {"console.log",3,"func","tsserver"},
{"fmt.Println",3,"func","tsserver"} }); // dup
auto items = orc.getCompletions();
C(items.size() == 3, "three unique items");
bool hasGoPrintln = false;
for (auto& i : items)
if (i.label == "fmt.Println") hasGoPrintln = true;
C(hasGoPrintln, "fmt.Println present");
P();
}
void t5(){
T(summary_reflects_state);
auto table = buildTable();
ws::LSPOrchestrator orc(table);
// Open two docs
auto open = [&](const std::string& uri, const std::string& lang){
json m = {{"jsonrpc","2.0"},{"method","textDocument/didOpen"},
{"params",{{"textDocument",{{"uri",uri},{"languageId",lang},
{"text",""},{"version",1}}}}}};
orc.handle(m);
};
open("file:///x.go", "go");
open("file:///y.ts", "typescript");
ws::Diagnostic err; err.uri="file:///x.go"; err.severity=1; err.message="E"; err.source="gopls";
orc.publishDiagnostics("gopls", "file:///x.go", {err});
orc.registerCompletions("gopls", { {"alpha",1,"","gopls"}, {"beta",1,"","gopls"} });
auto s = orc.summary();
C(s.openDocuments == 2, "two open docs");
C(s.diagnosticUris == 1, "one uri with diagnostics");
C(s.completionItems == 2, "two completion items");
C(s.errorCount == 1, "one error");
P();
}
int main(){
std::cout << "Step 1916: LSPOrchestrator\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
return f > 0 ? 1 : 0;
}