Skip to content

Commit 2d5d5ae

Browse files
committed
optimize discovering test cases for document
1 parent 070f474 commit 2d5d5ae

File tree

1 file changed

+54
-35
lines changed

1 file changed

+54
-35
lines changed

robotcode/language_server/robotframework/parts/discovering.py

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@
44
from dataclasses import dataclass
55
from itertools import chain
66
from pathlib import Path
7-
from typing import TYPE_CHECKING, Any, Iterator, List, Optional
7+
from typing import TYPE_CHECKING, Any, Iterator, List, Optional, cast
88

99
from ....jsonrpc2.protocol import rpc_method
1010
from ....utils.async_tools import run_coroutine_in_thread, run_in_thread
1111
from ....utils.logging import LoggingDescriptor
1212
from ....utils.uri import Uri
13-
from ...common.lsp_types import Model, Position, Range, TextDocumentIdentifier
13+
from ...common.lsp_types import (
14+
DocumentUri,
15+
Model,
16+
Position,
17+
Range,
18+
TextDocumentIdentifier,
19+
)
20+
from ..utils.async_ast import AsyncVisitor
1421
from .protocol_part import RobotLanguageServerProtocolPart
1522

1623
if TYPE_CHECKING:
@@ -39,21 +46,58 @@ class TestItem(Model):
3946
type: str
4047
id: str
4148
label: str
42-
uri: Optional[str] = None
49+
uri: Optional[DocumentUri] = None
4350
children: Optional[List[TestItem]] = None
4451
description: Optional[str] = None
4552
range: Optional[Range] = None
4653
tags: Optional[List[str]] = None
4754
error: Optional[str] = None
4855

4956

57+
class FindTestCasesVisitor(AsyncVisitor):
58+
async def get(self, source: DocumentUri, model: ast.AST, id: Optional[str]) -> List[TestItem]:
59+
self._results: List[TestItem] = []
60+
self.source = source
61+
self.id = id
62+
await self.visit(model)
63+
return self._results
64+
65+
async def visit_Section(self, node: ast.AST) -> None: # noqa: N802
66+
from robot.parsing.model.blocks import TestCaseSection
67+
68+
if isinstance(node, TestCaseSection):
69+
await self.generic_visit(node)
70+
71+
async def visit_TestCase(self, node: ast.AST) -> None: # noqa: N802
72+
from robot.parsing.model.blocks import TestCase
73+
from robot.parsing.model.statements import Tags
74+
75+
test_case = cast(TestCase, node)
76+
self._results.append(
77+
TestItem(
78+
type="test",
79+
id=f"{self.id}.{test_case.name}" if self.id else test_case.name,
80+
label=test_case.name,
81+
uri=self.source,
82+
range=Range(
83+
start=Position(line=test_case.lineno - 1, character=test_case.col_offset),
84+
end=Position(
85+
line=(test_case.end_lineno if test_case.end_lineno != -1 else test_case.lineno) - 1,
86+
character=test_case.end_col_offset if test_case.end_col_offset != -1 else test_case.col_offset,
87+
),
88+
),
89+
tags=[str(tag) for tag in chain(*[tags.values for tags in test_case.body if isinstance(tags, Tags)])],
90+
)
91+
)
92+
93+
5094
class DiscoveringProtocolPart(RobotLanguageServerProtocolPart):
5195
_logger = LoggingDescriptor()
5296

5397
def __init__(self, parent: RobotLanguageServerProtocol) -> None:
5498
super().__init__(parent)
5599

56-
def get_tests_from_workspace_threading(self, workspace_folder: Path, paths: Optional[List[str]]) -> List[TestItem]:
100+
def _get_tests_from_workspace(self, workspace_folder: Path, paths: Optional[List[str]]) -> List[TestItem]:
57101
from robot.output.logger import LOGGER
58102
from robot.running import TestCase, TestSuite
59103

@@ -152,55 +196,30 @@ def nonexisting_paths(paths: List[str]) -> Iterator[str]:
152196
return [TestItem(type="error", id=Path.cwd().name, label=Path.cwd().name, error=str(e))]
153197

154198
@rpc_method(name="robot/discovering/getTestsFromWorkspace", param_type=GetAllTestsParams)
199+
@_logger.call(entering=True, exiting=True, exception=True)
155200
async def get_tests_from_workspace(
156201
self,
157202
workspace_folder: str,
158203
paths: Optional[List[str]],
159204
*args: Any,
160205
**kwargs: Any,
161206
) -> List[TestItem]:
162-
return await run_in_thread(self.get_tests_from_workspace_threading, Uri(workspace_folder).to_path(), paths)
163-
164-
def get_tests_from_document_threading(
165-
self, text_document: TextDocumentIdentifier, id: Optional[str], model: ast.AST
166-
) -> List[TestItem]:
167-
from robot.parsing.model.blocks import TestCase
168-
from robot.parsing.model.statements import Tags
169-
170-
return [
171-
TestItem(
172-
type="test",
173-
id=f"{id}.{test_case.name}" if id else test_case.name,
174-
label=test_case.name,
175-
uri=text_document.uri,
176-
range=Range(
177-
start=Position(line=test_case.lineno - 1, character=test_case.col_offset),
178-
end=Position(
179-
line=(test_case.end_lineno if test_case.end_lineno != -1 else test_case.lineno) - 1,
180-
character=test_case.end_col_offset if test_case.end_col_offset != -1 else test_case.col_offset,
181-
),
182-
),
183-
tags=[
184-
str(tag) for tag in chain(*[tags.values for tags in ast.walk(test_case) if isinstance(tags, Tags)])
185-
],
186-
)
187-
for test_case in ast.walk(model)
188-
if isinstance(test_case, TestCase)
189-
]
207+
return await run_in_thread(self._get_tests_from_workspace, Uri(workspace_folder).to_path(), paths)
190208

191209
@rpc_method(name="robot/discovering/getTestsFromDocument", param_type=GetTestsParams)
210+
@_logger.call(entering=True, exiting=True, exception=True)
192211
async def get_tests_from_document(
193212
self, text_document: TextDocumentIdentifier, id: Optional[str], *args: Any, **kwargs: Any
194213
) -> List[TestItem]:
195214
async def run() -> List[TestItem]:
196-
return self.get_tests_from_document_threading(
197-
text_document,
198-
id,
215+
return await FindTestCasesVisitor().get(
216+
text_document.uri,
199217
await self.parent.documents_cache.get_model(
200218
await self.parent.robot_workspace.get_or_open_document(
201219
Uri(text_document.uri).to_path(), language_id="robotframework"
202220
)
203221
),
222+
id,
204223
)
205224

206225
return await run_coroutine_in_thread(run)

0 commit comments

Comments
 (0)