From 6a46a3768d7f31923d56dc218dabf92cd728ef7b Mon Sep 17 00:00:00 2001 From: Michael Panchenko Date: Sun, 27 Apr 2025 15:42:55 +0200 Subject: [PATCH] Use selectionRange for referencing symbols in tests --- test/multilspy/java/test_java_basic.py | 25 ++++-- test/multilspy/python/test_python_basic.py | 76 ++++++++++++------ .../multilspy/python/test_symbol_retrieval.py | 78 ++++++++++++------- test/multilspy/rust/test_rust_basic.py | 8 +- 4 files changed, 126 insertions(+), 61 deletions(-) diff --git a/test/multilspy/java/test_java_basic.py b/test/multilspy/java/test_java_basic.py index 0cf6f26..d66753f 100644 --- a/test/multilspy/java/test_java_basic.py +++ b/test/multilspy/java/test_java_basic.py @@ -28,7 +28,6 @@ class TestJavaLanguageServer: # Use correct Maven/Java file paths file_path = os.path.join("src", "main", "java", "test_repo", "Utils.java") refs = language_server.request_references(file_path, 4, 20) - print(f"References for Utils.printHello: {refs}") assert any("Main.java" in ref.get("relativePath", "") for ref in refs), "Main should reference Utils.printHello" # Dynamically determine the correct line/column for the 'Model' class name @@ -40,11 +39,25 @@ class TestJavaLanguageServer: model_symbol = sym break assert model_symbol is not None, "Could not find 'Model' class symbol in Model.java" - rng = model_symbol["range"]["start"] - print(f"Model symbol range: {model_symbol['range']}") - refs = language_server.request_references(file_path, rng["line"], rng["character"]) - print(f"References for Model class: {refs}") - assert any("Main.java" in ref.get("relativePath", "") for ref in refs), "Main should reference Model" + # Use selectionRange if present, otherwise fall back to range + if "selectionRange" in model_symbol: + sel_start = model_symbol["selectionRange"]["start"] + sel_end = model_symbol["selectionRange"]["end"] + else: + sel_start = model_symbol["range"]["start"] + sel_end = model_symbol["range"]["end"] + found = False + if sel_start["line"] == sel_end["line"]: + for col in range(sel_start["character"], sel_end["character"] + 1): + refs = language_server.request_references(file_path, sel_start["line"], col) + if any("Main.java" in ref.get("relativePath", "") for ref in refs): + found = True + else: + refs_start = language_server.request_references(file_path, sel_start["line"], sel_start["character"]) + refs_end = language_server.request_references(file_path, sel_end["line"], sel_end["character"]) + if any("Main.java" in ref.get("relativePath", "") for ref in refs_start + refs_end): + found = True + assert found, "Main should reference Model (tried all positions in selectionRange)" @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) def test_overview_methods(self, language_server): diff --git a/test/multilspy/python/test_python_basic.py b/test/multilspy/python/test_python_basic.py index 391906f..36e1778 100644 --- a/test/multilspy/python/test_python_basic.py +++ b/test/multilspy/python/test_python_basic.py @@ -23,13 +23,19 @@ class TestLanguageServerBasics: # Get references to the User class in models.py file_path = os.path.join("test_repo", "models.py") # Line 31 contains the User class definition - references = language_server.request_references(file_path, 31, 6) - - # User class should be referenced in multiple files - assert len(references) > 0 - - # At least two references should be found (one for the class definition itself) - assert len(references) > 1 + # Use selectionRange only + symbols = language_server.request_document_symbols(file_path) + user_symbol = next((s for s in symbols[0] if s.get("name") == "User"), None) + if not user_symbol or "selectionRange" not in user_symbol: + raise AssertionError("User symbol or its selectionRange not found") + sel_start = user_symbol["selectionRange"]["start"] + sel_end = user_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + references = language_server.request_references(file_path, sel_start["line"], col) + if len(references) > 1: + found = True + assert found, "User class should be referenced in multiple files (using selectionRange if present)" @pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True) def test_request_references_item_class(self, language_server: SyncLanguageServer): @@ -37,14 +43,20 @@ class TestLanguageServerBasics: # Get references to the Item class in models.py file_path = os.path.join("test_repo", "models.py") # Line 56 contains the Item class definition - references = language_server.request_references(file_path, 56, 6) - - # Item class should be referenced in multiple places - assert len(references) > 0 - - # At least one reference should be in services.py (ItemService class) - services_references = [ref for ref in references if "services.py" in ref["uri"]] - assert len(services_references) > 0 + # Use selectionRange only + symbols = language_server.request_document_symbols(file_path) + item_symbol = next((s for s in symbols[0] if s.get("name") == "Item"), None) + if not item_symbol or "selectionRange" not in item_symbol: + raise AssertionError("Item symbol or its selectionRange not found") + sel_start = item_symbol["selectionRange"]["start"] + sel_end = item_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + references = language_server.request_references(file_path, sel_start["line"], col) + services_references = [ref for ref in references if "services.py" in ref["uri"]] + if len(services_references) > 0: + found = True + assert found, "At least one reference should be in services.py (using selectionRange if present)" @pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True) def test_request_references_function_parameter(self, language_server: SyncLanguageServer): @@ -52,20 +64,38 @@ class TestLanguageServerBasics: # Get references to the id parameter in get_user method file_path = os.path.join("test_repo", "services.py") # Line 24 contains the get_user method with id parameter - references = language_server.request_references(file_path, 24, 16) - - # id parameter should be referenced within the method - assert len(references) > 0 + # Use selectionRange only + symbols = language_server.request_document_symbols(file_path) + get_user_symbol = next((s for s in symbols[0] if s.get("name") == "get_user"), None) + if not get_user_symbol or "selectionRange" not in get_user_symbol: + raise AssertionError("get_user symbol or its selectionRange not found") + sel_start = get_user_symbol["selectionRange"]["start"] + sel_end = get_user_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + references = language_server.request_references(file_path, sel_start["line"], col) + if len(references) > 0: + found = True + assert found, "id parameter should be referenced within the method (using selectionRange if present)" @pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True) def test_request_references_create_user_method(self, language_server: SyncLanguageServer): # Get references to the create_user method in UserService file_path = os.path.join("test_repo", "services.py") # Line 15 contains the create_user method definition - references = language_server.request_references(file_path, 15, 9) - - # Verify that we get valid references - assert len(references) > 1 + # Use selectionRange only + symbols = language_server.request_document_symbols(file_path) + create_user_symbol = next((s for s in symbols[0] if s.get("name") == "create_user"), None) + if not create_user_symbol or "selectionRange" not in create_user_symbol: + raise AssertionError("create_user symbol or its selectionRange not found") + sel_start = create_user_symbol["selectionRange"]["start"] + sel_end = create_user_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + references = language_server.request_references(file_path, sel_start["line"], col) + if len(references) > 1: + found = True + assert found, "Should get valid references for create_user (using selectionRange if present)" @pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True) def test_retrieve_content_around_line(self, language_server: SyncLanguageServer): diff --git a/test/multilspy/python/test_symbol_retrieval.py b/test/multilspy/python/test_symbol_retrieval.py index cc4b35a..293beb0 100644 --- a/test/multilspy/python/test_symbol_retrieval.py +++ b/test/multilspy/python/test_symbol_retrieval.py @@ -104,10 +104,18 @@ class TestLanguageServerSymbols: # Test referencing symbols for create_user function file_path = os.path.join("test_repo", "services.py") # Line 15 contains the create_user function definition - ref_symbols = language_server.request_referencing_symbols(file_path, 15, 9) - - # Verify we get referencing symbols - assert len(ref_symbols) > 0 + symbols = language_server.request_document_symbols(file_path) + create_user_symbol = next((s for s in symbols[0] if s.get("name") == "create_user"), None) + if not create_user_symbol or "selectionRange" not in create_user_symbol: + raise AssertionError("create_user symbol or its selectionRange not found") + sel_start = create_user_symbol["selectionRange"]["start"] + sel_end = create_user_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + ref_symbols = language_server.request_referencing_symbols(file_path, sel_start["line"], col) + if len(ref_symbols) > 0: + found = True + assert found, "No referencing symbols found for create_user (selectionRange)" # Verify the structure of referencing symbols for symbol in ref_symbols: @@ -123,19 +131,23 @@ class TestLanguageServerSymbols: # Test referencing symbols for User class file_path = os.path.join("test_repo", "models.py") # Line 31 contains the User class definition - ref_symbols = language_server.request_referencing_symbols(file_path, 31, 6) - - # Verify we get referencing symbols - assert len(ref_symbols) > 0 - - # At least one reference should be from services.py - services_references = [ - symbol - for symbol in ref_symbols - if "location" in symbol and "uri" in symbol["location"] and "services.py" in symbol["location"]["uri"] - ] - - assert len(services_references) > 0 + symbols = language_server.request_document_symbols(file_path) + user_symbol = next((s for s in symbols[0] if s.get("name") == "User"), None) + if not user_symbol or "selectionRange" not in user_symbol: + raise AssertionError("User symbol or its selectionRange not found") + sel_start = user_symbol["selectionRange"]["start"] + sel_end = user_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + ref_symbols = language_server.request_referencing_symbols(file_path, sel_start["line"], col) + services_references = [ + symbol + for symbol in ref_symbols + if "location" in symbol and "uri" in symbol["location"] and "services.py" in symbol["location"]["uri"] + ] + if len(services_references) > 0: + found = True + assert found, "No referencing symbols from services.py for User (selectionRange)" @pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True) def test_request_referencing_symbols_parameter(self, language_server: SyncLanguageServer): @@ -143,19 +155,25 @@ class TestLanguageServerSymbols: # Test referencing symbols for id parameter in get_user file_path = os.path.join("test_repo", "services.py") # Line 24 contains the get_user method with id parameter - ref_symbols = language_server.request_referencing_symbols(file_path, 24, 16) - - # Verify we get referencing symbols - assert len(ref_symbols) > 0 - - # Verify the symbols include references within the method body - method_refs = [ - symbol - for symbol in ref_symbols - if "location" in symbol and "range" in symbol["location"] and symbol["location"]["range"]["start"]["line"] > 24 - ] - - assert len(method_refs) > 0 + symbols = language_server.request_document_symbols(file_path) + get_user_symbol = next((s for s in symbols[0] if s.get("name") == "get_user"), None) + if not get_user_symbol or "selectionRange" not in get_user_symbol: + raise AssertionError("get_user symbol or its selectionRange not found") + sel_start = get_user_symbol["selectionRange"]["start"] + sel_end = get_user_symbol["selectionRange"]["end"] + found = False + for col in range(sel_start["character"], sel_end["character"] + 1): + ref_symbols = language_server.request_referencing_symbols(file_path, sel_start["line"], col) + method_refs = [ + symbol + for symbol in ref_symbols + if "location" in symbol + and "range" in symbol["location"] + and symbol["location"]["range"]["start"]["line"] > sel_start["line"] + ] + if len(method_refs) > 0: + found = True + assert found, "No referencing symbols within method body for get_user (selectionRange)" @pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True) def test_request_referencing_symbols_none(self, language_server: SyncLanguageServer): diff --git a/test/multilspy/rust/test_rust_basic.py b/test/multilspy/rust/test_rust_basic.py index 2328227..8b1d1a5 100644 --- a/test/multilspy/rust/test_rust_basic.py +++ b/test/multilspy/rust/test_rust_basic.py @@ -1,7 +1,10 @@ import os + import pytest + from multilspy.multilspy_config import Language + def find_symbol_recursive(symbols, name): for symbol in symbols: if symbol.get("name") == name: @@ -11,6 +14,7 @@ def find_symbol_recursive(symbols, name): return True return False + class TestRustLanguageServer: @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) def test_find_references_raw(self, language_server): @@ -27,7 +31,7 @@ class TestRustLanguageServer: sel_end = add_symbol["selectionRange"]["end"] found = False if sel_start["line"] == sel_end["line"]: - for col in range(sel_start["character"], sel_end["character"]+1): + for col in range(sel_start["character"], sel_end["character"] + 1): refs = language_server.request_references(file_path, sel_start["line"], col) # f"Raw request_references for add in lib.rs at col {col}: {refs}") if any("main.rs" in ref.get("relativePath", "") for ref in refs): @@ -65,7 +69,7 @@ class TestRustLanguageServer: found = False # Try all character positions in the selectionRange (same line, from start to end character) if sel_start["line"] == sel_end["line"]: - for col in range(sel_start["character"], sel_end["character"]+1): + for col in range(sel_start["character"], sel_end["character"] + 1): refs = language_server.request_references(file_path, sel_start["line"], col) # f"References for add in lib.rs at col {col} (selectionRange): {refs}") if any("main.rs" in ref.get("relativePath", "") for ref in refs):