192 lines
5.5 KiB
Go
192 lines
5.5 KiB
Go
package integration
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/marte-community/marte-dev-tools/internal/index"
|
|
"github.com/marte-community/marte-dev-tools/internal/lsp"
|
|
"github.com/marte-community/marte-dev-tools/internal/parser"
|
|
)
|
|
|
|
func TestLSPIncrementalSync(t *testing.T) {
|
|
lsp.Documents = make(map[string]string)
|
|
var buf bytes.Buffer
|
|
lsp.Output = &buf
|
|
|
|
content := "Line1\nLine2\nLine3"
|
|
uri := "file://inc.marte"
|
|
lsp.Documents[uri] = content
|
|
|
|
// Replace "Line2" (Line 1, 0-5) with "Modified"
|
|
change := lsp.TextDocumentContentChangeEvent{
|
|
Range: &lsp.Range{
|
|
Start: lsp.Position{Line: 1, Character: 0},
|
|
End: lsp.Position{Line: 1, Character: 5},
|
|
},
|
|
Text: "Modified",
|
|
}
|
|
|
|
params := lsp.DidChangeTextDocumentParams{
|
|
TextDocument: lsp.VersionedTextDocumentIdentifier{URI: uri, Version: 2},
|
|
ContentChanges: []lsp.TextDocumentContentChangeEvent{change},
|
|
}
|
|
|
|
lsp.HandleDidChange(params)
|
|
|
|
expected := "Line1\nModified\nLine3"
|
|
if lsp.Documents[uri] != expected {
|
|
t.Errorf("Incremental update failed. Got:\n%q\nWant:\n%q", lsp.Documents[uri], expected)
|
|
}
|
|
|
|
// Insert at end
|
|
change2 := lsp.TextDocumentContentChangeEvent{
|
|
Range: &lsp.Range{
|
|
Start: lsp.Position{Line: 2, Character: 5},
|
|
End: lsp.Position{Line: 2, Character: 5},
|
|
},
|
|
Text: "\nLine4",
|
|
}
|
|
params2 := lsp.DidChangeTextDocumentParams{
|
|
TextDocument: lsp.VersionedTextDocumentIdentifier{URI: uri, Version: 3},
|
|
ContentChanges: []lsp.TextDocumentContentChangeEvent{change2},
|
|
}
|
|
lsp.HandleDidChange(params2)
|
|
|
|
expected2 := "Line1\nModified\nLine3\nLine4"
|
|
if lsp.Documents[uri] != expected2 {
|
|
t.Errorf("Incremental insert failed. Got:\n%q\nWant:\n%q", lsp.Documents[uri], expected2)
|
|
}
|
|
}
|
|
|
|
func TestLSPLifecycle(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
lsp.Output = &buf
|
|
|
|
// Shutdown
|
|
msgShutdown := &lsp.JsonRpcMessage{
|
|
Method: "shutdown",
|
|
ID: 1,
|
|
}
|
|
lsp.HandleMessage(msgShutdown)
|
|
|
|
if !strings.Contains(buf.String(), `"result":null`) {
|
|
t.Error("Shutdown response incorrect")
|
|
}
|
|
|
|
// Exit
|
|
if os.Getenv("TEST_LSP_EXIT") == "1" {
|
|
msgExit := &lsp.JsonRpcMessage{Method: "exit"}
|
|
lsp.HandleMessage(msgExit)
|
|
return
|
|
}
|
|
cmd := exec.Command(os.Args[0], "-test.run=TestLSPLifecycle")
|
|
cmd.Env = append(os.Environ(), "TEST_LSP_EXIT=1")
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
t.Errorf("Exit failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLSPMalformedParams(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
lsp.Output = &buf
|
|
|
|
// Malformed Hover
|
|
msg := &lsp.JsonRpcMessage{
|
|
Method: "textDocument/hover",
|
|
ID: 2,
|
|
Params: json.RawMessage(`{invalid`),
|
|
}
|
|
lsp.HandleMessage(msg)
|
|
|
|
output := buf.String()
|
|
// Should respond with nil result
|
|
if !strings.Contains(output, `"result":null`) {
|
|
t.Errorf("Expected nil result for malformed params, got: %s", output)
|
|
}
|
|
}
|
|
|
|
func TestLSPDispatch(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
lsp.Output = &buf
|
|
|
|
// Initialize
|
|
msgInit := &lsp.JsonRpcMessage{Method: "initialize", ID: 1, Params: json.RawMessage(`{}`)}
|
|
lsp.HandleMessage(msgInit)
|
|
|
|
// DidOpen
|
|
msgOpen := &lsp.JsonRpcMessage{Method: "textDocument/didOpen", Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte","text":""}}`)}
|
|
lsp.HandleMessage(msgOpen)
|
|
|
|
// DidChange
|
|
msgChange := &lsp.JsonRpcMessage{Method: "textDocument/didChange", Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte","version":2},"contentChanges":[{"text":"A"}]}`)}
|
|
lsp.HandleMessage(msgChange)
|
|
|
|
// Hover
|
|
msgHover := &lsp.JsonRpcMessage{Method: "textDocument/hover", ID: 2, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0}}`)}
|
|
lsp.HandleMessage(msgHover)
|
|
|
|
// Definition
|
|
msgDef := &lsp.JsonRpcMessage{Method: "textDocument/definition", ID: 3, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0}}`)}
|
|
lsp.HandleMessage(msgDef)
|
|
|
|
// References
|
|
msgRef := &lsp.JsonRpcMessage{Method: "textDocument/references", ID: 4, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0},"context":{"includeDeclaration":true}}`)}
|
|
lsp.HandleMessage(msgRef)
|
|
|
|
// Completion
|
|
msgComp := &lsp.JsonRpcMessage{Method: "textDocument/completion", ID: 5, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0}}`)}
|
|
lsp.HandleMessage(msgComp)
|
|
|
|
// Formatting
|
|
msgFmt := &lsp.JsonRpcMessage{Method: "textDocument/formatting", ID: 6, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"options":{"tabSize":4,"insertSpaces":true}}`)}
|
|
lsp.HandleMessage(msgFmt)
|
|
|
|
// Rename
|
|
msgRename := &lsp.JsonRpcMessage{Method: "textDocument/rename", ID: 7, Params: json.RawMessage(`{"textDocument":{"uri":"file://d.marte"},"position":{"line":0,"character":0},"newName":"B"}`)}
|
|
lsp.HandleMessage(msgRename)
|
|
}
|
|
|
|
func TestLSPVariableDefinition(t *testing.T) {
|
|
lsp.Tree = index.NewProjectTree()
|
|
lsp.Documents = make(map[string]string)
|
|
|
|
content := `
|
|
#var MyVar: int = 10
|
|
+Obj = {
|
|
Field = @MyVar
|
|
}
|
|
`
|
|
uri := "file://var_def.marte"
|
|
lsp.Documents[uri] = content
|
|
|
|
p := parser.NewParser(content)
|
|
cfg, _ := p.Parse()
|
|
lsp.Tree.AddFile("var_def.marte", cfg)
|
|
lsp.Tree.ResolveReferences()
|
|
|
|
params := lsp.DefinitionParams{
|
|
TextDocument: lsp.TextDocumentIdentifier{URI: uri},
|
|
Position: lsp.Position{Line: 3, Character: 13},
|
|
}
|
|
|
|
res := lsp.HandleDefinition(params)
|
|
if res == nil {
|
|
t.Fatal("Definition not found for variable")
|
|
}
|
|
|
|
locs, ok := res.([]lsp.Location)
|
|
if !ok || len(locs) == 0 {
|
|
t.Fatal("Expected location list")
|
|
}
|
|
|
|
if locs[0].Range.Start.Line != 1 {
|
|
t.Errorf("Expected line 1, got %d", locs[0].Range.Start.Line)
|
|
}
|
|
}
|