diff --git a/packtools/sps/validation/journal_meta.py b/packtools/sps/validation/journal_meta.py index bd26964ea..6fe45dc37 100644 --- a/packtools/sps/validation/journal_meta.py +++ b/packtools/sps/validation/journal_meta.py @@ -1,3 +1,4 @@ +import re from packtools.sps.models.journal_meta import ISSN, Acronym, Title, Publisher, JournalID from packtools.sps.validation.exceptions import ( ValidationPublisherException, @@ -381,3 +382,394 @@ def validate(self, expected_values): list(nlm_ta.nlm_ta_id_validation(expected_values['nlm-ta'])) return resp_journal_meta + + +class JournalMetaPresenceValidation: + """ + Validates presence and uniqueness of journal-meta and its required elements. + Implements SPS 1.10 rules for structural validation. + """ + def __init__(self, xmltree): + self.xmltree = xmltree + + def validate_journal_meta_presence(self, error_level="CRITICAL"): + """ + Rule 1: Validates that element exists in . + + Returns + ------- + generator of dict + Validation result indicating presence of journal-meta. + """ + journal_meta = self.xmltree.find('.//front/journal-meta') + is_valid = journal_meta is not None + + yield format_response( + title='Journal meta presence', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='journal-meta', + sub_item=None, + validation_type='exist', + is_valid=is_valid, + expected=' element', + obtained='' if is_valid else None, + advice='Add element inside ', + data=None, + error_level=error_level, + ) + + def validate_journal_meta_uniqueness(self, error_level="CRITICAL"): + """ + Rule 2: Validates that appears exactly once in . + + Returns + ------- + generator of dict + Validation result indicating uniqueness of journal-meta. + """ + journal_meta_list = self.xmltree.xpath('.//front/journal-meta') + count = len(journal_meta_list) + is_valid = count == 1 + + if count == 0: + obtained = 'No found' + elif count == 1: + obtained = 'One element' + else: + obtained = f'{count} elements found' + + yield format_response( + title='Journal meta uniqueness', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='journal-meta', + sub_item=None, + validation_type='exist', + is_valid=is_valid, + expected='exactly one element', + obtained=obtained, + advice='Ensure exactly one element exists inside ', + data={'count': count}, + error_level=error_level, + ) + + def validate_publisher_id_presence(self, error_level="CRITICAL"): + """ + Rule 3: Validates presence of . + + Returns + ------- + generator of dict + Validation result for publisher-id presence. + """ + publisher_id = self.xmltree.findtext('.//journal-meta//journal-id[@journal-id-type="publisher-id"]') + is_valid = publisher_id is not None and publisher_id.strip() != '' + + yield format_response( + title='Journal publisher ID presence', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='journal-id', + sub_item='@journal-id-type="publisher-id"', + validation_type='exist', + is_valid=is_valid, + expected=' with non-empty value', + obtained=publisher_id if is_valid else None, + advice='Add ACRONYM inside ', + data={'publisher_id': publisher_id} if is_valid else None, + error_level=error_level, + ) + + def validate_journal_title_presence(self, error_level="CRITICAL"): + """ + Rule 4: Validates presence of . + + Returns + ------- + generator of dict + Validation result for journal-title presence. + """ + journal_title = self.xmltree.findtext('.//journal-meta//journal-title-group//journal-title') + is_valid = journal_title is not None and journal_title.strip() != '' + + yield format_response( + title='Journal title presence', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='journal-title-group', + sub_item='journal-title', + validation_type='exist', + is_valid=is_valid, + expected=' with non-empty value', + obtained=journal_title if is_valid else None, + advice='Add Title inside ', + data={'journal_title': journal_title} if is_valid else None, + error_level=error_level, + ) + + def validate_abbrev_journal_title_presence(self, error_level="CRITICAL"): + """ + Rule 5: Validates presence of . + + Returns + ------- + generator of dict + Validation result for abbreviated journal title presence. + """ + abbrev_title = self.xmltree.findtext('.//journal-meta//journal-title-group//abbrev-journal-title[@abbrev-type="publisher"]') + is_valid = abbrev_title is not None and abbrev_title.strip() != '' + + yield format_response( + title='Abbreviated journal title presence', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='journal-title-group', + sub_item='abbrev-journal-title', + validation_type='exist', + is_valid=is_valid, + expected=' with non-empty value', + obtained=abbrev_title if is_valid else None, + advice='Add Abbrev. Title inside ', + data={'abbrev_title': abbrev_title} if is_valid else None, + error_level=error_level, + ) + + def validate_issn_presence(self, error_level="CRITICAL"): + """ + Rule 6: Validates presence of at least one (epub or ppub). + + Returns + ------- + generator of dict + Validation result for ISSN presence. + """ + issn_list = self.xmltree.xpath('.//journal-meta//issn') + is_valid = len(issn_list) > 0 + + issn_data = [{'type': node.get('pub-type'), 'value': node.text} for node in issn_list] + + yield format_response( + title='ISSN presence', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='issn', + sub_item=None, + validation_type='exist', + is_valid=is_valid, + expected='at least one element', + obtained=f'{len(issn_list)} ISSN(s) found' if is_valid else 'No ISSN found', + advice='Add at least one XXXX-XXXX or XXXX-XXXX inside ', + data=issn_data, + error_level=error_level, + ) + + def validate_publisher_name_presence(self, error_level="CRITICAL"): + """ + Rule 7: Validates presence of . + + Returns + ------- + generator of dict + Validation result for publisher-name presence. + """ + publisher_name = self.xmltree.findtext('.//journal-meta//publisher//publisher-name') + is_valid = publisher_name is not None and publisher_name.strip() != '' + + yield format_response( + title='Publisher name presence', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='publisher', + sub_item='publisher-name', + validation_type='exist', + is_valid=is_valid, + expected=' with non-empty value', + obtained=publisher_name if is_valid else None, + advice='Add Publisher Name inside ', + data={'publisher_name': publisher_name} if is_valid else None, + error_level=error_level, + ) + + +class ISSNFormatValidation: + """ + Validates ISSN format and attributes. + Implements SPS 1.10 format validation rules. + """ + def __init__(self, xmltree): + self.xmltree = xmltree + self.journal_issns = ISSN(xmltree) + + def validate_issn_format(self, error_level="ERROR"): + """ + Rule 8: Validates ISSN format (XXXX-XXXX pattern). + ISSN must be 4 digits, hyphen, 4 digits (last digit can be X). + According to ISO 3297, the check digit X must be uppercase. + + Returns + ------- + generator of dict + Validation results for each ISSN format. + """ + # Regex pattern for ISSN: 4 digits, hyphen, 3 digits + (digit or uppercase X) + issn_pattern = re.compile(r'^\d{4}-\d{3}[\dX]$') + + for issn_data in self.journal_issns.data: + issn_value = issn_data.get('value', '') + issn_type = issn_data.get('type', '') + + is_valid = bool(issn_pattern.match(issn_value)) if issn_value else False + + yield format_response( + title='ISSN format', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='issn', + sub_item=f'@pub-type="{issn_type}"' if issn_type else None, + validation_type='format', + is_valid=is_valid, + expected='ISSN with format XXXX-XXXX (where X can be a digit or letter X)', + obtained=issn_value, + advice=f'Correct ISSN format to XXXX-XXXX pattern. Current value: {issn_value}', + data=issn_data, + error_level=error_level, + ) + + +class JournalMetaAttributeValidation: + """ + Validates allowed attribute values in journal-meta elements. + Implements SPS 1.10 attribute validation rules. + """ + def __init__(self, xmltree): + self.xmltree = xmltree + + def validate_journal_id_type_values(self, error_level="ERROR"): + """ + Rule 9: Validates allowed values for @journal-id-type (publisher-id, nlm-ta). + + Returns + ------- + generator of dict + Validation results for each journal-id type attribute. + """ + allowed_types = ['publisher-id', 'nlm-ta'] + journal_ids = self.xmltree.xpath('.//journal-meta//journal-id') + + for journal_id in journal_ids: + id_type = journal_id.get('journal-id-type') + id_value = journal_id.text + + is_valid = id_type in allowed_types if id_type else False + + yield format_response( + title='Journal ID type attribute', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='journal-id', + sub_item='@journal-id-type', + validation_type='value in list', + is_valid=is_valid, + expected=f'{allowed_types}', + obtained=id_type, + advice=f'Set @journal-id-type to one of {allowed_types}. Current value: {id_type}', + data={'journal_id_type': id_type, 'value': id_value}, + error_level=error_level, + ) + + def validate_issn_pub_type_values(self, error_level="ERROR"): + """ + Rule 10: Validates allowed values for @pub-type in (epub, ppub). + + Returns + ------- + generator of dict + Validation results for each ISSN pub-type attribute. + """ + allowed_types = ['epub', 'ppub'] + issns = self.xmltree.xpath('.//journal-meta//issn') + + for issn in issns: + pub_type = issn.get('pub-type') + issn_value = issn.text + + is_valid = pub_type in allowed_types if pub_type else False + + yield format_response( + title='ISSN pub-type attribute', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='issn', + sub_item='@pub-type', + validation_type='value in list', + is_valid=is_valid, + expected=f'{allowed_types}', + obtained=pub_type, + advice=f'Set @pub-type to one of {allowed_types}. Current value: {pub_type}', + data={'pub_type': pub_type, 'value': issn_value}, + error_level=error_level, + ) + + def validate_issn_type_uniqueness(self, error_level="WARNING"): + """ + Rule 11: Validates that there are no duplicate ISSN pub-types. + + Returns + ------- + generator of dict + Validation results for ISSN type uniqueness. + """ + issns = self.xmltree.xpath('.//journal-meta//issn') + pub_types = [issn.get('pub-type') for issn in issns if issn.get('pub-type')] + + # Count occurrences of each type + type_counts = {} + for pub_type in pub_types: + type_counts[pub_type] = type_counts.get(pub_type, 0) + 1 + + # Check for duplicates + duplicates = [pt for pt, count in type_counts.items() if count > 1] + is_valid = len(duplicates) == 0 + + if duplicates: + obtained = f'Duplicate pub-types found: {duplicates}' + else: + obtained = 'All ISSN pub-types are unique' + + yield format_response( + title='ISSN type uniqueness', + parent='article', + parent_id=None, + parent_article_type=self.xmltree.get("article-type"), + parent_lang=self.xmltree.get("{http://www.w3.org/XML/1998/namespace}lang"), + item='issn', + sub_item='@pub-type', + validation_type='uniqueness', + is_valid=is_valid, + expected='unique pub-type values for each ISSN', + obtained=obtained, + advice=f'Remove duplicate ISSN elements with same pub-type. Duplicates: {duplicates}' if duplicates else None, + data={'type_counts': type_counts, 'duplicates': duplicates}, + error_level=error_level, + ) diff --git a/src/scielo-scholarly-data b/src/scielo-scholarly-data new file mode 160000 index 000000000..a2899ce8a --- /dev/null +++ b/src/scielo-scholarly-data @@ -0,0 +1 @@ +Subproject commit a2899ce8a1fa77396c516640d36686351210d606 diff --git a/tests/sps/validation/test_journal_meta.py b/tests/sps/validation/test_journal_meta.py index da1995709..d98d2521c 100644 --- a/tests/sps/validation/test_journal_meta.py +++ b/tests/sps/validation/test_journal_meta.py @@ -32,24 +32,56 @@ def test_validate_issn_ok(self): expected = [ { - 'title': 'Journal ISSN element validation', - 'xpath': './/journal-meta//issn[@pub-type="ppub"]', + 'title': 'Journal ISSN', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'issn', + 'sub_item': 'pub-type', 'validation_type': 'value', 'response': 'OK', 'expected_value': '0103-5053', 'got_value': '0103-5053', - 'message': 'Got 0103-5053 expected 0103-5053', - 'advice': None + 'message': 'Got 0103-5053, expected 0103-5053', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': '0103-5053', + 'expected': '0103-5053', + }, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': [ + {'type': 'ppub', 'value': '0103-5053'}, + {'type': 'epub', 'value': '1678-4790'}, + ], }, { - 'title': 'Journal ISSN element validation', - 'xpath': './/journal-meta//issn[@pub-type="epub"]', + 'title': 'Journal ISSN', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'issn', + 'sub_item': 'pub-type', 'validation_type': 'value', 'response': 'OK', 'expected_value': '1678-4790', 'got_value': '1678-4790', - 'message': 'Got 1678-4790 expected 1678-4790', - 'advice': None + 'message': 'Got 1678-4790, expected 1678-4790', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': '1678-4790', + 'expected': '1678-4790', + }, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': [ + {'type': 'ppub', 'value': '0103-5053'}, + {'type': 'epub', 'value': '1678-4790'}, + ], } ] for i, item in enumerate(obtained): @@ -67,24 +99,56 @@ def test_validate_issn_not_ok(self): expected = [ { - 'title': 'Journal ISSN element validation', - 'xpath': './/journal-meta//issn[@pub-type="ppub"]', + 'title': 'Journal ISSN', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'issn', + 'sub_item': 'pub-type', 'validation_type': 'value', - 'response': 'ERROR', + 'response': 'CRITICAL', 'expected_value': '0103-5054', 'got_value': '0103-5053', - 'message': 'Got 0103-5053 expected 0103-5054', - 'advice': 'Provide an ISSN value as expected: 0103-5054' + 'message': 'Got 0103-5053, expected 0103-5054', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': '0103-5053', + 'expected': '0103-5054', + }, + 'advice': 'Mark print ISSN with 0103-5054 inside ', + 'adv_text': 'Mark print ISSN with 0103-5054 inside ', + 'adv_params': {}, + 'data': [ + {'type': 'ppub', 'value': '0103-5053'}, + {'type': 'epub', 'value': '1678-4790'}, + ], }, { - 'title': 'Journal ISSN element validation', - 'xpath': './/journal-meta//issn[@pub-type="epub"]', + 'title': 'Journal ISSN', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'issn', + 'sub_item': 'pub-type', 'validation_type': 'value', - 'response': 'ERROR', + 'response': 'CRITICAL', 'expected_value': '1678-4791', 'got_value': '1678-4790', - 'message': 'Got 1678-4790 expected 1678-4791', - 'advice': 'Provide an ISSN value as expected: 1678-4791' + 'message': 'Got 1678-4790, expected 1678-4791', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': '1678-4790', + 'expected': '1678-4791', + }, + 'advice': 'Mark electronic ISSN with 1678-4791 inside ', + 'adv_text': 'Mark electronic ISSN with 1678-4791 inside ', + 'adv_params': {}, + 'data': [ + {'type': 'ppub', 'value': '0103-5053'}, + {'type': 'epub', 'value': '1678-4790'}, + ], } ] for i, item in enumerate(obtained): @@ -113,14 +177,24 @@ def test_acronym_validation_success(self): self.maxDiff = None expected = [ { - 'title': 'Journal acronym element validation', - 'xpath': './/journal-meta//journal-id[@journal-id-type="publisher-id"]', + 'title': 'Journal acronym', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'pt', + 'item': 'journal-id', + 'sub_item': '@journal-id-type="publisher-id"', 'validation_type': 'value', 'response': 'OK', 'expected_value': 'hcsm', 'got_value': 'hcsm', - 'message': 'Got hcsm expected hcsm', - 'advice': None + 'message': 'Got hcsm, expected hcsm', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': {'obtained': 'hcsm', 'expected': 'hcsm'}, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': {'acronym': 'hcsm'}, } ] obtained = self.acronym.acronym_validation('hcsm') @@ -132,14 +206,24 @@ def test_acronym_validation_fail(self): self.maxDiff = None expected = [ { - 'title': 'Journal acronym element validation', - 'xpath': './/journal-meta//journal-id[@journal-id-type="publisher-id"]', + 'title': 'Journal acronym', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'pt', + 'item': 'journal-id', + 'sub_item': '@journal-id-type="publisher-id"', 'validation_type': 'value', - 'response': 'ERROR', + 'response': 'CRITICAL', 'expected_value': 'hcs', 'got_value': 'hcsm', - 'message': 'Got hcsm expected hcs', - 'advice': 'Provide an acronym value as expected: hcs' + 'message': 'Got hcsm, expected hcs', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': {'obtained': 'hcsm', 'expected': 'hcs'}, + 'advice': 'Mark journal acronym with hcs inside ', + 'adv_text': 'Mark journal acronym with hcs inside ', + 'adv_params': {}, + 'data': {'acronym': 'hcsm'}, } ] obtained = self.acronym.acronym_validation('hcs') @@ -173,14 +257,30 @@ def test_journal_title_validation_success(self): self.maxDiff = None expected = [ { - 'title': 'Journal title element validation', - 'xpath': './journal-meta/journal-title-group/journal-title', + 'title': 'Journal title', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'pt', + 'item': 'journal-title-group', + 'sub_item': 'journal-title', 'validation_type': 'value', 'response': 'OK', 'expected_value': 'História, Ciências, Saúde-Manguinhos', 'got_value': 'História, Ciências, Saúde-Manguinhos', - 'message': 'Got História, Ciências, Saúde-Manguinhos expected História, Ciências, Saúde-Manguinhos', - 'advice': None + 'message': 'Got História, Ciências, Saúde-Manguinhos, expected História, Ciências, Saúde-Manguinhos', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'História, Ciências, Saúde-Manguinhos', + 'expected': 'História, Ciências, Saúde-Manguinhos', + }, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': { + 'main': 'História, Ciências, Saúde-Manguinhos', + 'abbreviated': 'Hist. cienc. saude-Manguinhos', + }, } ] obtained = self.title.journal_title_validation('História, Ciências, Saúde-Manguinhos') @@ -192,14 +292,30 @@ def test_journal_title_validation_fail(self): self.maxDiff = None expected = [ { - 'title': 'Journal title element validation', - 'xpath': './journal-meta/journal-title-group/journal-title', + 'title': 'Journal title', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'pt', + 'item': 'journal-title-group', + 'sub_item': 'journal-title', 'validation_type': 'value', - 'response': 'ERROR', + 'response': 'CRITICAL', 'expected_value': 'História, Ciências, Saúde Manguinhos', 'got_value': 'História, Ciências, Saúde-Manguinhos', - 'message': 'Got História, Ciências, Saúde-Manguinhos expected História, Ciências, Saúde Manguinhos', - 'advice': 'Provide a journal title value as expected: História, Ciências, Saúde Manguinhos' + 'message': 'Got História, Ciências, Saúde-Manguinhos, expected História, Ciências, Saúde Manguinhos', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'História, Ciências, Saúde-Manguinhos', + 'expected': 'História, Ciências, Saúde Manguinhos', + }, + 'advice': 'Mark journal title with inside ', + 'adv_text': 'Mark journal title with inside ', + 'adv_params': {}, + 'data': { + 'main': 'História, Ciências, Saúde-Manguinhos', + 'abbreviated': 'Hist. cienc. saude-Manguinhos', + }, } ] obtained = self.title.journal_title_validation('História, Ciências, Saúde Manguinhos') @@ -223,7 +339,14 @@ def test_abbreviated_journal_title_validation_success(self): 'expected_value': 'Hist. cienc. saude-Manguinhos', 'got_value': 'Hist. cienc. saude-Manguinhos', 'message': 'Got Hist. cienc. saude-Manguinhos, expected Hist. cienc. saude-Manguinhos', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Hist. cienc. saude-Manguinhos', + 'expected': 'Hist. cienc. saude-Manguinhos', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': { 'main': 'História, Ciências, Saúde-Manguinhos', 'abbreviated': 'Hist. cienc. saude-Manguinhos' @@ -251,7 +374,14 @@ def test_abbreviated_journal_title_validation_fail(self): 'expected_value': 'Hist. cienc. saude Manguinhos', 'got_value': 'Hist. cienc. saude-Manguinhos', 'message': 'Got Hist. cienc. saude-Manguinhos, expected Hist. cienc. saude Manguinhos', - 'advice': 'Provide a journal title value as expected: Hist. cienc. saude Manguinhos', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Hist. cienc. saude-Manguinhos', + 'expected': 'Hist. cienc. saude Manguinhos', + }, + 'advice': 'Mark abbreviated journal title with inside ', + 'adv_text': 'Mark abbreviated journal title with inside ', + 'adv_params': {}, 'data': { 'main': 'História, Ciências, Saúde-Manguinhos', 'abbreviated': 'Hist. cienc. saude-Manguinhos' @@ -306,7 +436,7 @@ def test_validate_publisher_names_one_success(self): self.maxDiff = None expected = [ { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -318,7 +448,14 @@ def test_validate_publisher_names_one_success(self): 'expected_value': 'Fundação Oswaldo Cruz', 'got_value': 'Fundação Oswaldo Cruz', 'message': 'Got Fundação Oswaldo Cruz, expected Fundação Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Fundação Oswaldo Cruz', + 'expected': 'Fundação Oswaldo Cruz', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, } ] @@ -331,7 +468,7 @@ def test_validate_publisher_names_one_fail(self): self.maxDiff = None expected = [ { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -343,7 +480,14 @@ def test_validate_publisher_names_one_fail(self): 'expected_value': 'Fund. Oswaldo Cruz', 'got_value': 'Fundação Oswaldo Cruz', 'message': 'Got Fundação Oswaldo Cruz, expected Fund. Oswaldo Cruz', - 'advice': 'Provide the expected publisher name: Fund. Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Fundação Oswaldo Cruz', + 'expected': 'Fund. Oswaldo Cruz', + }, + 'advice': 'Mark publisher name with Fund. Oswaldo Cruz inside ', + 'adv_text': 'Mark publisher name with Fund. Oswaldo Cruz inside ', + 'adv_params': {}, 'data': None, } ] @@ -356,7 +500,7 @@ def test_validate_publisher_names_more_than_one_sucess(self): self.maxDiff = None expected = [ { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -368,11 +512,18 @@ def test_validate_publisher_names_more_than_one_sucess(self): 'expected_value': 'Fundação Oswaldo Cruz', 'got_value': 'Fundação Oswaldo Cruz', 'message': 'Got Fundação Oswaldo Cruz, expected Fundação Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Fundação Oswaldo Cruz', + 'expected': 'Fundação Oswaldo Cruz', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, }, { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -384,7 +535,14 @@ def test_validate_publisher_names_more_than_one_sucess(self): 'expected_value': 'UNESP', 'got_value': 'UNESP', 'message': 'Got UNESP, expected UNESP', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'UNESP', + 'expected': 'UNESP', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, } ] @@ -397,7 +555,7 @@ def test_validate_publisher_names_more_than_one_fail(self): self.maxDiff = None expected = [ { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -409,11 +567,18 @@ def test_validate_publisher_names_more_than_one_fail(self): 'expected_value': 'Fund. Oswaldo Cruz', 'got_value': 'Fundação Oswaldo Cruz', 'message': 'Got Fundação Oswaldo Cruz, expected Fund. Oswaldo Cruz', - 'advice': 'Provide the expected publisher name: Fund. Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Fundação Oswaldo Cruz', + 'expected': 'Fund. Oswaldo Cruz', + }, + 'advice': 'Mark publisher name with Fund. Oswaldo Cruz inside ', + 'adv_text': 'Mark publisher name with Fund. Oswaldo Cruz inside ', + 'adv_params': {}, 'data': None, }, { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -425,7 +590,14 @@ def test_validate_publisher_names_more_than_one_fail(self): 'expected_value': 'UNIFESP', 'got_value': 'UNESP', 'message': 'Got UNESP, expected UNIFESP', - 'advice': 'Provide the expected publisher name: UNIFESP', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'UNESP', + 'expected': 'UNIFESP', + }, + 'advice': 'Mark publisher name with UNIFESP inside ', + 'adv_text': 'Mark publisher name with UNIFESP inside ', + 'adv_params': {}, 'data': None, } ] @@ -438,7 +610,7 @@ def test_validate_publisher_names_XML_has_not_expected_items(self): self.maxDiff = None expected = [ { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -450,11 +622,18 @@ def test_validate_publisher_names_XML_has_not_expected_items(self): 'expected_value': 'Fundação Oswaldo Cruz', 'got_value': 'Fundação Oswaldo Cruz', 'message': 'Got Fundação Oswaldo Cruz, expected Fundação Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Fundação Oswaldo Cruz', + 'expected': 'Fundação Oswaldo Cruz', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, }, { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -466,7 +645,14 @@ def test_validate_publisher_names_XML_has_not_expected_items(self): 'expected_value': ['Fundação Oswaldo Cruz'], 'got_value': ['Fundação Oswaldo Cruz', 'UNESP'], 'message': "Got ['Fundação Oswaldo Cruz', 'UNESP'], expected ['Fundação Oswaldo Cruz']", + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': ['Fundação Oswaldo Cruz', 'UNESP'], + 'expected': ['Fundação Oswaldo Cruz'], + }, 'advice': 'Remove the following items from the XML: UNESP', + 'adv_text': 'Remove the following items from the XML: UNESP', + 'adv_params': {}, 'data': None, } ] @@ -479,7 +665,7 @@ def test_validate_publisher_names_function_has_not_expected_items(self): self.maxDiff = None expected = [ { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -491,11 +677,18 @@ def test_validate_publisher_names_function_has_not_expected_items(self): 'expected_value': 'Fundação Oswaldo Cruz', 'got_value': 'Fundação Oswaldo Cruz', 'message': 'Got Fundação Oswaldo Cruz, expected Fundação Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Fundação Oswaldo Cruz', + 'expected': 'Fundação Oswaldo Cruz', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, }, { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -507,7 +700,14 @@ def test_validate_publisher_names_function_has_not_expected_items(self): 'expected_value': ['Fundação Oswaldo Cruz', 'UNESP'], 'got_value': ['Fundação Oswaldo Cruz'], 'message': "Got ['Fundação Oswaldo Cruz'], expected ['Fundação Oswaldo Cruz', 'UNESP']", + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': ['Fundação Oswaldo Cruz'], + 'expected': ['Fundação Oswaldo Cruz', 'UNESP'], + }, 'advice': 'Complete the following items in the XML: UNESP', + 'adv_text': 'Complete the following items in the XML: UNESP', + 'adv_params': {}, 'data': None, } ] @@ -536,7 +736,7 @@ def test_nlm_ta_id_validation_success(self): self.maxDiff = None expected = [ { - 'title': 'Journal ID element validation', + 'title': 'Journal ID', 'parent': 'article', 'parent_article_type': "research-article", 'parent_id': None, @@ -548,7 +748,14 @@ def test_nlm_ta_id_validation_success(self): 'expected_value': 'Rev Saude Publica', 'got_value': 'Rev Saude Publica', 'message': 'Got Rev Saude Publica, expected Rev Saude Publica', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Rev Saude Publica', + 'expected': 'Rev Saude Publica', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, } ] @@ -561,7 +768,7 @@ def test_nlm_ta_id_validation_fail(self): self.maxDiff = None expected = [ { - 'title': 'Journal ID element validation', + 'title': 'Journal ID', 'parent': 'article', 'parent_article_type': "research-article", 'parent_id': None, @@ -573,7 +780,14 @@ def test_nlm_ta_id_validation_fail(self): 'expected_value': 'Rev de Saude Publica', 'got_value': 'Rev Saude Publica', 'message': 'Got Rev Saude Publica, expected Rev de Saude Publica', - 'advice': 'Provide an nlm-ta value as expected: Rev de Saude Publica', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Rev Saude Publica', + 'expected': 'Rev de Saude Publica', + }, + 'advice': 'Mark an nlm-ta value with Rev de Saude Publica inside ', + 'adv_text': 'Mark an nlm-ta value with Rev de Saude Publica inside ', + 'adv_params': {}, 'data': None, } ] @@ -612,44 +826,102 @@ def test_journal_meta_match(self): self.maxDiff = None expected = [ { - 'title': 'Journal ISSN element validation', - 'xpath': './/journal-meta//issn[@pub-type="ppub"]', + 'title': 'Journal ISSN', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'issn', + 'sub_item': 'pub-type', 'validation_type': 'value', 'response': 'OK', 'expected_value': '0103-5053', 'got_value': '0103-5053', - 'message': 'Got 0103-5053 expected 0103-5053', - 'advice': None + 'message': 'Got 0103-5053, expected 0103-5053', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': '0103-5053', + 'expected': '0103-5053', + }, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': [ + {'type': 'ppub', 'value': '0103-5053'}, + {'type': 'epub', 'value': '1678-4790'}, + ], }, { - 'title': 'Journal ISSN element validation', - 'xpath': './/journal-meta//issn[@pub-type="epub"]', + 'title': 'Journal ISSN', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'issn', + 'sub_item': 'pub-type', 'validation_type': 'value', 'response': 'OK', 'expected_value': '1678-4790', 'got_value': '1678-4790', - 'message': 'Got 1678-4790 expected 1678-4790', - 'advice': None + 'message': 'Got 1678-4790, expected 1678-4790', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': '1678-4790', + 'expected': '1678-4790', + }, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': [ + {'type': 'ppub', 'value': '0103-5053'}, + {'type': 'epub', 'value': '1678-4790'}, + ], }, { - 'title': 'Journal acronym element validation', - 'xpath': './/journal-meta//journal-id[@journal-id-type="publisher-id"]', + 'title': 'Journal acronym', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'journal-id', + 'sub_item': '@journal-id-type="publisher-id"', 'validation_type': 'value', 'response': 'OK', 'expected_value': 'hcsm', 'got_value': 'hcsm', - 'message': 'Got hcsm expected hcsm', - 'advice': None + 'message': 'Got hcsm, expected hcsm', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': {'obtained': 'hcsm', 'expected': 'hcsm'}, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': {'acronym': 'hcsm'}, }, { - 'title': 'Journal title element validation', - 'xpath': './journal-meta/journal-title-group/journal-title', + 'title': 'Journal title', + 'parent': 'article', + 'parent_id': None, + 'parent_article_type': 'research-article', + 'parent_lang': 'en', + 'item': 'journal-title-group', + 'sub_item': 'journal-title', 'validation_type': 'value', 'response': 'OK', 'expected_value': 'História, Ciências, Saúde-Manguinhos', 'got_value': 'História, Ciências, Saúde-Manguinhos', - 'message': 'Got História, Ciências, Saúde-Manguinhos expected História, Ciências, Saúde-Manguinhos', - 'advice': None + 'message': 'Got História, Ciências, Saúde-Manguinhos, expected História, Ciências, Saúde-Manguinhos', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'História, Ciências, Saúde-Manguinhos', + 'expected': 'História, Ciências, Saúde-Manguinhos', + }, + 'advice': None, + 'adv_text': None, + 'adv_params': None, + 'data': { + 'main': 'História, Ciências, Saúde-Manguinhos', + 'abbreviated': 'Hist. cienc. saude-Manguinhos', + }, }, { 'title': 'Abbreviated journal title element validation', @@ -664,14 +936,21 @@ def test_journal_meta_match(self): 'expected_value': 'Hist. cienc. saude-Manguinhos', 'got_value': 'Hist. cienc. saude-Manguinhos', 'message': 'Got Hist. cienc. saude-Manguinhos, expected Hist. cienc. saude-Manguinhos', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Hist. cienc. saude-Manguinhos', + 'expected': 'Hist. cienc. saude-Manguinhos', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': { 'main': 'História, Ciências, Saúde-Manguinhos', 'abbreviated': 'Hist. cienc. saude-Manguinhos' }, }, { - 'title': 'Publisher name element validation', + 'title': 'Publisher name', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -683,11 +962,18 @@ def test_journal_meta_match(self): 'expected_value': 'Casa de Oswaldo Cruz, Fundação Oswaldo Cruz', 'got_value': 'Casa de Oswaldo Cruz, Fundação Oswaldo Cruz', 'message': 'Got Casa de Oswaldo Cruz, Fundação Oswaldo Cruz, expected Casa de Oswaldo Cruz, Fundação Oswaldo Cruz', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Casa de Oswaldo Cruz, Fundação Oswaldo Cruz', + 'expected': 'Casa de Oswaldo Cruz, Fundação Oswaldo Cruz', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, }, { - 'title': 'Journal ID element validation', + 'title': 'Journal ID', 'parent': 'article', 'parent_article_type': 'research-article', 'parent_id': None, @@ -699,7 +985,14 @@ def test_journal_meta_match(self): 'expected_value': 'Rev Saude Publica', 'got_value': 'Rev Saude Publica', 'message': 'Got Rev Saude Publica, expected Rev Saude Publica', + 'msg_text': 'Got {obtained}, expected {expected}', + 'msg_params': { + 'obtained': 'Rev Saude Publica', + 'expected': 'Rev Saude Publica', + }, 'advice': None, + 'adv_text': None, + 'adv_params': None, 'data': None, } ] @@ -718,3 +1011,478 @@ def test_journal_meta_match(self): for i, item in enumerate(expected): with self.subTest(i): self.assertDictEqual(obtained[i], item) + + +class JournalMetaPresenceTest(TestCase): + """Tests for JournalMetaPresenceValidation class""" + + def test_validate_journal_meta_presence_success(self): + """Test journal-meta presence validation when element exists""" + xmltree = etree.fromstring( + """ +
+ + + test + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_journal_meta_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + self.assertEqual(result[0]['validation_type'], 'exist') + + def test_validate_journal_meta_presence_failure(self): + """Test journal-meta presence validation when element is missing""" + xmltree = etree.fromstring( + """ +
+ + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_journal_meta_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'CRITICAL') + self.assertIsNotNone(result[0]['advice']) + + def test_validate_journal_meta_uniqueness_success(self): + """Test journal-meta uniqueness validation when exactly one exists""" + xmltree = etree.fromstring( + """ +
+ + + test + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_journal_meta_uniqueness()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + self.assertEqual(result[0]['data']['count'], 1) + + def test_validate_journal_meta_uniqueness_failure_multiple(self): + """Test journal-meta uniqueness validation when multiple exist""" + xmltree = etree.fromstring( + """ +
+ + + test1 + + + test2 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_journal_meta_uniqueness()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'CRITICAL') + self.assertEqual(result[0]['data']['count'], 2) + + def test_validate_publisher_id_presence_success(self): + """Test publisher-id presence validation when element exists""" + xmltree = etree.fromstring( + """ +
+ + + bjmbr + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_publisher_id_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + self.assertEqual(result[0]['data']['publisher_id'], 'bjmbr') + + def test_validate_publisher_id_presence_failure(self): + """Test publisher-id presence validation when element is missing""" + xmltree = etree.fromstring( + """ +
+ + + Test + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_publisher_id_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'CRITICAL') + + def test_validate_journal_title_presence_success(self): + """Test journal-title presence validation when element exists""" + xmltree = etree.fromstring( + """ +
+ + + + Test Journal + + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_journal_title_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + + def test_validate_abbrev_journal_title_presence_success(self): + """Test abbreviated journal title presence validation""" + xmltree = etree.fromstring( + """ +
+ + + + Test J. + + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_abbrev_journal_title_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + + def test_validate_issn_presence_success(self): + """Test ISSN presence validation when at least one exists""" + xmltree = etree.fromstring( + """ +
+ + + 1234-5678 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_issn_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + + def test_validate_issn_presence_failure(self): + """Test ISSN presence validation when none exist""" + xmltree = etree.fromstring( + """ +
+ + + test + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_issn_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'CRITICAL') + + def test_validate_publisher_name_presence_success(self): + """Test publisher-name presence validation when element exists""" + xmltree = etree.fromstring( + """ +
+ + + + Test Publisher + + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaPresenceValidation + validation = JournalMetaPresenceValidation(xmltree) + result = list(validation.validate_publisher_name_presence()) + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]['response'], 'OK') + + +class ISSNFormatTest(TestCase): + """Tests for ISSNFormatValidation class""" + + def test_validate_issn_format_valid_standard(self): + """Test ISSN format validation with valid standard format""" + xmltree = etree.fromstring( + """ +
+ + + 1234-5678 + 0103-5053 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import ISSNFormatValidation + validation = ISSNFormatValidation(xmltree) + results = list(validation.validate_issn_format()) + + self.assertEqual(len(results), 2) + for result in results: + self.assertEqual(result['response'], 'OK') + self.assertEqual(result['validation_type'], 'format') + + def test_validate_issn_format_valid_with_x(self): + """Test ISSN format validation with X as check digit""" + xmltree = etree.fromstring( + """ +
+ + + 1234-567X + + +
+ """ + ) + from packtools.sps.validation.journal_meta import ISSNFormatValidation + validation = ISSNFormatValidation(xmltree) + results = list(validation.validate_issn_format()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'OK') + + def test_validate_issn_format_invalid_no_hyphen(self): + """Test ISSN format validation with missing hyphen""" + xmltree = etree.fromstring( + """ +
+ + + 12345678 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import ISSNFormatValidation + validation = ISSNFormatValidation(xmltree) + results = list(validation.validate_issn_format()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'ERROR') + + def test_validate_issn_format_invalid_wrong_length(self): + """Test ISSN format validation with wrong length""" + xmltree = etree.fromstring( + """ +
+ + + 123-456 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import ISSNFormatValidation + validation = ISSNFormatValidation(xmltree) + results = list(validation.validate_issn_format()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'ERROR') + + def test_validate_issn_format_invalid_lowercase_x(self): + """Test ISSN format validation rejects lowercase x (must be uppercase X)""" + xmltree = etree.fromstring( + """ +
+ + + 1234-567x + + +
+ """ + ) + from packtools.sps.validation.journal_meta import ISSNFormatValidation + validation = ISSNFormatValidation(xmltree) + results = list(validation.validate_issn_format()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'ERROR') + + + + +class JournalMetaAttributeTest(TestCase): + """Tests for JournalMetaAttributeValidation class""" + + def test_validate_journal_id_type_valid(self): + """Test journal-id-type validation with valid values""" + xmltree = etree.fromstring( + """ +
+ + + bjmbr + Rev Test + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaAttributeValidation + validation = JournalMetaAttributeValidation(xmltree) + results = list(validation.validate_journal_id_type_values()) + + self.assertEqual(len(results), 2) + for result in results: + self.assertEqual(result['response'], 'OK') + + def test_validate_journal_id_type_invalid(self): + """Test journal-id-type validation with invalid value""" + xmltree = etree.fromstring( + """ +
+ + + test + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaAttributeValidation + validation = JournalMetaAttributeValidation(xmltree) + results = list(validation.validate_journal_id_type_values()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'ERROR') + + def test_validate_issn_pub_type_valid(self): + """Test ISSN pub-type validation with valid values""" + xmltree = etree.fromstring( + """ +
+ + + 1234-5678 + 0103-5053 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaAttributeValidation + validation = JournalMetaAttributeValidation(xmltree) + results = list(validation.validate_issn_pub_type_values()) + + self.assertEqual(len(results), 2) + for result in results: + self.assertEqual(result['response'], 'OK') + + def test_validate_issn_pub_type_invalid(self): + """Test ISSN pub-type validation with invalid value""" + xmltree = etree.fromstring( + """ +
+ + + 1234-5678 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaAttributeValidation + validation = JournalMetaAttributeValidation(xmltree) + results = list(validation.validate_issn_pub_type_values()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'ERROR') + + def test_validate_issn_type_uniqueness_success(self): + """Test ISSN type uniqueness with unique types""" + xmltree = etree.fromstring( + """ +
+ + + 1234-5678 + 0103-5053 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaAttributeValidation + validation = JournalMetaAttributeValidation(xmltree) + results = list(validation.validate_issn_type_uniqueness()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'OK') + + def test_validate_issn_type_uniqueness_failure(self): + """Test ISSN type uniqueness with duplicate types""" + xmltree = etree.fromstring( + """ +
+ + + 1234-5678 + 8765-4321 + + +
+ """ + ) + from packtools.sps.validation.journal_meta import JournalMetaAttributeValidation + validation = JournalMetaAttributeValidation(xmltree) + results = list(validation.validate_issn_type_uniqueness()) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['response'], 'WARNING') + self.assertIn('epub', results[0]['data']['duplicates'])