@@ -261,23 +261,6 @@ def test_validate_article_issue_number_start_with_zero(self):
261261 """
262262 )
263263
264- expected = {
265- "title" : "number" ,
266- "parent" : "article" ,
267- "parent_article_type" : None ,
268- "parent_id" : None ,
269- "parent_lang" : None ,
270- "response" : "ERROR" ,
271- "item" : "number" ,
272- "sub_item" : None ,
273- "validation_type" : "format" ,
274- "expected_value" : "4" ,
275- "got_value" : "04" ,
276- "message" : "Got 04, expected 4" ,
277- "advice" : "Consulte SPS documentation to complete issue element" ,
278- "data" : {"number" : "04" , "volume" : "56" },
279- }
280-
281264 validator = IssueValidation (
282265 xml_tree , params = self .params
283266 )
@@ -307,23 +290,6 @@ def test_validate_article_issue_number_value_is_not_numeric(self):
307290 """
308291 )
309292
310- expected = {
311- "title" : "number" ,
312- "parent" : "article" ,
313- "parent_article_type" : None ,
314- "parent_id" : None ,
315- "parent_lang" : None ,
316- "response" : "OK" ,
317- "item" : "number" ,
318- "sub_item" : None ,
319- "validation_type" : "format" ,
320- "expected_value" : "4a" ,
321- "got_value" : "4a" ,
322- "message" : "Got 4a, expected 4a" ,
323- "advice" : None ,
324- "data" : {"number" : "4a" , "volume" : "56" },
325- }
326-
327293 validator = IssueValidation (
328294 xml_tree , params = self .params
329295 )
@@ -652,7 +618,7 @@ def test_validate_article_issue_number_supplement_with_dot_and_space(self):
652618
653619 self .assertDictEqual (expected , obtained )
654620
655- def test_suppl_matches (self ):
621+ def test_suppl_invalid_non_alphanumeric (self ):
656622 self .maxDiff = None
657623 xml_tree = etree .fromstring (
658624 """
@@ -693,7 +659,7 @@ def test_suppl_matches(self):
693659
694660 self .assertDictEqual (expected , obtained )
695661
696- def test_suppl_no_matches (self ):
662+ def test_suppl_valid_alphanumeric (self ):
697663 self .maxDiff = None
698664 xml_tree = etree .fromstring (
699665 """
@@ -823,9 +789,9 @@ def test_validate_article_issue(self):
823789 params = self .params ,
824790 )
825791
826- obtained = list ( validator .validate ())
792+ obtained = [ r for r in validator .validate () if r is not None ]
827793
828- self .assertEqual (len (obtained ), 5 )
794+ self .assertEqual (len (obtained ), 11 )
829795 for i , item in enumerate (obtained ):
830796 for key in self .expected_keys :
831797 with self .subTest (f"item: { i } , key: { key } " ):
@@ -863,26 +829,16 @@ def test_validation_pages(self):
863829 """
864830 xml_tree = etree .fromstring (xml )
865831
866- expected = {
867- "title" : "Pagination" ,
868- "parent" : "article" ,
869- "parent_article_type" : None ,
870- "parent_id" : None ,
871- "parent_lang" : None ,
872- "item" : "elocation-id | fpage / lpage" ,
873- "sub_item" : "elocation-id | fpage / lpage" ,
874- "validation_type" : "match" ,
875- "response" : "CRITICAL" ,
876- "expected_value" : "elocation-id or fpage + lpage" ,
877- "got_value" : "elocation-id: None, fpage: None, lpage: None" ,
878- "message" : "Got elocation-id: None, fpage: None, lpage: None, expected elocation-id or fpage + lpage" ,
879- "advice" : "Provide elocation-id or fpage + lpage" ,
880- "data" : {"volume" : "56" },
881- }
882-
883832 obtained = PaginationValidation (xml_tree , self .params ).validate ()
884833
885- self .assertDictEqual (expected , obtained )
834+ for key in self .expected_keys :
835+ self .assertIn (key , obtained , f"{ key } not found" )
836+
837+ self .assertEqual (obtained ["title" ], "Pagination" )
838+ self .assertEqual (obtained ["response" ], "CRITICAL" )
839+ self .assertEqual (obtained ["expected_value" ], "elocation id or first and last pages" )
840+ self .assertEqual (obtained ["message" ], "Got elocation-id: None, fpage: None, lpage: None, expected elocation id or first and last pages" )
841+ self .assertEqual (obtained ["advice" ], "Mark elocation id with <elocation-id> or first page with <fpage> and last page with <lpage>" )
886842
887843 def test_validation_e_location (self ):
888844 self .maxDiff = None
@@ -891,34 +847,24 @@ def test_validation_e_location(self):
891847 <front>
892848 <article-meta>
893849 <volume>56</volume>
850+ <elocation-id>e51467</elocation-id>
894851 </article-meta>
895852 </front>
896853 </article>
897854 """
898855 xml_tree = etree .fromstring (xml )
899856
900- expected = {
901- "title" : "Pagination" ,
902- "parent" : "article" ,
903- "parent_article_type" : None ,
904- "parent_id" : None ,
905- "parent_lang" : None ,
906- "item" : "elocation-id | fpage / lpage" ,
907- "sub_item" : "elocation-id | fpage / lpage" ,
908- "validation_type" : "match" ,
909- "response" : "CRITICAL" ,
910- "expected_value" : "elocation-id or fpage + lpage" ,
911- "got_value" : "elocation-id: None, fpage: None, lpage: None" ,
912- "message" : "Got elocation-id: None, fpage: None, lpage: None, expected elocation-id or fpage + lpage" ,
913- "advice" : "Provide elocation-id or fpage + lpage" ,
914- "data" : {"volume" : "56" },
915- }
916-
917857 obtained = PaginationValidation (xml_tree , self .params ).validate ()
918858
919- self .assertDictEqual (expected , obtained )
859+ for key in self .expected_keys :
860+ self .assertIn (key , obtained , f"{ key } not found" )
861+
862+ self .assertEqual (obtained ["title" ], "Pagination" )
863+ self .assertEqual (obtained ["response" ], "OK" )
864+ self .assertEqual (obtained ["message" ], "Got elocation-id: e51467, fpage: None, lpage: None, expected elocation id or first and last pages" )
865+ self .assertIsNone (obtained ["advice" ])
920866
921- def test_validation_pages_and_e_location_exists_fail (self ):
867+ def test_validation_elocation_and_pages_both_present_valid (self ):
922868 self .maxDiff = None
923869 xml = """
924870 <article xmlns:xlink="http://www.w3.org/1999/xlink" article-type="research-article" xml:lang="en">
@@ -941,7 +887,7 @@ def test_validation_pages_and_e_location_exists_fail(self):
941887
942888 self .assertEqual (obtained ["title" ], "Pagination" )
943889 self .assertEqual (obtained ["response" ], "OK" )
944- self .assertEqual (obtained ["message" ], "Got elocation-id: e51467, fpage: 220, lpage: 240, expected elocation- id or fpage + lpage " )
890+ self .assertEqual (obtained ["message" ], "Got elocation-id: e51467, fpage: 220, lpage: 240, expected elocation id or first and last pages " )
945891 self .assertIsNone (obtained ["advice" ])
946892
947893
@@ -1567,3 +1513,216 @@ def test_issue_zero_alone_valid(self):
15671513 obtained = validator .validate_issue_no_leading_zeros ()
15681514
15691515 self .assertEqual (obtained ["response" ], "OK" )
1516+
1517+
1518+ # Additional test coverage for missing cases
1519+
1520+ class VolumeZeroTest (TestCase ):
1521+ """Test for volume=0 validation"""
1522+
1523+ def setUp (self ):
1524+ self .params = {
1525+ "volume_format_error_level" : "CRITICAL" ,
1526+ }
1527+
1528+ def test_volume_zero_invalid (self ):
1529+ """Test that volume='0' is invalid (zero_is_allowed=False)"""
1530+ xml = """
1531+ <article>
1532+ <front>
1533+ <article-meta>
1534+ <volume>0</volume>
1535+ </article-meta>
1536+ </front>
1537+ </article>
1538+ """
1539+ xml_tree = etree .fromstring (xml )
1540+ validator = IssueValidation (xml_tree , params = self .params )
1541+ obtained = validator .validate_volume_format ()
1542+
1543+ self .assertEqual (obtained ["response" ], "CRITICAL" )
1544+ self .assertIn ("expected alphanumeric value, except 0" , obtained ["message" ])
1545+
1546+
1547+ class ExpectedIssuesTest (TestCase ):
1548+ """Tests for validate_expected_issues"""
1549+
1550+ def setUp (self ):
1551+ self .params = {
1552+ "expected_issues_error_level" : "CRITICAL" ,
1553+ }
1554+
1555+ def test_issue_present_in_registered_list (self ):
1556+ """Test that issue present in the list passes"""
1557+ xml = """
1558+ <article>
1559+ <front>
1560+ <article-meta>
1561+ <volume>56</volume>
1562+ <issue>4</issue>
1563+ </article-meta>
1564+ </front>
1565+ </article>
1566+ """
1567+ xml_tree = etree .fromstring (xml )
1568+ params = {
1569+ "expected_issues_error_level" : "CRITICAL" ,
1570+ "journal_data" : {
1571+ "issues" : [{"volume" : "56" , "number" : "4" , "supplement" : None }]
1572+ }
1573+ }
1574+ validator = IssueValidation (xml_tree , params = params )
1575+ obtained = validator .validate_expected_issues ()
1576+
1577+ self .assertEqual (obtained ["response" ], "OK" )
1578+
1579+ def test_issue_absent_from_registered_list (self ):
1580+ """Test that issue absent from the list fails"""
1581+ xml = """
1582+ <article>
1583+ <front>
1584+ <article-meta>
1585+ <volume>56</volume>
1586+ <issue>99</issue>
1587+ </article-meta>
1588+ </front>
1589+ </article>
1590+ """
1591+ xml_tree = etree .fromstring (xml )
1592+ params = {
1593+ "expected_issues_error_level" : "CRITICAL" ,
1594+ "journal_data" : {
1595+ "issues" : [{"volume" : "56" , "number" : "4" , "supplement" : None }]
1596+ }
1597+ }
1598+ validator = IssueValidation (xml_tree , params = params )
1599+ obtained = validator .validate_expected_issues ()
1600+
1601+ self .assertEqual (obtained ["response" ], "CRITICAL" )
1602+
1603+ def test_journal_data_absent (self ):
1604+ """Test that missing journal_data returns WARNING"""
1605+ xml = """
1606+ <article>
1607+ <front>
1608+ <article-meta>
1609+ <volume>56</volume>
1610+ <issue>4</issue>
1611+ </article-meta>
1612+ </front>
1613+ </article>
1614+ """
1615+ xml_tree = etree .fromstring (xml )
1616+ params = {"expected_issues_error_level" : "CRITICAL" }
1617+ validator = IssueValidation (xml_tree , params = params )
1618+ obtained = validator .validate_expected_issues ()
1619+
1620+ self .assertEqual (obtained ["response" ], "WARNING" )
1621+ self .assertIn ("Unable to check" , obtained ["advice" ])
1622+
1623+
1624+ class PaginationAdditionalTest (TestCase ):
1625+ """Additional pagination tests for missing coverage"""
1626+
1627+ def setUp (self ):
1628+ self .params = {
1629+ "pagination_error_level" : "CRITICAL" ,
1630+ }
1631+
1632+ def test_only_elocation_id_valid (self ):
1633+ """Test that only elocation-id is valid"""
1634+ xml = """
1635+ <article>
1636+ <front>
1637+ <article-meta>
1638+ <volume>56</volume>
1639+ <elocation-id>e12345</elocation-id>
1640+ </article-meta>
1641+ </front>
1642+ </article>
1643+ """
1644+ xml_tree = etree .fromstring (xml )
1645+ validator = PaginationValidation (xml_tree , params = self .params )
1646+ obtained = validator .validate ()
1647+
1648+ self .assertEqual (obtained ["response" ], "OK" )
1649+
1650+ def test_only_fpage_lpage_valid (self ):
1651+ """Test that only fpage and lpage is valid"""
1652+ xml = """
1653+ <article>
1654+ <front>
1655+ <article-meta>
1656+ <volume>56</volume>
1657+ <fpage>100</fpage>
1658+ <lpage>120</lpage>
1659+ </article-meta>
1660+ </front>
1661+ </article>
1662+ """
1663+ xml_tree = etree .fromstring (xml )
1664+ validator = PaginationValidation (xml_tree , params = self .params )
1665+ obtained = validator .validate ()
1666+
1667+ self .assertEqual (obtained ["response" ], "OK" )
1668+
1669+ def test_aop_no_pagination_valid (self ):
1670+ """Test that AOP (no volume, no issue, no pagination) is valid"""
1671+ xml = """
1672+ <article>
1673+ <front>
1674+ <article-meta>
1675+ </article-meta>
1676+ </front>
1677+ </article>
1678+ """
1679+ xml_tree = etree .fromstring (xml )
1680+ validator = PaginationValidation (xml_tree , params = self .params )
1681+ obtained = validator .validate ()
1682+
1683+ self .assertEqual (obtained ["response" ], "OK" )
1684+
1685+
1686+ class SpecialNomenclatureAdditionalTest (TestCase ):
1687+ """Additional tests for special issue nomenclature"""
1688+
1689+ def setUp (self ):
1690+ self .params = {
1691+ "issue_special_nomenclature_error_level" : "ERROR" ,
1692+ }
1693+
1694+ def test_issue_nspe_invalid (self ):
1695+ """Test that 'nspe' is rejected"""
1696+ xml = """
1697+ <article>
1698+ <front>
1699+ <article-meta>
1700+ <issue>nspe1</issue>
1701+ </article-meta>
1702+ </front>
1703+ </article>
1704+ """
1705+ xml_tree = etree .fromstring (xml )
1706+ validator = IssueValidation (xml_tree , params = self .params )
1707+ obtained = validator .validate_issue_special_nomenclature ()
1708+
1709+ self .assertEqual (obtained ["response" ], "ERROR" )
1710+ self .assertIn ("nspe" , obtained ["data" ]["invalid_terms" ])
1711+
1712+ def test_issue_noesp_invalid (self ):
1713+ """Test that 'noesp' is rejected"""
1714+ xml = """
1715+ <article>
1716+ <front>
1717+ <article-meta>
1718+ <issue>noesp1</issue>
1719+ </article-meta>
1720+ </front>
1721+ </article>
1722+ """
1723+ xml_tree = etree .fromstring (xml )
1724+ validator = IssueValidation (xml_tree , params = self .params )
1725+ obtained = validator .validate_issue_special_nomenclature ()
1726+
1727+ self .assertEqual (obtained ["response" ], "ERROR" )
1728+ self .assertIn ("noesp" , obtained ["data" ]["invalid_terms" ])
0 commit comments