Testing Guide for Prolog LSP Server
Test Structure
The Prolog LSP server includes comprehensive unit tests organized into categories:
Test File: prolog/language_client.plt
This is the main test suite for the LSP server, testing both the client-server communication and the LSP method implementations.
Test Categories
1. Initialization Tests
initialize: Tests the LSP initialization handshake
- Verifies that the server accepts
initialize request
- Confirms capabilities are returned
- Tests state transition to "initializing" → "initialized"
methods: Verifies all LSP methods are properly registered
- Lists all available methods on the server
- Ensures all expected methods are implemented
2. Utility Tests
echo: Tests basic request/response communication
- Sends an echo message and verifies it's returned correctly
- Validates JSON-RPC communication layer
shutdown / exit: Tests server lifecycle
- Verifies state transition to "shutting_down"
- Confirms invalid requests fail after shutdown
- Tests proper server termination
3. Document Synchronization Tests
These tests verify that the server correctly tracks open documents and their changes:
textDocument/didOpen: Opens a document
- Sends a document to the server with content
- Triggers indexing of the document
- Verifies document is stored in-memory
textDocument/didChange: Modifies an open document
- Updates document content after opening
- Triggers re-indexing of changed content
- Verifies document state is updated
textDocument/didClose: Closes an open document
- Removes document from server memory
- Clears associated indexes
- Verifies resources are freed
4. Language Feature Tests
These tests exercise LSP language features using actual project files:
textDocument/documentSymbol: Retrieves symbols from a document
- Queries symbols (functions, predicates, modules) in a file
- Returns structured symbol information with locations
- Accepts both null (no symbols) and list results
textDocument/hover: Provides hover information
- Gets information about a symbol at a given position
- Returns documentation or type information
- Handles positions where no symbol exists (null result)
textDocument/definition: Navigate to definition
- Finds where a symbol is defined
- Returns
location(s) of the definition
- Returns null if definition not found
textDocument/references: Find all references
- Locates all uses of a symbol
- Can include or exclude the declaration
- Returns list of locations where symbol is used
textDocument/completion: Code completion
- Provides completion suggestions at cursor position
- Returns list of completion items
- Returns null if no completions available
workspace/symbol: Global symbol search
- Searches for symbols across entire workspace
- Uses query string to filter results
- Supports workspace-wide refactoring and navigation
Running Tests
Run all tests
cd /Users/phil/src/prolog_lsp
swipl -s load.pl -g "load_files('prolog/language_client.plt'), run_tests(language_client), halt"
Run specific test
swipl -s load.pl -g "load_files('prolog/language_client.plt'), run_tests(language_client:textDocument_hover_with_project_file), halt"
Run with verbose output
swipl -s load.pl -g "set_prolog_flag(plunit_options, [verbose(true)]), load_files('prolog/language_client.plt'), run_tests(language_client), halt"
Test Infrastructure
Helper Predicates
The test file includes several helper predicates for constructing LSP data structures:
Setup/Teardown
Tests support both stdio and tcp server modes:
- stdio: Launches server as subprocess via stdio
- tcp: Starts server on port 3403 in separate thread
The test framework handles:
- Server startup/shutdown
- Connection management
- Stream cleanup
- Process management
Test Data
Tests use:
- Project source code: Actual LSP implementation files as indexed documents
- Test content: Small Prolog modules for document sync tests
- Real workspace: Indexes the entire project directory structure
Known Issues & Notes
- Document sync notifications (didOpen, didChange, didClose) may generate warnings
- These are notifications (not requests), so errors don't fail the test
- The server may not be fully processing all parameters currently
- Ongoing development may improve handler robustness
- Indexing delay: Tests include sleep/1 calls
- Allows asynchronous indexing to complete
- Duration (0.2-0.5s) may need tuning on slow systems
- Position-based queries may return null
- Positions in the middle of tokens may not match indexed terms
- This is expected behavior for unmapped positions
Adding New Tests
To add a new language feature test:
test(feature_name, [
forall(member(Type, [stdio])),
setup(setup(Type, Connection)),
cleanup(teardown(Type, Connection))
]) :-
% Initialize
init_params(InitParams),
call_method(Connection, initialize, InitParams, _),
notify_method(Connection, initialized, _{}),
sleep(0.5),
% Your test code here
ProjectFile = 'file:///Users/phil/src/prolog_lsp/prolog/methods.pl',
text_document(ProjectFile, TextDoc),
position(Line, Char, Pos),
Params = _{textDocument: TextDoc, position: Pos},
call_method(Connection, 'method/name', Params, Result),
% Assertions
(Result = null -> true ; is_list(Result)).
Future Test Improvements
- [ ] Add tests for multiple open documents simultaneously
- [ ] Test workspace symbol filtering with various queries
- [ ] Add performance benchmarks for indexing large projects
- [ ] Test error handling for malformed documents
- [ ] Add integration tests with external LSP clients
- [ ] Test concurrent edits to same document
- [ ] Add test fixtures for more complex Prolog code