102 lines
3.5 KiB
C++
102 lines
3.5 KiB
C++
|
|
// Step 1921: LSPErrorRecovery
|
||
|
|
// Tracks per-source health; returns stale cached diagnostics when crashed.
|
||
|
|
//
|
||
|
|
// t1: unknown sources are healthy by default
|
||
|
|
// t2: markCrashed/markRecovered toggle health
|
||
|
|
// t3: healthySources filters crashed sources
|
||
|
|
// t4: fallbackDiagnostics returns cache only when crashed
|
||
|
|
// t5: clearCache removes entries; crashedCount
|
||
|
|
|
||
|
|
#include "LSPErrorRecovery.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::Diagnostic diag(const std::string& uri, int sev,
|
||
|
|
const std::string& msg, const std::string& src) {
|
||
|
|
ws::Diagnostic d; d.uri=uri; d.severity=sev; d.message=msg; d.source=src; return d;
|
||
|
|
}
|
||
|
|
|
||
|
|
void t1(){
|
||
|
|
T(unknown_sources_healthy);
|
||
|
|
ws::LSPErrorRecovery r;
|
||
|
|
C(r.isHealthy("gopls"), "gopls healthy by default");
|
||
|
|
C(r.isHealthy("haskell-lsp"),"haskell-lsp healthy by default");
|
||
|
|
C(r.crashedCount() == 0, "none crashed");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t2(){
|
||
|
|
T(markCrashed_and_markRecovered);
|
||
|
|
ws::LSPErrorRecovery r;
|
||
|
|
r.markCrashed("haskell-lsp");
|
||
|
|
C(!r.isHealthy("haskell-lsp"), "crashed after markCrashed");
|
||
|
|
C( r.isHealthy("gopls"), "gopls still healthy");
|
||
|
|
C(r.crashedCount() == 1, "one crashed");
|
||
|
|
r.markRecovered("haskell-lsp");
|
||
|
|
C( r.isHealthy("haskell-lsp"), "healthy after markRecovered");
|
||
|
|
C(r.crashedCount() == 0, "none crashed after recovery");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t3(){
|
||
|
|
T(healthySources_filters_crashed);
|
||
|
|
ws::LSPErrorRecovery r;
|
||
|
|
r.markCrashed("haskell-lsp");
|
||
|
|
std::vector<std::string> all = {"gopls","haskell-lsp","tsserver"};
|
||
|
|
auto healthy = r.healthySources(all);
|
||
|
|
C(healthy.size() == 2, "two healthy");
|
||
|
|
C(healthy[0] == "gopls", "gopls healthy");
|
||
|
|
C(healthy[1] == "tsserver", "tsserver healthy");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t4(){
|
||
|
|
T(fallbackDiagnostics_only_when_crashed);
|
||
|
|
ws::LSPErrorRecovery r;
|
||
|
|
auto d = diag("file:///Parse.hs",1,"type error","haskell-lsp");
|
||
|
|
r.cacheDiagnostics("haskell-lsp","file:///Parse.hs",{d});
|
||
|
|
// healthy: fallback is empty
|
||
|
|
C(r.fallbackDiagnostics("haskell-lsp","file:///Parse.hs").empty(),
|
||
|
|
"healthy: no fallback");
|
||
|
|
// crash it: fallback returns cache
|
||
|
|
r.markCrashed("haskell-lsp");
|
||
|
|
auto fb = r.fallbackDiagnostics("haskell-lsp","file:///Parse.hs");
|
||
|
|
C(fb.size() == 1, "one fallback diag");
|
||
|
|
C(fb[0].message == "type error", "correct message");
|
||
|
|
// different uri: empty
|
||
|
|
C(r.fallbackDiagnostics("haskell-lsp","file:///Other.hs").empty(),
|
||
|
|
"missing uri empty");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t5(){
|
||
|
|
T(clearCache_and_crashedCount);
|
||
|
|
ws::LSPErrorRecovery r;
|
||
|
|
r.cacheDiagnostics("haskell-lsp","file:///A.hs",
|
||
|
|
{diag("file:///A.hs",1,"E","haskell-lsp")});
|
||
|
|
r.cacheDiagnostics("haskell-lsp","file:///B.hs",
|
||
|
|
{diag("file:///B.hs",2,"W","haskell-lsp")});
|
||
|
|
r.markCrashed("haskell-lsp");
|
||
|
|
C(!r.fallbackDiagnostics("haskell-lsp","file:///A.hs").empty(), "cache present");
|
||
|
|
r.clearCache("haskell-lsp");
|
||
|
|
C(r.fallbackDiagnostics("haskell-lsp","file:///A.hs").empty(), "cache cleared");
|
||
|
|
// crashedCount tracks multiple
|
||
|
|
r.markCrashed("gopls");
|
||
|
|
C(r.crashedCount() == 2, "two crashed");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(){
|
||
|
|
std::cout << "Step 1921: LSPErrorRecovery\n";
|
||
|
|
t1(); t2(); t3(); t4(); t5();
|
||
|
|
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
|
||
|
|
return f > 0 ? 1 : 0;
|
||
|
|
}
|