Skip to main content
Glama

MCP Language Server

diagnostics_test.go6.27 kB
package diagnostics_test import ( "context" "fmt" "path/filepath" "strings" "testing" "time" "github.com/isaacphi/mcp-language-server/integrationtests/tests/common" "github.com/isaacphi/mcp-language-server/integrationtests/tests/rust/internal" "github.com/isaacphi/mcp-language-server/internal/protocol" "github.com/isaacphi/mcp-language-server/internal/tools" ) // TestDiagnostics tests diagnostics functionality with the Rust language server func TestDiagnostics(t *testing.T) { // Helper function to open all files and wait for indexing openAllFilesAndWait := func(suite *common.TestSuite, ctx context.Context) { // Open all files to ensure rust-analyzer indexes everything filesToOpen := []string{ "src/main.rs", "src/types.rs", "src/helper.rs", "src/consumer.rs", "src/another_consumer.rs", "src/clean.rs", } for _, file := range filesToOpen { filePath := filepath.Join(suite.WorkspaceDir, file) err := suite.Client.OpenFile(ctx, filePath) if err != nil { // Don't fail the test, some files might not exist in certain tests t.Logf("Note: Failed to open %s: %v", file, err) } } } // Test with a clean file t.Run("CleanFile", func(t *testing.T) { // Get a test suite with clean code suite := internal.GetTestSuite(t) ctx, cancel := context.WithTimeout(suite.Context, 10*time.Second) defer cancel() // Open all files and wait for rust-analyzer to index them openAllFilesAndWait(suite, ctx) filePath := filepath.Join(suite.WorkspaceDir, "src/clean.rs") result, err := tools.GetDiagnosticsForFile(ctx, suite.Client, filePath, 2, true) if err != nil { t.Fatalf("GetDiagnosticsForFile failed: %v", err) } // Verify we have no diagnostics if !strings.Contains(result, "No diagnostics found") { t.Errorf("Expected no diagnostics but got: %s", result) } common.SnapshotTest(t, "rust", "diagnostics", "clean", result) }) // Test with a file containing an error t.Run("FileWithError", func(t *testing.T) { // Get a test suite with code that contains errors suite := internal.GetTestSuite(t) ctx, cancel := context.WithTimeout(suite.Context, 10*time.Second) defer cancel() // Open all files and wait for rust-analyzer to index them openAllFilesAndWait(suite, ctx) filePath := filepath.Join(suite.WorkspaceDir, "src/main.rs") result, err := tools.GetDiagnosticsForFile(ctx, suite.Client, filePath, 2, true) if err != nil { t.Fatalf("GetDiagnosticsForFile failed: %v", err) } // Verify we have diagnostics about unreachable code if strings.Contains(result, "No diagnostics found") { t.Errorf("Expected diagnostics but got none") } if !strings.Contains(result, "unreachable") { t.Errorf("Expected unreachable code error but got: %s", result) } t.Skip("Flaky snapshot. If we have diagnostics then it's working, but the format changes often.") // common.SnapshotTest(t, "rust", "diagnostics", "unreachable", result) }) // Test file dependency: file A (helper.rs) provides a function, // file B (consumer.rs) uses it, then modify A to break B t.Run("FileDependency", func(t *testing.T) { // Get a test suite with clean code suite := internal.GetTestSuite(t) ctx, cancel := context.WithTimeout(suite.Context, 10*time.Second) defer cancel() // Open all files and wait for rust-analyzer to index them openAllFilesAndWait(suite, ctx) // Ensure the relevant paths are accessible helperPath := filepath.Join(suite.WorkspaceDir, "src/helper.rs") consumerPath := filepath.Join(suite.WorkspaceDir, "src/consumer.rs") // Get initial diagnostics for consumer.rs result, err := tools.GetDiagnosticsForFile(ctx, suite.Client, consumerPath, 2, true) if err != nil { t.Fatalf("GetDiagnosticsForFile failed: %v", err) } // Should have no diagnostics initially if !strings.Contains(result, "No diagnostics found") { t.Errorf("Expected no diagnostics initially but got: %s", result) } // Now modify the helper function to cause an error in the consumer modifiedHelperContent := `// Helper functions for testing // A function that will be referenced from other files pub fn helper_function(value: i32) -> String { String::from("hello world") } ` // Write the modified content to the file err = suite.WriteFile("src/helper.rs", modifiedHelperContent) if err != nil { t.Fatalf("Failed to update helper.rs: %v", err) } // Explicitly notify the LSP server about the change helperURI := fmt.Sprintf("file://%s", helperPath) // Notify the LSP server about the file change err = suite.Client.NotifyChange(ctx, helperPath) if err != nil { t.Fatalf("Failed to notify change to helper.rs: %v", err) } // Also send a didChangeWatchedFiles notification for coverage // This simulates what the watcher would do fileChangeParams := protocol.DidChangeWatchedFilesParams{ Changes: []protocol.FileEvent{ { URI: protocol.DocumentUri(helperURI), Type: protocol.FileChangeType(protocol.Changed), }, }, } err = suite.Client.DidChangeWatchedFiles(ctx, fileChangeParams) if err != nil { t.Fatalf("Failed to send DidChangeWatchedFiles: %v", err) } // Wait for LSP to process the change time.Sleep(6 * time.Second) // Force reopen the consumer file to ensure LSP reevaluates it err = suite.Client.OpenFile(ctx, consumerPath) if err != nil { t.Fatalf("Failed to reopen consumer.rs: %v", err) } // 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, 2, true) if err != nil { t.Fatalf("GetDiagnosticsForFile failed after dependency change: %v", err) } // Should have diagnostics now if strings.Contains(result, "No diagnostics found") { t.Errorf("Expected diagnostics after dependency change but got none") } // Should contain an error about function arguments if !strings.Contains(result, "argument") && !strings.Contains(result, "parameter") && !strings.Contains(result, "expected") { t.Errorf("Expected error about wrong arguments but got: %s", result) } common.SnapshotTest(t, "rust", "diagnostics", "dependency", result) }) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/isaacphi/mcp-language-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server