diff --git a/packtools/sps/validation/media.py b/packtools/sps/validation/media.py index d9b43075a..5f791c4ca 100644 --- a/packtools/sps/validation/media.py +++ b/packtools/sps/validation/media.py @@ -24,7 +24,7 @@ def validate_mime_type_and_subtype(self): item="mime type and subtype", sub_item=None, is_valid=valid, - validation_type="value in lis", + validation_type="value in list", expected=mime_types_and_subtypes, obtained=got, advice=f"Use expected values: {mime_types_and_subtypes}", diff --git a/packtools/sps/validation_rules/visual_resource_base_rules.json b/packtools/sps/validation_rules/visual_resource_base_rules.json index 1e5e90b1b..806d3de08 100644 --- a/packtools/sps/validation_rules/visual_resource_base_rules.json +++ b/packtools/sps/validation_rules/visual_resource_base_rules.json @@ -2,13 +2,15 @@ "visual_resource_base_rules": { "media_attributes_error_level": "CRITICAL", "xlink_href_error_level": "CRITICAL", - "valid_extension": ["mp3", "mp4", "zip", "pdf", "xlsx"], + "valid_extension": ["mp3", "mp4", "zip", "pdf", "xlsx", "docx", "pptx"], "mime_types_and_subtypes": [ {"mimetype": "video", "mime-subtype": "mp4"}, {"mimetype": "audio", "mime-subtype": "mp3"}, {"mimetype": "application", "mime-subtype": "zip"}, {"mimetype": "application", "mime-subtype": "pdf"}, - {"mimetype": "application", "mime-subtype": "xlsx"} + {"mimetype": "application", "mime-subtype": "xlsx"}, + {"mimetype": "application", "mime-subtype": "docx"}, + {"mimetype": "application", "mime-subtype": "pptx"} ], "mime_type_error_level": "CRITICAL", "alt_text_exist_error_level": "WARNING", diff --git a/tests/sps/models/test_media.py b/tests/sps/models/test_media.py index 1abe5d3f9..68b147bed 100644 --- a/tests/sps/models/test_media.py +++ b/tests/sps/models/test_media.py @@ -14,9 +14,13 @@ def setUp(self): # Criando sub-artigo para validar extração por ArticleAndSubArticles self.sub_article = SubElement(self.article, "sub-article", {"id": "sub1"}) - # Adicionando ao sub-artigo + # Media elements must be inside body/front/back for XPath extraction + body = SubElement(self.sub_article, "body") + sec = SubElement(body, "sec") + + # Adicionando ao body do sub-artigo self.media1 = SubElement( - self.sub_article, + sec, "media", { "id": "media1", @@ -27,7 +31,7 @@ def setUp(self): ) self.media2 = SubElement( - self.sub_article, + sec, "media", { "id": "media2", @@ -38,7 +42,7 @@ def setUp(self): ) # Criando parágrafo com - paragraph = SubElement(self.sub_article, "p") + paragraph = SubElement(sec, "p") self.inline_media = SubElement( paragraph, "inline-media", @@ -98,7 +102,7 @@ def test_inline_media_data_output(self): def test_xmlmedia_generates_data(self): """Testa se XmlMedia gera corretamente um iterador de dicionários.""" xml_media = XmlMedias(self.article) - data_list = list(xml_media.data()) + data_list = list(xml_media.data) # Deve haver 3 elementos (2 + 1 ) self.assertEqual(len(data_list), 3) @@ -125,7 +129,7 @@ def test_xmlmedia_generates_data(self): def test_xmlmedia_handles_no_media(self): """Testa o comportamento quando o XML não contém mídias.""" xml_media = XmlMedias(self.article_no_media) - data_list = list(xml_media.data()) + data_list = list(xml_media.data) # Não há mídia no XML, o iterador deve ser vazio self.assertEqual(len(data_list), 0) diff --git a/tests/sps/validation/test_media.py b/tests/sps/validation/test_media.py index d04984feb..6cfd3148d 100644 --- a/tests/sps/validation/test_media.py +++ b/tests/sps/validation/test_media.py @@ -1,105 +1,167 @@ import unittest -from lxml import etree +from unittest.mock import MagicMock + from packtools.sps.validation.media import MediaValidation -from packtools.sps.models.media import ( - Media, -) # Importando a classe correta para obter media_data class MediaValidationTest(unittest.TestCase): + def setUp(self): + self.params = { + "media_attributes_error_level": "CRITICAL", + "xlink_href_error_level": "CRITICAL", + "valid_extension": ["mp3", "mp4", "zip", "pdf", "xlsx", "docx", "pptx"], + "mime_types_and_subtypes": [ + {"mimetype": "video", "mime-subtype": "mp4"}, + {"mimetype": "audio", "mime-subtype": "mp3"}, + {"mimetype": "application", "mime-subtype": "zip"}, + {"mimetype": "application", "mime-subtype": "pdf"}, + {"mimetype": "application", "mime-subtype": "xlsx"}, + {"mimetype": "application", "mime-subtype": "docx"}, + {"mimetype": "application", "mime-subtype": "pptx"}, + ], + "mime_type_error_level": "CRITICAL", + } + def test_validate_id_failure(self): """Fails when @id attribute is missing.""" - xml_content = """ - - - """ - media_node = etree.fromstring(xml_content) - media_data = Media(media_node).data # Criando media_data a partir de media_node - params = {"media_attributes_error_level": "CRITICAL"} - - validator = MediaValidation(media_node, media_data, params) - results = validator.validate_id() - self.assertEqual(results["response"], "CRITICAL") - self.assertEqual(results["advice"], "Ensure @id is included.") - - def test_validate_mime_type_failure(self): - """Fails when @mime-type is invalid.""" - xml_content = """ - - - """ - media_node = etree.fromstring(xml_content) - media_data = Media(media_node).data - params = {"mime_type_error_level": "CRITICAL"} - - validator = MediaValidation(media_node, media_data, params) - results = validator.validate_mime_type() - self.assertEqual(results["response"], "CRITICAL") - self.assertEqual( - results["advice"], "Use a valid @mime-type (application, video, audio)." - ) + data = { + "tag": "media", + "xml": "", + "id": None, + "xlink_href": "video.mp4", + "mimetype": "video", + "mime_subtype": "mp4", + } + validator = MediaValidation(data, self.params) + result = validator.validate_id() + self.assertEqual(result["response"], "CRITICAL") + self.assertIsNone(result["got_value"]) + + def test_validate_id_success(self): + """Passes when @id attribute is present.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "video.mp4", + "mimetype": "video", + "mime_subtype": "mp4", + } + validator = MediaValidation(data, self.params) + result = validator.validate_id() + self.assertEqual(result["response"], "OK") + + def test_validate_mime_type_and_subtype_failure(self): + """Fails when mime-type/mime-subtype combination is invalid.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "video.mp4", + "mimetype": "invalid", + "mime_subtype": "mp4", + } + validator = MediaValidation(data, self.params) + result = validator.validate_mime_type_and_subtype() + self.assertEqual(result["response"], "CRITICAL") + self.assertIsNotNone(result["advice"]) + + def test_validate_mime_type_and_subtype_success(self): + """Passes when mime-type/mime-subtype combination is valid.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "video.mp4", + "mimetype": "video", + "mime_subtype": "mp4", + } + validator = MediaValidation(data, self.params) + result = validator.validate_mime_type_and_subtype() + self.assertEqual(result["response"], "OK") - def test_validate_mime_subtype_failure(self): - """Fails when @mime-subtype does not match the expected format.""" - xml_content = """ - - - """ - media_node = etree.fromstring(xml_content) - media_data = Media(media_node).data - params = {"mime_subtype_error_level": "CRITICAL"} - - validator = MediaValidation(media_node, media_data, params) - results = validator.validate_mime_subtype() - self.assertEqual(results["response"], "CRITICAL") - self.assertEqual(results["advice"], "For video, use mp4 as @mime-subtype.") + def test_validate_mime_type_and_subtype_audio_failure(self): + """Fails when audio has wrong mime-subtype.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "audio.wav", + "mimetype": "audio", + "mime_subtype": "wav", + } + validator = MediaValidation(data, self.params) + result = validator.validate_mime_type_and_subtype() + self.assertEqual(result["response"], "CRITICAL") def test_validate_xlink_href_failure(self): - """Fails when @xlink:href is not in a valid format.""" - xml_content = """ - - - """ - media_node = etree.fromstring(xml_content) - media_data = Media(media_node).data - params = {"xlink_href_error_level": "CRITICAL"} - - validator = MediaValidation(media_node, media_data, params) - results = validator.validate_xlink_href() - self.assertEqual(results["response"], "CRITICAL") - self.assertEqual( - results["advice"], - "Provide a valid file name with its extension in @xlink:href.", - ) + """Fails when @xlink:href has invalid extension.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "invalid_file", + "mimetype": "video", + "mime_subtype": "mp4", + } + validator = MediaValidation(data, self.params) + result = validator.validate_xlink_href() + self.assertEqual(result["response"], "CRITICAL") + self.assertIsNotNone(result["advice"]) - def test_validate_accessibility_failure(self): - """Fails when no accessibility elements are provided.""" - xml_content = """ - - - """ - media_node = etree.fromstring(xml_content) - media_data = Media(media_node).data - params = { - "accessibility_error_level": "CRITICAL", - "mime_type_error_level": "CRITICAL", - "mime_subtype_error_level": "CRITICAL", - "alt_text_error_level": "CRITICAL", - "long_desc_error_level": "CRITICAL", - "transcript_error_level": "CRITICAL", - "content_type_error_level": "CRITICAL", - "speaker_speech_error_level": "CRITICAL", + def test_validate_xlink_href_success(self): + """Passes when @xlink:href has valid extension.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "video.mp4", + "mimetype": "video", + "mime_subtype": "mp4", } + validator = MediaValidation(data, self.params) + result = validator.validate_xlink_href() + self.assertEqual(result["response"], "OK") - validator = MediaValidation(media_node, media_data, params) - results = list(validator.validate()) - self.assertEqual(len(results), 9) + def test_validate_integration_with_mocked_accessibility(self): + """Tests full validate() flow with mocked accessibility.""" + data = { + "tag": "media", + "xml": "", + "id": "m1", + "xlink_href": "video.mp4", + "mimetype": "video", + "mime_subtype": "mp4", + } + + from packtools.sps.validation import visual_resource_base + original = visual_resource_base.AccessibilityDataValidation + visual_resource_base.AccessibilityDataValidation = lambda data, params: MagicMock( + validate=lambda: iter([{"mocked": True}]) + ) + + try: + validator = MediaValidation(data, self.params) + results = list(validator.validate()) + # 1 (mime_type_and_subtype) + 1 (id) + 1 (xlink_href) + 1 (mocked accessibility) + self.assertEqual(len(results), 4) + finally: + visual_resource_base.AccessibilityDataValidation = original + + def test_validate_inline_media_id_not_required(self): + """For inline-media, @id is not required.""" + data = { + "tag": "inline-media", + "xml": "", + "id": None, + "xlink_href": "document.pdf", + "mimetype": "application", + "mime_subtype": "pdf", + } + validator = MediaValidation(data, self.params) + result = validator.validate_id() + self.assertEqual(result["response"], "OK") if __name__ == "__main__":