diff --git a/docs/conf.py b/docs/conf.py index 8fa5cd4..7f1b2d2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,6 +101,19 @@ # Default is "file" but sphinx-codelinks also uses "file" for source code paths tr_file_option = "test_file" +# Make the "verifies" JUnit XML property available as a sphinx-needs field on +# every imported test-run need so that requirement traceability is captured +# directly from the test output. +# Docs: https://sphinx-test-reports.readthedocs.io/en/latest/configuration.html#tr-extra-options +tr_extra_options = ["verifies"] + +# Map the "verifies" property to the sphinx-needs "links" link type so that +# test-run needs automatically link back to the requirements they verify. +# Docs: https://sphinx-test-reports.readthedocs.io/en/latest/configuration.html#tr-property-link-types +tr_property_link_types = { + "verifies": "links", +} + ############################################################################### # SPHINX-TEST-REPORTS Config END ############################################################################### diff --git a/docs/testsuites/coffee_machine_junit.xml b/docs/testsuites/coffee_machine_junit.xml index 2f688be..5dad0d6 100644 --- a/docs/testsuites/coffee_machine_junit.xml +++ b/docs/testsuites/coffee_machine_junit.xml @@ -1,11 +1,35 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/cargo_test_to_junit.py b/scripts/cargo_test_to_junit.py index 31a66c6..f06a8f9 100644 --- a/scripts/cargo_test_to_junit.py +++ b/scripts/cargo_test_to_junit.py @@ -32,6 +32,17 @@ "interfaces::tests::test_user_command_variants": "TEST_BUTTON_DEBOUNCE", } +# Map each test spec ID to the space-separated list of SW requirement IDs it +# verifies. These are emitted as a ```` block so that sphinx-test-reports can map them to +# sphinx-needs link fields via ``tr_property_link_types``. +SPEC_TO_SWREQ: dict[str, str] = { + "TEST_TEMP_CONTROL": "SWREQ_TEMP_REGULATION", + "TEST_BREW_STRENGTH": "SWREQ_BREW_STRENGTH", + "TEST_BUTTON_DEBOUNCE": "SWREQ_BUTTON_INPUT", + "TEST_SAFETY_SHUTDOWN": "SWREQ_OVERTEMP_SHUTDOWN SWREQ_WATER_LEVEL", +} + def main() -> None: text = sys.stdin.read() @@ -60,6 +71,10 @@ def main() -> None: ) if status == "FAILED": ET.SubElement(tc, "failure", message="Test failed") + swreqs = SPEC_TO_SWREQ.get(spec_id) + if swreqs: + props = ET.SubElement(tc, "properties") + ET.SubElement(props, "property", name="verifies", value=swreqs) tree = ET.ElementTree(root) ET.indent(tree, space=" ")