""" Tests for XML processor module """ import unittest import tempfile import os from lxml import etree from unittest.mock import patch, MagicMock from config import Config from models import TranslationItem from xml_processor import XMLProcessor class TestXMLProcessor(unittest.TestCase): """Test cases for XMLProcessor class""" def setUp(self): """Set up test fixtures""" # Create a mock config self.mock_config = MagicMock(spec=Config) self.mock_config.output_config = { 'create_backups': True, 'backup_suffix': '.backup' } self.processor = XMLProcessor(self.mock_config) # Sample XML content (without XML declaration for testing) self.sample_xml = ''' Test App Welcome to our app! OK ''' def test_load_xml_file_success(self): """Test successful XML file loading""" with tempfile.NamedTemporaryFile(mode='w', suffix='.xml', delete=False) as f: f.write(self.sample_xml) temp_path = f.name try: root = self.processor.load_xml_file(temp_path) self.assertIsNotNone(root) self.assertEqual(root.tag, 'resources') self.assertEqual(len(root.findall('string')), 3) finally: os.unlink(temp_path) def test_load_xml_file_error(self): """Test error handling when loading invalid XML file""" with tempfile.NamedTemporaryFile(mode='w', suffix='.xml', delete=False) as f: f.write('invalid xml content') temp_path = f.name try: root = self.processor.load_xml_file(temp_path) self.assertIsNone(root) finally: os.unlink(temp_path) def test_extract_strings(self): """Test extracting strings from XML""" root = etree.fromstring(self.sample_xml) strings = self.processor.extract_strings(root) self.assertEqual(len(strings), 3) self.assertIn('app_name', strings) self.assertIn('welcome_message', strings) self.assertIn('button_ok', strings) # Check string values self.assertEqual(strings['app_name'].value, 'Test App') self.assertEqual(strings['welcome_message'].value, 'Welcome to our app!') self.assertEqual(strings['button_ok'].value, 'OK') # Check that all items are TranslationItem instances for item in strings.values(): self.assertIsInstance(item, TranslationItem) def test_add_missing_strings(self): """Test adding missing strings to XML""" # Create target XML with one existing string target_xml = ''' Existing value ''' target_root = etree.fromstring(target_xml) missing_strings = [ ('new_key1', 'New value 1', 'string', []), ('new_key2', 'New value 2', 'string', []), ('existing_key', 'Should not be added', 'string', []) # This should be ignored ] self.processor.add_missing_strings(target_root, missing_strings) # Check that new strings were added strings = target_root.findall('string') self.assertEqual(len(strings), 3) # 1 existing + 2 new # Check specific strings new_key1 = target_root.find(".//string[@name='new_key1']") self.assertIsNotNone(new_key1) self.assertEqual(new_key1.text, 'New value 1') new_key2 = target_root.find(".//string[@name='new_key2']") self.assertIsNotNone(new_key2) self.assertEqual(new_key2.text, 'New value 2') # Check existing string wasn't duplicated existing_strings = target_root.findall(".//string[@name='existing_key']") self.assertEqual(len(existing_strings), 1) def test_extract_string_array(self): """Test extracting string arrays from XML""" xml_with_array = ''' Test App Basic greetings Irregular verbs Vocabulary at the airport ''' root = etree.fromstring(xml_with_array) strings = self.processor.extract_strings(root) self.assertEqual(len(strings), 2) self.assertIn('app_name', strings) self.assertIn('vocabulary_hints', strings) # Check string array array_item = strings['vocabulary_hints'] self.assertEqual(array_item.item_type, 'string-array') self.assertEqual(len(array_item.items), 3) self.assertEqual(array_item.items[0], 'Basic greetings') self.assertEqual(array_item.items[1], 'Irregular verbs') self.assertEqual(array_item.items[2], 'Vocabulary at the airport') self.assertEqual(array_item.value, 'Basic greetings | Irregular verbs | Vocabulary at the airport') def test_add_missing_string_array(self): """Test adding missing string arrays to XML""" target_xml = ''' Existing value ''' target_root = etree.fromstring(target_xml) missing_strings = [ ('vocabulary_hints', '', 'string-array', ['Basic greetings', 'Irregular verbs']) ] self.processor.add_missing_strings(target_root, missing_strings) # Check that string-array was added string_array = target_root.find(".//string-array[@name='vocabulary_hints']") self.assertIsNotNone(string_array) # Check items items = string_array.findall('item') self.assertEqual(len(items), 2) self.assertEqual(items[0].text, 'Basic greetings') self.assertEqual(items[1].text, 'Irregular verbs') def test_skip_non_translatable_string_array(self): """Test that non-translatable string arrays are skipped""" xml_with_non_translatable = ''' Item 1 Item 2 ''' root = etree.fromstring(xml_with_non_translatable) strings = self.processor.extract_strings(root) self.assertEqual(len(strings), 1) self.assertIn('translatable_array', strings) self.assertNotIn('non_translatable_array', strings) # Note: File saving tests are complex to mock properly due to lxml internals # The core functionality is tested through integration tests if __name__ == '__main__': unittest.main()