// 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 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: "< 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; }