镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/news.d/1240.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed a ``KeyError`` during test prioritization on subsequent runs when
``scan_tests_from_file()`` was given a relative path, a ``pathlib.Path``, or a
forward-slash path on Windows instead of the project's exact source filename.
11 changes: 11 additions & 0 deletions tests/unit/test_test_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""

import unittest
from pathlib import Path
from unittest import mock
from vunit.test.runner import TestScheduler

Expand Down Expand Up @@ -63,6 +64,16 @@ def test_that_new_test_suites_go_to_set_2(self):
self.assertEqual(result[set_idx]["total_exec_time"], 0)
self.assertEqual(len(result[set_idx]["test_suites"]), 0)

def test_that_scanned_file_with_different_path_spelling_and_history_goes_to_set_3(self):
test_suite = self._create_test_suite("lib1.tb1.test1", ["lib1.tb1.test1"], "tests.vhd")
self._add_test_history(test_suite.name, test_suite.name, "passed", 1, 10)
latest_dependency_updates = {str(Path("tests.vhd").resolve()): 0}

scheduler = TestScheduler([test_suite], 1, latest_dependency_updates, self._test_history)
result = scheduler._create_test_suite_sets([test_suite])

self.assertEqual(result[3]["test_suites"], [{"test_suite": test_suite, "exec_time": 10}])

def test_that_skipped_test_suites_go_to_set_2(self):
latest_dependency_updates = dict(file1=0)
test_suites = [self._create_test_suite("lib1.tb1.test1", ["lib1.tb1.test1"], "file1")]
Expand Down
9 changes: 6 additions & 3 deletions vunit/test/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,12 @@ def _create_test_suite_sets(self, test_suites):
if test_data:
if test_data["total_time"] is not None:
exec_time += test_data["total_time"]
updated_dependency = self._latest_dependency_updates[test_suite.file_name] > test_data.get(
"start_time", 0
)
# Tests may be scanned from a file which is not a project source file
# (scan_tests_from_file). Without dependency information, treat it as
# updated like _get_latest_dependency_updates does for changed files.
updated_dependency = self._latest_dependency_updates.get(
test_suite.file_name, 10e9
) > test_data.get("start_time", 0)

if test_data["skipped"]:
set_idx = 2
Expand Down
3 changes: 2 additions & 1 deletion vunit/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,8 @@ def _get_test_list_depending_on_change(self, test_list):
self._test_history = self._get_test_history(simulator_if=None)

def depending_on_change(test_suite):
latest_dependency_update = self._latest_dependency_updates[test_suite.file_name]
# Unknown files (tests scanned from a non-project file) count as changed
latest_dependency_update = self._latest_dependency_updates.get(test_suite.file_name, 10e9)
test_suite_history = self._test_history.get(test_suite.name, None)
if test_suite_history:
test_start_times = [test_data["start_time"] for test_data in test_suite_history.values()]
Expand Down
20 changes: 19 additions & 1 deletion vunit/ui/testbench.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""

from fnmatch import fnmatch
from pathlib import Path
from .common import lower_generics
from .test import Test

Expand Down Expand Up @@ -240,4 +241,21 @@ def scan_tests_from_file(self, file_name):
the ``NESTED_TEST_SUITE`` macro should be used instead of
the ``TEST_SUITE`` macro.
"""
self._test_bench.scan_tests_from_file(file_name)
self._test_bench.scan_tests_from_file(self._get_project_file_name(file_name))

def _get_project_file_name(self, file_name):
"""
Return the name under which the project knows file_name.

Test suites are associated with the file their tests are scanned from, and that
name is used to look up dependency information (e.g. for test prioritization).
The project knows a source file by its resolved path, or by the path of its
preprocessed copy if preprocessing is enabled. Map any spelling of the path
(relative, pathlib.Path, posix style on Windows, original instead of preprocessed
file) to that name. Files which are not part of the project are returned resolved.
"""
path = Path(file_name).resolve()
for source_file in self._library._project.get_source_files_in_order(): # pylint: disable=protected-access
if Path(source_file.original_name).resolve() == path:
return source_file.name
return str(path)
Loading