Skip to content

Commit 980c4f6

Browse files
committed
support pytest-ruff plugin
1 parent 1fc37f5 commit 980c4f6

File tree

7 files changed

+175
-20
lines changed

7 files changed

+175
-20
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
# This file has no test, it's just a random script.
5+
6+
if __name__ == "__main__":
7+
print("Hello World!")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
5+
# This test passes.
6+
def test_function(): # test_marker--test_function
7+
assert 1 == 1

python_files/tests/pytestadapter/expected_discovery_test_output.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,3 +1577,94 @@
15771577
],
15781578
"id_": TEST_DATA_PATH_STR,
15791579
}
1580+
# This is the expected output for the folder_with_script folder when run with ruff
1581+
# └── .data
1582+
# └── folder_with_script
1583+
# └── script_random.py
1584+
# └── ruff
1585+
# └── test_simple.py
1586+
# └── ruff
1587+
# └── test_function
1588+
ruff_test_expected_output = {
1589+
"name": ".data",
1590+
"path": TEST_DATA_PATH_STR,
1591+
"type_": "folder",
1592+
"children": [
1593+
{
1594+
"name": "folder_with_script",
1595+
"path": os.fspath(TEST_DATA_PATH / "folder_with_script"),
1596+
"type_": "folder",
1597+
"id_": os.fspath(TEST_DATA_PATH / "folder_with_script"),
1598+
"children": [
1599+
{
1600+
"name": "script_random.py",
1601+
"path": os.fspath(TEST_DATA_PATH / "folder_with_script" / "script_random.py"),
1602+
"type_": "file",
1603+
"id_": os.fspath(TEST_DATA_PATH / "folder_with_script" / "script_random.py"),
1604+
"children": [
1605+
{
1606+
"name": "ruff",
1607+
"path": os.fspath(
1608+
TEST_DATA_PATH / "folder_with_script" / "script_random.py"
1609+
),
1610+
"lineno": "",
1611+
"type_": "test",
1612+
"id_": get_absolute_test_id(
1613+
"folder_with_script/script_random.py::ruff",
1614+
TEST_DATA_PATH / "folder_with_script" / "script_random.py",
1615+
),
1616+
"runID": get_absolute_test_id(
1617+
"folder_with_script/script_random.py::ruff",
1618+
TEST_DATA_PATH / "folder_with_script" / "script_random.py",
1619+
),
1620+
}
1621+
],
1622+
},
1623+
{
1624+
"name": "test_simple.py",
1625+
"path": os.fspath(TEST_DATA_PATH / "folder_with_script" / "test_simple.py"),
1626+
"type_": "file",
1627+
"id_": os.fspath(TEST_DATA_PATH / "folder_with_script" / "test_simple.py"),
1628+
"children": [
1629+
{
1630+
"name": "ruff",
1631+
"path": os.fspath(
1632+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py"
1633+
),
1634+
"lineno": "",
1635+
"type_": "test",
1636+
"id_": get_absolute_test_id(
1637+
"folder_with_script/test_simple.py::ruff",
1638+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py",
1639+
),
1640+
"runID": get_absolute_test_id(
1641+
"folder_with_script/test_simple.py::ruff",
1642+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py",
1643+
),
1644+
},
1645+
{
1646+
"name": "test_function",
1647+
"path": os.fspath(
1648+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py"
1649+
),
1650+
"lineno": find_test_line_number(
1651+
"test_function",
1652+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py",
1653+
),
1654+
"type_": "test",
1655+
"id_": get_absolute_test_id(
1656+
"folder_with_script/test_simple.py::test_function",
1657+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py",
1658+
),
1659+
"runID": get_absolute_test_id(
1660+
"folder_with_script/test_simple.py::test_function",
1661+
TEST_DATA_PATH / "folder_with_script" / "test_simple.py",
1662+
),
1663+
},
1664+
],
1665+
},
1666+
],
1667+
}
1668+
],
1669+
"id_": TEST_DATA_PATH_STR,
1670+
}

python_files/tests/pytestadapter/test_discovery.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,30 @@ def test_config_sub_folder():
329329
if actual_item.get("tests") is not None:
330330
tests: Any = actual_item.get("tests")
331331
assert tests.get("name") == "config_sub_folder"
332+
333+
334+
def test_ruff_plugin():
335+
"""Here the session node will be a subfolder of the workspace root and the test are in another subfolder.
336+
337+
This tests checks to see if test node path are under the session node and if so the
338+
session node is correctly updated to the common path.
339+
"""
340+
file_path = helpers.TEST_DATA_PATH / "folder_with_script"
341+
actual = helpers.runner(
342+
[os.fspath(file_path), "--collect-only", "--ruff"],
343+
)
344+
345+
assert actual
346+
actual_list: List[Dict[str, Any]] = actual
347+
if actual_list is not None:
348+
actual_item = actual_list.pop(0)
349+
assert all(item in actual_item for item in ("status", "cwd", "error"))
350+
assert (
351+
actual_item.get("status") == "success"
352+
), f"Status is not 'success', error is: {actual_item.get('error')}"
353+
assert actual_item.get("cwd") == os.fspath(helpers.TEST_DATA_PATH)
354+
assert is_same_tree(
355+
actual_item.get("tests"),
356+
expected_discovery_test_output.ruff_test_expected_output,
357+
["id_", "lineno", "name", "runID"],
358+
), f"Tests tree does not match expected value. \n Expected: {json.dumps(expected_discovery_test_output.ruff_test_expected_output, indent=4)}. \n Actual: {json.dumps(actual_item.get('tests'), indent=4)}"

python_files/vscode_pytest/__init__.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,7 @@
1010
import pathlib
1111
import sys
1212
import traceback
13-
from typing import (
14-
TYPE_CHECKING,
15-
Any,
16-
Dict,
17-
Generator,
18-
Literal,
19-
TypedDict,
20-
)
13+
from typing import TYPE_CHECKING, Any, Dict, Generator, Literal, TypedDict, cast
2114

2215
import pytest
2316

@@ -598,18 +591,44 @@ def build_test_tree(session: pytest.Session) -> TestNode:
598591
if test_class_node is not None and test_class_node not in test_file_node["children"]:
599592
test_file_node["children"].append(test_class_node)
600593
elif not hasattr(test_case, "callspec"):
601-
# This includes test cases that are pytest functions or a doctests.
602594
parent_path = get_node_path(test_case.parent)
595+
# # This includes test cases that are pytest functions or a doctests. got here with ruff test
596+
# is_ruff = False
597+
# # 'script_a.py::ruff'
598+
# for mark in test_case.own_markers:
599+
# if mark.name == "ruff":
600+
# # This is a ruff test, we do not want to include this in the tree.
601+
# print("[vscode-pytest]: Skipping ruff test: ", test_case.nodeid)
602+
# is_ruff = True
603+
# if is_ruff:
604+
# # cast RuffFile type to pytest.File
605+
# print("is_ruff true")
606+
# # parent_case = pytest.Module.from_parent(test_case.parent)
603607
try:
604608
parent_test_case = file_nodes_dict[os.fspath(parent_path)]
605609
except KeyError:
606610
parent_test_case = create_file_node(parent_path)
607611
file_nodes_dict[os.fspath(parent_path)] = parent_test_case
608612
parent_test_case["children"].append(test_node)
609613
created_files_folders_dict: dict[str, TestNode] = {}
610-
for file_node in file_nodes_dict.values():
614+
for name, file_node in file_nodes_dict.items():
611615
# Iterate through all the files that exist and construct them into nested folders.
612616
root_folder_node: TestNode
617+
print(name)
618+
# import pytest_ruff
619+
620+
# if isinstance(name, pytest_ruff.RuffFile):
621+
# # if ruff file, get the other file node and add the ruff test to it
622+
# other = None
623+
# for key, value in file_nodes_dict.items():
624+
# if value == file_node and key != name:
625+
# other = value
626+
# break
627+
# if other is None:
628+
# raise ValueError(f"Could not find matching file node for {name}")
629+
# other.children.append(file_node.children[0])
630+
# break
631+
613632
try:
614633
root_folder_node: TestNode = build_nested_folders(
615634
file_node, created_files_folders_dict, session_node

src/client/testing/testController/common/resultResolver.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,10 @@ export class PythonResultResolver implements ITestResultResolver {
189189
// search through freshly built array of testItem to find the failed test and update UI.
190190
testCases.forEach((indiItem) => {
191191
if (indiItem.id === grabVSid) {
192-
if (indiItem.uri && indiItem.range) {
193-
message.location = new Location(indiItem.uri, indiItem.range);
192+
if (indiItem.uri) {
193+
if (indiItem.range) {
194+
message.location = new Location(indiItem.uri, indiItem.range);
195+
}
194196
runInstance.errored(indiItem, message);
195197
}
196198
}
@@ -210,8 +212,10 @@ export class PythonResultResolver implements ITestResultResolver {
210212
// search through freshly built array of testItem to find the failed test and update UI.
211213
testCases.forEach((indiItem) => {
212214
if (indiItem.id === grabVSid) {
213-
if (indiItem.uri && indiItem.range) {
214-
message.location = new Location(indiItem.uri, indiItem.range);
215+
if (indiItem.uri) {
216+
if (indiItem.range) {
217+
message.location = new Location(indiItem.uri, indiItem.range);
218+
}
215219
runInstance.failed(indiItem, message);
216220
}
217221
}
@@ -222,7 +226,7 @@ export class PythonResultResolver implements ITestResultResolver {
222226
if (grabTestItem !== undefined) {
223227
testCases.forEach((indiItem) => {
224228
if (indiItem.id === grabVSid) {
225-
if (indiItem.uri && indiItem.range) {
229+
if (indiItem.uri) {
226230
runInstance.passed(grabTestItem);
227231
}
228232
}
@@ -234,7 +238,7 @@ export class PythonResultResolver implements ITestResultResolver {
234238
if (grabTestItem !== undefined) {
235239
testCases.forEach((indiItem) => {
236240
if (indiItem.id === grabVSid) {
237-
if (indiItem.uri && indiItem.range) {
241+
if (indiItem.uri) {
238242
runInstance.skipped(grabTestItem);
239243
}
240244
}

src/client/testing/testController/common/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,10 @@ export function populateTestTree(
209209
const testItem = testController.createTestItem(child.id_, child.name, Uri.file(child.path));
210210
testItem.tags = [RunTestTag, DebugTestTag];
211211

212-
const range = new Range(
213-
new Position(Number(child.lineno) - 1, 0),
214-
new Position(Number(child.lineno), 0),
215-
);
212+
let range: Range | undefined;
213+
if (child.lineno) {
214+
range = new Range(new Position(Number(child.lineno) - 1, 0), new Position(Number(child.lineno), 0));
215+
}
216216
testItem.canResolveChildren = false;
217217
testItem.range = range;
218218
testItem.tags = [RunTestTag, DebugTestTag];

0 commit comments

Comments
 (0)