From 640e189107af844fd8619e74eaf5c6791a96f08b Mon Sep 17 00:00:00 2001 From: Marco Heinemann Date: Mon, 12 Jan 2026 13:58:01 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AA=20Added=20nested=20needs=20test=20?= =?UTF-8?q?with=20schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/__snapshots__/test_nested.ambr | 21 +++++++++++++ tests/doc_test/doc_nested/conf.py | 3 ++ tests/doc_test/doc_nested/index.rst | 28 +++++++++++++++++ tests/doc_test/doc_nested/schemas.json | 40 ++++++++++++++++++++++++ tests/doc_test/doc_nested/ubproject.toml | 3 ++ tests/test_nested.py | 21 +++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 tests/__snapshots__/test_nested.ambr create mode 100644 tests/doc_test/doc_nested/conf.py create mode 100644 tests/doc_test/doc_nested/index.rst create mode 100644 tests/doc_test/doc_nested/schemas.json create mode 100644 tests/doc_test/doc_nested/ubproject.toml create mode 100644 tests/test_nested.py diff --git a/tests/__snapshots__/test_nested.ambr b/tests/__snapshots__/test_nested.ambr new file mode 100644 index 000000000..800772526 --- /dev/null +++ b/tests/__snapshots__/test_nested.ambr @@ -0,0 +1,21 @@ +# serializer version: 1 +# name: test_nested[test_app0] + list([ + ''' + Need 'SPEC_002' has schema violations: + Severity: violation + Need path: SPEC_002 > parent_needs + Schema path: spec-has-req-parent[0] > validate > network > parent_needs > contains + Schema message: Too few valid links of type 'parent_needs' (0 < 1) [sn_schema_violation.network_contains_too_few] + + ''', + ]) +# --- +# name: test_nested[test_app0].1 + list([ + NeedItem(core={'id': 'REQ_001', 'type': 'req', 'type_name': 'Requirement', 'type_prefix': 'R_', 'type_color': '#BFD8D2', 'type_style': 'node', 'title': 'Req lvl 1', 'status': 'open', 'tags': [], 'constraints': [], 'collapse': False, 'hide': False, 'style': None, 'layout': None, 'external_css': 'external_link', 'arch': {}, 'has_dead_links': False, 'has_forbidden_dead_links': False, 'sections': ('TEST DOCUMENT',), 'signature': None}, extras={'duration': None, 'completion': None, 'query': '', 'specific': '', 'max_amount': '', 'max_content_lines': '', 'id_prefix': '', 'user': '', 'created_at': '', 'updated_at': '', 'closed_at': '', 'service': '', 'url': '', 'avatar': '', 'params': '', 'prefix': '', 'url_postfix': ''}, links={'links': [], 'parent_needs': []}, backlinks={'links': ['TEST_001'], 'parent_needs': ['SPEC_001']}, source=NeedItemSourceDirective(docname='index', lineno=4, lineno_content=8), content=NeedsContent(doctype='.rst', content='Content before\n\n.. spec:: Spec lvl 2\n :id: SPEC_001\n :status: open\n\n .. test:: Test lvl 3\n :id: TEST_001\n :status: open\n :links: REQ_001\n\nContent after', pre_content=None, post_content=None, jinja_content=False, template=None, pre_template=None, post_template=None), parts={}, modifications=(), dynamic_fields={}), + NeedItem(core={'id': 'SPEC_001', 'type': 'spec', 'type_name': 'Specification', 'type_prefix': 'S_', 'type_color': '#FEDCD2', 'type_style': 'node', 'title': 'Spec lvl 2', 'status': 'open', 'tags': [], 'constraints': [], 'collapse': False, 'hide': False, 'style': None, 'layout': None, 'external_css': 'external_link', 'arch': {}, 'has_dead_links': False, 'has_forbidden_dead_links': False, 'sections': ('TEST DOCUMENT',), 'signature': None}, extras={'duration': None, 'completion': None, 'query': '', 'specific': '', 'max_amount': '', 'max_content_lines': '', 'id_prefix': '', 'user': '', 'created_at': '', 'updated_at': '', 'closed_at': '', 'service': '', 'url': '', 'avatar': '', 'params': '', 'prefix': '', 'url_postfix': ''}, links={'links': [], 'parent_needs': ['REQ_001']}, backlinks={'links': [], 'parent_needs': ['TEST_001']}, source=NeedItemSourceDirective(docname='index', lineno=10, lineno_content=14), content=NeedsContent(doctype='.rst', content='.. test:: Test lvl 3\n :id: TEST_001\n :status: open\n :links: REQ_001', pre_content=None, post_content=None, jinja_content=False, template=None, pre_template=None, post_template=None), parts={}, modifications=(), dynamic_fields={}), + NeedItem(core={'id': 'TEST_001', 'type': 'test', 'type_name': 'Test Case', 'type_prefix': 'T_', 'type_color': '#DCB239', 'type_style': 'node', 'title': 'Test lvl 3', 'status': 'open', 'tags': [], 'constraints': [], 'collapse': False, 'hide': False, 'style': None, 'layout': None, 'external_css': 'external_link', 'arch': {}, 'has_dead_links': False, 'has_forbidden_dead_links': False, 'sections': ('TEST DOCUMENT',), 'signature': None}, extras={'duration': None, 'completion': None, 'query': '', 'specific': '', 'max_amount': '', 'max_content_lines': '', 'id_prefix': '', 'user': '', 'created_at': '', 'updated_at': '', 'closed_at': '', 'service': '', 'url': '', 'avatar': '', 'params': '', 'prefix': '', 'url_postfix': ''}, links={'links': ['REQ_001'], 'parent_needs': ['SPEC_001']}, backlinks={'links': [], 'parent_needs': []}, source=NeedItemSourceDirective(docname='index', lineno=14, lineno_content=19), content=NeedsContent(doctype='.rst', content='', pre_content=None, post_content=None, jinja_content=False, template=None, pre_template=None, post_template=None), parts={}, modifications=(), dynamic_fields={}), + NeedItem(core={'id': 'SPEC_002', 'type': 'spec', 'type_name': 'Specification', 'type_prefix': 'S_', 'type_color': '#FEDCD2', 'type_style': 'node', 'title': 'Spec lvl 1', 'status': 'open', 'tags': [], 'constraints': [], 'collapse': False, 'hide': False, 'style': None, 'layout': None, 'external_css': 'external_link', 'arch': {}, 'has_dead_links': False, 'has_forbidden_dead_links': False, 'sections': ('TEST DOCUMENT',), 'signature': None}, extras={'duration': None, 'completion': None, 'query': '', 'specific': '', 'max_amount': '', 'max_content_lines': '', 'id_prefix': '', 'user': '', 'created_at': '', 'updated_at': '', 'closed_at': '', 'service': '', 'url': '', 'avatar': '', 'params': '', 'prefix': '', 'url_postfix': ''}, links={'links': [], 'parent_needs': []}, backlinks={'links': [], 'parent_needs': []}, source=NeedItemSourceDirective(docname='index', lineno=21, lineno_content=25), content=NeedsContent(doctype='.rst', content='', pre_content=None, post_content=None, jinja_content=False, template=None, pre_template=None, post_template=None), parts={}, modifications=(), dynamic_fields={}), + ]) +# --- diff --git a/tests/doc_test/doc_nested/conf.py b/tests/doc_test/doc_nested/conf.py new file mode 100644 index 000000000..41c9819fb --- /dev/null +++ b/tests/doc_test/doc_nested/conf.py @@ -0,0 +1,3 @@ +project = "nested needs test" +extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +needs_from_toml = "ubproject.toml" diff --git a/tests/doc_test/doc_nested/index.rst b/tests/doc_test/doc_nested/index.rst new file mode 100644 index 000000000..8948adf3a --- /dev/null +++ b/tests/doc_test/doc_nested/index.rst @@ -0,0 +1,28 @@ +TEST DOCUMENT +============= + +.. req:: Req lvl 1 + :id: REQ_001 + :status: open + + Content before + + .. spec:: Spec lvl 2 + :id: SPEC_001 + :status: open + + .. test:: Test lvl 3 + :id: TEST_001 + :status: open + :links: REQ_001 + + Content after + +.. spec:: Spec lvl 1 + :id: SPEC_002 + :status: open + +.. needtable:: Table from sphinx-needs 'needtable' directive + :columns: id;title;tags;links;parent_need;parent_needs + +.. needflow:: diff --git a/tests/doc_test/doc_nested/schemas.json b/tests/doc_test/doc_nested/schemas.json new file mode 100644 index 000000000..d1a7e4f1d --- /dev/null +++ b/tests/doc_test/doc_nested/schemas.json @@ -0,0 +1,40 @@ +{ + "$defs": { + "type-req": { + "properties": { + "type": { "const": "req" } + } + }, + "type-spec": { + "properties": { + "type": { "const": "spec" } + } + }, + "type-test": { + "properties": { + "type": { "const": "test" } + } + } + }, + "schemas": [ + { + "id": "spec-has-req-parent", + "select": { + "$ref": "#/$defs/type-spec" + }, + "validate": { + "network": { + "parent_needs": { + "contains": { + "local": { + "$ref": "#/$defs/type-req" + } + }, + "minContains": 1, + "maxContains": 1 + } + } + } + } + ] +} diff --git a/tests/doc_test/doc_nested/ubproject.toml b/tests/doc_test/doc_nested/ubproject.toml new file mode 100644 index 000000000..fdee5f4cf --- /dev/null +++ b/tests/doc_test/doc_nested/ubproject.toml @@ -0,0 +1,3 @@ +[needs] +build_json = true +schema_definitions_from_json = "schemas.json" diff --git a/tests/test_nested.py b/tests/test_nested.py new file mode 100644 index 000000000..9242a7661 --- /dev/null +++ b/tests/test_nested.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import pytest +from sphinx.testing.util import SphinxTestApp + +from sphinx_needs.api.need import get_needs_view + + +@pytest.mark.parametrize( + "test_app", + [{"buildername": "html", "srcdir": "doc_test/doc_nested", "no_plantuml": False}], + indirect=True, +) +def test_nested(test_app: SphinxTestApp, snapshot, get_warnings_list): + app = test_app + app.build() + warnings = get_warnings_list(app) + assert warnings == snapshot + + needs = list(get_needs_view(app).values()) + assert needs == snapshot