Files
whetstone_DSL/editor/tests/step1919_test.cpp
Bill 4d47e894c1 Sprint 278: LSP Proxy Hardening (steps 1918-1922)
- LSPMessageValidator: JSON-RPC 2.0 shape validation (method, id type, params type)
- LSPCapabilityNegotiator: per-source capability tracking; shouldRoute gates on declared caps
- LSPRequestThrottler: per-URI/method debounce; blocks rapid didChange floods
- LSPErrorRecovery: per-source health tracking; stale-cache fallback when crashed
- Sprint278IntegrationSummary: poly-parse (C++ + Haskell) end-to-end integration

26/26 tests passing (5+5+5+5+6). All new headers well under 600 lines.
LoRA recorded: sprint278-2026-03-01 (9 calls, 6437 tokens).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 20:28:31 -07:00

93 lines
3.8 KiB
C++

// Step 1919: LSPCapabilityNegotiator
// Tracks per-source capability sets; gates routing on capability support.
//
// t1: registerSource and supports
// t2: shouldRoute blocks unsupported method; passes unknown methods
// t3: capabilitiesFor returns sorted capability list
// t4: sourcesSupporting finds all sources with a given capability
// t5: unregistered source supports nothing; shouldRoute passes unknown sources
#include "LSPCapabilityNegotiator.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;}
void t1(){
T(registerSource_and_supports);
ws::LSPCapabilityNegotiator n;
n.registerSource("gopls", {"hoverProvider","definitionProvider","referencesProvider"});
C( n.supports("gopls","hoverProvider"), "gopls has hover");
C( n.supports("gopls","definitionProvider"), "gopls has definition");
C(!n.supports("gopls","completionProvider"), "gopls lacks completion");
C(!n.supports("tsserver","hoverProvider"), "unregistered lacks anything");
P();
}
void t2(){
T(shouldRoute_blocks_unsupported_passes_unknown);
ws::LSPCapabilityNegotiator n;
n.registerSource("gopls", {"hoverProvider","definitionProvider"});
n.registerSource("tsserver", {"hoverProvider","completionProvider"});
// gopls supports hover → route
C( n.shouldRoute("gopls", "textDocument/hover"), "gopls routes hover");
// gopls lacks completion → block
C(!n.shouldRoute("gopls", "textDocument/completion"), "gopls blocks completion");
// tsserver supports completion → route
C( n.shouldRoute("tsserver", "textDocument/completion"), "tsserver routes completion");
// unknown method passes through for all sources
C( n.shouldRoute("gopls", "workspace/symbol"), "unknown method passes");
C( n.shouldRoute("tsserver", "workspace/symbol"), "unknown method passes ts");
P();
}
void t3(){
T(capabilitiesFor_returns_list);
ws::LSPCapabilityNegotiator n;
n.registerSource("gopls", {"hoverProvider","definitionProvider","referencesProvider"});
auto caps = n.capabilitiesFor("gopls");
C(caps.size() == 3, "three caps");
C(n.capabilitiesFor("missing").empty(), "missing source empty");
P();
}
void t4(){
T(sourcesSupporting_finds_all);
ws::LSPCapabilityNegotiator n;
n.registerSource("gopls", {"hoverProvider","definitionProvider"});
n.registerSource("tsserver", {"hoverProvider","completionProvider"});
n.registerSource("pylsp", {"hoverProvider","referencesProvider"});
auto hover = n.sourcesSupporting("hoverProvider");
C(hover.size() == 3, "three hover sources");
auto def = n.sourcesSupporting("definitionProvider");
C(def.size() == 1, "one definition source");
C(def[0] == "gopls", "gopls for definition");
C(n.sourcesSupporting("renameProvider").empty(), "none for rename");
P();
}
void t5(){
T(unregistered_source_behavior);
ws::LSPCapabilityNegotiator n;
// unregistered source: supports() returns false
C(!n.supports("unknown","hoverProvider"), "unregistered lacks caps");
// unregistered source: known method requires capability → shouldRoute false
// because supports() returns false for the required cap
C(!n.shouldRoute("unknown","textDocument/hover"), "unregistered blocked on known method");
// unregistered source: unknown method → passes through
C( n.shouldRoute("unknown","$/custom"), "unknown method passes for unregistered");
P();
}
int main(){
std::cout << "Step 1919: LSPCapabilityNegotiator\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
return f > 0 ? 1 : 0;
}