-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reorganize and refactor server tests
- Loading branch information
Showing
12 changed files
with
772 additions
and
715 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
from __future__ import annotations | ||
|
||
import lsprotocol.types as lsp | ||
import pytest | ||
from pytest_lsp import LanguageClient | ||
|
||
from ..conftest import PATCH_DIR, TestCase | ||
|
||
|
||
class CompletionTestCase(TestCase): | ||
"""A dictionary to track an expected completion result.""" | ||
|
||
label: str | ||
detail: str | ||
kind: lsp.CompletionItemKind | ||
doc_contains: str | None | ||
uri: str | ||
|
||
|
||
COMPLETIONS: list[CompletionTestCase] = [ | ||
{ | ||
"name": "APOUT", | ||
"label": "APOUT", | ||
"detail": "(variable) APOUT: Literal[33]", | ||
"kind": lsp.CompletionItemKind.Variable, | ||
"doc_contains": None, | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "REG0", | ||
"label": "REG0", | ||
"detail": "(constant) REG0: Literal[32]", | ||
"kind": lsp.CompletionItemKind.Constant, | ||
"doc_contains": None, | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "CHO RDA", | ||
"label": "CHO RDA", | ||
"detail": "(opcode)", | ||
"kind": lsp.CompletionItemKind.Function, | ||
"doc_contains": "`CHO RDA, N, C, D`", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "EQU", | ||
"label": "EQU", | ||
"detail": "(opcode)", | ||
"kind": lsp.CompletionItemKind.Function, | ||
"doc_contains": "**`EQU`** allows one to define symbolic operands", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("test_case", COMPLETIONS, ids=lambda x: x["name"]) | ||
@pytest.mark.asyncio() | ||
async def test_completions(test_case: CompletionTestCase, client: LanguageClient): | ||
"""Test that expected completions are shown with details and documentation.""" | ||
results = await client.text_document_completion_async( | ||
params=lsp.CompletionParams( | ||
position=lsp.Position(line=0, character=0), | ||
text_document=lsp.TextDocumentIdentifier(uri=test_case["uri"]), | ||
) | ||
) | ||
assert results is not None, "Expected completions" | ||
|
||
matches = [item for item in results.items if item.label == test_case["label"]] | ||
|
||
assert ( | ||
len(matches) == 1 | ||
), f"Expected 1 matching label `{test_case['label']}, got {len(matches)}." | ||
match = matches[0] | ||
|
||
assert match.detail == test_case["detail"] | ||
assert match.kind == test_case["kind"] | ||
if test_case["doc_contains"] is not None: | ||
assert test_case["doc_contains"] in str(match.documentation) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
from __future__ import annotations | ||
|
||
import lsprotocol.types as lsp | ||
import pytest | ||
from pytest_lsp import LanguageClient | ||
|
||
from ..conftest import PATCH_DIR, TestCase | ||
|
||
|
||
class DefinitionTestCase(TestCase): | ||
"""A dictionary track where a symbol is referenced and defined.""" | ||
|
||
referenced: lsp.Position | ||
defined: lsp.Location | ||
uri: str | ||
|
||
|
||
DEFINITIONS: list[DefinitionTestCase] = [ | ||
{ | ||
# Variable | ||
"name": "apout", | ||
"referenced": lsp.Position(line=57, character=7), | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
"defined": lsp.Location( | ||
uri=f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
range=lsp.Range( | ||
start=lsp.Position(line=23, character=4), | ||
end=lsp.Position(line=23, character=9), | ||
), | ||
), | ||
}, | ||
{ | ||
# Memory | ||
"name": "lap2a", | ||
"referenced": lsp.Position(line=72, character=7), | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
"defined": lsp.Location( | ||
uri=f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
range=lsp.Range( | ||
start=lsp.Position(line=16, character=4), | ||
end=lsp.Position(line=16, character=9), | ||
), | ||
), | ||
}, | ||
{ | ||
# Memory. Note that this has an address modifier, but still points to the | ||
# original definition. | ||
"name": "lap2a#", | ||
"referenced": lsp.Position(line=71, character=7), | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
"defined": lsp.Location( | ||
uri=f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
range=lsp.Range( | ||
start=lsp.Position(line=16, character=4), | ||
end=lsp.Position(line=16, character=9), | ||
), | ||
), | ||
}, | ||
{ | ||
# Label | ||
"name": "endclr", | ||
"referenced": lsp.Position(line=37, character=9), | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
"defined": lsp.Location( | ||
uri=f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
range=lsp.Range( | ||
start=lsp.Position(line=41, character=0), | ||
end=lsp.Position(line=41, character=6), | ||
), | ||
), | ||
}, | ||
] | ||
|
||
|
||
@pytest.mark.asyncio() | ||
@pytest.mark.parametrize("test_case", DEFINITIONS, ids=lambda x: x["name"]) | ||
async def test_definition(test_case: DefinitionTestCase, client: LanguageClient): | ||
"""Test that the definition location of different assignments is correct.""" | ||
result = await client.text_document_definition_async( | ||
params=lsp.DefinitionParams( | ||
position=test_case["referenced"], | ||
text_document=lsp.TextDocumentIdentifier(uri=test_case["uri"]), | ||
) | ||
) | ||
|
||
assert result == test_case["defined"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import lsprotocol.types as lsp | ||
import pytest | ||
from pytest_lsp import LanguageClient | ||
|
||
|
||
@pytest.mark.asyncio() | ||
async def test_diagnostic_parsing_errors(client: LanguageClient): | ||
"""Test that parsing errors and warnings are correctly reported by the server.""" | ||
source_with_errors = """ | ||
; Undefined symbol a | ||
SOF 0,a | ||
; Label REG0 re-defined | ||
REG0 EQU 4 | ||
; Register out of range | ||
MULX 100 | ||
""" | ||
|
||
# We need a URI to associate with the source, but it doesn't need to be a real file. | ||
test_uri = "dummy_uri" | ||
client.text_document_did_open( | ||
lsp.DidOpenTextDocumentParams( | ||
text_document=lsp.TextDocumentItem( | ||
uri=test_uri, | ||
language_id="spinasm", | ||
version=1, | ||
text=source_with_errors, | ||
) | ||
) | ||
) | ||
|
||
await client.wait_for_notification(lsp.TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS) | ||
|
||
expected = [ | ||
lsp.Diagnostic( | ||
range=lsp.Range( | ||
start=lsp.Position(line=2, character=6), | ||
end=lsp.Position(line=2, character=6), | ||
), | ||
message="Undefined label a", | ||
severity=lsp.DiagnosticSeverity.Error, | ||
source="SPINAsm", | ||
), | ||
lsp.Diagnostic( | ||
range=lsp.Range( | ||
start=lsp.Position(line=5, character=9), | ||
end=lsp.Position(line=5, character=9), | ||
), | ||
message="Label REG0 re-defined", | ||
severity=lsp.DiagnosticSeverity.Warning, | ||
source="SPINAsm", | ||
), | ||
lsp.Diagnostic( | ||
range=lsp.Range( | ||
start=lsp.Position(line=8, character=0), | ||
end=lsp.Position(line=8, character=0), | ||
), | ||
message="Register 0x64 out of range for MULX", | ||
severity=lsp.DiagnosticSeverity.Error, | ||
source="SPINAsm", | ||
), | ||
] | ||
|
||
returned = client.diagnostics[test_uri] | ||
extra = len(returned) - len(expected) | ||
assert extra == 0, f"Expected {len(expected)} diagnostics, got {len(returned)}." | ||
|
||
for i, diag in enumerate(expected): | ||
assert diag == returned[i], f"Diagnostic {i} does not match expected" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
from __future__ import annotations | ||
|
||
import lsprotocol.types as lsp | ||
import pytest | ||
from pytest_lsp import LanguageClient | ||
|
||
from ..conftest import PATCH_DIR, TestCase | ||
|
||
|
||
class HoverTestCase(TestCase): | ||
"""A dictionary to record hover information for a symbol.""" | ||
|
||
position: lsp.Position | ||
contains: str | None | ||
uri: str | ||
|
||
|
||
HOVERS: list[HoverTestCase] = [ | ||
{ | ||
"name": "mem", | ||
"position": lsp.Position(line=8, character=0), | ||
"contains": "`MEM`", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "skp", | ||
"position": lsp.Position(line=37, character=2), | ||
"contains": "`SKP CMASK, N`", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "endclr", | ||
"position": lsp.Position(line=37, character=13), | ||
"contains": "(label) ENDCLR: Offset[4]", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "mono", | ||
"position": lsp.Position(line=47, character=5), | ||
"contains": "(variable) MONO: Literal[32]", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "reg0", | ||
"position": lsp.Position(line=22, character=9), | ||
"contains": "(constant) REG0: Literal[32]", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "lap2b#", | ||
"position": lsp.Position(line=73, character=4), | ||
"contains": "(variable) LAP2B#: Literal[9802]", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
# CHO RDA, hovering over CHO | ||
"name": "CHO_rda", | ||
"position": lsp.Position(line=85, character=0), | ||
"contains": "`CHO RDA, N, C, D`", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
# CHO RDA, hovering over RDA | ||
"name": "cho_RDA", | ||
"position": lsp.Position(line=85, character=4), | ||
"contains": "`CHO RDA, N, C, D`", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
# Hovering over an int, which should return no hover info | ||
"name": "None", | ||
"position": lsp.Position(line=8, character=8), | ||
"contains": None, | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("test_case", HOVERS, ids=lambda x: x["name"]) | ||
@pytest.mark.asyncio() | ||
async def test_hover(test_case: dict, client: LanguageClient): | ||
result = await client.text_document_hover_async( | ||
params=lsp.CompletionParams( | ||
position=test_case["position"], | ||
text_document=lsp.TextDocumentIdentifier(uri=test_case["uri"]), | ||
) | ||
) | ||
|
||
if test_case["contains"] is None: | ||
assert result is None, "Expected no hover result" | ||
else: | ||
msg = f"Hover does not contain `{test_case['contains']}`" | ||
assert test_case["contains"] in result.contents.value, msg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from __future__ import annotations | ||
|
||
import lsprotocol.types as lsp | ||
import pytest | ||
from pytest_lsp import LanguageClient | ||
|
||
from ..conftest import PATCH_DIR, TestCase | ||
|
||
|
||
class PrepareRenameTestCase(TestCase): | ||
"""A dictionary to record prepare rename results for a symbol.""" | ||
|
||
position: lsp.Position | ||
result: bool | ||
message: str | None | ||
uri: str | ||
|
||
|
||
PREPARE_RENAMES: list[PrepareRenameTestCase] = [ | ||
{ | ||
"name": "mem", | ||
"position": lsp.Position(line=8, character=0), | ||
"result": None, | ||
"message": "Can't rename non-user defined token MEM.", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "reg0", | ||
"position": lsp.Position(line=22, character=10), | ||
"result": None, | ||
"message": "Can't rename non-user defined token REG0.", | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "ap1", | ||
"position": lsp.Position(line=8, character=4), | ||
"result": lsp.PrepareRenameResult_Type2(default_behavior=True), | ||
"message": None, | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
{ | ||
"name": "endclr", | ||
"position": lsp.Position(line=37, character=10), | ||
"result": lsp.PrepareRenameResult_Type2(default_behavior=True), | ||
"message": None, | ||
"uri": f"file:///{PATCH_DIR / 'Basic.spn'}", | ||
}, | ||
] | ||
|
||
|
||
@pytest.mark.parametrize("test_case", PREPARE_RENAMES, ids=lambda x: x["name"]) | ||
@pytest.mark.asyncio() | ||
async def test_prepare_rename(test_case: PrepareRenameTestCase, client: LanguageClient): | ||
"""Test that prepare rename prevents renaming non-user defined tokens.""" | ||
result = await client.text_document_prepare_rename_async( | ||
params=lsp.PrepareRenameParams( | ||
position=test_case["position"], | ||
text_document=lsp.TextDocumentIdentifier(uri=test_case["uri"]), | ||
) | ||
) | ||
|
||
assert result == test_case["result"] | ||
|
||
if test_case["message"]: | ||
assert test_case["message"] in client.log_messages[0].message | ||
assert client.log_messages[0].type == lsp.MessageType.Info | ||
else: | ||
assert not client.log_messages |
Oops, something went wrong.