From e6eea3162e93b3856c3d9b190f17b8c1ea1f7597 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Mon, 16 Sep 2024 20:57:13 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AA=20improve=20some=20tests=20(#1301)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - condense broken doc tests into single module - condense api tests into single module - remove unnecessary test projects when `doc_basic` can be used - add testing of `signature` capture to `add_sections_sigs` test project --- sphinx_needs/api/__init__.py | 15 ++- .../__snapshots__/test_add_sections_sigs.ambr | 70 ++++++++++ tests/__snapshots__/test_api_usage.ambr | 35 +++++ .../test_build_html[test_app0].doctree.xml | 2 +- .../conf.py | 3 + .../index.rst | 15 +++ tests/doc_test/api_doc/conf.py | 32 ----- tests/doc_test/api_doc/index.rst | 15 --- tests/doc_test/api_doc_awesome/conf.py | 32 ----- tests/doc_test/api_doc_awesome/index.rst | 21 --- tests/doc_test/broken_tags_2/conf.py | 37 ------ tests/doc_test/broken_tags_2/index.rst | 22 ---- tests/doc_test/doc_basic/conf.py | 1 + tests/doc_test/doc_basic/index.rst | 2 +- tests/doc_test/doc_build_latex/conf.py | 44 ------- tests/doc_test/doc_build_latex/index.rst | 52 -------- .../{doc_basic_latex => doc_complex}/conf.py | 0 .../index.rst | 0 .../page_1.rst | 0 .../page_2.rst | 0 tests/test_add_sections.py | 30 ----- tests/test_add_sections_sigs.py | 43 +++++++ tests/test_api_configuration.py | 46 ------- tests/test_api_usage.py | 121 ++++++++++++++++++ tests/test_api_usage_in_extension.py | 33 ----- tests/test_basic_doc.py | 16 +++ tests/test_broken_doc.py | 26 ---- tests/test_broken_docs.py | 92 +++++++++++++ tests/test_broken_links.py | 25 ---- tests/test_broken_statuses.py | 17 --- tests/test_broken_syntax_doc.py | 25 ---- tests/test_broken_tags.py | 38 ------ ...omplex_builders.py => test_complex_doc.py} | 16 +-- tests/test_doc_build_latex.py | 29 ----- 34 files changed, 413 insertions(+), 542 deletions(-) create mode 100644 tests/__snapshots__/test_add_sections_sigs.ambr create mode 100644 tests/__snapshots__/test_api_usage.ambr rename tests/doc_test/{add_sections => add_sections_sigs}/conf.py (94%) rename tests/doc_test/{add_sections => add_sections_sigs}/index.rst (79%) delete mode 100644 tests/doc_test/api_doc/conf.py delete mode 100644 tests/doc_test/api_doc/index.rst delete mode 100644 tests/doc_test/api_doc_awesome/conf.py delete mode 100644 tests/doc_test/api_doc_awesome/index.rst delete mode 100644 tests/doc_test/broken_tags_2/conf.py delete mode 100644 tests/doc_test/broken_tags_2/index.rst delete mode 100644 tests/doc_test/doc_build_latex/conf.py delete mode 100644 tests/doc_test/doc_build_latex/index.rst rename tests/doc_test/{doc_basic_latex => doc_complex}/conf.py (100%) rename tests/doc_test/{doc_basic_latex => doc_complex}/index.rst (100%) rename tests/doc_test/{doc_basic_latex => doc_complex}/page_1.rst (100%) rename tests/doc_test/{doc_basic_latex => doc_complex}/page_2.rst (100%) delete mode 100644 tests/test_add_sections.py create mode 100644 tests/test_add_sections_sigs.py delete mode 100644 tests/test_api_configuration.py create mode 100644 tests/test_api_usage.py delete mode 100644 tests/test_api_usage_in_extension.py delete mode 100644 tests/test_broken_doc.py create mode 100644 tests/test_broken_docs.py delete mode 100644 tests/test_broken_links.py delete mode 100644 tests/test_broken_statuses.py delete mode 100644 tests/test_broken_syntax_doc.py delete mode 100644 tests/test_broken_tags.py rename tests/{test_complex_builders.py => test_complex_doc.py} (70%) delete mode 100644 tests/test_doc_build_latex.py diff --git a/sphinx_needs/api/__init__.py b/sphinx_needs/api/__init__.py index e124e8d49..4b482e0ee 100644 --- a/sphinx_needs/api/__init__.py +++ b/sphinx_needs/api/__init__.py @@ -1,7 +1,18 @@ -from .configuration import ( # noqa: F401 +from .configuration import ( add_dynamic_function, add_extra_option, add_need_type, get_need_types, ) -from .need import add_external_need, add_need, del_need, make_hashed_id # noqa: F401 +from .need import add_external_need, add_need, del_need, make_hashed_id + +__all__ = ( + "add_dynamic_function", + "add_extra_option", + "add_need_type", + "get_need_types", + "add_external_need", + "add_need", + "del_need", + "make_hashed_id", +) diff --git a/tests/__snapshots__/test_add_sections_sigs.ambr b/tests/__snapshots__/test_add_sections_sigs.ambr new file mode 100644 index 000000000..de53bc76e --- /dev/null +++ b/tests/__snapshots__/test_add_sections_sigs.ambr @@ -0,0 +1,70 @@ +# name: test_section_is_usable_in_filters[test_app0] + dict({ + 'R_12345': dict({ + 'description': 'The Tool **shall** have a command line interface.', + 'docname': 'index', + 'external_css': 'external_link', + 'full_title': 'Command line interface', + 'id': 'R_12345', + 'impacts': 'component_a', + 'introduced': '1.0.0', + 'layout': '', + 'section_name': '1.1 First Section', + 'sections': list([ + '1.1 First Section', + '1 TEST DOCUMENT', + ]), + 'tags': list([ + 'test', + 'test2', + ]), + 'target_id': 'R_12345', + 'title': 'Command line interface', + 'type': 'req', + 'type_name': 'Requirement', + 'updated': '1.5.1', + }), + 'R_12346': dict({ + 'description': 'The Tool **shall** have a command line interface.', + 'docname': 'index', + 'external_css': 'external_link', + 'full_title': 'Another Requirement', + 'id': 'R_12346', + 'impacts': 'component_b', + 'introduced': '1.1.1', + 'layout': '', + 'section_name': '1.2 Second Section', + 'sections': list([ + '1.2 Second Section', + '1 TEST DOCUMENT', + ]), + 'tags': list([ + 'test', + 'test2', + ]), + 'target_id': 'R_12346', + 'title': 'Another Requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated': '1.4.0', + }), + 'T_001': dict({ + 'description': '', + 'docname': 'index', + 'external_css': 'external_link', + 'full_title': 'test method', + 'id': 'T_001', + 'layout': '', + 'section_name': '1.3 need in API', + 'sections': list([ + '1.3 need in API', + '1 TEST DOCUMENT', + ]), + 'signature': 'test_method', + 'target_id': 'T_001', + 'title': 'test method', + 'type': 'test', + 'type_name': 'Test Case', + }), + }) +# --- diff --git a/tests/__snapshots__/test_api_usage.ambr b/tests/__snapshots__/test_api_usage.ambr new file mode 100644 index 000000000..5c98b6b20 --- /dev/null +++ b/tests/__snapshots__/test_api_usage.ambr @@ -0,0 +1,35 @@ +# name: test_api_add_type[test_app0] + list([ + dict({ + 'color': '#BFD8D2', + 'directive': 'story', + 'prefix': 'US_', + 'title': 'User Story', + }), + dict({ + 'color': '#FEDCD2', + 'directive': 'spec', + 'prefix': 'SP_', + 'title': 'Specification', + }), + dict({ + 'color': '#DF744A', + 'directive': 'impl', + 'prefix': 'IM_', + 'title': 'Implementation', + }), + dict({ + 'color': '#DCB239', + 'directive': 'test', + 'prefix': 'TC_', + 'title': 'Test Case', + }), + dict({ + 'color': '#000000', + 'directive': 'awesome', + 'prefix': 'AW_', + 'style': 'cloud', + 'title': 'Awesome', + }), + ]) +# --- diff --git a/tests/__snapshots__/test_basic_doc/test_build_html[test_app0].doctree.xml b/tests/__snapshots__/test_basic_doc/test_build_html[test_app0].doctree.xml index b4019c907..e50cbfc5a 100644 --- a/tests/__snapshots__/test_basic_doc/test_build_html[test_app0].doctree.xml +++ b/tests/__snapshots__/test_basic_doc/test_build_html[test_app0].doctree.xml @@ -7,4 +7,4 @@ - + diff --git a/tests/doc_test/add_sections/conf.py b/tests/doc_test/add_sections_sigs/conf.py similarity index 94% rename from tests/doc_test/add_sections/conf.py rename to tests/doc_test/add_sections_sigs/conf.py index 0a67ad2bb..e53563531 100644 --- a/tests/doc_test/add_sections/conf.py +++ b/tests/doc_test/add_sections_sigs/conf.py @@ -1,5 +1,8 @@ extensions = ["sphinx_needs"] +needs_build_json = True +needs_json_remove_defaults = True + needs_extra_options = [ "introduced", "updated", diff --git a/tests/doc_test/add_sections/index.rst b/tests/doc_test/add_sections_sigs/index.rst similarity index 79% rename from tests/doc_test/add_sections/index.rst rename to tests/doc_test/add_sections_sigs/index.rst index 0a1390de2..7a53f671e 100644 --- a/tests/doc_test/add_sections/index.rst +++ b/tests/doc_test/add_sections_sigs/index.rst @@ -26,6 +26,20 @@ Second Section The Tool **shall** have a command line interface. +need in API +----------- + +.. py:class:: TestClass + + This is a test class. + + .. py:method:: test_method(self) + + This is a test method. + + .. test:: test method + :id: T_001 + All Requirements ---------------- @@ -39,3 +53,4 @@ First Section Only .. needtable:: :columns: id;title;sections :filter: 'First Section' in sections[0] and sections[0].startswith('1.1') + \ No newline at end of file diff --git a/tests/doc_test/api_doc/conf.py b/tests/doc_test/api_doc/conf.py deleted file mode 100644 index df50838b8..000000000 --- a/tests/doc_test/api_doc/conf.py +++ /dev/null @@ -1,32 +0,0 @@ -extensions = ["sphinx_needs", "dummy_extension.dummy"] - -needs_types = [ - { - "directive": "story", - "title": "User Story", - "prefix": "US_", - "color": "#BFD8D2", - "style": "node", - }, - { - "directive": "spec", - "title": "Specification", - "prefix": "SP_", - "color": "#FEDCD2", - "style": "node", - }, - { - "directive": "impl", - "title": "Implementation", - "prefix": "IM_", - "color": "#DF744A", - "style": "node", - }, - { - "directive": "test", - "title": "Test Case", - "prefix": "TC_", - "color": "#DCB239", - "style": "node", - }, -] diff --git a/tests/doc_test/api_doc/index.rst b/tests/doc_test/api_doc/index.rst deleted file mode 100644 index cd3a0e0bf..000000000 --- a/tests/doc_test/api_doc/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -TEST DOCUMENT -============= - -.. spec:: Command line interface - :id: SP_TOO_001 - :status: implemented - :tags: test;test2 - - The Tool awesome shall have a command line interface. - -.. story:: A story - :tags: 1 - -.. needfilter:: - :tags: test;my_test diff --git a/tests/doc_test/api_doc_awesome/conf.py b/tests/doc_test/api_doc_awesome/conf.py deleted file mode 100644 index df50838b8..000000000 --- a/tests/doc_test/api_doc_awesome/conf.py +++ /dev/null @@ -1,32 +0,0 @@ -extensions = ["sphinx_needs", "dummy_extension.dummy"] - -needs_types = [ - { - "directive": "story", - "title": "User Story", - "prefix": "US_", - "color": "#BFD8D2", - "style": "node", - }, - { - "directive": "spec", - "title": "Specification", - "prefix": "SP_", - "color": "#FEDCD2", - "style": "node", - }, - { - "directive": "impl", - "title": "Implementation", - "prefix": "IM_", - "color": "#DF744A", - "style": "node", - }, - { - "directive": "test", - "title": "Test Case", - "prefix": "TC_", - "color": "#DCB239", - "style": "node", - }, -] diff --git a/tests/doc_test/api_doc_awesome/index.rst b/tests/doc_test/api_doc_awesome/index.rst deleted file mode 100644 index c13212437..000000000 --- a/tests/doc_test/api_doc_awesome/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -TEST DOCUMENT -============= - -.. spec:: Command line interface - :id: SP_TOO_001 - :status: implemented - :tags: test;test2 - - The Tool awesome shall have a command line interface. - -.. story:: A story - :tags: 1 - -.. awesome:: Awesome spec - :status: open - :tags: test - - - -.. needfilter:: - :tags: test;my_test diff --git a/tests/doc_test/broken_tags_2/conf.py b/tests/doc_test/broken_tags_2/conf.py deleted file mode 100644 index 6559d7fe0..000000000 --- a/tests/doc_test/broken_tags_2/conf.py +++ /dev/null @@ -1,37 +0,0 @@ -extensions = ["sphinx_needs"] - -needs_types = [ - { - "directive": "story", - "title": "User Story", - "prefix": "US_", - "color": "#BFD8D2", - "style": "node", - }, - { - "directive": "spec", - "title": "Specification", - "prefix": "SP_", - "color": "#FEDCD2", - "style": "node", - }, - { - "directive": "impl", - "title": "Implementation", - "prefix": "IM_", - "color": "#DF744A", - "style": "node", - }, - { - "directive": "test", - "title": "Test Case", - "prefix": "TC_", - "color": "#DCB239", - "style": "node", - }, -] - -needs_tags = [ - {"name": "new", "description": "new needs"}, - {"name": "security", "description": "tag for security needs"}, -] diff --git a/tests/doc_test/broken_tags_2/index.rst b/tests/doc_test/broken_tags_2/index.rst deleted file mode 100644 index c27aaff95..000000000 --- a/tests/doc_test/broken_tags_2/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -BROKEN DOCUMENT -=============== - -.. spec:: Command line interface - :id: SP_TOO_001 - :status: implemented - :tags: new - - The Tool awesome shall have a command line interface. - -.. spec:: Test spec - :id: SP_TOO_002 - :tags: new; security - - Test test - -.. spec:: Test unneeded ; - :id: SP_TOO_004 - :tags: new; security; - - Test test - diff --git a/tests/doc_test/doc_basic/conf.py b/tests/doc_test/doc_basic/conf.py index ec173fd2e..2eb8e8ff5 100644 --- a/tests/doc_test/doc_basic/conf.py +++ b/tests/doc_test/doc_basic/conf.py @@ -1,3 +1,4 @@ +project = "needs" version = "0.1.0" copyright = "2024" diff --git a/tests/doc_test/doc_basic/index.rst b/tests/doc_test/doc_basic/index.rst index de34aac29..f8332531b 100644 --- a/tests/doc_test/doc_basic/index.rst +++ b/tests/doc_test/doc_basic/index.rst @@ -9,5 +9,5 @@ TEST DOCUMENT :status: open -.. needtable:: +.. needtable:: Table from sphinx-needs 'needtable' directive :filter: status == "open" diff --git a/tests/doc_test/doc_build_latex/conf.py b/tests/doc_test/doc_build_latex/conf.py deleted file mode 100644 index df70aa270..000000000 --- a/tests/doc_test/doc_build_latex/conf.py +++ /dev/null @@ -1,44 +0,0 @@ -project = "needs test docs" - -extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] - -# note, the plantuml executable command is set globally in the test suite -plantuml_output_format = "svg" - -# figures, tables and code-blocks are automatically numbered if they have a caption -numfig = True - -needs_table_style = "datatables" - -needs_id_regex = "^[A-Za-z0-9_]" - -needs_types = [ - { - "directive": "story", - "title": "User Story", - "prefix": "US_", - "color": "#BFD8D2", - "style": "node", - }, - { - "directive": "spec", - "title": "Specification", - "prefix": "SP_", - "color": "#FEDCD2", - "style": "node", - }, - { - "directive": "impl", - "title": "Implementation", - "prefix": "IM_", - "color": "#DF744A", - "style": "node", - }, - { - "directive": "test", - "title": "Test Case", - "prefix": "TC_", - "color": "#DCB239", - "style": "node", - }, -] diff --git a/tests/doc_test/doc_build_latex/index.rst b/tests/doc_test/doc_build_latex/index.rst deleted file mode 100644 index 604b2a514..000000000 --- a/tests/doc_test/doc_build_latex/index.rst +++ /dev/null @@ -1,52 +0,0 @@ -TEST DOCUMENT BUILD LATEXPDF -============================ - -.. raw:: latex - - \listoftables - \listoffigures - - -Story ------ - -.. story:: A Story - :id: USER_STORY_001 - - This is a user defined custom story. - -Figure and Table ----------------- - -Example figure created: - -.. needflow:: Example Figure - :filter: id in ['USER_STORY_001'] - - -Table generated by Sphinx. - -.. list-table:: Table from Sphinx 'list-table' directive - :widths: 25 25 - :header-rows: 1 - - * - Header A - - Header B - * - Apple - - 10 - * - Banana - - 20 - -.. table:: Table from Sphinx 'table' directive - :widths: auto - - ===== ===== - A B - ===== ===== - True False - ===== ===== - -Table generated by sphinxcontrib-needs: - -.. needtable:: Table from sphinxneeds-contrib 'needtable' directive - :filter: id in ['USER_STORY_001'] diff --git a/tests/doc_test/doc_basic_latex/conf.py b/tests/doc_test/doc_complex/conf.py similarity index 100% rename from tests/doc_test/doc_basic_latex/conf.py rename to tests/doc_test/doc_complex/conf.py diff --git a/tests/doc_test/doc_basic_latex/index.rst b/tests/doc_test/doc_complex/index.rst similarity index 100% rename from tests/doc_test/doc_basic_latex/index.rst rename to tests/doc_test/doc_complex/index.rst diff --git a/tests/doc_test/doc_basic_latex/page_1.rst b/tests/doc_test/doc_complex/page_1.rst similarity index 100% rename from tests/doc_test/doc_basic_latex/page_1.rst rename to tests/doc_test/doc_complex/page_1.rst diff --git a/tests/doc_test/doc_basic_latex/page_2.rst b/tests/doc_test/doc_complex/page_2.rst similarity index 100% rename from tests/doc_test/doc_basic_latex/page_2.rst rename to tests/doc_test/doc_complex/page_2.rst diff --git a/tests/test_add_sections.py b/tests/test_add_sections.py deleted file mode 100644 index 4658beef8..000000000 --- a/tests/test_add_sections.py +++ /dev/null @@ -1,30 +0,0 @@ -import re -from pathlib import Path - -import pytest - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/add_sections"}], - indirect=True, -) -def test_section_is_usable_in_filters(test_app): - app = test_app - app.builder.build_all() - html = Path(app.outdir, "index.html").read_text() - - tables = re.findall("()", html, re.DOTALL) - assert len(tables) == 4 - - # All requirements should be in first table - assert "R_12345" in tables[2] - assert "First Section" in tables[2] - assert "R_12346" in tables[2] - assert "Second Section" in tables[2] - - # Only requirements from the first section should be in table 2 - assert "R_12345" in tables[3] - assert "First Section" in tables[3] - assert "R_12346" not in tables[3] - assert "Second Section" not in tables[3] diff --git a/tests/test_add_sections_sigs.py b/tests/test_add_sections_sigs.py new file mode 100644 index 000000000..e99c4352a --- /dev/null +++ b/tests/test_add_sections_sigs.py @@ -0,0 +1,43 @@ +import json +import re +from pathlib import Path + +import pytest +from sphinx.testing.util import SphinxTestApp + + +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/add_sections_sigs", + "no_plantuml": True, + } + ], + indirect=True, +) +def test_section_is_usable_in_filters(test_app: SphinxTestApp, snapshot): + app = test_app + app.build() + assert not app._warning.getvalue() + + needs_data = json.loads(Path(app.outdir, "needs.json").read_text()) + assert needs_data["versions"][""]["needs"] == snapshot + + html = Path(app.outdir, "index.html").read_text() + + tables = re.findall("(
)", html, re.DOTALL) + assert len(tables) == 5 + + # All requirements should be in first table + assert "R_12345" in tables[3] + assert "First Section" in tables[3] + assert "R_12346" in tables[3] + assert "Second Section" in tables[3] + + # Only requirements from the first section should be in table 2 + assert "R_12345" in tables[4] + assert "First Section" in tables[4] + assert "R_12346" not in tables[4] + assert "Second Section" not in tables[4] diff --git a/tests/test_api_configuration.py b/tests/test_api_configuration.py deleted file mode 100644 index c031f8e6e..000000000 --- a/tests/test_api_configuration.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys -import types -from pathlib import Path - -import pytest - -dummy_code = """ -def setup(app): - return {'version': '0.1'} -""" - -dummy_extension = types.ModuleType("dummy_extension.dummy") -exec(dummy_code, dummy_extension.__dict__) -sys.modules["dummy_extension.dummy"] = dummy_extension - - -@pytest.mark.parametrize( - "test_app", [{"buildername": "html", "srcdir": "doc_test/api_doc"}], indirect=True -) -def test_api_get_types(test_app): - from sphinx_needs.api import get_need_types - - app = test_app - - need_types = get_need_types(app) - assert set(need_types) == {"story", "spec", "impl", "test"} - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/api_doc_awesome"}], - indirect=True, -) -def test_api_add_type(test_app, snapshot): - from sphinx_needs.api import add_need_type - - app = test_app - - add_need_type(app, "awesome", "Awesome", "AW_", "#000000", "cloud") - need_types = app.config.needs_types - assert need_types == snapshot - - app.builder.build_all() - html = Path(app.outdir, "index.html").read_text() - assert html is not None - assert "Awesome spec" in html diff --git a/tests/test_api_usage.py b/tests/test_api_usage.py new file mode 100644 index 000000000..405a3ce73 --- /dev/null +++ b/tests/test_api_usage.py @@ -0,0 +1,121 @@ +import sys +import types +from pathlib import Path + +import pytest +from sphinx.testing.util import SphinxTestApp + +from sphinx_needs.api import add_need_type, get_need_types + + +@pytest.fixture() +def add_extension1(): + dummy_code = """ +def setup(app): + from sphinx_needs.api import get_need_types + + def after_config(app, config): + print(get_need_types(app)) + + # app.connect('config-inited', after_config) + print(get_need_types(app)) + return {'version': '0.1'} + """ + dummy_extension = types.ModuleType("dummy_extension.dummy") + exec(dummy_code, dummy_extension.__dict__) + sys.modules["dummy_extension.dummy"] = dummy_extension + yield + sys.modules.pop("dummy_extension.dummy") + + +@pytest.fixture() +def add_extension2(): + dummy_code = """ +def setup(app): + return {'version': '0.1'} +""" + dummy_extension = types.ModuleType("dummy_extension.dummy") + exec(dummy_code, dummy_extension.__dict__) + sys.modules["dummy_extension.dummy"] = dummy_extension + yield + sys.modules.pop("dummy_extension.dummy") + + +@pytest.mark.usefixtures("add_extension1") +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/doc_basic", + "no_plantuml": True, + "confoverrides": {"extensions": ["sphinx_needs", "dummy_extension.dummy"]}, + } + ], + indirect=True, +) +def test_api_configuration(test_app: SphinxTestApp): + app = test_app + + app.build() + assert app._warning.getvalue() == "" + + html = Path(app.outdir, "index.html").read_text() + assert html is not None + + +@pytest.mark.usefixtures("add_extension2") +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/doc_basic", + "no_plantuml": True, + "confoverrides": {"extensions": ["sphinx_needs", "dummy_extension.dummy"]}, + } + ], + indirect=True, +) +def test_api_get_types(test_app: SphinxTestApp): + app = test_app + + need_types = get_need_types(app) + assert set(need_types) == {"story", "spec", "impl", "test"} + + +@pytest.mark.usefixtures("add_extension2") +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/doc_basic", + "no_plantuml": True, + "confoverrides": {"extensions": ["sphinx_needs", "dummy_extension.dummy"]}, + } + ], + indirect=True, +) +def test_api_add_type(test_app: SphinxTestApp, snapshot): + app = test_app + + add_need_type(app, "awesome", "Awesome", "AW_", "#000000", "cloud") + need_types = app.config.needs_types + assert need_types == snapshot + + Path(app.srcdir, "other_api.rst").write_text( + """ +:orphan: + +.. awesome:: my awesome need + :id: AW_001 + """ + ) + + app.build() + assert app._warning.getvalue() == "" + + html = Path(app.outdir, "other_api.html").read_text() + assert html is not None + assert "my awesome need" in html diff --git a/tests/test_api_usage_in_extension.py b/tests/test_api_usage_in_extension.py deleted file mode 100644 index 2a434e8df..000000000 --- a/tests/test_api_usage_in_extension.py +++ /dev/null @@ -1,33 +0,0 @@ -import sys -import types -from pathlib import Path - -import pytest - -dummy_code = """ -def setup(app): - from sphinx_needs.api import get_need_types - - def after_config(app, config): - print(get_need_types(app)) - - # app.connect('config-inited', after_config) - print(get_need_types(app)) - return {'version': '0.1'} -""" - - -dummy_extension = types.ModuleType("dummy_extension.dummy") -exec(dummy_code, dummy_extension.__dict__) -sys.modules["dummy_extension.dummy"] = dummy_extension - - -@pytest.mark.parametrize( - "test_app", [{"buildername": "html", "srcdir": "doc_test/api_doc"}], indirect=True -) -def test_api_configuration(test_app): - app = test_app - - app.builder.build_all() - html = Path(app.outdir, "index.html").read_text() - assert html is not None diff --git a/tests/test_basic_doc.py b/tests/test_basic_doc.py index f27f93e14..7cf49a715 100644 --- a/tests/test_basic_doc.py +++ b/tests/test_basic_doc.py @@ -97,6 +97,22 @@ def test_build_latex(test_app: SphinxTestApp): app.build() assert app._warning.getvalue() == "" + print([p.name for p in Path(app.outdir).iterdir()]) + + latex_file = Path(app.outdir, "needs.tex") + assert latex_file + latex_content = latex_file.read_text() + + # Check table generated by Sphinxneeds has correct caption + assert ( + "\\sphinxcaption{Table from sphinx\\sphinxhyphen{}needs \\textquotesingle" + "{}needtable\\textquotesingle{} directive}" in latex_content + ) + + # Check that the ST_001 label is only created once in the LaTeX output. Split + # on the string, which should split latex_content into two. + assert len(latex_content.split(r"\label{\detokenize{index:ST_001}}")) == 2 + @pytest.mark.parametrize( "test_app", diff --git a/tests/test_broken_doc.py b/tests/test_broken_doc.py deleted file mode 100644 index 1eddf7f69..000000000 --- a/tests/test_broken_doc.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -import pytest -from sphinx.testing.util import SphinxTestApp -from sphinx.util.console import strip_colors - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/broken_doc", "no_plantuml": True}], - indirect=True, -) -def test_doc_build_html(test_app: SphinxTestApp): - test_app.build() - warnings = ( - strip_colors(test_app._warning.getvalue()) - .replace(str(test_app.srcdir) + os.path.sep, "/") - .strip() - ) - assert ( - warnings - == "/index.rst:11: WARNING: A need with ID SP_TOO_001 already exists, title: 'Command line interface'. [needs.duplicate_id]" - ) - html = (test_app.outdir / "index.html").read_text() - assert "

BROKEN DOCUMENT" in html - assert "SP_TOO_001" in html diff --git a/tests/test_broken_docs.py b/tests/test_broken_docs.py new file mode 100644 index 000000000..0f79e211a --- /dev/null +++ b/tests/test_broken_docs.py @@ -0,0 +1,92 @@ +import os +from pathlib import Path + +import pytest +from sphinx.testing.util import SphinxTestApp +from sphinx.util.console import strip_colors + +from sphinx_needs.api.need import NeedsStatusNotAllowed, NeedsTagNotAllowed + + +def get_warnings(app: SphinxTestApp): + return ( + strip_colors(app._warning.getvalue()) + .replace(str(app.srcdir) + os.path.sep, "/") + .splitlines() + ) + + +@pytest.mark.parametrize( + "test_app", + [{"buildername": "html", "srcdir": "doc_test/broken_doc", "no_plantuml": True}], + indirect=True, +) +def test_duplicate_id(test_app: SphinxTestApp): + test_app.build() + assert get_warnings(test_app) == [ + "/index.rst:11: WARNING: A need with ID SP_TOO_001 already exists, title: 'Command line interface'. [needs.duplicate_id]" + ] + html = (test_app.outdir / "index.html").read_text() + assert "

BROKEN DOCUMENT" in html + assert "SP_TOO_001" in html + + +@pytest.mark.parametrize( + "test_app", + [{"buildername": "html", "srcdir": "doc_test/broken_links", "no_plantuml": True}], + indirect=True, +) +def test_broken_links(test_app: SphinxTestApp): + app = test_app + app.build() + + assert get_warnings(test_app) == [ + "/index.rst:12: WARNING: Need 'SP_TOO_002' has unknown outgoing link 'NOT_WORKING_LINK' in field 'links' [needs.link_outgoing]", + "/index.rst:21: WARNING: linked need BROKEN_LINK not found [needs.link_ref]", + ] + + +@pytest.mark.parametrize( + "test_app", + [{"buildername": "html", "srcdir": "doc_test/broken_statuses"}], + indirect=True, +) +def test_broken_statuses(test_app: SphinxTestApp): + with pytest.raises(NeedsStatusNotAllowed): + test_app.build() + + +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/broken_syntax_doc", + "no_plantuml": True, + } + ], + indirect=True, +) +def test_broken_syntax(test_app: SphinxTestApp): + test_app.build() + + assert [li for li in get_warnings(test_app) if li.startswith("")] == [ + '/index.rst:4: ERROR: Error in "spec" directive:', + '/index.rst:11: ERROR: Error in "spec" directive:', + '/index.rst:19: ERROR: Error in "spec" directive:', + ] + + html = Path(test_app.outdir, "index.html").read_text() + assert "SP_TOO_001" not in html + assert "SP_TOO_002" not in html + assert "SP_TOO_003" not in html + + +@pytest.mark.parametrize( + "test_app", + [{"buildername": "html", "srcdir": "doc_test/broken_tags"}], + indirect=True, +) +def test_broken_tags(test_app: SphinxTestApp): + with pytest.raises(NeedsTagNotAllowed): + test_app.build() diff --git a/tests/test_broken_links.py b/tests/test_broken_links.py deleted file mode 100644 index 592666f8f..000000000 --- a/tests/test_broken_links.py +++ /dev/null @@ -1,25 +0,0 @@ -from pathlib import Path - -import pytest -from sphinx.util.console import strip_colors - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/broken_links", "no_plantuml": True}], - indirect=True, -) -def test_doc_build_html(test_app): - app = test_app - app.build() - - # check there are expected warnings - warnings = strip_colors(app._warning.getvalue()) - print(warnings.splitlines()) - - expected_warnings = [ - f"{Path(str(app.srcdir)) / 'index.rst'}:12: WARNING: Need 'SP_TOO_002' has unknown outgoing link 'NOT_WORKING_LINK' in field 'links' [needs.link_outgoing]", - f"{Path(str(app.srcdir)) / 'index.rst'}:21: WARNING: linked need BROKEN_LINK not found [needs.link_ref]", - ] - - assert warnings.splitlines() == expected_warnings diff --git a/tests/test_broken_statuses.py b/tests/test_broken_statuses.py deleted file mode 100644 index 4efc7abff..000000000 --- a/tests/test_broken_statuses.py +++ /dev/null @@ -1,17 +0,0 @@ -import pytest - -from sphinx_needs.api.need import NeedsStatusNotAllowed - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/broken_statuses"}], - indirect=True, -) -def test_doc_build_html(test_app): - with pytest.raises(NeedsStatusNotAllowed): - app = test_app - app.build() - html = (app.outdir / "index.html").read_text() - assert "

BROKEN DOCUMENT" in html - assert "SP_TOO_002" in html diff --git a/tests/test_broken_syntax_doc.py b/tests/test_broken_syntax_doc.py deleted file mode 100644 index 33552793f..000000000 --- a/tests/test_broken_syntax_doc.py +++ /dev/null @@ -1,25 +0,0 @@ -from pathlib import Path - -import pytest - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/broken_syntax_doc"}], - indirect=True, -) -def test_doc_broken_syntax(test_app): - app = test_app - - app.build() - html = Path(app.outdir, "index.html").read_text() - - warning = app._warning - warnings = warning.getvalue() - - assert 'invalid option value: (option: "links"; value: None)' in warnings - assert 'invalid option value: (option: "tags"; value: None)' in warnings - - assert "SP_TOO_001" not in html - assert "SP_TOO_002" not in html - assert "SP_TOO_003" not in html diff --git a/tests/test_broken_tags.py b/tests/test_broken_tags.py deleted file mode 100644 index 631c0b623..000000000 --- a/tests/test_broken_tags.py +++ /dev/null @@ -1,38 +0,0 @@ -from pathlib import Path - -import pytest - -from sphinx_needs.api.need import NeedsTagNotAllowed - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/broken_tags"}], - indirect=True, -) -def test_doc_build_html(test_app): - with pytest.raises(NeedsTagNotAllowed): - app = test_app - app.build() - html = Path(app.outdir, "index.html").read_text() - assert "

BROKEN DOCUMENT" in html - assert "SP_TOO_003" in html - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "html", "srcdir": "doc_test/broken_tags_2"}], - indirect=True, -) -def test_doc_build_html_unneeded_chars(test_app): - """ - Test for https://github.com/useblocks/sphinxcontrib-needs/issues/36 - ; at the end of tags needs to be removed #36 - """ - app = test_app - app.build() - html = Path(app.outdir, "index.html").read_text() - assert "

BROKEN DOCUMENT" in html - assert "SP_TOO_004" in html - assert ":needs_tag:" not in html - assert "``" not in html diff --git a/tests/test_complex_builders.py b/tests/test_complex_doc.py similarity index 70% rename from tests/test_complex_builders.py rename to tests/test_complex_doc.py index e56a43153..c0edc4033 100644 --- a/tests/test_complex_builders.py +++ b/tests/test_complex_doc.py @@ -10,13 +10,7 @@ @pytest.mark.parametrize( "test_app", - [ - { - "buildername": "latex", - "srcdir": "doc_test/doc_basic_latex", - "parallel": 2, - } - ], + [{"buildername": "latex", "srcdir": "doc_test/doc_complex"}], indirect=True, ) def test_doc_complex_latex(test_app): @@ -29,13 +23,7 @@ def test_doc_complex_latex(test_app): @pytest.mark.parametrize( "test_app", - [ - { - "buildername": "singlehtml", - "srcdir": "doc_test/doc_basic_latex", - "parallel": 2, - } - ], + [{"buildername": "singlehtml", "srcdir": "doc_test/doc_complex"}], indirect=True, ) def test_doc_complex_singlehtml(test_app): diff --git a/tests/test_doc_build_latex.py b/tests/test_doc_build_latex.py deleted file mode 100644 index 11b3a89e8..000000000 --- a/tests/test_doc_build_latex.py +++ /dev/null @@ -1,29 +0,0 @@ -from pathlib import Path - -import pytest - - -@pytest.mark.parametrize( - "test_app", - [{"buildername": "latex", "srcdir": "doc_test/doc_build_latex"}], - indirect=True, -) -def test_doc_build_latex(test_app): - app = test_app - - app.build() - - latex_file = Path(app.outdir, "needstestdocs.tex") - assert latex_file - - latex_content = latex_file.read_text() - - # Check table generated by Sphinxneeds has correct caption - assert ( - "\\sphinxcaption{Table from sphinxneeds\\sphinxhyphen{}contrib \\textquotesingle" - "{}needtable\\textquotesingle{} directive}" in latex_content - ) - - # Check that the USER_STORY_001 label is only created once in the LaTeX output. Split - # on the string, which should split latex_content into two. - assert len(latex_content.split(r"\label{\detokenize{index:USER_STORY_001}}")) == 2