feat(lsp): hover, documentSymbol, willSaveWaitUntil, token-wide diagnostic ranges
This commit is contained in:
@@ -268,3 +268,90 @@ func TestDidClose_ClearsDiagnostics(t *testing.T) {
|
||||
t.Errorf("expected empty diagnostics after didClose, got %d", len(lastDiags))
|
||||
}
|
||||
}
|
||||
|
||||
// request opens text at uri, sends one request, and returns its response
|
||||
// (skipping the initialize response and any notifications).
|
||||
func request(t *testing.T, text, method string, params map[string]interface{}) map[string]interface{} {
|
||||
t.Helper()
|
||||
uri := "file:///t.sql"
|
||||
params["textDocument"] = map[string]interface{}{"uri": uri}
|
||||
var input []byte
|
||||
input = append(input, frame(1, "initialize", map[string]interface{}{})...)
|
||||
input = append(input, notifFrame("initialized", nil)...)
|
||||
input = append(input, notifFrame("textDocument/didOpen", map[string]interface{}{
|
||||
"textDocument": map[string]interface{}{"uri": uri, "languageId": "sql", "version": 1, "text": text},
|
||||
})...)
|
||||
input = append(input, frame(2, method, params)...)
|
||||
input = append(input, frame(3, "shutdown", nil)...)
|
||||
input = append(input, notifFrame("exit", nil)...)
|
||||
out := runServer(t, input)
|
||||
for i := 0; i < 10; i++ {
|
||||
resp := readResp(t, out)
|
||||
if id, ok := resp["id"]; ok && id.(float64) == 2 {
|
||||
return resp
|
||||
}
|
||||
}
|
||||
t.Fatalf("no response to %s", method)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestDocumentSymbol(t *testing.T) {
|
||||
src := "create function public.foo(a int) returns void language plpgsql as $$ begin end $$;\n\ncreate procedure bar() language plpgsql as $$ begin end $$;\n"
|
||||
resp := request(t, src, "textDocument/documentSymbol", map[string]interface{}{})
|
||||
syms := resp["result"].([]interface{})
|
||||
if len(syms) != 2 {
|
||||
t.Fatalf("want 2 symbols, got %v", syms)
|
||||
}
|
||||
first := syms[0].(map[string]interface{})
|
||||
if first["name"] != "public.foo" || first["detail"] != "function" {
|
||||
t.Errorf("first symbol: %v", first)
|
||||
}
|
||||
second := syms[1].(map[string]interface{})
|
||||
if second["name"] != "bar" || second["detail"] != "procedure" {
|
||||
t.Errorf("second symbol: %v", second)
|
||||
}
|
||||
line := second["range"].(map[string]interface{})["start"].(map[string]interface{})["line"].(float64)
|
||||
if line != 2 {
|
||||
t.Errorf("bar should start on line 2, got %v", line)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHoverShowsDiagnostic(t *testing.T) {
|
||||
resp := request(t, "select * from t;", "textDocument/hover", map[string]interface{}{
|
||||
"position": map[string]interface{}{"line": 0, "character": 7},
|
||||
})
|
||||
res, ok := resp["result"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected hover result, got %v", resp["result"])
|
||||
}
|
||||
val := res["contents"].(map[string]interface{})["value"].(string)
|
||||
if !strings.Contains(val, "COR001") {
|
||||
t.Errorf("hover should name the rule, got %q", val)
|
||||
}
|
||||
resp = request(t, "select * from t;", "textDocument/hover", map[string]interface{}{
|
||||
"position": map[string]interface{}{"line": 0, "character": 14},
|
||||
})
|
||||
if resp["result"] != nil {
|
||||
t.Errorf("no diagnostic at col 14, want null, got %v", resp["result"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWillSaveWaitUntilFormats(t *testing.T) {
|
||||
resp := request(t, "select a from t", "textDocument/willSaveWaitUntil", map[string]interface{}{"reason": 1})
|
||||
edits := resp["result"].([]interface{})
|
||||
if len(edits) != 1 || !strings.Contains(edits[0].(map[string]interface{})["newText"].(string), "SELECT a") {
|
||||
t.Errorf("expected a formatting edit, got %v", edits)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiagSpanCoversToken(t *testing.T) {
|
||||
if got := diagSpan("select * from t;", 0, 7); got != 1 {
|
||||
t.Errorf("'*' span = %d, want 1", got)
|
||||
}
|
||||
if got := diagSpan("select foo from t;", 0, 7); got != 3 {
|
||||
t.Errorf("'foo' span = %d, want 3", got)
|
||||
}
|
||||
if got := diagSpan("select foo from t;", 0, 40); got != 1 {
|
||||
t.Errorf("out-of-range span = %d, want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user