Skip to content

Commit 4dd85bd

Browse files
committed
Added support for repeating seeds from previous test run.
1 parent 08b2a6d commit 4dd85bd

File tree

18 files changed

+333
-34
lines changed

18 files changed

+333
-34
lines changed

docs/news.d/1113.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for repeating seeds from previous test run by setting the ``--seed`` option to ``repeat``.

docs/run/user_guide.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ To reproduce the failing test setup and verify a bug fix, the failing seed can b
295295
.. raw:: html
296296
:file: img/seed_option.html
297297

298+
``--seed`` can also be set to ``repeat``, in which case the values from the previous test run will be repeated.
299+
298300
Running A VUnit Testbench Standalone
299301
------------------------------------
300302

0 Bytes
Binary file not shown.
274 Bytes
Binary file not shown.

tests/acceptance/artificial/vhdl/run.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ def pre_config(output_path):
164164
for idx, (extra_time, fail) in enumerate([(5, False), (2, True)], 1):
165165
tb.add_config(name=f"test_{idx}", pre_config=make_pre_config(idx, extra_time, fail))
166166

167+
def configure_tb_seed(ui):
168+
tb = ui.library("lib").test_bench("tb_seed")
169+
170+
if args.seed == "0123456789abcdef":
171+
tb.test("test_1").set_generic("expected_seed", "2e373913e5ad677d")
172+
tb.test("test_2").set_generic("expected_seed", "2e373913e5ad677d")
173+
elif args.seed == "repeat":
174+
tb.test("test_1").set_generic("expected_seed", "ffa08cd9489aad14")
175+
tb.test("test_2").set_generic("expected_seed", "9a292b3679afd081")
167176

168177
configure_tb_with_generic_config()
169178
configure_tb_same_sim_all_pass(vu)
@@ -172,6 +181,7 @@ def pre_config(output_path):
172181
configure_tb_with_vhdl_configuration(vu)
173182
configure_tb_no_fail_on_warning(vu)
174183
configure_tb_test_prio(vu)
184+
configure_tb_seed(vu)
175185
lib.entity("tb_no_generic_override").set_generic("g_val", False)
176186
lib.entity("tb_ieee_warning").test("pass").set_sim_option("disable_ieee_warnings", True)
177187
lib.entity("tb_other_file_tests").scan_tests_from_file(str(root / "other_file_tests.vhd"))
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
-- This Source Code Form is subject to the terms of the Mozilla Public
2+
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
-- You can obtain one at http://mozilla.org/MPL/2.0/.
4+
--
5+
-- Copyright (c) 2014-2025, Lars Asplund [email protected]
6+
7+
-- This attribute should be ignored when VHDL assert stop level is used
8+
-- vunit: fail_on_warning
9+
10+
library vunit_lib;
11+
context vunit_lib.vunit_context;
12+
13+
entity tb_seed is
14+
generic (
15+
runner_cfg : string;
16+
expected_seed : string := ""
17+
);
18+
end entity;
19+
20+
architecture tb of tb_seed is
21+
constant seed : string := get_seed(runner_cfg);
22+
begin
23+
test_runner : process
24+
begin
25+
test_runner_setup(runner, runner_cfg);
26+
show(display_handler, pass);
27+
28+
while test_suite loop
29+
if expected_seed = "" then
30+
-- Not expecting the seed derived from --seed=0123456789abcdef
31+
check(seed /= "2e373913e5ad677d");
32+
else
33+
check_equal(seed, expected_seed);
34+
end if;
35+
36+
if run("test_1") then
37+
-- Not expecting the seed derived from --seed=repeat
38+
check_implication(expected_seed = "", seed /= "ffa08cd9489aad14");
39+
elsif run("test_2") then
40+
-- Not expecting the seed derived from --seed=repeat
41+
check_implication(expected_seed = "", seed /= "9a292b3679afd081");
42+
end if;
43+
end loop;
44+
45+
test_runner_cleanup(runner);
46+
end process;
47+
end architecture;

tests/acceptance/test_artificial.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,26 @@ def test_artificial_changed(self):
8787
],
8888
)
8989

90+
def test_hardcoded_seed(self):
91+
self.check(self.artificial_run_vhdl, args=["lib.tb_seed*", "--seed=0123456789AbCdEf"])
92+
check_report(
93+
self.report_file,
94+
[
95+
("passed", "lib.tb_seed.test_1"),
96+
("passed", "lib.tb_seed.test_2"),
97+
],
98+
)
99+
100+
def test_repeated_seed(self):
101+
self.check(self.artificial_run_vhdl, args=["lib.tb_seed*", "--seed=repeat"])
102+
check_report(
103+
self.report_file,
104+
[
105+
("passed", "lib.tb_seed.test_1"),
106+
("passed", "lib.tb_seed.test_2"),
107+
],
108+
)
109+
90110
def _test_artificial(self, args=None):
91111
"""
92112
Utility function to run and check the result of all test benches
@@ -289,4 +309,6 @@ def test_exit_0_flag(self):
289309
("passed", "lib.tb_test_prio_1.test_4"),
290310
("passed", "lib.tb_test_prio_2.test_1"),
291311
("failed", "lib.tb_test_prio_2.test_2"),
312+
("passed", "lib.tb_seed.test_1"),
313+
("passed", "lib.tb_seed.test_2"),
292314
)

tests/unit/test_test_bench.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
FileLocation,
2828
Attribute,
2929
LegacyAttribute,
30+
_get_historic_seed,
3031
)
3132
from vunit.configuration import AttributeException
3233
from vunit.ostools import write_file
@@ -483,7 +484,7 @@ def test_error_on_global_attributes_from_python_on_tests(self, tempdir):
483484

484485
test_bench = TestBench(design_unit)
485486
test = test_bench.get_test_case("Test 1")
486-
self.assertRaises(AttributeException, test.set_attribute, "run_all_in_same_sim", True)
487+
self.assertRaises(AttributeException, test.set_attribute, "run_all_in_same_sim", True)
487488

488489
@with_tempdir
489490
def test_test_information(self, tempdir):
@@ -904,6 +905,19 @@ def assert_has_tests(self, test_list, tests):
904905
self.assertEqual(test1.name, test2)
905906
self.assertEqual(test1.test_names, [test2])
906907

908+
def test_seed_from_test_history(self):
909+
test_history = dict(test_suite1=dict(test1=dict(seed="11"), test2=dict(seed="12")), test_suite2=dict())
910+
911+
self.assertEqual(_get_historic_seed(test_history, test_suite_name="test_suite1"), "11")
912+
self.assertEqual(_get_historic_seed(test_history, test_suite_name="test_suite1", test_name="test2"), "12")
913+
914+
def test_no_seed_from_test_history(self):
915+
test_history = dict(test_suite1=dict(test1=dict(seed="11"), test2=dict(seed="12")), test_suite2=dict())
916+
917+
self.assertIsNone(_get_historic_seed(test_history, test_suite_name="foo"))
918+
self.assertIsNone(_get_historic_seed(test_history, test_suite_name="test_suite1", test_name="test3"))
919+
self.assertIsNone(_get_historic_seed(test_history, test_suite_name="test_suite2"))
920+
907921
@staticmethod
908922
def create_tests(test_bench):
909923
"""

tests/unit/test_test_report.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,13 @@ def test_junit_report_with_some_skipped_tests(self):
289289
def test_junit_report_with_testcase_classname(self):
290290
report = self._new_report()
291291
report.add_result(
292-
"test", PASSED, time=1.0, output_file_name=self.output_file_name, test_suite_name="test", start_time=0
292+
"test",
293+
PASSED,
294+
time=1.0,
295+
output_file_name=self.output_file_name,
296+
test_suite_name="test",
297+
start_time=0,
298+
seed="0123456789abcdef",
293299
)
294300
report.add_result(
295301
"lib.entity",
@@ -298,6 +304,7 @@ def test_junit_report_with_testcase_classname(self):
298304
output_file_name=self.output_file_name,
299305
test_suite_name="lib.entity",
300306
start_time=0,
307+
seed="0123456789abcdef",
301308
)
302309
report.add_result(
303310
"lib.entity.test",
@@ -306,6 +313,7 @@ def test_junit_report_with_testcase_classname(self):
306313
output_file_name=self.output_file_name,
307314
test_suite_name="lib.entity.test",
308315
start_time=0,
316+
seed="0123456789abcdef",
309317
)
310318
report.add_result(
311319
"lib.entity.config.test",
@@ -314,6 +322,7 @@ def test_junit_report_with_testcase_classname(self):
314322
output_file_name=self.output_file_name,
315323
test_suite_name="lib.entity.config.test",
316324
start_time=0,
325+
seed="0123456789abcdef",
317326
)
318327
root = ElementTree.fromstring(report.to_junit_xml_str())
319328
names = set(
@@ -372,6 +381,7 @@ def _report_with_all_passed_tests(self, output_file_name=None):
372381
output_file_name=output_file_name,
373382
test_suite_name="passed_test0",
374383
start_time=0,
384+
seed="0123456789abcdef",
375385
)
376386
report.add_result(
377387
"passed_test1",
@@ -380,6 +390,7 @@ def _report_with_all_passed_tests(self, output_file_name=None):
380390
output_file_name=output_file_name,
381391
test_suite_name="passed_test0",
382392
start_time=0,
393+
seed="0123456789abcdef",
383394
)
384395
report.set_expected_num_tests(2)
385396
return report
@@ -394,6 +405,7 @@ def _report_with_missing_tests(self):
394405
output_file_name=self.output_file_name,
395406
test_suite_name="passed_test0",
396407
start_time=0,
408+
seed="0123456789abcdef",
397409
)
398410
report.add_result(
399411
"passed_test1",
@@ -402,6 +414,7 @@ def _report_with_missing_tests(self):
402414
output_file_name=self.output_file_name,
403415
test_suite_name="passed_test0",
404416
start_time=0,
417+
seed="0123456789abcdef",
405418
)
406419
report.set_expected_num_tests(3)
407420
return report
@@ -416,6 +429,7 @@ def _report_with_some_failed_tests(self):
416429
output_file_name=self.output_file_name,
417430
test_suite_name="failed_test0",
418431
start_time=0,
432+
seed="0123456789abcdef",
419433
)
420434
report.add_result(
421435
"passed_test",
@@ -424,6 +438,7 @@ def _report_with_some_failed_tests(self):
424438
output_file_name=self.output_file_name,
425439
test_suite_name="passed_test",
426440
start_time=0,
441+
seed="0123456789abcdef",
427442
)
428443
report.add_result(
429444
"failed_test1",
@@ -432,6 +447,7 @@ def _report_with_some_failed_tests(self):
432447
output_file_name=self.output_file_name,
433448
test_suite_name="failed_test1",
434449
start_time=0,
450+
seed="0123456789abcdef",
435451
)
436452
report.set_expected_num_tests(3)
437453
return report
@@ -446,6 +462,7 @@ def _report_with_some_skipped_tests(self):
446462
output_file_name=self.output_file_name,
447463
test_suite_name="passed_test",
448464
start_time=0,
465+
seed="0123456789abcdef",
449466
)
450467
report.add_result(
451468
"skipped_test",
@@ -454,6 +471,7 @@ def _report_with_some_skipped_tests(self):
454471
output_file_name=self.output_file_name,
455472
test_suite_name="skipped_test",
456473
start_time=0,
474+
seed="0123456789abcdef",
457475
)
458476
report.add_result(
459477
"failed_test",
@@ -462,6 +480,7 @@ def _report_with_some_skipped_tests(self):
462480
output_file_name=self.output_file_name,
463481
test_suite_name="failed_test",
464482
start_time=0,
483+
seed="0123456789abcdef",
465484
)
466485
report.set_expected_num_tests(3)
467486
return report
@@ -476,6 +495,7 @@ def _report_with_mixed_length_tests(self):
476495
output_file_name=self.output_file_name,
477496
test_suite_name="passed_test0",
478497
start_time=0,
498+
seed="0123456789abcdef",
479499
)
480500
report.add_result(
481501
"passed_test1",
@@ -484,6 +504,7 @@ def _report_with_mixed_length_tests(self):
484504
output_file_name=self.output_file_name,
485505
test_suite_name="passed_test1",
486506
start_time=0,
507+
seed="0123456789abcdef",
487508
)
488509
report.add_result(
489510
"passed_test2",
@@ -492,6 +513,7 @@ def _report_with_mixed_length_tests(self):
492513
output_file_name=self.output_file_name,
493514
test_suite_name="passed_test2",
494515
start_time=0,
516+
seed="0123456789abcdef",
495517
)
496518
report.add_result(
497519
"passed_test3",
@@ -500,6 +522,7 @@ def _report_with_mixed_length_tests(self):
500522
output_file_name=self.output_file_name,
501523
test_suite_name="passed_test3",
502524
start_time=0,
525+
seed="0123456789abcdef",
503526
)
504527
report.set_expected_num_tests(4)
505528
return report
@@ -514,6 +537,7 @@ def _report_with_long_tests(self):
514537
output_file_name=self.output_file_name,
515538
test_suite_name="passed_test0",
516539
start_time=0,
540+
seed="0123456789abcdef",
517541
)
518542
report.add_result(
519543
"passed_test1",
@@ -522,6 +546,7 @@ def _report_with_long_tests(self):
522546
output_file_name=self.output_file_name,
523547
test_suite_name="passed_test1",
524548
start_time=0,
549+
seed="0123456789abcdef",
525550
)
526551
report.add_result(
527552
"passed_test2",
@@ -530,6 +555,7 @@ def _report_with_long_tests(self):
530555
output_file_name=self.output_file_name,
531556
test_suite_name="passed_test2",
532557
start_time=0,
558+
seed="0123456789abcdef",
533559
)
534560
report.add_result(
535561
"passed_test3",
@@ -538,6 +564,7 @@ def _report_with_long_tests(self):
538564
output_file_name=self.output_file_name,
539565
test_suite_name="passed_test3",
540566
start_time=0,
567+
seed="0123456789abcdef",
541568
)
542569
report.add_result(
543570
"passed_test4",
@@ -546,6 +573,7 @@ def _report_with_long_tests(self):
546573
output_file_name=self.output_file_name,
547574
test_suite_name="passed_test4",
548575
start_time=0,
576+
seed="0123456789abcdef",
549577
)
550578
report.add_result(
551579
"passed_test5",
@@ -554,6 +582,7 @@ def _report_with_long_tests(self):
554582
output_file_name=self.output_file_name,
555583
test_suite_name="passed_test5",
556584
start_time=0,
585+
seed="0123456789abcdef",
557586
)
558587
report.set_expected_num_tests(6)
559588
return report

tests/unit/test_test_runner.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,6 @@ def run(self, output_path, read_output):
256256
self.output_path = output_path
257257
self.read_output = read_output
258258
return self.run_side_effect(output_path=output_path, read_output=read_output)
259+
260+
def get_seed(self):
261+
return "0123456789abcdef"

0 commit comments

Comments
 (0)