diff --git a/docs/functions.rst b/docs/functions.rst index aff28dd..82886fb 100644 --- a/docs/functions.rst +++ b/docs/functions.rst @@ -10,7 +10,7 @@ from Sphinx-Needs documentation to know how to use them. tr_link ---------- +------- Links a need (e.g testcase) automatically to other needs, which have a specific value in a given option. **Usage**:: @@ -25,8 +25,8 @@ Links a need (e.g testcase) automatically to other needs, which have a specific ``tr_link`` needs the following arguments: -* **source_option**: Name of an option of the test-need, which is used for comparision. E.g. ``classname``. -* **target_option**: Name of an option of all other needs, which is used for comparision. E.g. ``title``. +* **source_option**: Name of an option of the test-need, which is used for comparison. E.g. ``classname``. +* **target_option**: Name of an option of all other needs, which is used for comparison. E.g. ``title``. The function reads the ``target_option`` from the need, where it is used. Then it goes through **all** other needs and checks if the value of their ``source_option`` is equal to @@ -34,7 +34,7 @@ the ``target_option``. If this is the case, their IDs get stored and finally returned. ``source_option`` can also reference an option with comma separated values. -In this case a comparions is performed for each value, which may lead to multiple links. +In this case a comparison is performed for each value, which may lead to multiple links. **Example**:: @@ -81,3 +81,25 @@ In this case a comparions is performed for each value, which may lead to multipl .. needflow:: :tags: link_example + + +tr_link_match +------------- + +Similar to ``tr_link``, but allows using a regex to find needs to link to. +When using ``tr_link_match``, the value of the ``source_option`` is compiled as a regular expression, and all other needs +whose ``target_option`` values match this pattern are linked. + +**Usage**:: + + .. test-case:: Tests/TestSuite.TestCase/* + :id: TESTLINK_1 + :results: "[[tr_link_match('title', 'case')]]", + +The example above will link all test results which have a classname starting with ``Tests/TestSuite.TestCase`` +(given that the ``results`` are defined as ``needs_extra_links`` in the ``conf.py``). + +``tr_link_match`` needs the following arguments: + +* **source_option**: Name of an option of the test-need (regex is taken from its value). +* **target_option**: Name of an option in other needs, which must match the regex in ``source_option``. diff --git a/sphinxcontrib/test_reports/functions/__init__.py b/sphinxcontrib/test_reports/functions/__init__.py index 79d4896..c6e1d5c 100644 --- a/sphinxcontrib/test_reports/functions/__init__.py +++ b/sphinxcontrib/test_reports/functions/__init__.py @@ -1,3 +1,6 @@ +import re + + def tr_link(app, need, needs, test_option, target_option, *args, **kwargs): if test_option not in need: return "" @@ -19,3 +22,31 @@ def tr_link(app, need, needs, test_option, target_option, *args, **kwargs): links.append(need_target["id"]) return links + + +def tr_link_match(app, need, needs, test_option, target_option, *args, **kwargs): + if test_option not in need: + return "" + test_option_value = need[test_option] + if test_option_value is None or len(test_option_value) <= 0: + return [] + + links = [] + test_pattern = re.compile(test_option_value) + for need_target in needs.values(): + # Skip linking to itself + if need_target["id"] == need["id"]: + continue + + if target_option not in need_target: + continue + + target_option_value = need_target[target_option] + if ( + target_option_value is not None + and len(target_option_value) > 0 + and test_pattern.match(target_option_value) + ): + links.append(need_target["id"]) + + return links diff --git a/tests/test_tr_link.py b/tests/test_tr_link.py new file mode 100644 index 0000000..7ec9dd0 --- /dev/null +++ b/tests/test_tr_link.py @@ -0,0 +1,65 @@ +from sphinxcontrib.test_reports.functions import tr_link, tr_link_match + + +def test_tr_link_option_not_in_need(): + """ + Return an empty string when the specified test option is missing from the need. + """ + assert tr_link(app=None, need={}, needs={}, test_option="a", target_option="b") == "" + +def test_tr_link_no_target_option_in_needs(): + """ + Return an empty list when the target option is missing in all items of needs. + """ + assert tr_link(app=None, need={"a": "1"}, needs={"x": {"id": "123"}}, test_option="a", target_option="b") == [] + +def test_tr_link_no_match(): + """ + Returns an empty list when no matching value for the test option is found in any of the target options within needs. + """ + assert tr_link(app=None, need={"a": "1"}, needs={"x": {"b": "2", "id": "123"}}, test_option="a", target_option="b") == [] + +def test_tr_link_match(): + """ + Returns a list of ids when there is a matching value in both need and needs. + """ + assert tr_link(app=None, need={"a": "1"}, needs={"x": {"b": "1", "id": "123"}}, test_option="a", target_option="b") == ["123"] + +def test_tr_link_regex_match(): + """ + Returns a list of ids when the test option value containing an asterisk (*) + correctly matches target options using regular expression patterns. + """ + needs = { + "x": {"b": "abc123", "id": "111"}, + "q": {"b": "abc/123", "id": "112"}, + "y": {"b": "def456", "id": "222"}, + "z": {"b": "ghi789", "id": "333"}, + } + need = {"id": "1", "a": "abc.*"} + assert tr_link_match( + app=None, need=need, needs=needs, test_option="a", target_option="b" + ) == ["111", "112"] + + +def test_tr_link_regex_no_match(): + """ + Returns an empty list when the test option value containing an asterisk (*) + does not match any target options using regular expression patterns. + """ + needs = {"x": {"b": "abc123", "id": "111"}, "y": {"b": "def456", "id": "222"}} + need = {"id": "1", "a": "xyz.*"} + assert ( + tr_link_match(app=None, need=need, needs=needs, test_option="a", target_option="b") + == [] + ) + +def test_tr_link_regex_skip_linking_to_itself(): + """ + Returns an empty list when the need and needs have the same 'id'. + """ + needs = {"x": {"b": "abc123", "id": "111"}, "y": {"b": "abc123", "id": "222"}} + need = {"id": "111", "a": "abc123"} + assert tr_link_match( + app=None, need=need, needs=needs, test_option="a", target_option="b" + ) == ["222"]