From 2a30c994a86283666eaed0fe10b26170a94f695f Mon Sep 17 00:00:00 2001 From: Stanislav Pankevich Date: Sun, 19 May 2024 22:30:26 +0200 Subject: [PATCH] backend/sdoc: allow using "DESCRIPTION" or "CONTENT" field instead of "STATEMENT" Closes #1823 --- strictdoc/backend/sdoc/error_handling.py | 30 +++++++++++-- .../backend/sdoc/models/document_grammar.py | 24 +++++++++-- strictdoc/backend/sdoc/models/free_text.py | 2 +- strictdoc/backend/sdoc/models/node.py | 38 ++++++++--------- strictdoc/backend/sdoc/models/type_system.py | 8 ++++ strictdoc/backend/sdoc/processor.py | 34 +++++++++++---- .../form_objects/requirement_form_object.py | 10 +++-- .../requirement/statement/index.jinja | 4 +- .../__init__.py | 0 .../expected_output/document.sdoc | 23 ++++++++++ .../input/document.sdoc | 23 ++++++++++ .../test_case.py | 42 +++++++++++++++++++ tests/integration/expect_exit.py | 2 +- .../input.sdoc | 29 +++++++++++++ .../test.itest | 10 +++++ .../test.itest | 5 +-- .../input.sdoc | 16 +++++++ .../test.itest | 6 +++ .../sdoc/test_requirement_from_dict.py | 3 ++ tools/confluence_html_table_import.py | 2 + 20 files changed, 267 insertions(+), 44 deletions(-) create mode 100644 tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/__init__.py create mode 100644 tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/expected_output/document.sdoc create mode 100644 tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/input/document.sdoc create mode 100644 tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/test_case.py create mode 100644 tests/integration/features/document_grammar/30_grammar_without_statement_field/input.sdoc create mode 100644 tests/integration/features/document_grammar/30_grammar_without_statement_field/test.itest create mode 100644 tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/input.sdoc create mode 100644 tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/test.itest diff --git a/strictdoc/backend/sdoc/error_handling.py b/strictdoc/backend/sdoc/error_handling.py index e1dc0a48c..fe1101c81 100644 --- a/strictdoc/backend/sdoc/error_handling.py +++ b/strictdoc/backend/sdoc/error_handling.py @@ -261,12 +261,36 @@ def grammar_missing_reserved_statement( return StrictDocSemanticError( title=( f"Grammar element '{grammar_element.tag}' is missing a reserved" - " STATEMENT field declaration." + " content field declaration, one of {STATEMENT, DESCRIPTION, CONTENT}." ), hint=( - "STATEMENT plays a key role in StrictDoc's HTML user interface " + "A content field plays a key role in StrictDoc's HTML user interface " "as well as in the other export formats. It is a reserved field" - " that any grammar must provide." + " that any grammar element must have." + ), + example=None, + line=line, + col=column, + filename=path_to_sdoc_file, + ) + + @staticmethod + def grammar_reserved_statement_must_be_required( + grammar_element: GrammarElement, + field_title: str, + path_to_sdoc_file: str, + line: int, + column: int, + ): + return StrictDocSemanticError( + title=( + f"Grammar element '{grammar_element.tag}'s {field_title} field " + f"must be declared as 'REQUIRED: True'." + ), + hint=( + "A content field plays a key role in StrictDoc's HTML user interface " + "as well as in the other export formats. It is a reserved field" + " that any grammar element must have with 'REQUIRED: True'." ), example=None, line=line, diff --git a/strictdoc/backend/sdoc/models/document_grammar.py b/strictdoc/backend/sdoc/models/document_grammar.py index 3420d7c65..8c05b3063 100644 --- a/strictdoc/backend/sdoc/models/document_grammar.py +++ b/strictdoc/backend/sdoc/models/document_grammar.py @@ -1,6 +1,6 @@ # mypy: disable-error-code="no-redef,no-untyped-call,no-untyped-def,union-attr,type-arg" from collections import OrderedDict -from typing import Dict, List, Optional, Set, Union +from typing import Dict, List, Optional, Set, Tuple, Union from strictdoc.backend.sdoc.models.type_system import ( RESERVED_NON_META_FIELDS, @@ -75,9 +75,27 @@ def __init__( else create_default_relations(self) ) fields_map: OrderedDict = OrderedDict() - for field in fields: - fields_map[field.title] = field + + statement_field: Optional[Tuple[str, int]] = None + description_field: Optional[Tuple[str, int]] = None + content_field: Optional[Tuple[str, int]] = None + for field_idx_, field_ in enumerate(fields): + fields_map[field_.title] = field_ + if field_.title == RequirementFieldName.STATEMENT: + statement_field = (RequirementFieldName.STATEMENT, field_idx_) + elif field_.title == "DESCRIPTION": + description_field = ( + RequirementFieldName.DESCRIPTION, + field_idx_, + ) + elif field_.title == "CONTENT": + content_field = (RequirementFieldName.CONTENT, field_idx_) + else: + pass self.fields_map: Dict[str, GrammarElementField] = fields_map + self.content_field: Tuple[str, int] = ( + statement_field or description_field or content_field or ("", -1) + ) self.mid: MID = MID.create() @staticmethod diff --git a/strictdoc/backend/sdoc/models/free_text.py b/strictdoc/backend/sdoc/models/free_text.py index 820bbc02b..00a4d6be6 100644 --- a/strictdoc/backend/sdoc/models/free_text.py +++ b/strictdoc/backend/sdoc/models/free_text.py @@ -1,5 +1,5 @@ import html -from typing import List, Any, Optional +from typing import Any, List, Optional from strictdoc.backend.sdoc.models.anchor import Anchor from strictdoc.backend.sdoc.models.inline_link import InlineLink diff --git a/strictdoc/backend/sdoc/models/node.py b/strictdoc/backend/sdoc/models/node.py index 3309fb5f4..538d5be81 100644 --- a/strictdoc/backend/sdoc/models/node.py +++ b/strictdoc/backend/sdoc/models/node.py @@ -205,8 +205,11 @@ def reserved_title(self) -> Optional[str]: @property def reserved_statement(self) -> Optional[str]: + element: GrammarElement = self.document.grammar.elements_by_type[ + self.requirement_type + ] return self._get_cached_field( - RequirementFieldName.STATEMENT, singleline_only=False + element.content_field[0], singleline_only=False ) @property @@ -276,6 +279,12 @@ def get_requirement_style_mode(self) -> str: assert self.ng_document_reference.get_document() is not None return self.ng_document_reference.get_document().config.get_requirement_style_mode() + def get_content_field_name(self) -> str: + element: GrammarElement = self.document.grammar.elements_by_type[ + self.requirement_type + ] + return element.content_field[0] + def has_requirement_references(self, ref_type: str) -> bool: if len(self.relations) == 0: return False @@ -374,9 +383,7 @@ def enumerate_meta_fields( self.requirement_type ] grammar_field_titles = list(map(lambda f: f.title, element.fields)) - statement_field_index = grammar_field_titles.index( - RequirementFieldName.STATEMENT - ) + statement_field_index: int = element.content_field[1] for field in self.enumerate_fields(): if field.field_name in RESERVED_NON_META_FIELDS: continue @@ -412,6 +419,13 @@ def get_field_human_title(self, field_name: str) -> str: field_human_title = element.fields_map[field_name] return field_human_title.get_field_human_name() + def get_field_human_title_for_statement(self) -> str: + element: GrammarElement = self.document.grammar.elements_by_type[ + self.requirement_type + ] + field_human_title = element.fields_map[element.content_field[0]] + return field_human_title.get_field_human_name() + def get_requirement_prefix(self) -> str: parent: Union[SDocSection, SDocDocument] = assert_cast( self.parent, (SDocSection, SDocDocument, SDocCompositeNode) @@ -479,25 +493,11 @@ def set_field_value( self.requirement_type ] grammar_field_titles = list(map(lambda f: f.title, element.fields)) - # FIXME: This will go away very soon when the RELATIONS become a - # separate field in SDoc REQUIREMENT's grammar. - grammar_field_titles.append("REFS") field_index = grammar_field_titles.index(field_name) - try: - title_field_index = grammar_field_titles.index( - RequirementFieldName.TITLE - ) - except ValueError: - # It is a rare edge case when a grammar is without a TITLE but if it - # happens, use STATEMENT as a fallback. - title_field_index = grammar_field_titles.index( - RequirementFieldName.STATEMENT - ) - field_value = None field_value_multiline = None - if field_index <= title_field_index: + if field_index < element.content_field[1]: field_value = value else: field_value_multiline = value diff --git a/strictdoc/backend/sdoc/models/type_system.py b/strictdoc/backend/sdoc/models/type_system.py index 6815d7a17..c8049df8b 100644 --- a/strictdoc/backend/sdoc/models/type_system.py +++ b/strictdoc/backend/sdoc/models/type_system.py @@ -11,7 +11,13 @@ class RequirementFieldName: STATUS = "STATUS" TAGS = "TAGS" TITLE = "TITLE" + + # {STATEMENT, DESCRIPTION, CONTENT} are aliases. + # It is assumed that either field is provided for each node. STATEMENT = "STATEMENT" + DESCRIPTION = "DESCRIPTION" + CONTENT = "CONTENT" + RATIONALE = "RATIONALE" COMMENT = "COMMENT" @@ -19,6 +25,8 @@ class RequirementFieldName: RESERVED_NON_META_FIELDS = [ RequirementFieldName.TITLE, RequirementFieldName.STATEMENT, + RequirementFieldName.DESCRIPTION, + RequirementFieldName.CONTENT, RequirementFieldName.COMMENT, RequirementFieldName.RATIONALE, RequirementFieldName.LEVEL, diff --git a/strictdoc/backend/sdoc/processor.py b/strictdoc/backend/sdoc/processor.py index d7ab0dd51..a1a3ecc41 100644 --- a/strictdoc/backend/sdoc/processor.py +++ b/strictdoc/backend/sdoc/processor.py @@ -19,6 +19,10 @@ SDocNode, ) from strictdoc.backend.sdoc.models.section import SDocSection +from strictdoc.backend.sdoc.models.type_system import ( + GrammarElementField, + RequirementFieldName, +) from strictdoc.helpers.exception import StrictDocException @@ -29,13 +33,10 @@ def __init__(self, path_to_sdoc_file: Optional[str]): if path_to_sdoc_file is not None: assert os.path.isfile(path_to_sdoc_file), path_to_sdoc_file self.path_to_sdoc_dir = os.path.dirname(path_to_sdoc_file) - + self.document_grammar: Optional[DocumentGrammar] = None self.document_reference: DocumentReference = DocumentReference() self.context_document_reference: DocumentReference = DocumentReference() self.document_config: Optional[DocumentConfig] = None - self.document_grammar: DocumentGrammar = DocumentGrammar.create_default( - None - ) self.document_view: Optional[DocumentView] = None self.document_has_requirements = False @@ -48,7 +49,10 @@ def __init__(self, parse_context: ParseContext): self.parse_context: ParseContext = parse_context def process_document(self, document: SDocDocument): - document.grammar = self.parse_context.document_grammar + document.grammar = ( + self.parse_context.document_grammar + or DocumentGrammar.create_default(document) + ) self.parse_context.document = document document.ng_including_document_reference = ( self.parse_context.context_document_reference @@ -86,12 +90,26 @@ def process_document_grammar_element(self, grammar_element: GrammarElement): grammar_element._tx_position ) + if grammar_element.content_field[0] not in grammar_element.fields_map: + raise StrictDocSemanticError.grammar_missing_reserved_statement( + grammar_element, + self.parse_context.path_to_sdoc_file, + line_start, + col_start, + ) + content_field: GrammarElementField = grammar_element.fields_map[ + grammar_element.content_field[0] + ] + # FIXME: Enable for STATEMENT as well. For now, don't want to break + # backward compatibility. if ( - grammar_element.tag == "REQUIREMENT" - and "STATEMENT" not in grammar_element.fields_map + content_field.title + in (RequirementFieldName.DESCRIPTION, RequirementFieldName.CONTENT) + and not content_field.required ): - raise StrictDocSemanticError.grammar_missing_reserved_statement( + raise StrictDocSemanticError.grammar_reserved_statement_must_be_required( grammar_element, + content_field.title, self.parse_context.path_to_sdoc_file, line_start, col_start, diff --git a/strictdoc/export/html/form_objects/requirement_form_object.py b/strictdoc/export/html/form_objects/requirement_form_object.py index 3e08a9c7e..d1082a274 100644 --- a/strictdoc/export/html/form_objects/requirement_form_object.py +++ b/strictdoc/export/html/form_objects/requirement_form_object.py @@ -644,13 +644,15 @@ def validate( ), ) - requirement_statement = self.fields["STATEMENT"][ + requirement_element = self.grammar.elements_by_type[self.element_type] + statement_field_name = requirement_element.content_field[0] + requirement_statement = self.fields[statement_field_name][ 0 ].field_unescaped_value if requirement_statement is None or len(requirement_statement) == 0: self.add_error( - "STATEMENT", - "Node statement must not be empty.", + statement_field_name, + f"Node {statement_field_name.lower()} must not be empty.", ) else: ( @@ -661,7 +663,7 @@ def validate( context_document=context_document, ).write_with_validation(requirement_statement) if parsed_html is None: - self.add_error("STATEMENT", rst_error) + self.add_error(statement_field_name, rst_error) requirement_uid: Optional[str] = ( self.fields["UID"][0].field_unescaped_value diff --git a/strictdoc/export/html/templates/components/requirement/statement/index.jinja b/strictdoc/export/html/templates/components/requirement/statement/index.jinja index 76e6b66b8..1053cf870 100644 --- a/strictdoc/export/html/templates/components/requirement/statement/index.jinja +++ b/strictdoc/export/html/templates/components/requirement/statement/index.jinja @@ -1,4 +1,4 @@ -{%- if requirement.reserved_statement and view_object.current_view.includes_field(requirement.requirement_type, "STATEMENT") -%} +{%- if requirement.reserved_statement and view_object.current_view.includes_field(requirement.requirement_type, requirement.get_content_field_name()) -%} {%- if truncated_statement is true -%} {# truncated in DTR tiny card #} @@ -6,7 +6,7 @@ {%- else -%} {# default with label #} - {{ requirement.get_field_human_title("STATEMENT") }}: + {{ requirement.get_field_human_title_for_statement() }}: diff --git a/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/__init__.py b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/expected_output/document.sdoc b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/expected_output/document.sdoc new file mode 100644 index 000000000..b2031d66d --- /dev/null +++ b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/expected_output/document.sdoc @@ -0,0 +1,23 @@ +[DOCUMENT] +TITLE: Document 1 + +[GRAMMAR] +ELEMENTS: +- TAG: REQUIREMENT + FIELDS: + - TITLE: TITLE + TYPE: String + REQUIRED: True + - TITLE: DESCRIPTION + TYPE: String + REQUIRED: True + +[FREETEXT] +Hello world! +[/FREETEXT] + +[REQUIREMENT] +TITLE: Requirement title +DESCRIPTION: >>> +Requirement statement. +<<< diff --git a/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/input/document.sdoc b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/input/document.sdoc new file mode 100644 index 000000000..b2031d66d --- /dev/null +++ b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/input/document.sdoc @@ -0,0 +1,23 @@ +[DOCUMENT] +TITLE: Document 1 + +[GRAMMAR] +ELEMENTS: +- TAG: REQUIREMENT + FIELDS: + - TITLE: TITLE + TYPE: String + REQUIRED: True + - TITLE: DESCRIPTION + TYPE: String + REQUIRED: True + +[FREETEXT] +Hello world! +[/FREETEXT] + +[REQUIREMENT] +TITLE: Requirement title +DESCRIPTION: >>> +Requirement statement. +<<< diff --git a/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/test_case.py b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/test_case.py new file mode 100644 index 000000000..b0a3bcf4a --- /dev/null +++ b/tests/end2end/screens/document/update_requirement/_validation/update_requirement_empty_statement_DESCRIPTION_instead_STATEMENT/test_case.py @@ -0,0 +1,42 @@ +from tests.end2end.e2e_case import E2ECase +from tests.end2end.end2end_test_setup import End2EndTestSetup +from tests.end2end.helpers.screens.document.form_edit_requirement import ( + Form_EditRequirement, +) +from tests.end2end.helpers.screens.project_index.screen_project_index import ( + Screen_ProjectIndex, +) +from tests.end2end.server import SDocTestServer + + +class Test(E2ECase): + def test(self): + test_setup = End2EndTestSetup(path_to_test_file=__file__) + + with SDocTestServer( + input_path=test_setup.path_to_sandbox + ) as test_server: + self.open(test_server.get_host_and_port()) + + screen_project_index = Screen_ProjectIndex(self) + + screen_project_index.assert_on_screen() + screen_project_index.assert_contains_document("Document 1") + + screen_document = screen_project_index.do_click_on_first_document() + + screen_document.assert_on_screen_document() + screen_document.assert_header_document_title("Document 1") + + screen_document.assert_text("Hello world!") + + requirement = screen_document.get_requirement() + form_edit_requirement: Form_EditRequirement = ( + requirement.do_open_form_edit_requirement() + ) + form_edit_requirement.do_clear_field("DESCRIPTION") + form_edit_requirement.do_form_submit_and_catch_error( + "Node description must not be empty." + ) + + assert test_setup.compare_sandbox_and_expected_output() diff --git a/tests/integration/expect_exit.py b/tests/integration/expect_exit.py index 24d6c0fc1..badb45a5d 100644 --- a/tests/integration/expect_exit.py +++ b/tests/integration/expect_exit.py @@ -52,7 +52,7 @@ if unexpected_exit_code: print( # noqa: T201 "error: expect_exit: expected exit code: " - "f{expected_exit_code}, actual: {process.returncode}." + f"{expected_exit_code}, actual: {process.returncode}." ) unexpected_content = expect_no_content and len(stdout) > 0 diff --git a/tests/integration/features/document_grammar/30_grammar_without_statement_field/input.sdoc b/tests/integration/features/document_grammar/30_grammar_without_statement_field/input.sdoc new file mode 100644 index 000000000..7ca15e996 --- /dev/null +++ b/tests/integration/features/document_grammar/30_grammar_without_statement_field/input.sdoc @@ -0,0 +1,29 @@ +[DOCUMENT] +TITLE: Test document + +[GRAMMAR] +ELEMENTS: +- TAG: THREAT + FIELDS: + - TITLE: UID + TYPE: String + REQUIRED: True + - TITLE: TITLE + TYPE: String + REQUIRED: True + - TITLE: DESCRIPTION + TYPE: String + REQUIRED: True + - TITLE: SEVERITY + TYPE: SingleChoice(Low, Medium, High) + REQUIRED: True + - TITLE: SCORE + TYPE: String + REQUIRED: False + +[THREAT] +UID: ABC-123 +TITLE: Title +DESCRIPTION: Description. +SEVERITY: Low +SCORE: Score. diff --git a/tests/integration/features/document_grammar/30_grammar_without_statement_field/test.itest b/tests/integration/features/document_grammar/30_grammar_without_statement_field/test.itest new file mode 100644 index 000000000..6d7bbdb85 --- /dev/null +++ b/tests/integration/features/document_grammar/30_grammar_without_statement_field/test.itest @@ -0,0 +1,10 @@ +RUN: %strictdoc export %S --output-dir Output/ | filecheck %s --dump-input=fail +CHECK: Published: Test document + +RUN: %cat %S/Output/html/30_grammar_without_statement_field/input.html | filecheck %s --dump-input=fail --check-prefix CHECK-HTML + +CHECK-HTML: ABC-123 +CHECK-HTML: Title +CHECK-HTML: Description. +CHECK-HTML: Low +CHECK-HTML: Score. \ No newline at end of file diff --git a/tests/integration/features/document_grammar/validation/07_grammar_missing_reserved_statement_field/test.itest b/tests/integration/features/document_grammar/validation/07_grammar_missing_reserved_statement_field/test.itest index efd637b51..0519fbd8b 100644 --- a/tests/integration/features/document_grammar/validation/07_grammar_missing_reserved_statement_field/test.itest +++ b/tests/integration/features/document_grammar/validation/07_grammar_missing_reserved_statement_field/test.itest @@ -1,7 +1,6 @@ RUN: %expect_exit 1 %strictdoc export %S --output-dir Output/ | filecheck %s --dump-input=fail -CHECK: error: could not parse file: {{.*}}input.sdoc. -CHECK: Semantic error: Grammar element 'REQUIREMENT' is missing a reserved STATEMENT field declaration. +CHECK: Semantic error: Grammar element 'REQUIREMENT' is missing a reserved content field declaration, one of {STATEMENT, DESCRIPTION, CONTENT}. CHECK: Location: {{.*}}input.sdoc:6:1 -CHECK: Hint: STATEMENT plays a key role in StrictDoc's HTML user interface as well as in the other export formats. It is a reserved field that any grammar must provide. +CHECK: Hint: A content field plays a key role in StrictDoc's HTML user interface as well as in the other export formats. It is a reserved field that any grammar element must have. CHECK: error: Parallelizer: One of the child processes has exited prematurely. diff --git a/tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/input.sdoc b/tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/input.sdoc new file mode 100644 index 000000000..f71b1a6ce --- /dev/null +++ b/tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/input.sdoc @@ -0,0 +1,16 @@ +[DOCUMENT] +TITLE: Test document + +[GRAMMAR] +ELEMENTS: +- TAG: REQUIREMENT + FIELDS: + - TITLE: TITLE + TYPE: String + REQUIRED: True + - TITLE: DESCRIPTION + TYPE: String + REQUIRED: False + +[REQUIREMENT] +TITLE: Hello diff --git a/tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/test.itest b/tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/test.itest new file mode 100644 index 000000000..f37adbe8b --- /dev/null +++ b/tests/integration/features/document_grammar/validation/08_grammar_reserved_statement_field_must_be_declared_REQUIRED_True/test.itest @@ -0,0 +1,6 @@ +RUN: %expect_exit 1 %strictdoc export %S --output-dir Output/ | filecheck %s --dump-input=fail + +CHECK: Semantic error: Grammar element 'REQUIREMENT's DESCRIPTION field must be declared as 'REQUIRED: True'. +CHECK: Location: {{.*}}input.sdoc:6:1 +CHECK: Hint: A content field plays a key role in StrictDoc's HTML user interface as well as in the other export formats. It is a reserved field that any grammar element must have with 'REQUIRED: True'. +CHECK: error: Parallelizer: One of the child processes has exited prematurely. diff --git a/tests/unit/strictdoc/backend/sdoc/test_requirement_from_dict.py b/tests/unit/strictdoc/backend/sdoc/test_requirement_from_dict.py index 91806f422..bb6413bbd 100644 --- a/tests/unit/strictdoc/backend/sdoc/test_requirement_from_dict.py +++ b/tests/unit/strictdoc/backend/sdoc/test_requirement_from_dict.py @@ -1,3 +1,4 @@ +from strictdoc.backend.sdoc.models.document_grammar import DocumentGrammar from strictdoc.backend.sdoc.models.object_factory import SDocObjectFactory from strictdoc.backend.sdoc.models.type_system import RequirementFieldName @@ -10,6 +11,7 @@ def test_010_full_dict(): RequirementFieldName.RATIONALE: "REQ RATIONALE", } document = SDocObjectFactory.create_document(title="NONAME") + document.grammar = DocumentGrammar.create_default(document) requirement = SDocObjectFactory.create_requirement_from_dict( requirement_dict, document, 1 ) @@ -34,6 +36,7 @@ def test_010_full_dict(): def test_020_empty_dict(): requirement_dict = {} document = SDocObjectFactory.create_document(title=None) + document.grammar = DocumentGrammar.create_default(document) requirement = SDocObjectFactory.create_requirement_from_dict( requirement_dict, document, 1 ) diff --git a/tools/confluence_html_table_import.py b/tools/confluence_html_table_import.py index 7b8da18ef..eab172ca2 100644 --- a/tools/confluence_html_table_import.py +++ b/tools/confluence_html_table_import.py @@ -6,6 +6,7 @@ from bs4 import BeautifulSoup from strictdoc.backend.sdoc.document_reference import DocumentReference +from strictdoc.backend.sdoc.models.document_grammar import DocumentGrammar from strictdoc.backend.sdoc.models.object_factory import SDocObjectFactory STRICTDOC_ROOT_PATH = os.path.join(os.path.dirname(__file__), "..") @@ -47,6 +48,7 @@ def import_from_file(path_to_html): free_texts=[], section_contents=[], ) + document.grammar = DocumentGrammar.create_default(document) for section_idx, reqs in enumerate(reqs_array_array): section_name = headers[section_idx].text section = SDocSection(