import pytest from unittest.mock import MagicMock, patch from lsprotocol.types import ( DidOpenTextDocumentParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, Position, Range, Diagnostic, DiagnosticSeverity, ) from pygls.workspace import TextDocument import skillls.main as main_module from skillls.main import SkillLanguageServer @pytest.fixture def server(): """Fixture to provide a clean instance of the Language Server.""" s = SkillLanguageServer("TestServer", "1.0.0") # Manually mock the protocol's workspace to prevent RuntimeError s.protocol._workspace = MagicMock() # When calling get_text_document, always return a doc with an int version def side_effect(uri): doc = MagicMock(spec=TextDocument) doc.version = 1 return doc s.workspace.get_text_document.side_effect = side_effect return s @pytest.fixture def sample_uri(): return "file:///test.il" def test_on_open_adds_to_files(server, sample_uri): """Test that opening a document adds it to the server's opened_files set.""" params = MagicMock(spec=DidOpenTextDocumentParams) params.text_document.uri = sample_uri main_module.on_open(server, params) assert sample_uri in server.opened_files def test_on_close_removes_from_files(server, sample_uri): """Test that closing a document removes it from the server's opened_files set.""" server.opened_files.add(sample_uri) params = MagicMock(spec=DidCloseTextDocumentParams) params.text_document.uri = sample_uri main_module.on_close(server, params) assert sample_uri not in server.opened_files def test_update_diagnostics_publishes_errors(server, sample_uri): """Test that update_diagnments correctly publishes diagnostics.""" server.opened_files = {sample_uri} mock_doc = MagicMock(spec=TextDocument) mock_doc.version = 1 server.workspace.get_text_document.return_value = mock_doc error_range = Range(Position(0, 0), Position(0, 5)) diagnostic = Diagnostic( message="Test error", severity=DiagnosticSeverity.Error, range=error_range ) server.diagnostics[sample_uri] = [diagnostic] with patch.object(server, 'text_document_publish_diagnostics') as mock_publish: server.update_diagnostics() assert mock_publish.called args, _ = mock_publish.call_args params = args[0] assert params.uri == sample_uri assert len(params.diagnostics) == 1 assert params.diagnostics[0].message == "Test error" def test_on_change_updates_scopes(server, sample_uri): """Test that changing a document triggers scope updates.""" mock_doc = MagicMock(spec=TextDocument) mock_doc.source = "(defun test_func (x) x)" server.workspace.get_text_document.return_value = mock_doc params = MagicMock(spec=DidChangeTextDocumentParams) params.text_document.uri = sample_uri with patch('skillls.parser.SkillParser.parse_document', return_value=([], [])) as mock_parse: main_module.on_change(server, params) assert mock_parse.called assert sample_uri in server.scopes