Skip to main content
Glama

MCP Language Server

mock_client.go3.71 kB
package testing import ( "context" "sync" "github.com/isaacphi/mcp-language-server/internal/protocol" "github.com/isaacphi/mcp-language-server/internal/watcher" ) // FileEvent represents a file event notification type FileEvent struct { URI string Type protocol.FileChangeType } // MockLSPClient implements the watcher.LSPClient interface for testing type MockLSPClient struct { mu sync.Mutex events []FileEvent openedFiles map[string]bool openErrors map[string]error notifyErrors map[string]error changeErrors map[string]error eventsReceived chan struct{} } // NewMockLSPClient creates a new mock LSP client for testing func NewMockLSPClient() *MockLSPClient { return &MockLSPClient{ events: []FileEvent{}, openedFiles: make(map[string]bool), openErrors: make(map[string]error), notifyErrors: make(map[string]error), changeErrors: make(map[string]error), eventsReceived: make(chan struct{}, 100), // Buffer to avoid blocking } } // IsFileOpen checks if a file is already open in the editor func (m *MockLSPClient) IsFileOpen(path string) bool { m.mu.Lock() defer m.mu.Unlock() return m.openedFiles[path] } // OpenFile mocks opening a file in the editor func (m *MockLSPClient) OpenFile(ctx context.Context, path string) error { m.mu.Lock() defer m.mu.Unlock() if err, ok := m.openErrors[path]; ok { return err } m.openedFiles[path] = true return nil } // NotifyChange mocks notifying the server of a file change func (m *MockLSPClient) NotifyChange(ctx context.Context, path string) error { m.mu.Lock() defer m.mu.Unlock() if err, ok := m.notifyErrors[path]; ok { return err } // Record this as a change event m.events = append(m.events, FileEvent{ URI: "file://" + path, Type: protocol.FileChangeType(protocol.Changed), }) // Signal that an event was received select { case m.eventsReceived <- struct{}{}: default: // Channel is full, but we don't want to block } return nil } // DidChangeWatchedFiles mocks sending watched file events to the server func (m *MockLSPClient) DidChangeWatchedFiles(ctx context.Context, params protocol.DidChangeWatchedFilesParams) error { m.mu.Lock() defer m.mu.Unlock() for _, change := range params.Changes { uri := string(change.URI) if err, ok := m.changeErrors[uri]; ok { return err } // Record the event m.events = append(m.events, FileEvent{ URI: uri, Type: change.Type, }) } // Signal that an event was received select { case m.eventsReceived <- struct{}{}: default: // Channel is full, but we don't want to block } return nil } // GetEvents returns a copy of all recorded events func (m *MockLSPClient) GetEvents() []FileEvent { m.mu.Lock() defer m.mu.Unlock() // Make a copy to avoid race conditions result := make([]FileEvent, len(m.events)) copy(result, m.events) return result } // CountEvents counts events for a specific file and event type func (m *MockLSPClient) CountEvents(uri string, eventType protocol.FileChangeType) int { m.mu.Lock() defer m.mu.Unlock() count := 0 for _, evt := range m.events { if evt.URI == uri && evt.Type == eventType { count++ } } return count } // ResetEvents clears the recorded events func (m *MockLSPClient) ResetEvents() { m.mu.Lock() defer m.mu.Unlock() m.events = []FileEvent{} } // WaitForEvent waits for at least one event to be received or context to be done func (m *MockLSPClient) WaitForEvent(ctx context.Context) bool { select { case <-m.eventsReceived: return true case <-ctx.Done(): return false } } // Verify the MockLSPClient implements the watcher.LSPClient interface var _ watcher.LSPClient = (*MockLSPClient)(nil)

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