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=" ")