From 3fe17ce2c905d1d117f1e528014a7ae31ef4704b Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 19 Jul 2023 10:14:01 -0700 Subject: [PATCH 1/2] correct discovery on unittest skip at file level --- .../.data/unittest_skip/unittest_skip_file.py | 10 + .../unittest_skip/unittest_skip_function.py | 18 + .../expected_discovery_test_output.py | 68 +++ .../tests/unittestadapter/test_discovery.py | 451 +++++++++--------- .../tests/unittestadapter/test_execution.py | 28 ++ pythonFiles/unittestadapter/utils.py | 8 + 6 files changed, 367 insertions(+), 216 deletions(-) create mode 100644 pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py create mode 100644 pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py create mode 100644 pythonFiles/tests/unittestadapter/expected_discovery_test_output.py diff --git a/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py new file mode 100644 index 000000000000..927a56bc920b --- /dev/null +++ b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_file.py @@ -0,0 +1,10 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from unittest import SkipTest + +raise SkipTest("This is unittest.SkipTest calling") + + +def test_example(): + assert 1 == 1 diff --git a/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py new file mode 100644 index 000000000000..59e66e9a1d40 --- /dev/null +++ b/pythonFiles/tests/unittestadapter/.data/unittest_skip/unittest_skip_function.py @@ -0,0 +1,18 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import unittest + + +def add(x, y): + return x + y + + +class SimpleTest(unittest.TestCase): + @unittest.skip("demonstrating skipping") + def testadd1(self): + self.assertEquals(add(4, 5), 9) + + +if __name__ == "__main__": + unittest.main() diff --git a/pythonFiles/tests/unittestadapter/expected_discovery_test_output.py b/pythonFiles/tests/unittestadapter/expected_discovery_test_output.py new file mode 100644 index 000000000000..3043ec158a2e --- /dev/null +++ b/pythonFiles/tests/unittestadapter/expected_discovery_test_output.py @@ -0,0 +1,68 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import os +from unittestadapter.utils import TestNodeTypeEnum +from .helpers import TEST_DATA_PATH + +skip_unittest_folder_discovery_output = { + "path": os.fspath(TEST_DATA_PATH / "unittest_skip"), + "name": "unittest_skip", + "type_": TestNodeTypeEnum.folder, + "children": [ + { + "path": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_file.py" + ), + "name": "unittest_skip_file.py", + "type_": TestNodeTypeEnum.file, + "children": [], + "id_": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_file.py" + ), + }, + { + "path": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ), + "name": "unittest_skip_function.py", + "type_": TestNodeTypeEnum.file, + "children": [ + { + "path": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ), + "name": "SimpleTest", + "type_": TestNodeTypeEnum.class_, + "children": [ + { + "name": "testadd1", + "path": os.fspath( + TEST_DATA_PATH + / "unittest_skip" + / "unittest_skip_function.py" + ), + "lineno": "13", + "type_": TestNodeTypeEnum.test, + "id_": os.fspath( + TEST_DATA_PATH + / "unittest_skip" + / "unittest_skip_function.py" + ) + + "\\SimpleTest\\testadd1", + "runID": "unittest_skip_function.SimpleTest.testadd1", + } + ], + "id_": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ) + + "\\SimpleTest", + } + ], + "id_": os.fspath( + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py" + ), + }, + ], + "id_": os.fspath(TEST_DATA_PATH / "unittest_skip"), +} diff --git a/pythonFiles/tests/unittestadapter/test_discovery.py b/pythonFiles/tests/unittestadapter/test_discovery.py index 28dc51f55dcd..91d10d245027 100644 --- a/pythonFiles/tests/unittestadapter/test_discovery.py +++ b/pythonFiles/tests/unittestadapter/test_discovery.py @@ -1,216 +1,235 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import os -import pathlib -from typing import List - -import pytest -from unittestadapter.discovery import ( - DEFAULT_PORT, - discover_tests, - parse_discovery_cli_args, -) -from unittestadapter.utils import TestNodeTypeEnum, parse_unittest_args - -from .helpers import TEST_DATA_PATH, is_same_tree - - -@pytest.mark.parametrize( - "args, expected", - [ - (["--port", "6767", "--uuid", "some-uuid"], (6767, "some-uuid")), - (["--foo", "something", "--bar", "another"], (int(DEFAULT_PORT), None)), - (["--port", "4444", "--foo", "something", "--port", "9999"], (9999, None)), - ( - ["--uuid", "first-uuid", "--bar", "other", "--uuid", "second-uuid"], - (int(DEFAULT_PORT), "second-uuid"), - ), - ], -) -def test_parse_cli_args(args: List[str], expected: List[str]) -> None: - """The parse_cli_args function should parse and return the port and uuid passed as command-line options. - - If there were no --port or --uuid command-line option, it should return default values). - If there are multiple options, the last one wins. - """ - actual = parse_discovery_cli_args(args) - - assert expected == actual - - -@pytest.mark.parametrize( - "args, expected", - [ - ( - ["-s", "something", "-p", "other*", "-t", "else"], - ("something", "other*", "else"), - ), - ( - [ - "--start-directory", - "foo", - "--pattern", - "bar*", - "--top-level-directory", - "baz", - ], - ("foo", "bar*", "baz"), - ), - ( - ["--foo", "something"], - (".", "test*.py", None), - ), - ], -) -def test_parse_unittest_args(args: List[str], expected: List[str]) -> None: - """The parse_unittest_args function should return values for the start_dir, pattern, and top_level_dir arguments - when passed as command-line options, and ignore unrecognized arguments. - """ - actual = parse_unittest_args(args) - - assert actual == expected - - -def test_simple_discovery() -> None: - """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and a test tree - if unittest discovery was performed successfully. - """ - start_dir = os.fsdecode(TEST_DATA_PATH) - pattern = "discovery_simple*" - file_path = os.fsdecode(pathlib.PurePath(TEST_DATA_PATH / "discovery_simple.py")) - - expected = { - "path": start_dir, - "type_": TestNodeTypeEnum.folder, - "name": ".data", - "children": [ - { - "name": "discovery_simple.py", - "type_": TestNodeTypeEnum.file, - "path": file_path, - "children": [ - { - "name": "DiscoverySimple", - "path": file_path, - "type_": TestNodeTypeEnum.class_, - "children": [ - { - "name": "test_one", - "path": file_path, - "type_": TestNodeTypeEnum.test, - "lineno": "14", - "id_": file_path - + "\\" - + "DiscoverySimple" - + "\\" - + "test_one", - }, - { - "name": "test_two", - "path": file_path, - "type_": TestNodeTypeEnum.test, - "lineno": "17", - "id_": file_path - + "\\" - + "DiscoverySimple" - + "\\" - + "test_two", - }, - ], - "id_": file_path + "\\" + "DiscoverySimple", - } - ], - "id_": file_path, - } - ], - "id_": start_dir, - } - - uuid = "some-uuid" - actual = discover_tests(start_dir, pattern, None, uuid) - - assert actual["status"] == "success" - assert is_same_tree(actual.get("tests"), expected) - assert "error" not in actual - - -def test_empty_discovery() -> None: - """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and no test tree - if unittest discovery was performed successfully but no tests were found. - """ - start_dir = os.fsdecode(TEST_DATA_PATH) - pattern = "discovery_empty*" - - uuid = "some-uuid" - actual = discover_tests(start_dir, pattern, None, uuid) - - assert actual["status"] == "success" - assert "tests" in actual - assert "error" not in actual - - -def test_error_discovery() -> None: - """The discover_tests function should return a dictionary with an "error" status, a uuid, the discovered tests, and a list of errors - if unittest discovery failed at some point. - """ - # Discover tests in .data/discovery_error/. - start_path = pathlib.PurePath(TEST_DATA_PATH / "discovery_error") - start_dir = os.fsdecode(start_path) - pattern = "file*" - - file_path = os.fsdecode(start_path / "file_two.py") - - expected = { - "path": start_dir, - "type_": TestNodeTypeEnum.folder, - "name": "discovery_error", - "children": [ - { - "name": "file_two.py", - "type_": TestNodeTypeEnum.file, - "path": file_path, - "children": [ - { - "name": "DiscoveryErrorTwo", - "path": file_path, - "type_": TestNodeTypeEnum.class_, - "children": [ - { - "name": "test_one", - "path": file_path, - "type_": TestNodeTypeEnum.test, - "lineno": "14", - "id_": file_path - + "\\" - + "DiscoveryErrorTwo" - + "\\" - + "test_one", - }, - { - "name": "test_two", - "path": file_path, - "type_": TestNodeTypeEnum.test, - "lineno": "17", - "id_": file_path - + "\\" - + "DiscoveryErrorTwo" - + "\\" - + "test_two", - }, - ], - "id_": file_path + "\\" + "DiscoveryErrorTwo", - } - ], - "id_": file_path, - } - ], - "id_": start_dir, - } - - uuid = "some-uuid" - actual = discover_tests(start_dir, pattern, None, uuid) - - assert actual["status"] == "error" - assert is_same_tree(expected, actual.get("tests")) - assert len(actual.get("error", [])) == 1 +# # Copyright (c) Microsoft Corporation. All rights reserved. +# # Licensed under the MIT License. + +# import os +# import pathlib +# from typing import List + +# import pytest +# from unittestadapter.discovery import ( +# DEFAULT_PORT, +# discover_tests, +# parse_discovery_cli_args, +# ) +# from unittestadapter.utils import TestNodeTypeEnum, parse_unittest_args +# from . import expected_discovery_test_output +# from .helpers import TEST_DATA_PATH, is_same_tree + + +# @pytest.mark.parametrize( +# "args, expected", +# [ +# (["--port", "6767", "--uuid", "some-uuid"], (6767, "some-uuid")), +# (["--foo", "something", "--bar", "another"], (int(DEFAULT_PORT), None)), +# (["--port", "4444", "--foo", "something", "--port", "9999"], (9999, None)), +# ( +# ["--uuid", "first-uuid", "--bar", "other", "--uuid", "second-uuid"], +# (int(DEFAULT_PORT), "second-uuid"), +# ), +# ], +# ) +# def test_parse_cli_args(args: List[str], expected: List[str]) -> None: +# """The parse_cli_args function should parse and return the port and uuid passed as command-line options. + +# If there were no --port or --uuid command-line option, it should return default values). +# If there are multiple options, the last one wins. +# """ +# actual = parse_discovery_cli_args(args) + +# assert expected == actual + + +# @pytest.mark.parametrize( +# "args, expected", +# [ +# ( +# ["-s", "something", "-p", "other*", "-t", "else"], +# ("something", "other*", "else"), +# ), +# ( +# [ +# "--start-directory", +# "foo", +# "--pattern", +# "bar*", +# "--top-level-directory", +# "baz", +# ], +# ("foo", "bar*", "baz"), +# ), +# ( +# ["--foo", "something"], +# (".", "test*.py", None), +# ), +# ], +# ) +# def test_parse_unittest_args(args: List[str], expected: List[str]) -> None: +# """The parse_unittest_args function should return values for the start_dir, pattern, and top_level_dir arguments +# when passed as command-line options, and ignore unrecognized arguments. +# """ +# actual = parse_unittest_args(args) + +# assert actual == expected + + +# def test_simple_discovery() -> None: +# """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and a test tree +# if unittest discovery was performed successfully. +# """ +# start_dir = os.fsdecode(TEST_DATA_PATH) +# pattern = "discovery_simple*" +# file_path = os.fsdecode(pathlib.PurePath(TEST_DATA_PATH / "discovery_simple.py")) + +# expected = { +# "path": start_dir, +# "type_": TestNodeTypeEnum.folder, +# "name": ".data", +# "children": [ +# { +# "name": "discovery_simple.py", +# "type_": TestNodeTypeEnum.file, +# "path": file_path, +# "children": [ +# { +# "name": "DiscoverySimple", +# "path": file_path, +# "type_": TestNodeTypeEnum.class_, +# "children": [ +# { +# "name": "test_one", +# "path": file_path, +# "type_": TestNodeTypeEnum.test, +# "lineno": "14", +# "id_": file_path +# + "\\" +# + "DiscoverySimple" +# + "\\" +# + "test_one", +# }, +# { +# "name": "test_two", +# "path": file_path, +# "type_": TestNodeTypeEnum.test, +# "lineno": "17", +# "id_": file_path +# + "\\" +# + "DiscoverySimple" +# + "\\" +# + "test_two", +# }, +# ], +# "id_": file_path + "\\" + "DiscoverySimple", +# } +# ], +# "id_": file_path, +# } +# ], +# "id_": start_dir, +# } + +# uuid = "some-uuid" +# actual = discover_tests(start_dir, pattern, None, uuid) + +# assert actual["status"] == "success" +# assert is_same_tree(actual.get("tests"), expected) +# assert "error" not in actual + + +# def test_empty_discovery() -> None: +# """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and no test tree +# if unittest discovery was performed successfully but no tests were found. +# """ +# start_dir = os.fsdecode(TEST_DATA_PATH) +# pattern = "discovery_empty*" + +# uuid = "some-uuid" +# actual = discover_tests(start_dir, pattern, None, uuid) + +# assert actual["status"] == "success" +# assert "tests" in actual +# assert "error" not in actual + + +# def test_error_discovery() -> None: +# """The discover_tests function should return a dictionary with an "error" status, a uuid, the discovered tests, and a list of errors +# if unittest discovery failed at some point. +# """ +# # Discover tests in .data/discovery_error/. +# start_path = pathlib.PurePath(TEST_DATA_PATH / "discovery_error") +# start_dir = os.fsdecode(start_path) +# pattern = "file*" + +# file_path = os.fsdecode(start_path / "file_two.py") + +# expected = { +# "path": start_dir, +# "type_": TestNodeTypeEnum.folder, +# "name": "discovery_error", +# "children": [ +# { +# "name": "file_two.py", +# "type_": TestNodeTypeEnum.file, +# "path": file_path, +# "children": [ +# { +# "name": "DiscoveryErrorTwo", +# "path": file_path, +# "type_": TestNodeTypeEnum.class_, +# "children": [ +# { +# "name": "test_one", +# "path": file_path, +# "type_": TestNodeTypeEnum.test, +# "lineno": "14", +# "id_": file_path +# + "\\" +# + "DiscoveryErrorTwo" +# + "\\" +# + "test_one", +# }, +# { +# "name": "test_two", +# "path": file_path, +# "type_": TestNodeTypeEnum.test, +# "lineno": "17", +# "id_": file_path +# + "\\" +# + "DiscoveryErrorTwo" +# + "\\" +# + "test_two", +# }, +# ], +# "id_": file_path + "\\" + "DiscoveryErrorTwo", +# } +# ], +# "id_": file_path, +# } +# ], +# "id_": start_dir, +# } + +# uuid = "some-uuid" +# actual = discover_tests(start_dir, pattern, None, uuid) + +# assert actual["status"] == "error" +# assert is_same_tree(expected, actual.get("tests")) +# assert len(actual.get("error", [])) == 1 + + +# def test_unit_skip() -> None: +# """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and test tree. +# if unittest discovery was performed and found a test in one file marked as skipped and another file marked as skipped. +# """ +# start_dir = os.fsdecode(TEST_DATA_PATH / "unittest_skip") +# pattern = "unittest_*" + +# uuid = "some-uuid" +# actual = discover_tests(start_dir, pattern, None, uuid) + +# assert actual["status"] == "success" +# assert "tests" in actual +# assert is_same_tree( +# actual.get("tests"), +# expected_discovery_test_output.skip_unittest_folder_discovery_output, +# ) +# assert "error" not in actual diff --git a/pythonFiles/tests/unittestadapter/test_execution.py b/pythonFiles/tests/unittestadapter/test_execution.py index 057f64d7396a..b5eaad2ba207 100644 --- a/pythonFiles/tests/unittestadapter/test_execution.py +++ b/pythonFiles/tests/unittestadapter/test_execution.py @@ -16,6 +16,34 @@ TEST_DATA_PATH = pathlib.Path(__file__).parent / ".data" +def test_skipped_file_folder() -> None: + """This test runs on a single test_id, therefore it should return + a dict with a single key-value pair for the result. + + This single test passes so the outcome should be 'success'. + """ + id = "discovery_simple.DiscoverySimple.test_one" + actual = run_tests( + os.fspath(TEST_DATA_PATH / "unittest_skip"), + [id], + "unittest_*", + None, + "fake-uuid", + ) + assert actual + assert all(item in actual for item in ("cwd", "status")) + assert actual["status"] == "success" + assert actual["cwd"] == os.fspath(TEST_DATA_PATH) + assert actual["result"] is not None + result = actual["result"] + assert len(result) == 1 + assert id in result + id_result = result[id] + assert id_result is not None + assert "outcome" in id_result + assert id_result["outcome"] == "success" + + @pytest.mark.parametrize( "args, expected", [ diff --git a/pythonFiles/unittestadapter/utils.py b/pythonFiles/unittestadapter/utils.py index a461baf7d870..78000e2a945f 100644 --- a/pythonFiles/unittestadapter/utils.py +++ b/pythonFiles/unittestadapter/utils.py @@ -159,6 +159,14 @@ def build_test_tree( test_id = test_case.id() if test_id.startswith("unittest.loader._FailedTest"): error.append(str(test_case._exception)) # type: ignore + elif test_id.startswith("unittest.loader.ModuleSkipped"): + components = test_id.split(".") + class_name = f"{components[-1]}.py" + # Find/build class node. + file_path = os.fsdecode(os.path.join(directory_path, class_name)) + current_node = get_child_node( + class_name, file_path, TestNodeTypeEnum.file, root + ) else: # Get the static test path components: filename, class name and function name. components = test_id.split(".") From eaa1d857527cca0b90d29ef8969a5d0d32a61d80 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 19 Jul 2023 13:42:39 -0700 Subject: [PATCH 2/2] fix tests --- .../tests/unittestadapter/test_discovery.py | 470 +++++++++--------- .../tests/unittestadapter/test_execution.py | 28 -- 2 files changed, 235 insertions(+), 263 deletions(-) diff --git a/pythonFiles/tests/unittestadapter/test_discovery.py b/pythonFiles/tests/unittestadapter/test_discovery.py index 91d10d245027..c4778aa85852 100644 --- a/pythonFiles/tests/unittestadapter/test_discovery.py +++ b/pythonFiles/tests/unittestadapter/test_discovery.py @@ -1,235 +1,235 @@ -# # Copyright (c) Microsoft Corporation. All rights reserved. -# # Licensed under the MIT License. - -# import os -# import pathlib -# from typing import List - -# import pytest -# from unittestadapter.discovery import ( -# DEFAULT_PORT, -# discover_tests, -# parse_discovery_cli_args, -# ) -# from unittestadapter.utils import TestNodeTypeEnum, parse_unittest_args -# from . import expected_discovery_test_output -# from .helpers import TEST_DATA_PATH, is_same_tree - - -# @pytest.mark.parametrize( -# "args, expected", -# [ -# (["--port", "6767", "--uuid", "some-uuid"], (6767, "some-uuid")), -# (["--foo", "something", "--bar", "another"], (int(DEFAULT_PORT), None)), -# (["--port", "4444", "--foo", "something", "--port", "9999"], (9999, None)), -# ( -# ["--uuid", "first-uuid", "--bar", "other", "--uuid", "second-uuid"], -# (int(DEFAULT_PORT), "second-uuid"), -# ), -# ], -# ) -# def test_parse_cli_args(args: List[str], expected: List[str]) -> None: -# """The parse_cli_args function should parse and return the port and uuid passed as command-line options. - -# If there were no --port or --uuid command-line option, it should return default values). -# If there are multiple options, the last one wins. -# """ -# actual = parse_discovery_cli_args(args) - -# assert expected == actual - - -# @pytest.mark.parametrize( -# "args, expected", -# [ -# ( -# ["-s", "something", "-p", "other*", "-t", "else"], -# ("something", "other*", "else"), -# ), -# ( -# [ -# "--start-directory", -# "foo", -# "--pattern", -# "bar*", -# "--top-level-directory", -# "baz", -# ], -# ("foo", "bar*", "baz"), -# ), -# ( -# ["--foo", "something"], -# (".", "test*.py", None), -# ), -# ], -# ) -# def test_parse_unittest_args(args: List[str], expected: List[str]) -> None: -# """The parse_unittest_args function should return values for the start_dir, pattern, and top_level_dir arguments -# when passed as command-line options, and ignore unrecognized arguments. -# """ -# actual = parse_unittest_args(args) - -# assert actual == expected - - -# def test_simple_discovery() -> None: -# """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and a test tree -# if unittest discovery was performed successfully. -# """ -# start_dir = os.fsdecode(TEST_DATA_PATH) -# pattern = "discovery_simple*" -# file_path = os.fsdecode(pathlib.PurePath(TEST_DATA_PATH / "discovery_simple.py")) - -# expected = { -# "path": start_dir, -# "type_": TestNodeTypeEnum.folder, -# "name": ".data", -# "children": [ -# { -# "name": "discovery_simple.py", -# "type_": TestNodeTypeEnum.file, -# "path": file_path, -# "children": [ -# { -# "name": "DiscoverySimple", -# "path": file_path, -# "type_": TestNodeTypeEnum.class_, -# "children": [ -# { -# "name": "test_one", -# "path": file_path, -# "type_": TestNodeTypeEnum.test, -# "lineno": "14", -# "id_": file_path -# + "\\" -# + "DiscoverySimple" -# + "\\" -# + "test_one", -# }, -# { -# "name": "test_two", -# "path": file_path, -# "type_": TestNodeTypeEnum.test, -# "lineno": "17", -# "id_": file_path -# + "\\" -# + "DiscoverySimple" -# + "\\" -# + "test_two", -# }, -# ], -# "id_": file_path + "\\" + "DiscoverySimple", -# } -# ], -# "id_": file_path, -# } -# ], -# "id_": start_dir, -# } - -# uuid = "some-uuid" -# actual = discover_tests(start_dir, pattern, None, uuid) - -# assert actual["status"] == "success" -# assert is_same_tree(actual.get("tests"), expected) -# assert "error" not in actual - - -# def test_empty_discovery() -> None: -# """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and no test tree -# if unittest discovery was performed successfully but no tests were found. -# """ -# start_dir = os.fsdecode(TEST_DATA_PATH) -# pattern = "discovery_empty*" - -# uuid = "some-uuid" -# actual = discover_tests(start_dir, pattern, None, uuid) - -# assert actual["status"] == "success" -# assert "tests" in actual -# assert "error" not in actual - - -# def test_error_discovery() -> None: -# """The discover_tests function should return a dictionary with an "error" status, a uuid, the discovered tests, and a list of errors -# if unittest discovery failed at some point. -# """ -# # Discover tests in .data/discovery_error/. -# start_path = pathlib.PurePath(TEST_DATA_PATH / "discovery_error") -# start_dir = os.fsdecode(start_path) -# pattern = "file*" - -# file_path = os.fsdecode(start_path / "file_two.py") - -# expected = { -# "path": start_dir, -# "type_": TestNodeTypeEnum.folder, -# "name": "discovery_error", -# "children": [ -# { -# "name": "file_two.py", -# "type_": TestNodeTypeEnum.file, -# "path": file_path, -# "children": [ -# { -# "name": "DiscoveryErrorTwo", -# "path": file_path, -# "type_": TestNodeTypeEnum.class_, -# "children": [ -# { -# "name": "test_one", -# "path": file_path, -# "type_": TestNodeTypeEnum.test, -# "lineno": "14", -# "id_": file_path -# + "\\" -# + "DiscoveryErrorTwo" -# + "\\" -# + "test_one", -# }, -# { -# "name": "test_two", -# "path": file_path, -# "type_": TestNodeTypeEnum.test, -# "lineno": "17", -# "id_": file_path -# + "\\" -# + "DiscoveryErrorTwo" -# + "\\" -# + "test_two", -# }, -# ], -# "id_": file_path + "\\" + "DiscoveryErrorTwo", -# } -# ], -# "id_": file_path, -# } -# ], -# "id_": start_dir, -# } - -# uuid = "some-uuid" -# actual = discover_tests(start_dir, pattern, None, uuid) - -# assert actual["status"] == "error" -# assert is_same_tree(expected, actual.get("tests")) -# assert len(actual.get("error", [])) == 1 - - -# def test_unit_skip() -> None: -# """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and test tree. -# if unittest discovery was performed and found a test in one file marked as skipped and another file marked as skipped. -# """ -# start_dir = os.fsdecode(TEST_DATA_PATH / "unittest_skip") -# pattern = "unittest_*" - -# uuid = "some-uuid" -# actual = discover_tests(start_dir, pattern, None, uuid) - -# assert actual["status"] == "success" -# assert "tests" in actual -# assert is_same_tree( -# actual.get("tests"), -# expected_discovery_test_output.skip_unittest_folder_discovery_output, -# ) -# assert "error" not in actual +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import os +import pathlib +from typing import List + +import pytest +from unittestadapter.discovery import ( + DEFAULT_PORT, + discover_tests, + parse_discovery_cli_args, +) +from unittestadapter.utils import TestNodeTypeEnum, parse_unittest_args +from . import expected_discovery_test_output +from .helpers import TEST_DATA_PATH, is_same_tree + + +@pytest.mark.parametrize( + "args, expected", + [ + (["--port", "6767", "--uuid", "some-uuid"], (6767, "some-uuid")), + (["--foo", "something", "--bar", "another"], (int(DEFAULT_PORT), None)), + (["--port", "4444", "--foo", "something", "--port", "9999"], (9999, None)), + ( + ["--uuid", "first-uuid", "--bar", "other", "--uuid", "second-uuid"], + (int(DEFAULT_PORT), "second-uuid"), + ), + ], +) +def test_parse_cli_args(args: List[str], expected: List[str]) -> None: + """The parse_cli_args function should parse and return the port and uuid passed as command-line options. + + If there were no --port or --uuid command-line option, it should return default values). + If there are multiple options, the last one wins. + """ + actual = parse_discovery_cli_args(args) + + assert expected == actual + + +@pytest.mark.parametrize( + "args, expected", + [ + ( + ["-s", "something", "-p", "other*", "-t", "else"], + ("something", "other*", "else"), + ), + ( + [ + "--start-directory", + "foo", + "--pattern", + "bar*", + "--top-level-directory", + "baz", + ], + ("foo", "bar*", "baz"), + ), + ( + ["--foo", "something"], + (".", "test*.py", None), + ), + ], +) +def test_parse_unittest_args(args: List[str], expected: List[str]) -> None: + """The parse_unittest_args function should return values for the start_dir, pattern, and top_level_dir arguments + when passed as command-line options, and ignore unrecognized arguments. + """ + actual = parse_unittest_args(args) + + assert actual == expected + + +def test_simple_discovery() -> None: + """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and a test tree + if unittest discovery was performed successfully. + """ + start_dir = os.fsdecode(TEST_DATA_PATH) + pattern = "discovery_simple*" + file_path = os.fsdecode(pathlib.PurePath(TEST_DATA_PATH / "discovery_simple.py")) + + expected = { + "path": start_dir, + "type_": TestNodeTypeEnum.folder, + "name": ".data", + "children": [ + { + "name": "discovery_simple.py", + "type_": TestNodeTypeEnum.file, + "path": file_path, + "children": [ + { + "name": "DiscoverySimple", + "path": file_path, + "type_": TestNodeTypeEnum.class_, + "children": [ + { + "name": "test_one", + "path": file_path, + "type_": TestNodeTypeEnum.test, + "lineno": "14", + "id_": file_path + + "\\" + + "DiscoverySimple" + + "\\" + + "test_one", + }, + { + "name": "test_two", + "path": file_path, + "type_": TestNodeTypeEnum.test, + "lineno": "17", + "id_": file_path + + "\\" + + "DiscoverySimple" + + "\\" + + "test_two", + }, + ], + "id_": file_path + "\\" + "DiscoverySimple", + } + ], + "id_": file_path, + } + ], + "id_": start_dir, + } + + uuid = "some-uuid" + actual = discover_tests(start_dir, pattern, None, uuid) + + assert actual["status"] == "success" + assert is_same_tree(actual.get("tests"), expected) + assert "error" not in actual + + +def test_empty_discovery() -> None: + """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and no test tree + if unittest discovery was performed successfully but no tests were found. + """ + start_dir = os.fsdecode(TEST_DATA_PATH) + pattern = "discovery_empty*" + + uuid = "some-uuid" + actual = discover_tests(start_dir, pattern, None, uuid) + + assert actual["status"] == "success" + assert "tests" in actual + assert "error" not in actual + + +def test_error_discovery() -> None: + """The discover_tests function should return a dictionary with an "error" status, a uuid, the discovered tests, and a list of errors + if unittest discovery failed at some point. + """ + # Discover tests in .data/discovery_error/. + start_path = pathlib.PurePath(TEST_DATA_PATH / "discovery_error") + start_dir = os.fsdecode(start_path) + pattern = "file*" + + file_path = os.fsdecode(start_path / "file_two.py") + + expected = { + "path": start_dir, + "type_": TestNodeTypeEnum.folder, + "name": "discovery_error", + "children": [ + { + "name": "file_two.py", + "type_": TestNodeTypeEnum.file, + "path": file_path, + "children": [ + { + "name": "DiscoveryErrorTwo", + "path": file_path, + "type_": TestNodeTypeEnum.class_, + "children": [ + { + "name": "test_one", + "path": file_path, + "type_": TestNodeTypeEnum.test, + "lineno": "14", + "id_": file_path + + "\\" + + "DiscoveryErrorTwo" + + "\\" + + "test_one", + }, + { + "name": "test_two", + "path": file_path, + "type_": TestNodeTypeEnum.test, + "lineno": "17", + "id_": file_path + + "\\" + + "DiscoveryErrorTwo" + + "\\" + + "test_two", + }, + ], + "id_": file_path + "\\" + "DiscoveryErrorTwo", + } + ], + "id_": file_path, + } + ], + "id_": start_dir, + } + + uuid = "some-uuid" + actual = discover_tests(start_dir, pattern, None, uuid) + + assert actual["status"] == "error" + assert is_same_tree(expected, actual.get("tests")) + assert len(actual.get("error", [])) == 1 + + +def test_unit_skip() -> None: + """The discover_tests function should return a dictionary with a "success" status, a uuid, no errors, and test tree. + if unittest discovery was performed and found a test in one file marked as skipped and another file marked as skipped. + """ + start_dir = os.fsdecode(TEST_DATA_PATH / "unittest_skip") + pattern = "unittest_*" + + uuid = "some-uuid" + actual = discover_tests(start_dir, pattern, None, uuid) + + assert actual["status"] == "success" + assert "tests" in actual + assert is_same_tree( + actual.get("tests"), + expected_discovery_test_output.skip_unittest_folder_discovery_output, + ) + assert "error" not in actual diff --git a/pythonFiles/tests/unittestadapter/test_execution.py b/pythonFiles/tests/unittestadapter/test_execution.py index b5eaad2ba207..057f64d7396a 100644 --- a/pythonFiles/tests/unittestadapter/test_execution.py +++ b/pythonFiles/tests/unittestadapter/test_execution.py @@ -16,34 +16,6 @@ TEST_DATA_PATH = pathlib.Path(__file__).parent / ".data" -def test_skipped_file_folder() -> None: - """This test runs on a single test_id, therefore it should return - a dict with a single key-value pair for the result. - - This single test passes so the outcome should be 'success'. - """ - id = "discovery_simple.DiscoverySimple.test_one" - actual = run_tests( - os.fspath(TEST_DATA_PATH / "unittest_skip"), - [id], - "unittest_*", - None, - "fake-uuid", - ) - assert actual - assert all(item in actual for item in ("cwd", "status")) - assert actual["status"] == "success" - assert actual["cwd"] == os.fspath(TEST_DATA_PATH) - assert actual["result"] is not None - result = actual["result"] - assert len(result) == 1 - assert id in result - id_result = result[id] - assert id_result is not None - assert "outcome" in id_result - assert id_result["outcome"] == "success" - - @pytest.mark.parametrize( "args, expected", [