189 lines
6.9 KiB
Python
189 lines
6.9 KiB
Python
"""
|
|
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 = '''<resources>
|
|
<string name="app_name">Test App</string>
|
|
<string name="welcome_message">Welcome to our app!</string>
|
|
<!-- This is a comment -->
|
|
<string name="button_ok">OK</string>
|
|
</resources>'''
|
|
|
|
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 = '''<resources>
|
|
<string name="existing_key">Existing value</string>
|
|
</resources>'''
|
|
|
|
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 = '''<resources>
|
|
<string name="app_name">Test App</string>
|
|
<string-array name="vocabulary_hints">
|
|
<item>Basic greetings</item>
|
|
<item>Irregular verbs</item>
|
|
<item>Vocabulary at the airport</item>
|
|
</string-array>
|
|
</resources>'''
|
|
|
|
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 = '''<resources>
|
|
<string name="existing_key">Existing value</string>
|
|
</resources>'''
|
|
|
|
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 = '''<resources>
|
|
<string-array name="translatable_array" translatable="true">
|
|
<item>Item 1</item>
|
|
</string-array>
|
|
<string-array name="non_translatable_array" translatable="false">
|
|
<item>Item 2</item>
|
|
</string-array>
|
|
</resources>'''
|
|
|
|
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()
|