"""
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()