From 0ea69c6bc63c520b00827fa6a3e8049ff67db12c Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:54:34 -0700 Subject: [PATCH 1/6] support branch coverage for testing --- build/test-requirements.txt | 4 +-- .../tests/pytestadapter/test_coverage.py | 5 +++ .../tests/unittestadapter/test_coverage.py | 2 ++ python_files/unittestadapter/execution.py | 20 +++++++++++- python_files/unittestadapter/pvsc_utils.py | 4 +++ python_files/vscode_pytest/__init__.py | 31 +++++++++++++++++-- .../vscode_pytest/run_pytest_script.py | 2 +- .../testController/common/resultResolver.ts | 21 +++++++++++-- .../testing/testController/common/types.ts | 2 ++ .../testing/common/testingAdapter.test.ts | 4 +++ 10 files changed, 85 insertions(+), 10 deletions(-) diff --git a/build/test-requirements.txt b/build/test-requirements.txt index 097b18256764..31d058633b21 100644 --- a/build/test-requirements.txt +++ b/build/test-requirements.txt @@ -28,8 +28,8 @@ namedpipe; platform_system == "Windows" # typing for Django files django-stubs -# for coverage -coverage +# for branch coverage testing, need version >= 7.7 +coverage>=7.7 pytest-cov pytest-json pytest-timeout diff --git a/python_files/tests/pytestadapter/test_coverage.py b/python_files/tests/pytestadapter/test_coverage.py index d0f802a23672..8012e2f3b417 100644 --- a/python_files/tests/pytestadapter/test_coverage.py +++ b/python_files/tests/pytestadapter/test_coverage.py @@ -45,6 +45,8 @@ def test_simple_pytest_coverage(): assert focal_function_coverage.get("lines_missed") is not None assert set(focal_function_coverage.get("lines_covered")) == {4, 5, 7, 9, 10, 11, 12, 13, 14, 17} assert len(set(focal_function_coverage.get("lines_missed"))) >= 3 + assert focal_function_coverage.get("executed_branches") == 4 + assert focal_function_coverage.get("total_branches") == 6 coverage_gen_file_path = TEST_DATA_PATH / "coverage_gen" / "coverage.json" @@ -88,6 +90,8 @@ def test_coverage_gen_report(cleanup_coverage_gen_file): # noqa: ARG001 assert focal_function_coverage.get("lines_missed") is not None assert set(focal_function_coverage.get("lines_covered")) == {4, 5, 7, 9, 10, 11, 12, 13, 14, 17} assert set(focal_function_coverage.get("lines_missed")) == {18, 19, 6} + assert focal_function_coverage.get("executed_branches") == 4 + assert focal_function_coverage.get("total_branches") == 6 # assert that the coverage file was created at the right path assert os.path.exists(coverage_gen_file_path) # noqa: PTH110 @@ -129,3 +133,4 @@ def test_coverage_w_omit_config(): assert results # assert one file is reported and one file (as specified in pyproject.toml) is omitted assert len(results) == 1 + diff --git a/python_files/tests/unittestadapter/test_coverage.py b/python_files/tests/unittestadapter/test_coverage.py index 8fce53c1854a..d3ab43a364e4 100644 --- a/python_files/tests/unittestadapter/test_coverage.py +++ b/python_files/tests/unittestadapter/test_coverage.py @@ -51,6 +51,8 @@ def test_basic_coverage(): assert focal_function_coverage.get("lines_missed") is not None assert set(focal_function_coverage.get("lines_covered")) == {4, 5, 7, 9, 10, 11, 12, 13, 14} assert set(focal_function_coverage.get("lines_missed")) == {6} + assert focal_function_coverage.get("executed_branches") == 3 + assert focal_function_coverage.get("total_branches") == 4 @pytest.mark.parametrize("manage_py_file", ["manage.py", "old_manage.py"]) diff --git a/python_files/unittestadapter/execution.py b/python_files/unittestadapter/execution.py index 644b233fc530..65f271f5647c 100644 --- a/python_files/unittestadapter/execution.py +++ b/python_files/unittestadapter/execution.py @@ -11,6 +11,8 @@ import unittest from types import TracebackType from typing import Dict, List, Optional, Set, Tuple, Type, Union +from packaging.version import Version + # Adds the scripts directory to the PATH as a workaround for enabling shell for test execution. path_var_name = "PATH" if "PATH" in os.environ else "Path" @@ -316,12 +318,18 @@ def send_run_data(raw_data, test_run_pipe): # For unittest COVERAGE_ENABLED is to the root of the workspace so correct data is collected cov = None is_coverage_run = os.environ.get("COVERAGE_ENABLED") is not None + include_branches = False if is_coverage_run: print( "COVERAGE_ENABLED env var set, starting coverage. workspace_root used as parent dir:", workspace_root, ) import coverage + coverage_version = Version(coverage.__version__) + # only include branches if coverage version is 7.7.0 or greater (as this was when the api saves) + if coverage_version >= Version("7.7.0"): + include_branches = True + source_ar: List[str] = [] if workspace_root: @@ -330,7 +338,7 @@ def send_run_data(raw_data, test_run_pipe): source_ar.append(top_level_dir) if start_dir: source_ar.append(os.path.abspath(start_dir)) # noqa: PTH100 - cov = coverage.Coverage(branch=True, source=source_ar) # is at least 1 of these required?? + cov = coverage.Coverage(branch=include_branches, source=source_ar) # is at least 1 of these required?? cov.start() # If no error occurred, we will have test ids to run. @@ -362,12 +370,22 @@ def send_run_data(raw_data, test_run_pipe): file_coverage_map: Dict[str, FileCoverageInfo] = {} for file in file_set: analysis = cov.analysis2(file) + taken_file_branches = 0 + total_file_branches = -1 + + if include_branches: + branch_stats: dict[int, tuple[int, int]] = cov.branch_stats(file) + total_file_branches = sum([total_exits for total_exits, _ in branch_stats.values()]) + taken_file_branches = sum([taken_exits for _, taken_exits in branch_stats.values()]) + lines_executable = {int(line_no) for line_no in analysis[1]} lines_missed = {int(line_no) for line_no in analysis[3]} lines_covered = lines_executable - lines_missed file_info: FileCoverageInfo = { "lines_covered": list(lines_covered), # list of int "lines_missed": list(lines_missed), # list of int + "executed_branches": taken_file_branches, + "total_branches": total_file_branches, } file_coverage_map[file] = file_info diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index 4d1cbfb5e110..f253007cfb81 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -75,6 +75,10 @@ class ExecutionPayloadDict(TypedDict): class FileCoverageInfo(TypedDict): lines_covered: List[int] lines_missed: List[int] + executed_branches: int + total_branches: int + + class CoveragePayloadDict(Dict): diff --git a/python_files/vscode_pytest/__init__.py b/python_files/vscode_pytest/__init__.py index bf9466991383..3d45ca9be395 100644 --- a/python_files/vscode_pytest/__init__.py +++ b/python_files/vscode_pytest/__init__.py @@ -11,6 +11,7 @@ import sys import traceback from typing import TYPE_CHECKING, Any, Dict, Generator, Literal, TypedDict +from packaging.version import Version import pytest @@ -61,6 +62,7 @@ def __init__(self, message): collected_tests_so_far = [] TEST_RUN_PIPE = os.getenv("TEST_RUN_PIPE") SYMLINK_PATH = None +INCLUDE_BRANCHES = False def pytest_load_initial_conftests(early_config, parser, args): # noqa: ARG001 @@ -70,6 +72,9 @@ def pytest_load_initial_conftests(early_config, parser, args): # noqa: ARG001 raise VSCodePytestError( "\n \nERROR: pytest-cov is not installed, please install this before running pytest with coverage as pytest-cov is required. \n" ) + if "--cov-branch" in args: + global INCLUDE_BRANCHES + INCLUDE_BRANCHES = True global TEST_RUN_PIPE TEST_RUN_PIPE = os.getenv("TEST_RUN_PIPE") @@ -363,6 +368,8 @@ def check_skipped_condition(item): class FileCoverageInfo(TypedDict): lines_covered: list[int] lines_missed: list[int] + executed_branches: int + total_branches: int def pytest_sessionfinish(session, exitstatus): @@ -436,6 +443,15 @@ def pytest_sessionfinish(session, exitstatus): # load the report and build the json result to return import coverage + coverage_version = Version(coverage.__version__) + global INCLUDE_BRANCHES + # only include branches if coverage version is 7.7.0 or greater (as this was when the api saves) + if coverage_version < Version("7.7.0") and INCLUDE_BRANCHES: + print( + "Plugin warning[vscode-pytest]: Branch coverage not supported in this coverage versions < 7.7.0. Please upgrade coverage package if you would like to see branch coverage." + ) + INCLUDE_BRANCHES = False + try: from coverage.exceptions import NoSource except ImportError: @@ -448,9 +464,8 @@ def pytest_sessionfinish(session, exitstatus): file_coverage_map: dict[str, FileCoverageInfo] = {} # remove files omitted per coverage report config if any - omit_files = cov.config.report_omit - if omit_files: - print("Plugin info[vscode-pytest]: Omit files/rules: ", omit_files) + omit_files: list[str] | None = cov.config.report_omit + if omit_files is not None: for pattern in omit_files: for file in list(file_set): if pathlib.Path(file).match(pattern): @@ -459,6 +474,14 @@ def pytest_sessionfinish(session, exitstatus): for file in file_set: try: analysis = cov.analysis2(file) + taken_file_branches = 0 + total_file_branches = -1 + + if INCLUDE_BRANCHES: + branch_stats: dict[int, tuple[int, int]] = cov.branch_stats(file) + total_file_branches = sum([total_exits for total_exits, _ in branch_stats.values()]) + taken_file_branches = sum([taken_exits for _, taken_exits in branch_stats.values()]) + except NoSource: # as per issue 24308 this best way to handle this edge case continue @@ -473,6 +496,8 @@ def pytest_sessionfinish(session, exitstatus): file_info: FileCoverageInfo = { "lines_covered": list(lines_covered), # list of int "lines_missed": list(lines_missed), # list of int + "executed_branches": taken_file_branches, + "total_branches": total_file_branches, } # convert relative path to absolute path if not pathlib.Path(file).is_absolute(): diff --git a/python_files/vscode_pytest/run_pytest_script.py b/python_files/vscode_pytest/run_pytest_script.py index 1abfb8b27004..c0f5114b375c 100644 --- a/python_files/vscode_pytest/run_pytest_script.py +++ b/python_files/vscode_pytest/run_pytest_script.py @@ -47,7 +47,7 @@ def run_pytest(args): coverage_enabled = True break if not coverage_enabled: - args = [*args, "--cov=."] + args = [*args, "--cov=.", "--cov-branch"] run_test_ids_pipe = os.environ.get("RUN_TEST_IDS_PIPE") if run_test_ids_pipe: diff --git a/src/client/testing/testController/common/resultResolver.ts b/src/client/testing/testController/common/resultResolver.ts index 80e57edbabd2..82856627e0c9 100644 --- a/src/client/testing/testController/common/resultResolver.ts +++ b/src/client/testing/testController/common/resultResolver.ts @@ -17,7 +17,13 @@ import { Range, } from 'vscode'; import * as util from 'util'; -import { CoveragePayload, DiscoveredTestPayload, ExecutionTestPayload, ITestResultResolver } from './types'; +import { + CoveragePayload, + DiscoveredTestPayload, + ExecutionTestPayload, + FileCoverageMetrics, + ITestResultResolver, +} from './types'; import { TestProvider } from '../../types'; import { traceError, traceVerbose } from '../../../logging'; import { Testing } from '../../../common/utils/localize'; @@ -120,16 +126,25 @@ export class PythonResultResolver implements ITestResultResolver { } for (const [key, value] of Object.entries(payload.result)) { const fileNameStr = key; - const fileCoverageMetrics = value; + const fileCoverageMetrics: FileCoverageMetrics = value; const linesCovered = fileCoverageMetrics.lines_covered ? fileCoverageMetrics.lines_covered : []; // undefined if no lines covered const linesMissed = fileCoverageMetrics.lines_missed ? fileCoverageMetrics.lines_missed : []; // undefined if no lines missed + const executedBranches = fileCoverageMetrics.executed_branches; + const totalBranches = fileCoverageMetrics.total_branches; const lineCoverageCount = new TestCoverageCount( linesCovered.length, linesCovered.length + linesMissed.length, ); + let fileCoverage: FileCoverage; const uri = Uri.file(fileNameStr); - const fileCoverage = new FileCoverage(uri, lineCoverageCount); + if (totalBranches === -1) { + // branch coverage was not enabled and should not be displayed + fileCoverage = new FileCoverage(uri, lineCoverageCount); + } else { + const branchCoverageCount = new TestCoverageCount(executedBranches, totalBranches); + fileCoverage = new FileCoverage(uri, lineCoverageCount, branchCoverageCount); + } runInstance.addCoverage(fileCoverage); // create detailed coverage array for each file (only line coverage on detailed, not branch) diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index 7139788a8177..282379abdb85 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -222,6 +222,8 @@ export type FileCoverageMetrics = { lines_covered: number[]; // eslint-disable-next-line camelcase lines_missed: number[]; + executed_branches: number; + total_branches: number; }; export type ExecutionTestPayload = { diff --git a/src/test/testing/common/testingAdapter.test.ts b/src/test/testing/common/testingAdapter.test.ts index 834bccbd905f..dcd78dc23dba 100644 --- a/src/test/testing/common/testingAdapter.test.ts +++ b/src/test/testing/common/testingAdapter.test.ts @@ -711,6 +711,8 @@ suite('End to End Tests: test adapters', () => { // since only one test was run, the other test in the same file will have missed coverage lines assert.strictEqual(simpleFileCov.lines_covered.length, 3, 'Expected 1 line to be covered in even.py'); assert.strictEqual(simpleFileCov.lines_missed.length, 1, 'Expected 3 lines to be missed in even.py'); + assert.strictEqual(simpleFileCov.executed_branches, 1, 'Expected 1 branch to be executed in even.py'); + assert.strictEqual(simpleFileCov.total_branches, 2, 'Expected 2 branches in even.py'); return Promise.resolve(); }; @@ -759,6 +761,8 @@ suite('End to End Tests: test adapters', () => { // since only one test was run, the other test in the same file will have missed coverage lines assert.strictEqual(simpleFileCov.lines_covered.length, 3, 'Expected 1 line to be covered in even.py'); assert.strictEqual(simpleFileCov.lines_missed.length, 1, 'Expected 3 lines to be missed in even.py'); + assert.strictEqual(simpleFileCov.executed_branches, 1, 'Expected 1 branch to be executed in even.py'); + assert.strictEqual(simpleFileCov.total_branches, 2, 'Expected 2 branches in even.py'); return Promise.resolve(); }; From e096196a7936b6b52966fe804b24c720b094380e Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:00:25 -0700 Subject: [PATCH 2/6] fix ruff --- python_files/unittestadapter/execution.py | 8 +++++--- python_files/vscode_pytest/__init__.py | 10 +++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/python_files/unittestadapter/execution.py b/python_files/unittestadapter/execution.py index 65f271f5647c..8df2f279aa71 100644 --- a/python_files/unittestadapter/execution.py +++ b/python_files/unittestadapter/execution.py @@ -11,8 +11,8 @@ import unittest from types import TracebackType from typing import Dict, List, Optional, Set, Tuple, Type, Union -from packaging.version import Version +from packaging.version import Version # Adds the scripts directory to the PATH as a workaround for enabling shell for test execution. path_var_name = "PATH" if "PATH" in os.environ else "Path" @@ -325,12 +325,12 @@ def send_run_data(raw_data, test_run_pipe): workspace_root, ) import coverage + coverage_version = Version(coverage.__version__) # only include branches if coverage version is 7.7.0 or greater (as this was when the api saves) if coverage_version >= Version("7.7.0"): include_branches = True - source_ar: List[str] = [] if workspace_root: source_ar.append(workspace_root) @@ -338,7 +338,9 @@ def send_run_data(raw_data, test_run_pipe): source_ar.append(top_level_dir) if start_dir: source_ar.append(os.path.abspath(start_dir)) # noqa: PTH100 - cov = coverage.Coverage(branch=include_branches, source=source_ar) # is at least 1 of these required?? + cov = coverage.Coverage( + branch=include_branches, source=source_ar + ) # is at least 1 of these required?? cov.start() # If no error occurred, we will have test ids to run. diff --git a/python_files/vscode_pytest/__init__.py b/python_files/vscode_pytest/__init__.py index 3d45ca9be395..649e5bc59058 100644 --- a/python_files/vscode_pytest/__init__.py +++ b/python_files/vscode_pytest/__init__.py @@ -11,9 +11,9 @@ import sys import traceback from typing import TYPE_CHECKING, Any, Dict, Generator, Literal, TypedDict -from packaging.version import Version import pytest +from packaging.version import Version if TYPE_CHECKING: from pluggy import Result @@ -479,8 +479,12 @@ def pytest_sessionfinish(session, exitstatus): if INCLUDE_BRANCHES: branch_stats: dict[int, tuple[int, int]] = cov.branch_stats(file) - total_file_branches = sum([total_exits for total_exits, _ in branch_stats.values()]) - taken_file_branches = sum([taken_exits for _, taken_exits in branch_stats.values()]) + total_file_branches = sum( + [total_exits for total_exits, _ in branch_stats.values()] + ) + taken_file_branches = sum( + [taken_exits for _, taken_exits in branch_stats.values()] + ) except NoSource: # as per issue 24308 this best way to handle this edge case From da4816c6d0f3f117dd9a394089d4709611e7c17b Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:09:26 -0700 Subject: [PATCH 3/6] add version check to tests --- .../tests/pytestadapter/test_coverage.py | 36 +++++++++++-------- .../tests/unittestadapter/test_coverage.py | 21 ++++++----- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/python_files/tests/pytestadapter/test_coverage.py b/python_files/tests/pytestadapter/test_coverage.py index 8012e2f3b417..d2d276172a8d 100644 --- a/python_files/tests/pytestadapter/test_coverage.py +++ b/python_files/tests/pytestadapter/test_coverage.py @@ -5,7 +5,9 @@ import pathlib import sys +import coverage import pytest +from packaging.version import Version script_dir = pathlib.Path(__file__).parent.parent sys.path.append(os.fspath(script_dir)) @@ -34,9 +36,9 @@ def test_simple_pytest_coverage(): cov_folder_path = TEST_DATA_PATH / "coverage_gen" actual = runner_with_cwd_env(args, cov_folder_path, env_add) assert actual - coverage = actual[-1] - assert coverage - results = coverage["result"] + cov = actual[-1] + assert cov + results = cov["result"] assert results assert len(results) == 3 focal_function_coverage = results.get(os.fspath(TEST_DATA_PATH / "coverage_gen" / "reverse.py")) @@ -45,8 +47,12 @@ def test_simple_pytest_coverage(): assert focal_function_coverage.get("lines_missed") is not None assert set(focal_function_coverage.get("lines_covered")) == {4, 5, 7, 9, 10, 11, 12, 13, 14, 17} assert len(set(focal_function_coverage.get("lines_missed"))) >= 3 - assert focal_function_coverage.get("executed_branches") == 4 - assert focal_function_coverage.get("total_branches") == 6 + + coverage_version = Version(coverage.__version__) + # only include check for branches if the version is >= 7.7.0 + if coverage_version >= Version("7.7.0"): + assert focal_function_coverage.get("executed_branches") == 4 + assert focal_function_coverage.get("total_branches") == 6 coverage_gen_file_path = TEST_DATA_PATH / "coverage_gen" / "coverage.json" @@ -79,9 +85,9 @@ def test_coverage_gen_report(cleanup_coverage_gen_file): # noqa: ARG001 print("cov_folder_path", cov_folder_path) actual = runner_with_cwd_env(args, cov_folder_path, env_add) assert actual - coverage = actual[-1] - assert coverage - results = coverage["result"] + cov = actual[-1] + assert cov + results = cov["result"] assert results assert len(results) == 3 focal_function_coverage = results.get(os.fspath(TEST_DATA_PATH / "coverage_gen" / "reverse.py")) @@ -90,8 +96,11 @@ def test_coverage_gen_report(cleanup_coverage_gen_file): # noqa: ARG001 assert focal_function_coverage.get("lines_missed") is not None assert set(focal_function_coverage.get("lines_covered")) == {4, 5, 7, 9, 10, 11, 12, 13, 14, 17} assert set(focal_function_coverage.get("lines_missed")) == {18, 19, 6} - assert focal_function_coverage.get("executed_branches") == 4 - assert focal_function_coverage.get("total_branches") == 6 + coverage_version = Version(coverage.__version__) + # only include check for branches if the version is >= 7.7.0 + if coverage_version >= Version("7.7.0"): + assert focal_function_coverage.get("executed_branches") == 4 + assert focal_function_coverage.get("total_branches") == 6 # assert that the coverage file was created at the right path assert os.path.exists(coverage_gen_file_path) # noqa: PTH110 @@ -127,10 +136,9 @@ def test_coverage_w_omit_config(): actual = runner_with_cwd_env([], cov_folder_path, env_add) assert actual print("actual", json.dumps(actual, indent=2)) - coverage = actual[-1] - assert coverage - results = coverage["result"] + cov = actual[-1] + assert cov + results = cov["result"] assert results # assert one file is reported and one file (as specified in pyproject.toml) is omitted assert len(results) == 1 - diff --git a/python_files/tests/unittestadapter/test_coverage.py b/python_files/tests/unittestadapter/test_coverage.py index d3ab43a364e4..80e6986ed1c7 100644 --- a/python_files/tests/unittestadapter/test_coverage.py +++ b/python_files/tests/unittestadapter/test_coverage.py @@ -8,7 +8,9 @@ import pathlib import sys +import coverage import pytest +from packaging.version import Version sys.path.append(os.fspath(pathlib.Path(__file__).parent)) @@ -40,9 +42,9 @@ def test_basic_coverage(): ) assert actual - coverage = actual[-1] - assert coverage - results = coverage["result"] + cov = actual[-1] + assert cov + results = cov["result"] assert results assert len(results) == 3 focal_function_coverage = results.get(os.fspath(TEST_DATA_PATH / "coverage_ex" / "reverse.py")) @@ -51,8 +53,11 @@ def test_basic_coverage(): assert focal_function_coverage.get("lines_missed") is not None assert set(focal_function_coverage.get("lines_covered")) == {4, 5, 7, 9, 10, 11, 12, 13, 14} assert set(focal_function_coverage.get("lines_missed")) == {6} - assert focal_function_coverage.get("executed_branches") == 3 - assert focal_function_coverage.get("total_branches") == 4 + coverage_version = Version(coverage.__version__) + # only include check for branches if the version is >= 7.7.0 + if coverage_version >= Version("7.7.0"): + assert focal_function_coverage.get("executed_branches") == 3 + assert focal_function_coverage.get("total_branches") == 4 @pytest.mark.parametrize("manage_py_file", ["manage.py", "old_manage.py"]) @@ -81,9 +86,9 @@ def test_basic_django_coverage(manage_py_file): ) assert actual - coverage = actual[-1] - assert coverage - results = coverage["result"] + cov = actual[-1] + assert cov + results = cov["result"] assert results assert len(results) == 16 polls_views_coverage = results.get(str(data_path / "polls" / "views.py")) From dd32d2e7f17a921eefbe3125ac3108439d5a22fa Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:11:15 -0700 Subject: [PATCH 4/6] small edit --- python_files/unittestadapter/pvsc_utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index f253007cfb81..017bad38966a 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -79,8 +79,6 @@ class FileCoverageInfo(TypedDict): total_branches: int - - class CoveragePayloadDict(Dict): """A dictionary that is used to send a execution post request to the server.""" From 3e3de7fd16978bfb12f9e7fb35ba49b802354a50 Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:17:14 -0700 Subject: [PATCH 5/6] add django coverage branch check --- python_files/tests/unittestadapter/test_coverage.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python_files/tests/unittestadapter/test_coverage.py b/python_files/tests/unittestadapter/test_coverage.py index 80e6986ed1c7..76fdfec43376 100644 --- a/python_files/tests/unittestadapter/test_coverage.py +++ b/python_files/tests/unittestadapter/test_coverage.py @@ -97,3 +97,10 @@ def test_basic_django_coverage(manage_py_file): assert polls_views_coverage.get("lines_missed") is not None assert set(polls_views_coverage.get("lines_covered")) == {3, 4, 6} assert set(polls_views_coverage.get("lines_missed")) == {7} + + model_cov = results.get(str(data_path / "polls" / "models.py")) + coverage_version = Version(coverage.__version__) + # only include check for branches if the version is >= 7.7.0 + if coverage_version >= Version("7.7.0"): + assert model_cov.get("executed_branches") == 1 + assert model_cov.get("total_branches") == 2 From 2bb2de0086c25137de62b0a2a8212c34c6177f56 Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:18:51 -0700 Subject: [PATCH 6/6] remove explicit version requirement for testing --- build/test-requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/test-requirements.txt b/build/test-requirements.txt index 31d058633b21..df9fd2b08c6e 100644 --- a/build/test-requirements.txt +++ b/build/test-requirements.txt @@ -28,8 +28,7 @@ namedpipe; platform_system == "Windows" # typing for Django files django-stubs -# for branch coverage testing, need version >= 7.7 -coverage>=7.7 +coverage pytest-cov pytest-json pytest-timeout