From 0556804a098dc553f52aad808f77bc9d353dda42 Mon Sep 17 00:00:00 2001 From: Piotr Korkus Date: Tue, 24 Mar 2026 18:56:02 +0100 Subject: [PATCH] add attribute plugin --- MODULE.bazel | 2 +- pyproject.toml | 4 ++ pytest.ini | 3 ++ score/itf/plugins/BUILD | 9 ++++ test/BUILD | 10 ++++ test/test_attribute_plugin.py | 87 +++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 test/test_attribute_plugin.py diff --git a/MODULE.bazel b/MODULE.bazel index 85a246b..51b848b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -113,7 +113,7 @@ bazel_dep(name = "bazel_skylib", version = "1.9.0") # Score custom modules loading # ############################################################################### -bazel_dep(name = "score_tooling", version = "1.0.4") +bazel_dep(name = "score_tooling", version = "1.1.2") bazel_dep(name = "score_bazel_platforms", version = "0.0.3") bazel_dep(name = "platforms", version = "1.0.0") diff --git a/pyproject.toml b/pyproject.toml index dac1774..ed6ac4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,5 +15,9 @@ junit_suite_name = "ITF" junit_duration_report = "call" junit_family = "xunit1" +markers = [ + "test_properties(dict)", # add custom properties to test XML output +] + [tool.ruff] line-length = 120 diff --git a/pytest.ini b/pytest.ini index 01f779b..40117fb 100644 --- a/pytest.ini +++ b/pytest.ini @@ -14,3 +14,6 @@ log_file_date_format = %Y-%m-%d %H:%M:%S junit_suite_name = ITF junit_duration_report = call junit_family = xunit1 + +markers = + test_properties(dict): Add custom properties to test XML output diff --git a/score/itf/plugins/BUILD b/score/itf/plugins/BUILD index 0357a90..8a0d516 100644 --- a/score/itf/plugins/BUILD +++ b/score/itf/plugins/BUILD @@ -70,3 +70,12 @@ py_itf_plugin( py_library = "//score/itf/plugins/dlt", visibility = ["//visibility:public"], ) + +py_itf_plugin( + name = "attribute_plugin", + enabled_plugins = [ + "attribute_plugin", + ], + py_library = "@score_tooling//python_basics/score_pytest:attribute_plugin", + visibility = ["//visibility:public"], +) diff --git a/test/BUILD b/test/BUILD index ef9ed98..5b3c40f 100644 --- a/test/BUILD +++ b/test/BUILD @@ -205,3 +205,13 @@ py_itf_test( "@rules_python//python/runfiles", ], ) + +py_itf_test( + name = "test_attribute_plugin", + srcs = [ + "test_attribute_plugin.py", + ], + plugins = [ + "//score/itf/plugins:attribute_plugin", + ], +) diff --git a/test/test_attribute_plugin.py b/test/test_attribute_plugin.py new file mode 100644 index 0000000..c6e53d0 --- /dev/null +++ b/test/test_attribute_plugin.py @@ -0,0 +1,87 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +""" +Example test demonstrating the use of @add_test_properties decorator. + +This test shows how to add custom properties to test cases that will appear +in the JUnit XML report, including requirement verification information and +test classification metadata. +""" + +import os +import xml.etree.ElementTree as ET +from pathlib import Path + +from attribute_plugin import add_test_properties + + +@add_test_properties( + fully_verifies=["REQ-001", "REQ-002"], + test_type="requirements-based", + derivation_technique="requirements-analysis", +) +def test_example_with_properties(request): + """ + Example test case with custom properties. + + This test demonstrates the @add_test_properties decorator which adds + custom metadata to the XML test report. + """ + assert True + + +def pytest_sessionfinish(session, exitstatus): + """ + Hook that runs after all tests complete and XML is written. + + This validates that the XML report contains the expected properties + from the @add_test_properties decorator. + """ + xml_output_file = os.environ.get("XML_OUTPUT_FILE") + xml_path = Path(xml_output_file) + + assert xml_path.exists(), f"XML report not found at {xml_path}" + + # Parse the XML file + tree = ET.parse(xml_path) + root = tree.getroot() + + # Find the test case + testcase = root.find(".//testcase[@name='test_example_with_properties']") + assert testcase is not None, "test_example_with_properties not found in XML" + + # Find and validate properties + properties = testcase.find("properties") + assert properties is not None, "No properties element found in testcase" + + # Extract properties into a dictionary + props_dict = {} + for prop in properties.findall("property"): + props_dict[prop.get("name")] = prop.get("value") + + # Validate expected properties with clear assertions + assert "fully_verifies" in props_dict, "fully_verifies property not found" + assert props_dict["fully_verifies"] == "['REQ-001', 'REQ-002']", ( + f"fully_verifies: expected ['REQ-001', 'REQ-002'], got {props_dict['fully_verifies']}" + ) + + assert "test_type" in props_dict, "test_type property not found" + assert props_dict["test_type"] == "requirements-based", ( + f"test_type: expected 'requirements-based', got {props_dict['test_type']}" + ) + + assert "derivation_technique" in props_dict, "derivation_technique property not found" + assert props_dict["derivation_technique"] == "requirements-analysis", ( + f"derivation_technique: expected 'requirements-analysis', got {props_dict['derivation_technique']}" + )