From 2b526fcc995a9f6676730c381028566f208bcf7f Mon Sep 17 00:00:00 2001 From: Luciano <41302084+Rossi-Luciano@users.noreply.github.com> Date: Fri, 27 Dec 2024 10:33:55 -0300 Subject: [PATCH] Feat: footnotes validation (#702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adiciona atributos ausentes em 'corresp' e 'fn' * Adequa os testes * Adiciona validação para 'label', 'title' e 'bold' * Adequa os testes * Corrige 'BaseNoteGroups' * Corrige teste * Refatora módulo 'footnotes.py' * Adapta e adiciona testes * Refatora validação de notas * Adequa os testes * Adiciona 'fn_rules.json' * Refatora validação de notas de rodapé * Adapta os testes * Corrige local de 'validation_rules' * Renomeia funções --- packtools/sps/models/v2/notes.py | 25 +- packtools/sps/validation/footnotes.py | 341 ++++++++++++------- packtools/validation_rules/__init__.py | 0 packtools/validation_rules/fn_rules.json | 9 + tests/sps/models/v2/test_notes.py | 225 ++++++++----- tests/sps/validation/test_footnotes.py | 400 ++++++++++++++--------- 6 files changed, 648 insertions(+), 352 deletions(-) create mode 100644 packtools/validation_rules/__init__.py create mode 100644 packtools/validation_rules/fn_rules.json diff --git a/packtools/sps/models/v2/notes.py b/packtools/sps/models/v2/notes.py index 48ed2d1b3..60dbd54ce 100644 --- a/packtools/sps/models/v2/notes.py +++ b/packtools/sps/models/v2/notes.py @@ -32,7 +32,12 @@ def __init__(self, article_or_sub_article_node, fn_parent_tag_name, NoteGroupCla @property def items(self): - for fn_parent_node in self.article_or_sub_article_node.xpath(f".//{self.fn_parent_tag_name}"): + if self.parent == "article": + xpath = f".//front//{self.fn_parent_tag_name} | .//body//{self.fn_parent_tag_name} | .//back//{self.fn_parent_tag_name}" + else: + xpath = f".//{self.fn_parent_tag_name}" + + for fn_parent_node in self.article_or_sub_article_node.xpath(xpath): data = self.NoteGroupClass(fn_parent_node).data yield put_parent_context(data, self.parent_lang, self.parent_article_type, self.parent, self.parent_id) @@ -45,6 +50,7 @@ def __init__(self, node): self.label = self.node.findtext("label") self.text = process_subtags(self.node) self.bold = self.node.findtext("bold") + self.title = self.node.findtext("title") @property def data(self): @@ -53,7 +59,8 @@ def data(self): "fn_type": self.type, "fn_label": self.label, "fn_text": self.text, - "fn_bold": self.bold + "fn_bold": self.bold, + "fn_title": self.title } @@ -91,13 +98,23 @@ def corresp(self): def corresp_label(self): return process_subtags(self.fn_parent_node.find("corresp/label")) + @property + def corresp_title(self): + return process_subtags(self.fn_parent_node.find("corresp/title")) + + @property + def corresp_bold(self): + return process_subtags(self.fn_parent_node.find("corresp/bold")) + @property def data(self): return { **super().data, "corresp": self.corresp, - "corresp_label": self.corresp_label - } + "corresp_label": self.corresp_label, + "corresp_title": self.corresp_title, + "corresp_bold": self.corresp_bold + } class AuthorNotes(BaseNoteGroups): diff --git a/packtools/sps/validation/footnotes.py b/packtools/sps/validation/footnotes.py index f1f674c82..c40c95f70 100644 --- a/packtools/sps/validation/footnotes.py +++ b/packtools/sps/validation/footnotes.py @@ -1,146 +1,241 @@ -from packtools.sps.models.footnotes import ArticleFootnotes -from packtools.sps.models.article_and_subarticles import ArticleAndSubArticles +from packtools.sps.models.v2.notes import ArticleNotes from packtools.sps.validation.utils import format_response from packtools.sps.validation.exceptions import ValidationFootnotes -class FootnoteValidation: - def __init__(self, xmltree): - self.xmltree = xmltree +class FnValidation: + """ + Validates individual footnotes based on provided rules and DTD version. + + Attributes: + fn_data (dict): The data of the footnote to be validated. + rules (dict): Validation rules with error levels. + dtd_version (float): The DTD version for specific validations. + """ + + def __init__(self, fn_data, rules, dtd_version): + """ + Initialize the FnValidation object. + + Args: + fn_data (dict): Data related to the footnote. + rules (dict): Rules defining validation constraints and error levels. + dtd_version (float): The version of the DTD schema. + """ + self.fn_data = fn_data + self.rules = rules + self.dtd_version = dtd_version + + def _generate_response(self, name, expected=None, obtained=None, advice=None): + """ + Generate a standardized validation response. + + Args: + name (str): The name of the validation. + expected (str, optional): The expected value for the validation. Defaults to None. + obtained (str, optional): The obtained value for the validation. Defaults to None. + advice (str, optional): Suggestion to fix the issue. Defaults to None. + + Returns: + dict: A formatted response detailing the validation result. + """ + key_error_level = f"fn_{name}_error_level" + return format_response( + title=name, + parent=None, + parent_id=None, + parent_article_type=None, + parent_lang=None, + item=name, + sub_item=None, + validation_type="exist", + is_valid=False, + expected=expected or name, + obtained=obtained, + advice=advice or f"Identify the {name}", + data=self.fn_data, + error_level=self.rules[key_error_level], + ) + + def _validate(self, condition, name, expected=None, obtained=None, advice=None): + """ + Perform a validation and generate a response if the condition fails. + + Args: + condition (bool): Condition to validate. If False, it generates a response. + name (str): The name of the validation. + expected (str, optional): The expected value. Defaults to None. + obtained (str, optional): The obtained value. Defaults to None. + advice (str, optional): Suggestion to fix the issue. Defaults to None. + + Returns: + dict or None: A validation response if the condition fails, otherwise None. + """ + if condition: + return self._generate_response(name, expected, obtained, advice) + return None + + def validate(self): + """ + Execute all registered validations for the footnote. + + Returns: + list[dict]: A list of validation responses (excluding None responses). + """ + validations = [ + self.validate_label, + self.validate_title, + self.validate_bold, + self.validate_type, + self.validate_dtd_version, + ] + return [response for validate in validations if (response := validate())] + + # Individual validation methods + def validate_label(self): + """ + Validate the presence of the 'label' in the footnote. + """ + return self._validate(not self.fn_data.get("fn_label"), name="label") + + def validate_title(self): + """ + Validate the presence of 'title' when 'label' is expected. + """ + return self._validate( + self.fn_data.get("fn_title"), + name="title", + expected="label", + obtained="title", + advice="Replace title by label", + ) + + def validate_bold(self): + """ + Validate the presence of 'bold' when 'label' is expected. + """ + return self._validate( + self.fn_data.get("fn_bold"), + name="bold", + expected="label", + obtained="bold", + advice="Replace bold by label", + ) + + def validate_type(self): + """ + Validate the presence of 'type' in the footnote. + """ + return self._validate(not self.fn_data.get("fn_type"), name="type") + + def validate_dtd_version(self): + """ + Validate the 'dtd_version' of the footnote for compatibility with its type. + """ + fn_type = self.fn_data.get("fn_type") + if self.dtd_version: + if self.dtd_version >= 1.3 and fn_type == "conflict": + return self._validate( + True, + name="dtd_version", + expected='', + obtained='', + advice="Replace conflict with coi-statement", + ) + elif self.dtd_version < 1.3 and fn_type == "coi-statement": + return self._validate( + True, + name="dtd_version", + expected='', + obtained='', + advice="Replace coi-statement with conflict", + ) + + +class FnGroupValidation: + """ + Validates groups of footnotes in an XML document. + + Attributes: + xml_tree (ElementTree): The XML tree representing the document. + rules (dict): Validation rules. + """ + + def __init__(self, xml_tree, rules): + """ + Initialize the FnGroupValidation object. + + Args: + xml_tree (ElementTree): The XML tree to validate. + rules (dict): Validation rules. + """ + self.xml_tree = xml_tree + self.rules = rules + self.article_fn_groups = list(ArticleNotes(xml_tree).article_fn_groups_notes()) + self.sub_article_fn_groups = list(ArticleNotes(xml_tree).sub_article_fn_groups_notes()) @property - def dtd_version(self): - article = ArticleAndSubArticles(self.xmltree) - return article.main_dtd_version - - def fn_validation(self): - """ - Checks if fn-type is coi-statement for dtd-version >= 1.3 - - XML input - --------- -
- - - - -

Os autores declaram não haver conflito de interesses.

-
-
-
-
- - - - -

The authors declare there is no conflict of interest.

-
-
-
-
-
- - Returns - ------- - list of dict - A list of dictionaries, such as: - [ - { - 'title': 'Footnotes validation', - 'parent': 'article', - 'parent_id': None, - 'parent_article_type': 'research-article', - 'parent_lang': 'pt', - 'item': 'author-notes', - 'sub_item': 'fn', - 'validation_type': 'match', - 'response': 'ERROR', - 'expected_value': '', - 'got_value': '', - 'message': 'Got , expected ', - 'advice': 'replace conflict with coi-statement', - 'data': { - 'fn_id': 'fn_01', - 'fn_parent': 'author-notes', - 'fn_type': 'conflict', - 'parent': 'article', - 'parent_id': None, - 'parent_article_type': 'research-article', - 'parent_lang': 'pt' - }, - },... - ] + def _dtd_version(self): + """ + Retrieve the DTD version from the XML document. + + Returns: + float: The DTD version. + + Raises: + ValidationFootnotes: If the DTD version is not valid. """ try: - dtd = float(self.dtd_version) + dtd = float(self.xml_tree.find(".").get("dtd-version")) except (TypeError, ValueError) as e: raise ValidationFootnotes(f"dtd-version is not valid: {str(e)}") - if not dtd: - return + return dtd - fns = ArticleFootnotes(self.xmltree) - for fn in fns.article_footnotes: - fn_type = fn.get("fn_type") - parent = fn.get("parent") - parent_id = fn.get("parent_id") - parent_article_type = fn.get("parent_article_type") - parent_lang = fn.get("parent_lang") - fn_parent = fn.get("fn_parent") - - if dtd >= 1.3 and fn_type == "conflict": - yield self._generate_response(fn, parent, parent_id, parent_article_type, parent_lang, fn_parent, "coi-statement", "conflict") - elif dtd < 1.3 and fn_type == "coi-statement": - yield self._generate_response(fn, parent, parent_id, parent_article_type, parent_lang, fn_parent, "conflict", "coi-statement") - - def _generate_response(self, fn, parent, parent_id, parent_article_type, parent_lang, fn_parent, expected, obtained): + def validate(self): """ - Helper method to generate the response dictionary for validation. - - Params - ------ - fn : dict - The footnote dictionary. + Validate all footnote groups in the XML document. - parent : str - The parent element. + Yields: + dict: Validation results for each footnote. + """ + for fn_group in [*self.article_fn_groups, *self.sub_article_fn_groups]: + context = self._build_context(fn_group) + for fn in fn_group.get("fns", []): + yield from self.validate_fn(fn, context) - parent_id : str or None - The parent ID if available. + def _build_context(self, fn_group): + """ + Build the context for a specific footnote group. - parent_article_type : str - The type of the parent article. + Args: + fn_group (dict): A group of footnotes. - parent_lang : str - The language of the parent article. + Returns: + dict: Context containing metadata about the parent element. + """ + return { + "parent": fn_group.get("parent"), + "parent_id": fn_group.get("parent_id"), + "parent_article_type": fn_group.get("parent_article_type"), + "parent_lang": fn_group.get("parent_lang"), + } - fn_parent : str - The footnote parent element. - expected : str - The expected value. + def validate_fn(self, fn, context): + """ + Validate an individual footnote and update the response with context. - obtained : str - The obtained value. + Args: + fn (dict): The footnote to validate. + context (dict): Context metadata for the footnote. - Returns - ------- - dict - The formatted response dictionary. + Yields: + dict: Validation results for the footnote. """ - return format_response( - title="Footnotes validation", - parent=parent, - parent_id=parent_id, - parent_article_type=parent_article_type, - parent_lang=parent_lang, - item=fn_parent, - sub_item="fn", - validation_type="match", - is_valid=False, - expected=f'', - obtained=f'', - advice=f"replace {obtained} with {expected}", - data=fn + validator = FnValidation( + fn_data=fn, rules=self.rules, dtd_version=self._dtd_version ) + for response in validator.validate(): + response.update(context) + yield response diff --git a/packtools/validation_rules/__init__.py b/packtools/validation_rules/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/packtools/validation_rules/fn_rules.json b/packtools/validation_rules/fn_rules.json new file mode 100644 index 000000000..0d8605df6 --- /dev/null +++ b/packtools/validation_rules/fn_rules.json @@ -0,0 +1,9 @@ +{ + "fn_rules": { + "fn_label_error_level": "WARNING", + "fn_title_error_level": "WARNING", + "fn_bold_error_level": "WARNING", + "fn_type_error_level": "ERROR", + "fn_dtd_version_error_level": "ERROR", + } +} diff --git a/tests/sps/models/v2/test_notes.py b/tests/sps/models/v2/test_notes.py index aaed22123..2c0f15ad8 100644 --- a/tests/sps/models/v2/test_notes.py +++ b/tests/sps/models/v2/test_notes.py @@ -54,7 +54,8 @@ def test_fn_data(self): "fn_type": "conflict", "fn_label": "1", "fn_text": "*1Os autores declaram não haver conflito de interesses.", - "fn_bold": "*" + "fn_bold": "*", + 'fn_title': None, } ) @@ -91,7 +92,8 @@ def test_fn_group(self): 'fn_label': None, 'fn_type': 'other', 'fn_parent': 'fn-group', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, }, { 'fn_id': 'fn3', @@ -100,7 +102,8 @@ def test_fn_group(self): 'fn_label': None, 'fn_type': 'other', 'fn_parent': 'fn-group', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, }, { 'fn_id': 'fn4', @@ -109,7 +112,8 @@ def test_fn_group(self): 'fn_label': None, 'fn_type': 'other', 'fn_parent': 'fn-group', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, } ] for i, item in enumerate(obtained): @@ -158,7 +162,8 @@ def test_fn_groups(self): 'fn_label': None, 'fn_type': 'other', 'fn_parent': 'fn-group', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, }, { 'fn_id': 'fn3', @@ -167,7 +172,8 @@ def test_fn_groups(self): 'fn_label': None, 'fn_type': 'other', 'fn_parent': 'fn-group', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, }, { 'fn_id': 'fn4', @@ -176,7 +182,8 @@ def test_fn_groups(self): 'fn_label': None, 'fn_type': 'other', 'fn_parent': 'fn-group', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, } ] } @@ -219,7 +226,8 @@ def test_author_note(self): 'fn_parent': 'author-notes', 'fn_text': '1Os autores declaram não haver conflito de interesses.', 'fn_type': 'conflict', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, } ] for i, item in enumerate(obtained): @@ -278,6 +286,8 @@ def test_author_notes(self): 'Recanto Real Rua 4, 440 15021-450 São José do Rio Preto, SP, ' 'Brasil E-mail: roseanap@gmail.com', 'corresp_label': 'Correspondência', + "corresp_title": None, + "corresp_bold": None, 'fns': [ { 'fn_id': 'fn_01', @@ -285,7 +295,8 @@ def test_author_notes(self): 'fn_parent': 'author-notes', 'fn_text': '1Os autores declaram não haver conflito de interesses.', 'fn_type': 'conflict', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, }, ] }, @@ -297,6 +308,8 @@ def test_author_notes(self): 'corresp': '*Correspondence: Dr. Edmundo Figueira Departamento de ' 'Fisioterapia,Universidade FISP - Hogwarts,', 'corresp_label': '*', + "corresp_title": None, + "corresp_bold": 'Correspondence', 'fns': [ { 'fn_id': None, @@ -304,7 +317,8 @@ def test_author_notes(self): 'fn_parent': 'author-notes', 'fn_text': 'Não há conflito de interesse entre os autores do artigo.', 'fn_type': 'coi-statement', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, }, { 'fn_id': None, @@ -312,7 +326,8 @@ def test_author_notes(self): 'fn_parent': 'author-notes', 'fn_text': 'Todos os autores tiveram contribuição igualitária na criação do artigo.', 'fn_type': 'equal', - 'fn_bold': None + 'fn_bold': None, + 'fn_title': None, } ] } @@ -370,6 +385,20 @@ def setUp(self): '' '' '' + '' + '' + '' + '' + ': John Doe, Example Institution, 123 Example Street, Example City, Country.' + 'Email: johndoe@example.com' + '' + '' + '' + '

The authors declare there is no conflict of interest.

' + '
' + '
' + '
' + '
' '' ) self.xml_tree = etree.fromstring(xml) @@ -379,90 +408,128 @@ def test_all_notes(self): obtained = list(ArticleNotes(self.xml_tree).all_notes()) expected = [ { - 'parent': 'article', - 'parent_article_type': 'research-article', - 'parent_id': None, - 'parent_lang': 'pt', - 'label': None, - 'title': 'Highlights: ', - 'fns': [ + "fns": [ { - 'fn_id': 'fn2', - 'fn_text': 'A)Study presents design and production of an LED lamp for photovoltaic light traps.', - 'fn_label': None, - 'fn_type': 'other', - 'fn_parent': 'fn-group', - 'fn_bold': "A)" + "fn_bold": "A)", + "fn_id": "fn2", + "fn_label": None, + "fn_parent": "fn-group", + "fn_text": "A)Study presents design and production of an LED lamp " + "for photovoltaic light traps.", + "fn_title": None, + "fn_type": "other", }, { - 'fn_id': 'fn3', - 'fn_text': 'The LED lamp switches on and off automatically, controls the battery charge and indicates ' - 'the operating status of the system.', - 'fn_label': None, - 'fn_type': 'other', - 'fn_parent': 'fn-group', - 'fn_bold': None + "fn_bold": None, + "fn_id": "fn3", + "fn_label": None, + "fn_parent": "fn-group", + "fn_text": "The LED lamp switches on and off automatically, controls " + "the battery charge and indicates the operating status of " + "the system.", + "fn_title": None, + "fn_type": "other", }, { - 'fn_id': 'fn4', - 'fn_text': 'The LED lamp is a superior substitute for the standard fluorescent lamps used in ' - 'conventional light traps.', - 'fn_label': None, - 'fn_type': 'other', - 'fn_parent': 'fn-group', - 'fn_bold': None + "fn_bold": None, + "fn_id": "fn4", + "fn_label": None, + "fn_parent": "fn-group", + "fn_text": "The LED lamp is a superior substitute for the standard " + "fluorescent lamps used in conventional light traps.", + "fn_title": None, + "fn_type": "other", + }, + ], + "label": None, + "parent": "article", + "parent_article_type": "research-article", + "parent_id": None, + "parent_lang": "pt", + "title": "Highlights: ", + } + , + { + "corresp": "Correspondência: Roseana Mara Aredes Priuli Av. Juscelino " + "Kubistcheck de Oliveira, 1220, Jardim Panorama, Condomínio " + "Recanto Real Rua 4, 440 15021-450 São José do Rio Preto, SP, " + "Brasil E-mail: roseanap@gmail.com", + "corresp_label": "Correspondência", + "corresp_title": None, + "corresp_bold": None, + "fns": [ + { + "fn_bold": None, + "fn_id": "fn_01", + "fn_label": "1", + "fn_parent": "author-notes", + "fn_text": "1Os autores declaram não haver conflito de interesses.", + "fn_type": "conflict", + 'fn_title': None, } - ] + ], + "parent": "article", + "parent_article_type": "research-article", + "parent_id": None, + "parent_lang": "pt", }, { - 'parent': 'article', - 'parent_article_type': 'research-article', - 'parent_id': None, - 'parent_lang': 'pt', - 'corresp': 'Correspondência: Roseana Mara Aredes Priuli Av. Juscelino ' - 'Kubistcheck de Oliveira, 1220, Jardim Panorama, Condomínio ' - 'Recanto Real Rua 4, 440 15021-450 São José do Rio Preto, SP, ' - 'Brasil E-mail: roseanap@gmail.com', - 'corresp_label': 'Correspondência', - 'fns': [ + "corresp": "*Correspondence: Dr. Edmundo Figueira Departamento de " + "Fisioterapia,Universidade FISP - Hogwarts,", + "corresp_label": "*", + "corresp_title": None, + "corresp_bold": "Correspondence", + "fns": [ { - 'fn_id': 'fn_01', - 'fn_label': '1', - 'fn_parent': 'author-notes', - 'fn_text': '1Os autores declaram não haver conflito de interesses.', - 'fn_type': 'conflict', - 'fn_bold': None + "fn_bold": None, + "fn_id": None, + "fn_label": None, + "fn_parent": "author-notes", + "fn_text": "Não há conflito de interesse entre os autores do artigo.", + "fn_type": "coi-statement", + 'fn_title': None, }, - ] - }, - { - 'parent': 'article', - 'parent_article_type': 'research-article', - 'parent_id': None, - 'parent_lang': 'pt', - 'corresp': '*Correspondence: Dr. Edmundo Figueira Departamento de ' - 'Fisioterapia,Universidade FISP - Hogwarts,', - 'corresp_label': '*', - 'fns': [ { - 'fn_id': None, - 'fn_label': None, - 'fn_parent': 'author-notes', - 'fn_text': 'Não há conflito de interesse entre os autores do artigo.', - 'fn_type': 'coi-statement', - 'fn_bold': None + "fn_bold": None, + "fn_id": None, + "fn_label": None, + "fn_parent": "author-notes", + "fn_text": "Todos os autores tiveram contribuição igualitária na " + "criação do artigo.", + "fn_type": "equal", + 'fn_title': None, }, + ], + "parent": "article", + "parent_article_type": "research-article", + "parent_id": None, + "parent_lang": "pt", + }, + { + "corresp": "Correspondence: John Doe, Example Institution, 123 Example " + "Street, Example City, Country.Email: johndoe@example.com", + "corresp_label": "Correspondence", + "corresp_title": None, + "corresp_bold": None, + "fns": [ { - 'fn_id': None, - 'fn_label': None, - 'fn_parent': 'author-notes', - 'fn_text': 'Todos os autores tiveram contribuição igualitária na criação do artigo.', - 'fn_type': 'equal', - 'fn_bold': None + "fn_bold": None, + "fn_id": None, + "fn_label": "2", + "fn_parent": "author-notes", + "fn_text": "2The authors declare there is no conflict of interest.", + "fn_type": "conflict", + 'fn_title': None, } - ] + ], + "parent": "sub-article", + "parent_article_type": "translation", + "parent_id": "TRen", + "parent_lang": "en", } + ] + self.assertEqual(len(obtained), 4) for i, item in enumerate(obtained): with self.subTest(i): self.assertDictEqual(item, expected[i]) diff --git a/tests/sps/validation/test_footnotes.py b/tests/sps/validation/test_footnotes.py index cf93480d7..a10d54d0c 100644 --- a/tests/sps/validation/test_footnotes.py +++ b/tests/sps/validation/test_footnotes.py @@ -1,89 +1,116 @@ -import unittest +from unittest import TestCase from lxml import etree -from packtools.sps.validation.footnotes import FootnoteValidation +from packtools.sps.validation.footnotes import FnGroupValidation -class MyTestCase(unittest.TestCase): - def test_fn_validation_coi_statement_expected(self): +class FnGroupValidationValidationTest(TestCase): + def test_label(self): self.maxDiff = None - xmltree = etree.fromstring( + xml_tree = etree.fromstring( '
' - '' - '' - '' - '' - ': Roseana Mara Aredes Priuli Av. Juscelino Kubistcheck de Oliveira, 1220, ' - 'Jardim Panorama, Condomínio Recanto Real Rua 4, 440 15021-450 São José do Rio Preto, SP, Brasil E-mail: ' - 'roseanap@gmail.com' - '' - '' - '

Os autores declaram não haver conflito de interesses.

' - '
' - '
' - '
' - '
' - '' - '' - '' - '' - '

The authors declare there is no conflict of interest.

' - '
' - '
' - '
' - '
' - '
' + "" + "" + "Notas" + '' + "

Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis

" + "
" + "
" + "
" + "" + ) + + obtained = list( + FnGroupValidation( + xml_tree=xml_tree, + rules={ + "fn_label_error_level": "WARNING", + }, + ).validate() ) - obtained = list(FootnoteValidation(xmltree).fn_validation()) expected = [ { - 'title': 'Footnotes validation', - 'parent': 'article', - 'parent_id': None, - 'parent_article_type': 'research-article', - 'parent_lang': 'pt', - 'item': 'author-notes', - 'sub_item': 'fn', - 'validation_type': 'match', - 'response': 'ERROR', - 'expected_value': '', - 'got_value': '', - 'message': 'Got , expected ', - 'advice': 'replace conflict with coi-statement', - 'data': { - 'fn_id': 'fn_01', - 'fn_parent': 'author-notes', - 'fn_type': 'conflict', - 'parent': 'article', - 'parent_id': None, - 'parent_article_type': 'research-article', - 'parent_lang': 'pt' + "title": "label", + "parent": "article", + "parent_id": None, + "parent_article_type": "research-article", + "parent_lang": "pt", + "item": "label", + "sub_item": None, + "validation_type": "exist", + "response": "WARNING", + "expected_value": "label", + "got_value": None, + "message": "Got None, expected label", + "advice": "Identify the label", + "data": { + "fn_bold": None, + "fn_id": "fn01", + "fn_label": None, + "fn_parent": "fn-group", + "fn_text": "Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis", + "fn_title": None, + "fn_type": "supported-by", + }, + } + ] + + for i, item in enumerate(expected): + with self.subTest(i): + self.assertDictEqual(item, obtained[i]) + + def test_title(self): + self.maxDiff = None + xml_tree = etree.fromstring( + '
' + "" + "" + "Notas" + '' + "" + "título" + "

Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis

" + "
" + "
" + "
" + "
" + ) + + obtained = list( + FnGroupValidation( + xml_tree=xml_tree, + rules={ + "fn_title_error_level": "WARNING", }, - }, + ).validate() + ) + + expected = [ { - 'title': 'Footnotes validation', - 'parent': 'sub-article', - 'parent_id': 'TRen', - 'parent_article_type': 'translation', - 'parent_lang': 'en', - 'item': 'author-notes', - 'sub_item': 'fn', - 'validation_type': 'match', - 'response': 'ERROR', - 'expected_value': '', - 'got_value': '', - 'message': 'Got , expected ', - 'advice': 'replace conflict with coi-statement', - 'data': { - 'fn_id': None, - 'fn_parent': 'author-notes', - 'fn_type': 'conflict', - 'parent': 'sub-article', - 'parent_id': 'TRen', - 'parent_article_type': 'translation', - 'parent_lang': 'en' + "title": "title", + "parent": "article", + "parent_id": None, + "parent_article_type": "research-article", + "parent_lang": "pt", + "item": "title", + "sub_item": None, + "validation_type": "exist", + "response": "WARNING", + "expected_value": "label", + "got_value": "title", + "message": "Got title, expected label", + "advice": "Replace title by label", + "data": { + "fn_bold": None, + "fn_id": "fn01", + "fn_label": "*", + "fn_parent": "fn-group", + "fn_text": "*títuloVivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis", + "fn_title": "título", + "fn_type": "supported-by", }, } ] @@ -92,85 +119,113 @@ def test_fn_validation_coi_statement_expected(self): with self.subTest(i): self.assertDictEqual(item, obtained[i]) - def test_fn_validation_conflit_expected(self): + def test_bold(self): self.maxDiff = None - xmltree = etree.fromstring( + xml_tree = etree.fromstring( '
' - '' - '' - '' - '' - ': Roseana Mara Aredes Priuli Av. Juscelino Kubistcheck de Oliveira, 1220, ' - 'Jardim Panorama, Condomínio Recanto Real Rua 4, 440 15021-450 São José do Rio Preto, SP, Brasil E-mail: ' - 'roseanap@gmail.com' - '' - '' - '

Os autores declaram não haver conflito de interesses.

' - '
' - '
' - '
' - '
' - '' - '' - '' - '' - '

The authors declare there is no conflict of interest.

' - '
' - '
' - '
' - '
' - '
' + 'dtd-version="1.3" article-type="research-article" xml:lang="pt">' + "" + "" + "Notas" + '' + "" + "negrito" + "

Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis

" + "
" + "
" + "
" + "" + ) + + obtained = list( + FnGroupValidation( + xml_tree=xml_tree, + rules={ + "fn_bold_error_level": "WARNING", + }, + ).validate() ) - obtained = list(FootnoteValidation(xmltree).fn_validation()) expected = [ { - 'title': 'Footnotes validation', - 'parent': 'article', - 'parent_id': None, - 'parent_article_type': 'research-article', - 'parent_lang': 'pt', - 'item': 'author-notes', - 'sub_item': 'fn', - 'validation_type': 'match', - 'response': 'ERROR', - 'expected_value': '', - 'got_value': '', - 'message': 'Got , expected ', - 'advice': 'replace coi-statement with conflict', - 'data': { - 'fn_id': 'fn_01', - 'fn_parent': 'author-notes', - 'fn_type': 'coi-statement', - 'parent': 'article', - 'parent_id': None, - 'parent_article_type': 'research-article', - 'parent_lang': 'pt' + "title": "bold", + "parent": "article", + "parent_id": None, + "parent_article_type": "research-article", + "parent_lang": "pt", + "item": "bold", + "sub_item": None, + "validation_type": "exist", + "response": "WARNING", + "expected_value": "label", + "got_value": "bold", + "message": "Got bold, expected label", + "advice": "Replace bold by label", + "data": { + "fn_bold": "negrito", + "fn_id": "fn01", + "fn_label": "*", + "fn_parent": "fn-group", + "fn_text": "*negritoVivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis", + "fn_title": None, + "fn_type": "supported-by", }, - }, + } + ] + + for i, item in enumerate(expected): + with self.subTest(i): + self.assertDictEqual(item, obtained[i]) + + def test_type(self): + self.maxDiff = None + xml_tree = etree.fromstring( + '
' + "" + "" + "Notas" + '' + "" + "

Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis

" + "
" + "
" + "
" + "
" + ) + + obtained = list( + FnGroupValidation( + xml_tree=xml_tree, + rules={ + "fn_type_error_level": "ERROR", + }, + ).validate() + ) + + expected = [ { - 'title': 'Footnotes validation', - 'parent': 'sub-article', - 'parent_id': 'TRen', - 'parent_article_type': 'translation', - 'parent_lang': 'en', - 'item': 'author-notes', - 'sub_item': 'fn', - 'validation_type': 'match', - 'response': 'ERROR', - 'expected_value': '', - 'got_value': '', - 'message': 'Got , expected ', - 'advice': 'replace coi-statement with conflict', - 'data': { - 'fn_id': None, - 'fn_parent': 'author-notes', - 'fn_type': 'coi-statement', - 'parent': 'sub-article', - 'parent_id': 'TRen', - 'parent_article_type': 'translation', - 'parent_lang': 'en' + "title": "type", + "parent": "article", + "parent_id": None, + "parent_article_type": "research-article", + "parent_lang": "pt", + "item": "type", + "sub_item": None, + "validation_type": "exist", + "response": "ERROR", + "expected_value": "type", + "got_value": None, + "message": "Got None, expected type", + "advice": "Identify the type", + "data": { + "fn_bold": None, + "fn_id": "fn01", + "fn_label": "*", + "fn_parent": "fn-group", + "fn_text": "*Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis", + "fn_title": None, + "fn_type": None, }, } ] @@ -179,6 +234,59 @@ def test_fn_validation_conflit_expected(self): with self.subTest(i): self.assertDictEqual(item, obtained[i]) + def test_dtd_version(self): + self.maxDiff = None + xml_tree = etree.fromstring( + '
' + "" + "" + "Notas" + '' + "" + "

Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis

" + "
" + "
" + "
" + "
" + ) + + obtained = list( + FnGroupValidation( + xml_tree=xml_tree, + rules={ + "fn_dtd_version_error_level": "ERROR", + }, + ).validate() + ) -if __name__ == '__main__': - unittest.main() + expected = [ + { + "title": "dtd_version", + "parent": "article", + "parent_id": None, + "parent_article_type": "research-article", + "parent_lang": "pt", + "item": "dtd_version", + "sub_item": None, + "validation_type": "exist", + "response": "ERROR", + "expected_value": '', + "got_value": '', + "message": 'Got , expected ', + "advice": "Replace conflict with coi-statement", + "data": { + "fn_bold": None, + "fn_id": "fn01", + "fn_label": "*", + "fn_parent": "fn-group", + "fn_text": "*Vivamus sodales fermentum lorem, consectetur mollis lacus sollicitudin quis", + "fn_title": None, + "fn_type": "conflict", + }, + } + ] + + for i, item in enumerate(expected): + with self.subTest(i): + self.assertDictEqual(item, obtained[i])