Files
clice/tests/integration/features/test_index.py
ykiko 8b3e3a9595 refactor(tests): reorganize integration tests into domain-based subdirectories (#409)
## Summary
- Extract shared test utilities into `tests/integration/utils/` (client,
workspace, assertions, wait, cache)
- Migrate 12 test files into categorized subdirectories: `lifecycle/`,
`compilation/`, `features/`, `modules/`, `extensions/`, `stress/`
- Merge `test_include_completion.py` + `test_import_completion.py` →
`features/test_completion.py`
- Remove stale directory-tree comments and section divider comments

## Test plan
- [x] `pytest --collect-only` collects all 113 tests
- [x] All test module imports verified
- [x] `pixi run format` applied

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Reorganized integration suites: added new feature tests (completion,
server) and removed older duplicated modules.
* Centralized shared test utilities and assertion helpers for
diagnostics, workspace operations, waiting/synchronization, and cache
inspection.
* **Chores / Refactor**
* Standardized test client lifecycle and helper usage across suites for
more reliable test flows.
* Improved server session lifecycle handling for more predictable
document/session resets during tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 02:40:10 +08:00

229 lines
8.7 KiB
Python

"""Integration tests for index-based LSP features: GoToDefinition, FindReferences,
CallHierarchy, TypeHierarchy, and WorkspaceSymbol."""
import pytest
from lsprotocol.types import (
CallHierarchyIncomingCallsParams,
CallHierarchyOutgoingCallsParams,
CallHierarchyPrepareParams,
Position,
TypeHierarchyPrepareParams,
TypeHierarchySubtypesParams,
TypeHierarchySupertypesParams,
WorkspaceSymbolParams,
)
from tests.integration.utils import doc
from tests.integration.utils.wait import wait_for_index
@pytest.mark.workspace("index_features")
async def test_goto_definition(client, workspace):
"""Test GoToDefinition navigates from a call site to the function definition."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# 'add' call on line 24 (0-indexed), column 12
result = await client.definition_at(uri, 24, 12)
assert result is not None
locs = result if isinstance(result, list) else [result]
assert len(locs) > 0, f"GoToDefinition returned empty list, result={result}"
# Definition should point to line 18 where 'int add(...)' is declared
assert any(loc.range.start.line == 18 for loc in locs), (
f"Expected line 18, got locations:"
f" {[(loc.uri, loc.range.start.line, loc.range.start.character) for loc in locs]}"
)
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_find_references(client, workspace):
"""Test FindReferences returns all usages of global_var."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# global_var definition on line 30 (0-indexed), column 4
result = await client.references_at(uri, 30, 4, include_declaration=True)
assert result is not None, "FindReferences returned None"
# global_var is declared on line 30 and used on lines 33 and 37
assert len(result) >= 3, (
f"Expected >=3 refs, got {len(result)}:"
f" {[(r.uri, r.range.start.line) for r in result]}"
)
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_call_hierarchy_prepare(client, workspace):
"""Test prepareCallHierarchy returns a CallHierarchyItem for 'add'."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# 'add' definition at line 18 (0-indexed), column 4
result = await client.text_document_prepare_call_hierarchy_async(
CallHierarchyPrepareParams(
text_document=doc(uri),
position=Position(line=18, character=4),
)
)
assert result is not None, "prepareCallHierarchy returned None"
assert len(result) > 0, f"prepareCallHierarchy returned empty, result={result}"
assert result[0].name == "add", f"Expected 'add', got '{result[0].name}'"
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_call_hierarchy_incoming(client, workspace):
"""Test incomingCalls shows compute() calls add()."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# Prepare call hierarchy for 'add' at line 18 (0-indexed), column 4
items = await client.text_document_prepare_call_hierarchy_async(
CallHierarchyPrepareParams(
text_document=doc(uri),
position=Position(line=18, character=4),
)
)
assert items and len(items) > 0, f"prepareCallHierarchy returned {items}"
incoming = await client.call_hierarchy_incoming_calls_async(
CallHierarchyIncomingCallsParams(item=items[0])
)
assert incoming is not None, "incomingCalls returned None"
caller_names = [call.from_.name for call in incoming]
assert "compute" in caller_names, (
f"Expected 'compute' in callers, got {caller_names}"
)
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_call_hierarchy_outgoing(client, workspace):
"""Test outgoingCalls shows compute() calls add()."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# Prepare call hierarchy for 'compute' at line 23 (0-indexed), column 4
items = await client.text_document_prepare_call_hierarchy_async(
CallHierarchyPrepareParams(
text_document=doc(uri),
position=Position(line=23, character=4),
)
)
assert items and len(items) > 0, f"prepareCallHierarchy returned {items}"
outgoing = await client.call_hierarchy_outgoing_calls_async(
CallHierarchyOutgoingCallsParams(item=items[0])
)
assert outgoing is not None, "outgoingCalls returned None"
callee_names = [call.to.name for call in outgoing]
assert "add" in callee_names, f"Expected 'add' in callees, got {callee_names}"
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_type_hierarchy_prepare(client, workspace):
"""Test prepareTypeHierarchy returns a TypeHierarchyItem for 'Dog'."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# 'Dog' at line 8 (0-indexed), column 7
result = await client.text_document_prepare_type_hierarchy_async(
TypeHierarchyPrepareParams(
text_document=doc(uri),
position=Position(line=8, character=7),
)
)
assert result is not None, "prepareTypeHierarchy returned None"
assert len(result) > 0, f"prepareTypeHierarchy returned empty"
assert result[0].name == "Dog", f"Expected 'Dog', got '{result[0].name}'"
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_type_hierarchy_supertypes(client, workspace):
"""Test supertypes of Dog includes Animal."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# 'Dog' at line 8 (0-indexed), column 7
items = await client.text_document_prepare_type_hierarchy_async(
TypeHierarchyPrepareParams(
text_document=doc(uri),
position=Position(line=8, character=7),
)
)
assert items and len(items) > 0, f"prepareTypeHierarchy returned {items}"
supertypes = await client.type_hierarchy_supertypes_async(
TypeHierarchySupertypesParams(item=items[0])
)
assert supertypes is not None, "supertypes returned None"
supertype_names = [t.name for t in supertypes]
assert "Animal" in supertype_names, (
f"Expected 'Animal' in supertypes, got {supertype_names}"
)
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_type_hierarchy_subtypes(client, workspace):
"""Test subtypes of Animal includes Dog and Cat."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
# 'Animal' at line 1, column 7
items = await client.text_document_prepare_type_hierarchy_async(
TypeHierarchyPrepareParams(
text_document=doc(uri),
position=Position(line=1, character=7),
)
)
assert items and len(items) > 0, f"prepareTypeHierarchy returned {items}"
subtypes = await client.type_hierarchy_subtypes_async(
TypeHierarchySubtypesParams(item=items[0])
)
assert subtypes is not None, "subtypes returned None"
subtype_names = [t.name for t in subtypes]
assert "Dog" in subtype_names, f"Expected 'Dog' in subtypes, got {subtype_names}"
assert "Cat" in subtype_names, f"Expected 'Cat' in subtypes, got {subtype_names}"
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_workspace_symbol(client, workspace):
"""Test workspace/symbol finds symbols by query string."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
result = await client.workspace_symbol_async(WorkspaceSymbolParams(query="add"))
assert result is not None
names = [s.name for s in result]
assert "add" in names
client.close(uri)
@pytest.mark.workspace("index_features")
async def test_workspace_symbol_class(client, workspace):
"""Test workspace/symbol finds class symbols."""
uri, _ = await client.open_and_wait(workspace / "main.cpp")
assert await wait_for_index(client, uri), "Index not ready after 30s"
result = await client.workspace_symbol_async(WorkspaceSymbolParams(query="Animal"))
assert result is not None
names = [s.name for s in result]
assert "Animal" in names
client.close(uri)