diff --git a/docs/news.d/1157.feature.rst b/docs/news.d/1157.feature.rst new file mode 100644 index 000000000..4341a50ef --- /dev/null +++ b/docs/news.d/1157.feature.rst @@ -0,0 +1 @@ +Compilation is now skipped when no tests match the active filters (e.g. ``--with-attributes``), avoiding unnecessary work when no tests would run. diff --git a/tests/unit/test_ui.py b/tests/unit/test_ui.py index f6625836b..ced9f8902 100644 --- a/tests/unit/test_ui.py +++ b/tests/unit/test_ui.py @@ -650,6 +650,31 @@ def check_stdout(ui, expected): setup(ui) check_stdout(ui, "lib.tb_filter.Test 1\n" "Listed 1 tests") + @with_tempdir + def test_skips_compilation_when_no_matching_tests(self, tempdir): + """ + Test that compilation is skipped when attribute filtering results in + no matching tests, e.g. --with-attributes=.nonexistent + """ + ui = self._create_ui("--with-attributes", ".nonexistent", "--no-color") + lib = ui.add_library("lib") + file_name = str(Path(tempdir) / "tb_skip.vhd") + create_vhdl_test_bench_file( + "tb_skip", + file_name, + tests=["Test 1"], + ) + lib.add_source_file(file_name) + + post_run = mock.Mock() + with mock.patch("sys.stdout", autospec=True) as stdout: + with mock.patch.object(ui, "_compile") as compile_mock: + self._run_main(ui, post_run=post_run) + compile_mock.assert_not_called() + text = "".join([call[1][0] for call in stdout.write.mock_calls]) + self.assertEqual(set(text.splitlines()), {"No tests were run!"}) + self.assertTrue(post_run.called) + @with_tempdir def test_export_json(self, tempdir): tdir = Path(tempdir) diff --git a/vunit/ui/__init__.py b/vunit/ui/__init__.py index da1bbfcf4..dd7be6597 100644 --- a/vunit/ui/__init__.py +++ b/vunit/ui/__init__.py @@ -1041,6 +1041,10 @@ def _main_run(self, post_run): if self._args.changed: test_list = self._get_test_list_depending_on_change(test_list) + if test_list.num_tests == 0: + LOGGER.info("Skipping compilation: no matching tests after filtering.") + return self._main_run_report(post_run, simulator_if) + self._compile(simulator_if) print() @@ -1057,6 +1061,15 @@ def _main_run(self, post_run): report.set_real_total_time(ostools.get_time() - start_time) self._update_test_history(report, simulator_if) + return self._main_run_report(post_run, simulator_if, report) + + def _main_run_report(self, post_run, simulator_if, report=None): + """ + Print report and handle post_run callback and xunit XML output. + """ + if report is None: + report = TestReport(printer=self._printer) + report.print_str() if post_run is not None: