Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
failed to rename symbol: request failed: column is beyond end of line (code: 0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Successfully renamed symbol to 'UpdatedConstant'.
Updated 4 occurrences across 3 files.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Failed to rename symbol. 0 occurrences found.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Successfully renamed symbol to 'UPDATED_CONSTANT'.
Updated 6 occurrences across 3 files.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
failed to rename symbol: request failed: No references found at position (code: -32602)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Successfully renamed symbol to 'UPDATED_CONSTANT'.
Updated 5 occurrences across 3 files.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Failed to rename symbol. 0 occurrences found.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Successfully renamed symbol to 'UpdatedConstant'.
Updated 5 occurrences across 3 files.
112 changes: 112 additions & 0 deletions integrationtests/languages/go/rename_symbol/rename_symbol_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package rename_symbol_test

import (
"context"
"path/filepath"
"strings"
"testing"
"time"

"github.com/isaacphi/mcp-language-server/integrationtests/languages/common"
"github.com/isaacphi/mcp-language-server/integrationtests/languages/go/internal"
"github.com/isaacphi/mcp-language-server/internal/tools"
)

// TestRenameSymbol tests the RenameSymbol functionality with the Go language server
func TestRenameSymbol(t *testing.T) {
// Test with a successful rename of a symbol that exists
t.Run("SuccessfulRename", func(t *testing.T) {
// Get a test suite with clean code
suite := internal.GetTestSuite(t)

// Wait for initialization
time.Sleep(2 * time.Second)

ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
defer cancel()

// Ensure the file is open
filePath := filepath.Join(suite.WorkspaceDir, "types.go")
err := suite.Client.OpenFile(ctx, filePath)
if err != nil {
t.Fatalf("Failed to open types.go: %v", err)
}

// Request to rename SharedConstant to UpdatedConstant at its definition
// The constant is defined at line 25, column 7 of types.go
result, err := tools.RenameSymbol(ctx, suite.Client, filePath, 25, 7, "UpdatedConstant")
if err != nil {
t.Fatalf("RenameSymbol failed: %v", err)
}

// Verify the constant was renamed
if !strings.Contains(result, "Successfully renamed symbol") {
t.Errorf("Expected success message but got: %s", result)
}

// Verify it's mentioned that it renamed multiple occurrences
if !strings.Contains(result, "occurrences") {
t.Errorf("Expected multiple occurrences to be renamed but got: %s", result)
}

common.SnapshotTest(t, "go", "rename_symbol", "successful", result)

// Verify that the rename worked by checking for the updated constant name in the file
fileContent, err := suite.ReadFile("types.go")
if err != nil {
t.Fatalf("Failed to read types.go: %v", err)
}

if !strings.Contains(fileContent, "UpdatedConstant") {
t.Errorf("Expected to find renamed constant 'UpdatedConstant' in types.go")
}

// Also check that it was renamed in the consumer file
consumerContent, err := suite.ReadFile("consumer.go")
if err != nil {
t.Fatalf("Failed to read consumer.go: %v", err)
}

if !strings.Contains(consumerContent, "UpdatedConstant") {
t.Errorf("Expected to find renamed constant 'UpdatedConstant' in consumer.go")
}
})

// Test with a symbol that doesn't exist
t.Run("SymbolNotFound", func(t *testing.T) {
// Get a test suite with clean code
suite := internal.GetTestSuite(t)

// Wait for initialization
time.Sleep(2 * time.Second)

ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
defer cancel()

// Ensure the file is open
filePath := filepath.Join(suite.WorkspaceDir, "clean.go")
err := suite.Client.OpenFile(ctx, filePath)
if err != nil {
t.Fatalf("Failed to open clean.go: %v", err)
}

// Request to rename a symbol at a position where no symbol exists
// The clean.go file doesn't have content at this position
_, err = tools.RenameSymbol(ctx, suite.Client, filePath, 10, 10, "NewName")

// Expect an error because there's no symbol at that position
if err == nil {
t.Errorf("Expected an error when renaming non-existent symbol, but got success")
}

// Save the error message for the snapshot
errorMessage := err.Error()

// Verify it mentions failing to rename
if !strings.Contains(errorMessage, "failed to rename") {
t.Errorf("Expected error message about failed rename but got: %s", errorMessage)
}

common.SnapshotTest(t, "go", "rename_symbol", "not_found", errorMessage)
})
}
145 changes: 145 additions & 0 deletions integrationtests/languages/python/rename_symbol/rename_symbol_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package rename_symbol_test

import (
"context"
"path/filepath"
"strings"
"testing"
"time"

"github.com/isaacphi/mcp-language-server/integrationtests/languages/common"
"github.com/isaacphi/mcp-language-server/integrationtests/languages/python/internal"
"github.com/isaacphi/mcp-language-server/internal/tools"
)

// TestRenameSymbol tests the RenameSymbol functionality with the Python language server
func TestRenameSymbol(t *testing.T) {
// Test with a successful rename of a symbol that exists
t.Run("SuccessfulRename", func(t *testing.T) {
// Get a test suite with clean code
suite := internal.GetTestSuite(t)

// Wait for initialization
time.Sleep(2 * time.Second)

ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
defer cancel()

// Ensure the file is open
filePath := filepath.Join(suite.WorkspaceDir, "helper.py")
err := suite.Client.OpenFile(ctx, filePath)
if err != nil {
t.Fatalf("Failed to open helper.py: %v", err)
}

// Open the consumer file too to ensure references are indexed
consumerPath := filepath.Join(suite.WorkspaceDir, "consumer.py")
err = suite.Client.OpenFile(ctx, consumerPath)
if err != nil {
t.Fatalf("Failed to open consumer.py: %v", err)
}

// Give the language server time to process the files
time.Sleep(2 * time.Second)

// Request to rename SHARED_CONSTANT to UPDATED_CONSTANT at its definition
// The constant is defined at line 8, column 1 of helper.py
result, err := tools.RenameSymbol(ctx, suite.Client, filePath, 8, 1, "UPDATED_CONSTANT")
if err != nil {
t.Fatalf("RenameSymbol failed: %v", err)
}

// Verify the constant was renamed
if !strings.Contains(result, "Successfully renamed symbol") {
t.Errorf("Expected success message but got: %s", result)
}

// Verify it's mentioned that it renamed multiple occurrences
if !strings.Contains(result, "occurrences") {
t.Errorf("Expected multiple occurrences to be renamed but got: %s", result)
}

common.SnapshotTest(t, "python", "rename_symbol", "successful", result)

// Verify that the rename worked by checking for the updated constant name in the file
fileContent, err := suite.ReadFile("helper.py")
if err != nil {
t.Fatalf("Failed to read helper.py: %v", err)
}

if !strings.Contains(fileContent, "UPDATED_CONSTANT") {
t.Errorf("Expected to find renamed constant 'UPDATED_CONSTANT' in helper.py")
}

// Also check that it was renamed in the consumer file
consumerContent, err := suite.ReadFile("consumer.py")
if err != nil {
t.Fatalf("Failed to read consumer.py: %v", err)
}

if !strings.Contains(consumerContent, "UPDATED_CONSTANT") {
t.Errorf("Expected to find renamed constant 'UPDATED_CONSTANT' in consumer.py")
}
})

// Test with a symbol that doesn't exist
t.Run("SymbolNotFound", func(t *testing.T) {
// Get a test suite with clean code
suite := internal.GetTestSuite(t)

// Wait for initialization
time.Sleep(2 * time.Second)

ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
defer cancel()

// Ensure the file is open
filePath := filepath.Join(suite.WorkspaceDir, "clean.py")
err := suite.Client.OpenFile(ctx, filePath)
if err != nil {
t.Fatalf("Failed to open clean.py: %v", err)
}

// Create a simple file with known content first
simpleContent := `"""A simple Python file for testing."""

def dummy_function():
"""This is a dummy function."""
pass
`
err = suite.WriteFile("position_test.py", simpleContent)
if err != nil {
t.Fatalf("Failed to create position_test.py: %v", err)
}

testFilePath := filepath.Join(suite.WorkspaceDir, "position_test.py")
err = suite.Client.OpenFile(ctx, testFilePath)
if err != nil {
t.Fatalf("Failed to open position_test.py: %v", err)
}

time.Sleep(1 * time.Second) // Give time for the file to be processed

// Request to rename a symbol at a position where no symbol exists (in whitespace)
result, err := tools.RenameSymbol(ctx, suite.Client, testFilePath, 4, 1, "NewName")

// The language server might actually succeed with no rename operations
// In this case, we check if it reports no occurrences
if err == nil {
// Check if result indicates nothing was renamed
if !strings.Contains(result, "0 occurrences") {
t.Errorf("Expected 0 occurrences or error for non-existent symbol, but got: %s", result)
}
common.SnapshotTest(t, "python", "rename_symbol", "not_found", result)
} else {
// If there was an error, check it and snapshot that instead
errorMessage := err.Error()
if !strings.Contains(errorMessage, "failed to rename") &&
!strings.Contains(errorMessage, "not found") &&
!strings.Contains(errorMessage, "cannot rename") {
t.Errorf("Expected error message about failed rename but got: %s", errorMessage)
}
common.SnapshotTest(t, "python", "rename_symbol", "not_found", errorMessage)
}
})
}
11 changes: 3 additions & 8 deletions integrationtests/languages/rust/diagnostics/diagnostics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,21 +158,16 @@ pub fn helper_function(value: i32) -> String {
}

// Wait for LSP to process the change
time.Sleep(3 * time.Second)
time.Sleep(6 * time.Second)

// Force reopen the consumer file to ensure LSP reevaluates it
err = suite.Client.CloseFile(ctx, consumerPath)
if err != nil {
t.Fatalf("Failed to close consumer.rs: %v", err)
}

err = suite.Client.OpenFile(ctx, consumerPath)
if err != nil {
t.Fatalf("Failed to reopen consumer.rs: %v", err)
}

// Wait for diagnostics to be generated
time.Sleep(3 * time.Second)
// Wait for LSP to process the change
time.Sleep(6 * time.Second)

// Check diagnostics again on consumer file - should now have an error
result, err = tools.GetDiagnosticsForFile(ctx, suite.Client, consumerPath, true, true)
Expand Down
4 changes: 3 additions & 1 deletion integrationtests/languages/rust/hover/hover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestHover(t *testing.T) {
// Get a test suite
suite := internal.GetTestSuite(t)

ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
ctx, cancel := context.WithTimeout(suite.Context, 10*time.Second)
defer cancel()

// Open all files and wait for rust-analyzer to index them
Expand All @@ -131,6 +131,8 @@ func TestHover(t *testing.T) {
t.Fatalf("Failed to open %s: %v", tt.file, err)
}

time.Sleep(3 * time.Second)

// Get hover info
result, err := tools.GetHoverInfo(ctx, suite.Client, filePath, tt.line, tt.column)
if err != nil {
Expand Down
Loading
Loading