Skip to content

Commit 5c6e841

Browse files
authored
rename symbol (#19)
* rename symbol * fmt * lint * flaky test * remove delay * revert * sleep on hover * increase timeout
1 parent d34205c commit 5c6e841

File tree

16 files changed

+716
-9
lines changed

16 files changed

+716
-9
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
failed to rename symbol: request failed: column is beyond end of line (code: 0)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Successfully renamed symbol to 'UpdatedConstant'.
2+
Updated 4 occurrences across 3 files.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Failed to rename symbol. 0 occurrences found.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Successfully renamed symbol to 'UPDATED_CONSTANT'.
2+
Updated 6 occurrences across 3 files.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
failed to rename symbol: request failed: No references found at position (code: -32602)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Successfully renamed symbol to 'UPDATED_CONSTANT'.
2+
Updated 5 occurrences across 3 files.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Failed to rename symbol. 0 occurrences found.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Successfully renamed symbol to 'UpdatedConstant'.
2+
Updated 5 occurrences across 3 files.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package rename_symbol_test
2+
3+
import (
4+
"context"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
"time"
9+
10+
"github.com/isaacphi/mcp-language-server/integrationtests/languages/common"
11+
"github.com/isaacphi/mcp-language-server/integrationtests/languages/go/internal"
12+
"github.com/isaacphi/mcp-language-server/internal/tools"
13+
)
14+
15+
// TestRenameSymbol tests the RenameSymbol functionality with the Go language server
16+
func TestRenameSymbol(t *testing.T) {
17+
// Test with a successful rename of a symbol that exists
18+
t.Run("SuccessfulRename", func(t *testing.T) {
19+
// Get a test suite with clean code
20+
suite := internal.GetTestSuite(t)
21+
22+
// Wait for initialization
23+
time.Sleep(2 * time.Second)
24+
25+
ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
26+
defer cancel()
27+
28+
// Ensure the file is open
29+
filePath := filepath.Join(suite.WorkspaceDir, "types.go")
30+
err := suite.Client.OpenFile(ctx, filePath)
31+
if err != nil {
32+
t.Fatalf("Failed to open types.go: %v", err)
33+
}
34+
35+
// Request to rename SharedConstant to UpdatedConstant at its definition
36+
// The constant is defined at line 25, column 7 of types.go
37+
result, err := tools.RenameSymbol(ctx, suite.Client, filePath, 25, 7, "UpdatedConstant")
38+
if err != nil {
39+
t.Fatalf("RenameSymbol failed: %v", err)
40+
}
41+
42+
// Verify the constant was renamed
43+
if !strings.Contains(result, "Successfully renamed symbol") {
44+
t.Errorf("Expected success message but got: %s", result)
45+
}
46+
47+
// Verify it's mentioned that it renamed multiple occurrences
48+
if !strings.Contains(result, "occurrences") {
49+
t.Errorf("Expected multiple occurrences to be renamed but got: %s", result)
50+
}
51+
52+
common.SnapshotTest(t, "go", "rename_symbol", "successful", result)
53+
54+
// Verify that the rename worked by checking for the updated constant name in the file
55+
fileContent, err := suite.ReadFile("types.go")
56+
if err != nil {
57+
t.Fatalf("Failed to read types.go: %v", err)
58+
}
59+
60+
if !strings.Contains(fileContent, "UpdatedConstant") {
61+
t.Errorf("Expected to find renamed constant 'UpdatedConstant' in types.go")
62+
}
63+
64+
// Also check that it was renamed in the consumer file
65+
consumerContent, err := suite.ReadFile("consumer.go")
66+
if err != nil {
67+
t.Fatalf("Failed to read consumer.go: %v", err)
68+
}
69+
70+
if !strings.Contains(consumerContent, "UpdatedConstant") {
71+
t.Errorf("Expected to find renamed constant 'UpdatedConstant' in consumer.go")
72+
}
73+
})
74+
75+
// Test with a symbol that doesn't exist
76+
t.Run("SymbolNotFound", func(t *testing.T) {
77+
// Get a test suite with clean code
78+
suite := internal.GetTestSuite(t)
79+
80+
// Wait for initialization
81+
time.Sleep(2 * time.Second)
82+
83+
ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
84+
defer cancel()
85+
86+
// Ensure the file is open
87+
filePath := filepath.Join(suite.WorkspaceDir, "clean.go")
88+
err := suite.Client.OpenFile(ctx, filePath)
89+
if err != nil {
90+
t.Fatalf("Failed to open clean.go: %v", err)
91+
}
92+
93+
// Request to rename a symbol at a position where no symbol exists
94+
// The clean.go file doesn't have content at this position
95+
_, err = tools.RenameSymbol(ctx, suite.Client, filePath, 10, 10, "NewName")
96+
97+
// Expect an error because there's no symbol at that position
98+
if err == nil {
99+
t.Errorf("Expected an error when renaming non-existent symbol, but got success")
100+
}
101+
102+
// Save the error message for the snapshot
103+
errorMessage := err.Error()
104+
105+
// Verify it mentions failing to rename
106+
if !strings.Contains(errorMessage, "failed to rename") {
107+
t.Errorf("Expected error message about failed rename but got: %s", errorMessage)
108+
}
109+
110+
common.SnapshotTest(t, "go", "rename_symbol", "not_found", errorMessage)
111+
})
112+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package rename_symbol_test
2+
3+
import (
4+
"context"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
"time"
9+
10+
"github.com/isaacphi/mcp-language-server/integrationtests/languages/common"
11+
"github.com/isaacphi/mcp-language-server/integrationtests/languages/python/internal"
12+
"github.com/isaacphi/mcp-language-server/internal/tools"
13+
)
14+
15+
// TestRenameSymbol tests the RenameSymbol functionality with the Python language server
16+
func TestRenameSymbol(t *testing.T) {
17+
// Test with a successful rename of a symbol that exists
18+
t.Run("SuccessfulRename", func(t *testing.T) {
19+
// Get a test suite with clean code
20+
suite := internal.GetTestSuite(t)
21+
22+
// Wait for initialization
23+
time.Sleep(2 * time.Second)
24+
25+
ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
26+
defer cancel()
27+
28+
// Ensure the file is open
29+
filePath := filepath.Join(suite.WorkspaceDir, "helper.py")
30+
err := suite.Client.OpenFile(ctx, filePath)
31+
if err != nil {
32+
t.Fatalf("Failed to open helper.py: %v", err)
33+
}
34+
35+
// Open the consumer file too to ensure references are indexed
36+
consumerPath := filepath.Join(suite.WorkspaceDir, "consumer.py")
37+
err = suite.Client.OpenFile(ctx, consumerPath)
38+
if err != nil {
39+
t.Fatalf("Failed to open consumer.py: %v", err)
40+
}
41+
42+
// Give the language server time to process the files
43+
time.Sleep(2 * time.Second)
44+
45+
// Request to rename SHARED_CONSTANT to UPDATED_CONSTANT at its definition
46+
// The constant is defined at line 8, column 1 of helper.py
47+
result, err := tools.RenameSymbol(ctx, suite.Client, filePath, 8, 1, "UPDATED_CONSTANT")
48+
if err != nil {
49+
t.Fatalf("RenameSymbol failed: %v", err)
50+
}
51+
52+
// Verify the constant was renamed
53+
if !strings.Contains(result, "Successfully renamed symbol") {
54+
t.Errorf("Expected success message but got: %s", result)
55+
}
56+
57+
// Verify it's mentioned that it renamed multiple occurrences
58+
if !strings.Contains(result, "occurrences") {
59+
t.Errorf("Expected multiple occurrences to be renamed but got: %s", result)
60+
}
61+
62+
common.SnapshotTest(t, "python", "rename_symbol", "successful", result)
63+
64+
// Verify that the rename worked by checking for the updated constant name in the file
65+
fileContent, err := suite.ReadFile("helper.py")
66+
if err != nil {
67+
t.Fatalf("Failed to read helper.py: %v", err)
68+
}
69+
70+
if !strings.Contains(fileContent, "UPDATED_CONSTANT") {
71+
t.Errorf("Expected to find renamed constant 'UPDATED_CONSTANT' in helper.py")
72+
}
73+
74+
// Also check that it was renamed in the consumer file
75+
consumerContent, err := suite.ReadFile("consumer.py")
76+
if err != nil {
77+
t.Fatalf("Failed to read consumer.py: %v", err)
78+
}
79+
80+
if !strings.Contains(consumerContent, "UPDATED_CONSTANT") {
81+
t.Errorf("Expected to find renamed constant 'UPDATED_CONSTANT' in consumer.py")
82+
}
83+
})
84+
85+
// Test with a symbol that doesn't exist
86+
t.Run("SymbolNotFound", func(t *testing.T) {
87+
// Get a test suite with clean code
88+
suite := internal.GetTestSuite(t)
89+
90+
// Wait for initialization
91+
time.Sleep(2 * time.Second)
92+
93+
ctx, cancel := context.WithTimeout(suite.Context, 5*time.Second)
94+
defer cancel()
95+
96+
// Ensure the file is open
97+
filePath := filepath.Join(suite.WorkspaceDir, "clean.py")
98+
err := suite.Client.OpenFile(ctx, filePath)
99+
if err != nil {
100+
t.Fatalf("Failed to open clean.py: %v", err)
101+
}
102+
103+
// Create a simple file with known content first
104+
simpleContent := `"""A simple Python file for testing."""
105+
106+
def dummy_function():
107+
"""This is a dummy function."""
108+
pass
109+
`
110+
err = suite.WriteFile("position_test.py", simpleContent)
111+
if err != nil {
112+
t.Fatalf("Failed to create position_test.py: %v", err)
113+
}
114+
115+
testFilePath := filepath.Join(suite.WorkspaceDir, "position_test.py")
116+
err = suite.Client.OpenFile(ctx, testFilePath)
117+
if err != nil {
118+
t.Fatalf("Failed to open position_test.py: %v", err)
119+
}
120+
121+
time.Sleep(1 * time.Second) // Give time for the file to be processed
122+
123+
// Request to rename a symbol at a position where no symbol exists (in whitespace)
124+
result, err := tools.RenameSymbol(ctx, suite.Client, testFilePath, 4, 1, "NewName")
125+
126+
// The language server might actually succeed with no rename operations
127+
// In this case, we check if it reports no occurrences
128+
if err == nil {
129+
// Check if result indicates nothing was renamed
130+
if !strings.Contains(result, "0 occurrences") {
131+
t.Errorf("Expected 0 occurrences or error for non-existent symbol, but got: %s", result)
132+
}
133+
common.SnapshotTest(t, "python", "rename_symbol", "not_found", result)
134+
} else {
135+
// If there was an error, check it and snapshot that instead
136+
errorMessage := err.Error()
137+
if !strings.Contains(errorMessage, "failed to rename") &&
138+
!strings.Contains(errorMessage, "not found") &&
139+
!strings.Contains(errorMessage, "cannot rename") {
140+
t.Errorf("Expected error message about failed rename but got: %s", errorMessage)
141+
}
142+
common.SnapshotTest(t, "python", "rename_symbol", "not_found", errorMessage)
143+
}
144+
})
145+
}

0 commit comments

Comments
 (0)