using any instead of interface
This commit is contained in:
@@ -16,8 +16,8 @@ type JsonRpcMessage struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Params json.RawMessage `json:"params,omitempty"`
|
||||
ID interface{} `json:"id,omitempty"`
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
ID any `json:"id,omitempty"`
|
||||
Result any `json:"result,omitempty"`
|
||||
Error *JsonRpcError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ type Position struct {
|
||||
}
|
||||
|
||||
type Hover struct {
|
||||
Contents interface{} `json:"contents"`
|
||||
Contents any `json:"contents"`
|
||||
}
|
||||
|
||||
type MarkupContent struct {
|
||||
@@ -121,8 +121,8 @@ func readMessage(reader *bufio.Reader) (*JsonRpcMessage, error) {
|
||||
func handleMessage(msg *JsonRpcMessage) {
|
||||
switch msg.Method {
|
||||
case "initialize":
|
||||
respond(msg.ID, map[string]interface{}{
|
||||
"capabilities": map[string]interface{}{
|
||||
respond(msg.ID, map[string]any{
|
||||
"capabilities": map[string]any{
|
||||
"textDocumentSync": 1, // Full sync
|
||||
"hoverProvider": true,
|
||||
"definitionProvider": true,
|
||||
@@ -267,7 +267,7 @@ elems := node.Metadata["NumberOfElements"]
|
||||
return info
|
||||
}
|
||||
|
||||
func respond(id interface{}, result interface{}) {
|
||||
func respond(id any, result any) {
|
||||
msg := JsonRpcMessage{
|
||||
Jsonrpc: "2.0",
|
||||
ID: id,
|
||||
@@ -276,7 +276,7 @@ func respond(id interface{}, result interface{}) {
|
||||
send(msg)
|
||||
}
|
||||
|
||||
func send(msg interface{}) {
|
||||
func send(msg any) {
|
||||
body, _ := json.Marshal(msg)
|
||||
fmt.Printf("Content-Length: %d\r\n\r\n%s", len(body), body)
|
||||
}
|
||||
5
test/integration/signal_no_class.marte
Normal file
5
test/integration/signal_no_class.marte
Normal file
@@ -0,0 +1,5 @@
|
||||
#package TEST.SIGNAL
|
||||
+MySignal = {
|
||||
Type = uint32
|
||||
NumberOfElements = 1
|
||||
}
|
||||
58
test/lsp_doc_test.go
Normal file
58
test/lsp_doc_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||
)
|
||||
|
||||
func TestLSPHoverDoc(t *testing.T) {
|
||||
content := `
|
||||
//# Object Documentation
|
||||
//# Second line
|
||||
+MyObject = {
|
||||
Class = Type
|
||||
}
|
||||
|
||||
+RefObject = {
|
||||
Class = Type
|
||||
RefField = MyObject
|
||||
}
|
||||
`
|
||||
p := parser.NewParser(content)
|
||||
config, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
|
||||
idx := index.NewProjectTree()
|
||||
file := "doc.marte"
|
||||
idx.AddFile(file, config)
|
||||
idx.ResolveReferences()
|
||||
|
||||
// Test 1: Hover over +MyObject definition
|
||||
res := idx.Query(file, 4, 2) // Line 4: +MyObject
|
||||
if res == nil || res.Node == nil {
|
||||
t.Fatal("Query failed for definition")
|
||||
}
|
||||
|
||||
expectedDoc := "Object Documentation\nSecond line"
|
||||
if res.Node.Doc != expectedDoc {
|
||||
t.Errorf("Expected definition doc:\n%q\nGot:\n%q", expectedDoc, res.Node.Doc)
|
||||
}
|
||||
|
||||
// Test 2: Hover over MyObject reference
|
||||
resRef := idx.Query(file, 10, 16) // Line 10: RefField = MyObject
|
||||
if resRef == nil || resRef.Reference == nil {
|
||||
t.Fatal("Query failed for reference")
|
||||
}
|
||||
|
||||
if resRef.Reference.Target == nil {
|
||||
t.Fatal("Reference target not resolved")
|
||||
}
|
||||
|
||||
if resRef.Reference.Target.Doc != expectedDoc {
|
||||
t.Errorf("Expected reference target definition doc:\n%q\nGot:\n%q", expectedDoc, resRef.Reference.Target.Doc)
|
||||
}
|
||||
}
|
||||
49
test/lsp_signal_test.go
Normal file
49
test/lsp_signal_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||
)
|
||||
|
||||
func TestLSPSignalMetadata(t *testing.T) {
|
||||
content := `
|
||||
+MySignal = {
|
||||
Class = Signal
|
||||
Type = uint32
|
||||
NumberOfElements = 10
|
||||
NumberOfDimensions = 1
|
||||
DataSource = DDB1
|
||||
}
|
||||
`
|
||||
p := parser.NewParser(content)
|
||||
config, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
|
||||
idx := index.NewProjectTree()
|
||||
file := "signal.marte"
|
||||
idx.AddFile(file, config)
|
||||
|
||||
res := idx.Query(file, 2, 2) // Query +MySignal
|
||||
if res == nil || res.Node == nil {
|
||||
t.Fatal("Query failed for signal definition")
|
||||
}
|
||||
|
||||
meta := res.Node.Metadata
|
||||
if meta["Class"] != "Signal" {
|
||||
t.Errorf("Expected Class Signal, got %s", meta["Class"])
|
||||
}
|
||||
if meta["Type"] != "uint32" {
|
||||
t.Errorf("Expected Type uint32, got %s", meta["Type"])
|
||||
}
|
||||
if meta["NumberOfElements"] != "10" {
|
||||
t.Errorf("Expected 10 elements, got %s", meta["NumberOfElements"])
|
||||
}
|
||||
|
||||
// Since handleHover logic is in internal/lsp which we can't easily test directly without
|
||||
// exposing formatNodeInfo, we rely on the fact that Metadata is populated correctly.
|
||||
// If Metadata is correct, server.go logic (verified by code review) should display it.
|
||||
}
|
||||
142
test/lsp_test.go
Normal file
142
test/lsp_test.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||
"github.com/marte-dev/marte-dev-tools/internal/validator"
|
||||
)
|
||||
|
||||
// Helper to load and parse a file
|
||||
func loadConfig(t *testing.T, filename string) *parser.Configuration {
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read %s: %v", filename, err)
|
||||
}
|
||||
p := parser.NewParser(string(content))
|
||||
config, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func TestLSPDiagnostics(t *testing.T) {
|
||||
inputFile := "integration/check_dup.marte"
|
||||
config := loadConfig(t, inputFile)
|
||||
|
||||
// Simulate LSP logic: Build Index -> Validate
|
||||
idx := index.NewProjectTree()
|
||||
idx.AddFile(inputFile, config)
|
||||
|
||||
v := validator.NewValidator(idx)
|
||||
v.ValidateProject()
|
||||
|
||||
// Check for expected diagnostics
|
||||
found := false
|
||||
for _, d := range v.Diagnostics {
|
||||
if d.Message == "Duplicate Field Definition: 'Field' is already defined in integration/check_dup.marte" {
|
||||
found = true
|
||||
if d.Position.Line != 5 {
|
||||
t.Errorf("Expected diagnostic at line 5, got %d", d.Position.Line)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Error("LSP Diagnostic for duplicate field not found")
|
||||
}
|
||||
}
|
||||
|
||||
// For GoToDefinition and References, we need to test the Indexer's ability to resolve symbols.
|
||||
// Currently, my Indexer (ProjectTree) stores structure but doesn't explicitly track
|
||||
// "references" in a way that maps a source position to a target symbol yet.
|
||||
// The ProjectTree is built for structure merging.
|
||||
// To support LSP "Go To Definition", we need to map usage -> definition.
|
||||
|
||||
// Let's verify what we have implemented.
|
||||
// `internal/index/index.go`:
|
||||
// ProjectTree has Fragments.
|
||||
// It does NOT have a "Lookup(position)" method or a reference map.
|
||||
// Previously (before rewrite), `index.go` had `References []Reference`.
|
||||
// I removed it during the rewrite to ProjectTree!
|
||||
|
||||
// I need to re-implement reference tracking in `ProjectTree` or a parallel structure
|
||||
// to support LSP features.
|
||||
func TestLSPDefinition(t *testing.T) {
|
||||
// Create a virtual file content with a definition and a reference
|
||||
content := `
|
||||
+MyObject = {
|
||||
Class = Type
|
||||
}
|
||||
+RefObject = {
|
||||
Class = Type
|
||||
RefField = MyObject
|
||||
}
|
||||
`
|
||||
p := parser.NewParser(content)
|
||||
config, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
|
||||
idx := index.NewProjectTree()
|
||||
idx.AddFile("memory.marte", config)
|
||||
idx.ResolveReferences()
|
||||
|
||||
// Find the reference to "MyObject"
|
||||
var foundRef *index.Reference
|
||||
for _, ref := range idx.References {
|
||||
if ref.Name == "MyObject" {
|
||||
foundRef = &ref
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if foundRef == nil {
|
||||
t.Fatal("Reference to MyObject not found in index")
|
||||
}
|
||||
|
||||
if foundRef.Target == nil {
|
||||
t.Fatal("Reference to MyObject was not resolved to a target")
|
||||
}
|
||||
|
||||
if foundRef.Target.RealName != "+MyObject" {
|
||||
t.Errorf("Expected target to be +MyObject, got %s", foundRef.Target.RealName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLSPHover(t *testing.T) {
|
||||
content := `
|
||||
+MyObject = {
|
||||
Class = Type
|
||||
}
|
||||
`
|
||||
p := parser.NewParser(content)
|
||||
config, err := p.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
}
|
||||
|
||||
idx := index.NewProjectTree()
|
||||
file := "hover.marte"
|
||||
idx.AddFile(file, config)
|
||||
|
||||
// +MyObject is at line 2.
|
||||
// Query at line 2, col 2 (on 'M' of MyObject)
|
||||
res := idx.Query(file, 2, 2)
|
||||
|
||||
if res == nil {
|
||||
t.Fatal("Query returned nil")
|
||||
}
|
||||
|
||||
if res.Node == nil {
|
||||
t.Fatal("Expected Node result")
|
||||
}
|
||||
|
||||
if res.Node.RealName != "+MyObject" {
|
||||
t.Errorf("Expected +MyObject, got %s", res.Node.RealName)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user