# -*- coding: utf-8 -*- import unittest from io import BytesIO from docx import Document from odoo.addons.survey_custom_certificate_template.services.certificate_template_parser import ( CertificateTemplateParser, ) class TestCertificateTemplateParser(unittest.TestCase): """Test cases for CertificateTemplateParser service""" def setUp(self): """Set up test fixtures""" self.parser = CertificateTemplateParser() def _create_test_docx(self, text_content): """ Helper method to create a DOCX file with given text content. Args: text_content: String or list of strings to add as paragraphs Returns: bytes: Binary content of the created DOCX file """ doc = Document() if isinstance(text_content, str): text_content = [text_content] for text in text_content: doc.add_paragraph(text) # Save to BytesIO doc_stream = BytesIO() doc.save(doc_stream) doc_stream.seek(0) return doc_stream.read() def test_get_placeholder_pattern(self): """Test that get_placeholder_pattern returns the correct regex pattern""" pattern = self.parser.get_placeholder_pattern() self.assertEqual(pattern, r'\{key\.[a-zA-Z0-9_]+\}') def test_validate_template_valid_docx(self): """Test validation of a valid DOCX file""" docx_binary = self._create_test_docx("Test content") is_valid, error_msg = self.parser.validate_template(docx_binary) self.assertTrue(is_valid) self.assertEqual(error_msg, "") def test_validate_template_empty_file(self): """Test validation of an empty file""" is_valid, error_msg = self.parser.validate_template(b"") self.assertFalse(is_valid) self.assertEqual(error_msg, "Template file is empty") def test_validate_template_invalid_type(self): """Test validation with non-binary input""" is_valid, error_msg = self.parser.validate_template("not bytes") self.assertFalse(is_valid) self.assertEqual(error_msg, "Template must be provided as binary data") def test_validate_template_corrupted_file(self): """Test validation of a corrupted DOCX file""" corrupted_data = b"This is not a valid DOCX file" is_valid, error_msg = self.parser.validate_template(corrupted_data) self.assertFalse(is_valid) self.assertIn("not a valid DOCX file", error_msg) def test_parse_template_single_placeholder(self): """Test parsing a template with a single placeholder""" docx_binary = self._create_test_docx("Hello {key.name}, welcome!") placeholders = self.parser.parse_template(docx_binary) self.assertEqual(placeholders, ["{key.name}"]) def test_parse_template_multiple_placeholders(self): """Test parsing a template with multiple placeholders""" text = "Certificate for {key.name} who completed {key.course_name} on {key.date}" docx_binary = self._create_test_docx(text) placeholders = self.parser.parse_template(docx_binary) expected = ["{key.course_name}", "{key.date}", "{key.name}"] self.assertEqual(placeholders, expected) def test_parse_template_no_placeholders(self): """Test parsing a template with no placeholders""" docx_binary = self._create_test_docx("This is a static certificate") placeholders = self.parser.parse_template(docx_binary) self.assertEqual(placeholders, []) def test_parse_template_duplicate_placeholders(self): """Test that duplicate placeholders are only returned once""" text_content = [ "Hello {key.name}", "Welcome {key.name}", "Course: {key.course_name}" ] docx_binary = self._create_test_docx(text_content) placeholders = self.parser.parse_template(docx_binary) expected = ["{key.course_name}", "{key.name}"] self.assertEqual(placeholders, expected) def test_parse_template_with_table(self): """Test parsing placeholders from tables""" doc = Document() doc.add_paragraph("Header text with {key.header}") # Add a table with placeholders table = doc.add_table(rows=2, cols=2) table.cell(0, 0).text = "Name: {key.name}" table.cell(0, 1).text = "Date: {key.date}" table.cell(1, 0).text = "Course: {key.course_name}" table.cell(1, 1).text = "Score: {key.score}" # Save to bytes doc_stream = BytesIO() doc.save(doc_stream) doc_stream.seek(0) docx_binary = doc_stream.read() placeholders = self.parser.parse_template(docx_binary) expected = [ "{key.course_name}", "{key.date}", "{key.header}", "{key.name}", "{key.score}" ] self.assertEqual(placeholders, expected) def test_parse_template_invalid_placeholder_format(self): """Test that invalid placeholder formats are not extracted""" text = "Valid: {key.name}, Invalid: {invalid}, {key}, {key.}" docx_binary = self._create_test_docx(text) placeholders = self.parser.parse_template(docx_binary) # Only the valid placeholder should be extracted self.assertEqual(placeholders, ["{key.name}"]) def test_parse_template_with_underscores_and_numbers(self): """Test placeholders with underscores and numbers in field names""" text = "Fields: {key.field_1} and {key.field_name_2} and {key.field123}" docx_binary = self._create_test_docx(text) placeholders = self.parser.parse_template(docx_binary) expected = ["{key.field123}", "{key.field_1}", "{key.field_name_2}"] self.assertEqual(placeholders, expected) def test_parse_template_raises_on_invalid_file(self): """Test that parse_template raises ValueError for invalid files""" corrupted_data = b"This is not a valid DOCX file" with self.assertRaises(ValueError) as context: self.parser.parse_template(corrupted_data) self.assertIn("not a valid DOCX file", str(context.exception)) def test_parse_template_with_headers_and_footers(self): """Test parsing placeholders from headers and footers""" doc = Document() # Add content to body doc.add_paragraph("Body: {key.body_field}") # Add header section = doc.sections[0] header = section.header header.paragraphs[0].text = "Header: {key.header_field}" # Add footer footer = section.footer footer.paragraphs[0].text = "Footer: {key.footer_field}" # Save to bytes doc_stream = BytesIO() doc.save(doc_stream) doc_stream.seek(0) docx_binary = doc_stream.read() placeholders = self.parser.parse_template(docx_binary) expected = [ "{key.body_field}", "{key.footer_field}", "{key.header_field}" ] self.assertEqual(placeholders, expected) if __name__ == '__main__': unittest.main()