Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify error about incomplete traceability_relationship_to_string #361

Merged
merged 9 commits into from
Oct 27, 2023
6 changes: 2 additions & 4 deletions mlx/directives/item_directive.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,13 @@ def _list_targets_for_relation(self, relation, targets, dl_node, app):
dl_node (nodes.definition_list): Definition list of the item.
app: Sphinx's application object to use.
"""
env = app.builder.env
li_node = nodes.definition_list_item()
dt_node = nodes.term()
if relation in app.config.traceability_relationship_to_string:
relstr = app.config.traceability_relationship_to_string[relation]
else:
report_warning('Traceability: relation {rel} cannot be translated to string'
.format(rel=relation),
env.docname, self.line)
report_warning(f'Traceability: relation {relation} cannot be translated to string',
docname=self['document'], lineno=self['line'])
relstr = relation
dt_node.append(nodes.Text(relstr))
li_node.append(dt_node)
Expand Down
2 changes: 1 addition & 1 deletion mlx/traceability.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def initialize_environment(app):
undefined_stringifications = all_relationships.difference(app.config.traceability_relationship_to_string)
if undefined_stringifications:
raise TraceabilityException(f"Relationships {undefined_stringifications!r} are missing from configuration "
"variable `traceability_relationships`")
"variable 'traceability_relationship_to_string'")

app.config.traceability_checklist['has_checklist_items'] = False
add_checklist_attribute(app.config.traceability_checklist,
Expand Down
73 changes: 39 additions & 34 deletions tests/directives/test_item_directive.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from unittest import TestCase
from unittest.mock import Mock, MagicMock
import logging

from docutils import nodes
from sphinx.application import Sphinx
from sphinx.builders.latex import LaTeXBuilder
from sphinx.builders.html import StandaloneHTMLBuilder
Expand All @@ -13,6 +15,8 @@

from parameterized import parameterized

LOGGER = logging.getLogger()


def raise_no_uri(*args, **kwargs):
raise NoUri
Expand All @@ -31,15 +35,22 @@ def setUp(self):
self.item.node = self.node
self.app.config = Mock()
self.app.config.traceability_hyperlink_colors = {}

def test_make_internal_item_ref_no_caption(self):
mock_builder = MagicMock(spec=StandaloneHTMLBuilder)
mock_builder.link_suffix = '.html'
self.collection = TraceableCollection()
self.collection.add_item(self.item)

def init_builder(self, spec=StandaloneHTMLBuilder):
mock_builder = MagicMock(spec=spec)
if spec == StandaloneHTMLBuilder:
mock_builder.link_suffix = '.html'
else:
mock_builder.get_relative_uri = Mock(side_effect=raise_no_uri)
mock_builder.env = BuildEnvironment(self.app)
self.app.builder = mock_builder
self.app.builder.env.traceability_collection = TraceableCollection()
self.app.builder.env.traceability_collection = self.collection
self.app.builder.env.traceability_ref_nodes = {}
self.app.builder.env.traceability_collection.add_item(self.item)

def test_make_internal_item_ref_no_caption(self):
self.init_builder()
p_node = self.node.make_internal_item_ref(self.app, self.node['id'])
ref_node = p_node.children[0]
em_node = ref_node.children[0]
Expand All @@ -54,13 +65,7 @@ def test_make_internal_item_ref_no_caption(self):
self.assertNotIn('onlycaptions', cache)

def test_make_internal_item_ref_show_caption(self):
mock_builder = MagicMock(spec=StandaloneHTMLBuilder)
mock_builder.link_suffix = '.html'
mock_builder.env = BuildEnvironment(self.app)
self.app.builder = mock_builder
self.app.builder.env.traceability_collection = TraceableCollection()
self.app.builder.env.traceability_ref_nodes = {}
self.app.builder.env.traceability_collection.add_item(self.item)
self.init_builder()
self.item.caption = 'caption text'
p_node = self.node.make_internal_item_ref(self.app, self.node['id'])
ref_node = p_node.children[0]
Expand All @@ -75,13 +80,7 @@ def test_make_internal_item_ref_show_caption(self):
self.assertEqual(p_node, cache['default'][f'{self.node["document"]}.html'])

def test_make_internal_item_ref_only_caption(self):
mock_builder = MagicMock(spec=StandaloneHTMLBuilder)
mock_builder.link_suffix = '.html'
mock_builder.env = BuildEnvironment(self.app)
self.app.builder = mock_builder
self.app.builder.env.traceability_collection = TraceableCollection()
self.app.builder.env.traceability_ref_nodes = {}
self.app.builder.env.traceability_collection.add_item(self.item)
self.init_builder()
self.item.caption = 'caption text'
self.node['nocaptions'] = True
self.node['onlycaptions'] = True
Expand All @@ -100,13 +99,7 @@ def test_make_internal_item_ref_only_caption(self):
self.assertEqual(p_node, cache['onlycaptions'][f'{self.node["document"]}.html'])

def test_make_internal_item_ref_hide_caption_html(self):
mock_builder = MagicMock(spec=StandaloneHTMLBuilder)
mock_builder.link_suffix = '.html'
mock_builder.env = BuildEnvironment(self.app)
self.app.builder = mock_builder
self.app.builder.env.traceability_collection = TraceableCollection()
self.app.builder.env.traceability_ref_nodes = {}
self.app.builder.env.traceability_collection.add_item(self.item)
self.init_builder()
self.item.caption = 'caption text'
self.node['nocaptions'] = True
p_node = self.node.make_internal_item_ref(self.app, self.node['id'])
Expand All @@ -124,13 +117,7 @@ def test_make_internal_item_ref_hide_caption_html(self):
self.assertEqual(p_node, cache['nocaptions'][f'{self.node["document"]}.html'])

def test_make_internal_item_ref_hide_caption_latex(self):
mock_builder = MagicMock(spec=LaTeXBuilder)
mock_builder.get_relative_uri = Mock(side_effect=raise_no_uri)
mock_builder.env = BuildEnvironment(self.app)
self.app.builder = mock_builder
self.app.builder.env.traceability_collection = TraceableCollection()
self.app.builder.env.traceability_ref_nodes = {}
self.app.builder.env.traceability_collection.add_item(self.item)
self.init_builder(spec=LaTeXBuilder)
self.item.caption = 'caption text'
self.node['nocaptions'] = True
p_node = self.node.make_internal_item_ref(self.app, self.node['id'])
Expand All @@ -154,3 +141,21 @@ def test_make_internal_item_ref_hide_caption_latex(self):
def test_is_relation_external(self, relation_name, expected):
external = self.node.is_relation_external(relation_name)
self.assertEqual(external, expected)

def test_item_node_replacement(self):
self.collection.add_relation_pair('depends_on', 'impacts_on')
# leaving out depends_on to test warning
self.app.config.traceability_relationship_to_string = {'impacts_on': 'Impacts on'}

target_item = TraceableItem('target_id')
self.collection.add_item(target_item)
self.collection.add_relation(self.item.identifier, 'depends_on', target_item.identifier)

with self.assertLogs(LOGGER, logging.DEBUG) as c_m:
self.node.parent = nodes.container()
self.node.parent.append(self.node)
self.node.perform_replacement(self.app, self.collection)

warning = "WARNING:sphinx.mlx.traceability_exception:Traceability: relation depends_on cannot be translated "\
"to string"
self.assertEqual(c_m.output, [warning])