migrate to gitea
This commit is contained in:
3
tests/__init__.py
Normal file
3
tests/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Test package for Android XML Translation Tool
|
||||
"""
|
||||
141
tests/test_config.py
Normal file
141
tests/test_config.py
Normal file
@@ -0,0 +1,141 @@
|
||||
"""
|
||||
Tests for configuration module
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import tempfile
|
||||
import os
|
||||
import yaml
|
||||
from unittest.mock import patch
|
||||
from config import Config
|
||||
|
||||
|
||||
class TestConfig(unittest.TestCase):
|
||||
"""Test cases for Config class"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures"""
|
||||
self.test_config_data = {
|
||||
'llm': {
|
||||
'base_url': 'http://localhost:1234',
|
||||
'api_key': 'test-key',
|
||||
'model': 'test-model'
|
||||
},
|
||||
'android': {
|
||||
'input_folder': 'app/src/main/res',
|
||||
'base_values_folder': 'values',
|
||||
'target_folders': ['values-de-rDE'],
|
||||
'files_to_translate': ['strings.xml']
|
||||
},
|
||||
'translation': {
|
||||
'batch_size': 5,
|
||||
'interactive_approval': True
|
||||
}
|
||||
}
|
||||
|
||||
def test_load_valid_config(self):
|
||||
"""Test loading a valid configuration file"""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||
yaml.dump(self.test_config_data, f)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
config = Config(temp_path)
|
||||
self.assertEqual(config.llm_config['base_url'], 'http://localhost:1234')
|
||||
self.assertEqual(config.android_config['input_folder'], 'app/src/main/res')
|
||||
self.assertEqual(config.translation_config['batch_size'], 5)
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_missing_file_error(self):
|
||||
"""Test error handling for missing configuration file"""
|
||||
with patch('sys.exit') as mock_exit:
|
||||
Config('nonexistent.yaml')
|
||||
mock_exit.assert_called_once_with(1)
|
||||
|
||||
def test_missing_required_section(self):
|
||||
"""Test error handling for missing required sections"""
|
||||
incomplete_data = {'llm': self.test_config_data['llm']} # Missing android and translation
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||
yaml.dump(incomplete_data, f)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
with patch('sys.exit') as mock_exit:
|
||||
Config(temp_path)
|
||||
mock_exit.assert_called_with(1) # Remove assert_called_once
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_output_config_default(self):
|
||||
"""Test default output configuration"""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||
yaml.dump(self.test_config_data, f)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
config = Config(temp_path)
|
||||
output_config = config.output_config
|
||||
self.assertEqual(output_config, {}) # Should be empty dict when not specified
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_examples_config_missing(self):
|
||||
"""Test examples config when not specified"""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||
yaml.dump(self.test_config_data, f)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
config = Config(temp_path)
|
||||
self.assertFalse(config.has_examples_config())
|
||||
self.assertEqual(config.examples_config, {})
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_examples_config_present(self):
|
||||
"""Test examples config when specified"""
|
||||
config_with_examples = self.test_config_data.copy()
|
||||
config_with_examples['examples'] = {
|
||||
'input_folder': 'examples',
|
||||
'base_folder': 'assets/hints',
|
||||
'target_folders': ['assets/hints-de-rDE'],
|
||||
'file_extension': '.md'
|
||||
}
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||
yaml.dump(config_with_examples, f)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
config = Config(temp_path)
|
||||
self.assertTrue(config.has_examples_config())
|
||||
self.assertEqual(config.examples_config['input_folder'], 'examples')
|
||||
self.assertEqual(config.examples_config['base_folder'], 'assets/hints')
|
||||
self.assertEqual(config.examples_config['target_folders'], ['assets/hints-de-rDE'])
|
||||
self.assertEqual(config.examples_config['file_extension'], '.md')
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_examples_config_incomplete(self):
|
||||
"""Test has_examples_config returns False for incomplete config"""
|
||||
config_with_examples = self.test_config_data.copy()
|
||||
config_with_examples['examples'] = {
|
||||
'input_folder': 'examples',
|
||||
# Missing base_folder and target_folders
|
||||
}
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
|
||||
yaml.dump(config_with_examples, f)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
config = Config(temp_path)
|
||||
self.assertFalse(config.has_examples_config())
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
272
tests/test_md_processor.py
Normal file
272
tests/test_md_processor.py
Normal file
@@ -0,0 +1,272 @@
|
||||
"""
|
||||
Tests for MD processor module
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import tempfile
|
||||
import os
|
||||
from md_processor import MDProcessor, MDTranslationItem
|
||||
|
||||
|
||||
class TestMDProcessor(unittest.TestCase):
|
||||
"""Test cases for MDProcessor class"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures"""
|
||||
self.processor = MDProcessor()
|
||||
|
||||
def test_get_md_files(self):
|
||||
"""Test getting .md files from a folder"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create test files
|
||||
open(os.path.join(tmpdir, "file1.md"), 'w').close()
|
||||
open(os.path.join(tmpdir, "file2.md"), 'w').close()
|
||||
open(os.path.join(tmpdir, "not_md.txt"), 'w').close()
|
||||
os.makedirs(os.path.join(tmpdir, "subdir"))
|
||||
open(os.path.join(tmpdir, "subdir", "file3.md"), 'w').close()
|
||||
|
||||
# Get .md files (non-recursive)
|
||||
files = self.processor.get_md_files(tmpdir)
|
||||
|
||||
self.assertEqual(len(files), 2)
|
||||
self.assertIn("file1.md", files)
|
||||
self.assertIn("file2.md", files)
|
||||
self.assertNotIn("not_md.txt", files)
|
||||
self.assertNotIn("file3.md", files) # In subdir, not included
|
||||
|
||||
def test_get_md_files_nonexistent_folder(self):
|
||||
"""Test getting .md files from a non-existent folder"""
|
||||
files = self.processor.get_md_files("/nonexistent/path")
|
||||
self.assertEqual(files, [])
|
||||
|
||||
def test_load_md_file(self):
|
||||
"""Test loading markdown file content"""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
||||
f.write("# Test Content\n\nThis is a test.")
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
content = self.processor.load_md_file(temp_path)
|
||||
self.assertEqual(content, "# Test Content\n\nThis is a test.")
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_load_md_file_nonexistent(self):
|
||||
"""Test loading a non-existent markdown file"""
|
||||
content = self.processor.load_md_file("/nonexistent/file.md")
|
||||
self.assertEqual(content, "")
|
||||
|
||||
def test_save_md_file(self):
|
||||
"""Test saving markdown file"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
file_path = os.path.join(tmpdir, "test.md")
|
||||
content = "# Test Content\n\nThis is a test."
|
||||
|
||||
self.processor.save_md_file(content, file_path)
|
||||
|
||||
# Verify file was created
|
||||
self.assertTrue(os.path.exists(file_path))
|
||||
|
||||
# Verify content
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
saved_content = f.read()
|
||||
self.assertEqual(saved_content, content)
|
||||
|
||||
def test_save_md_file_creates_directories(self):
|
||||
"""Test that save_md_file creates parent directories"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
nested_path = os.path.join(tmpdir, "subdir1", "subdir2", "test.md")
|
||||
content = "# Nested Content"
|
||||
|
||||
self.processor.save_md_file(content, nested_path)
|
||||
|
||||
# Verify file was created in nested directory
|
||||
self.assertTrue(os.path.exists(nested_path))
|
||||
|
||||
def test_extract_content(self):
|
||||
"""Test extracting content from all .md files"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create test files
|
||||
with open(os.path.join(tmpdir, "file1.md"), 'w') as f:
|
||||
f.write("# File 1")
|
||||
with open(os.path.join(tmpdir, "file2.md"), 'w') as f:
|
||||
f.write("# File 2")
|
||||
|
||||
items = self.processor.extract_content(tmpdir)
|
||||
|
||||
self.assertEqual(len(items), 2)
|
||||
self.assertIn("file1.md", items)
|
||||
self.assertIn("file2.md", items)
|
||||
self.assertEqual(items["file1.md"].content, "# File 1")
|
||||
self.assertEqual(items["file2.md"].content, "# File 2")
|
||||
self.assertEqual(items["file1.md"].filename, "file1.md")
|
||||
|
||||
def test_extract_content_empty_folder(self):
|
||||
"""Test extracting content from empty folder"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
items = self.processor.extract_content(tmpdir)
|
||||
self.assertEqual(items, {})
|
||||
|
||||
def test_check_asset_counts_valid(self):
|
||||
"""Test asset count check when all folders have same count"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create base folder with files
|
||||
base_folder = os.path.join(tmpdir, "base")
|
||||
os.makedirs(base_folder)
|
||||
open(os.path.join(base_folder, "file1.md"), 'w').close()
|
||||
open(os.path.join(base_folder, "file2.md"), 'w').close()
|
||||
|
||||
# Create target folders with same files
|
||||
target1 = os.path.join(tmpdir, "target1")
|
||||
os.makedirs(target1)
|
||||
open(os.path.join(target1, "file1.md"), 'w').close()
|
||||
open(os.path.join(target1, "file2.md"), 'w').close()
|
||||
|
||||
target2 = os.path.join(tmpdir, "target2")
|
||||
os.makedirs(target2)
|
||||
open(os.path.join(target2, "file1.md"), 'w').close()
|
||||
open(os.path.join(target2, "file2.md"), 'w').close()
|
||||
|
||||
is_valid, errors = self.processor.check_asset_counts(base_folder, [target1, target2])
|
||||
|
||||
self.assertTrue(is_valid)
|
||||
self.assertEqual(errors, [])
|
||||
|
||||
def test_check_asset_counts_missing_files(self):
|
||||
"""Test asset count check when target is missing files"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create base folder with files
|
||||
base_folder = os.path.join(tmpdir, "base")
|
||||
os.makedirs(base_folder)
|
||||
open(os.path.join(base_folder, "file1.md"), 'w').close()
|
||||
open(os.path.join(base_folder, "file2.md"), 'w').close()
|
||||
|
||||
# Create target folder with missing file
|
||||
target1 = os.path.join(tmpdir, "target1")
|
||||
os.makedirs(target1)
|
||||
open(os.path.join(target1, "file1.md"), 'w').close()
|
||||
# file2.md is missing
|
||||
|
||||
is_valid, errors = self.processor.check_asset_counts(base_folder, [target1])
|
||||
|
||||
self.assertFalse(is_valid)
|
||||
self.assertEqual(len(errors), 1)
|
||||
self.assertIn("file2.md", errors[0])
|
||||
|
||||
def test_check_asset_counts_extra_files(self):
|
||||
"""Test asset count check when target has extra files"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create base folder with files
|
||||
base_folder = os.path.join(tmpdir, "base")
|
||||
os.makedirs(base_folder)
|
||||
open(os.path.join(base_folder, "file1.md"), 'w').close()
|
||||
|
||||
# Create target folder with extra file
|
||||
target1 = os.path.join(tmpdir, "target1")
|
||||
os.makedirs(target1)
|
||||
open(os.path.join(target1, "file1.md"), 'w').close()
|
||||
open(os.path.join(target1, "extra.md"), 'w').close()
|
||||
|
||||
is_valid, errors = self.processor.check_asset_counts(base_folder, [target1])
|
||||
|
||||
self.assertFalse(is_valid)
|
||||
self.assertEqual(len(errors), 1)
|
||||
self.assertIn("extra.md", errors[0])
|
||||
|
||||
def test_check_asset_counts_empty_base(self):
|
||||
"""Test asset count check with empty base folder"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
base_folder = os.path.join(tmpdir, "base")
|
||||
os.makedirs(base_folder)
|
||||
|
||||
target1 = os.path.join(tmpdir, "target1")
|
||||
os.makedirs(target1)
|
||||
|
||||
is_valid, errors = self.processor.check_asset_counts(base_folder, [target1])
|
||||
|
||||
self.assertFalse(is_valid)
|
||||
self.assertEqual(len(errors), 1)
|
||||
self.assertIn("no .md files", errors[0])
|
||||
|
||||
def test_find_missing_files(self):
|
||||
"""Test finding missing files in target folder"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create base folder with files
|
||||
base_folder = os.path.join(tmpdir, "base")
|
||||
os.makedirs(base_folder)
|
||||
open(os.path.join(base_folder, "file1.md"), 'w').close()
|
||||
open(os.path.join(base_folder, "file2.md"), 'w').close()
|
||||
open(os.path.join(base_folder, "file3.md"), 'w').close()
|
||||
|
||||
# Create target folder with some files
|
||||
target_folder = os.path.join(tmpdir, "target")
|
||||
os.makedirs(target_folder)
|
||||
open(os.path.join(target_folder, "file1.md"), 'w').close()
|
||||
# file2.md and file3.md are missing
|
||||
|
||||
missing = self.processor.find_missing_files(base_folder, target_folder)
|
||||
|
||||
self.assertEqual(len(missing), 2)
|
||||
self.assertIn("file2.md", missing)
|
||||
self.assertIn("file3.md", missing)
|
||||
self.assertNotIn("file1.md", missing)
|
||||
|
||||
def test_find_missing_files_all_present(self):
|
||||
"""Test finding missing files when all are present"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
base_folder = os.path.join(tmpdir, "base")
|
||||
os.makedirs(base_folder)
|
||||
open(os.path.join(base_folder, "file1.md"), 'w').close()
|
||||
|
||||
target_folder = os.path.join(tmpdir, "target")
|
||||
os.makedirs(target_folder)
|
||||
open(os.path.join(target_folder, "file1.md"), 'w').close()
|
||||
|
||||
missing = self.processor.find_missing_files(base_folder, target_folder)
|
||||
|
||||
self.assertEqual(missing, [])
|
||||
|
||||
def test_custom_extension(self):
|
||||
"""Test MDProcessor with custom file extension"""
|
||||
processor = MDProcessor(file_extension=".txt")
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
open(os.path.join(tmpdir, "file1.txt"), 'w').close()
|
||||
open(os.path.join(tmpdir, "file2.md"), 'w').close()
|
||||
|
||||
files = processor.get_md_files(tmpdir)
|
||||
|
||||
self.assertEqual(len(files), 1)
|
||||
self.assertIn("file1.txt", files)
|
||||
self.assertNotIn("file2.md", files)
|
||||
|
||||
|
||||
class TestMDTranslationItem(unittest.TestCase):
|
||||
"""Test cases for MDTranslationItem dataclass"""
|
||||
|
||||
def test_create_item(self):
|
||||
"""Test creating MDTranslationItem"""
|
||||
item = MDTranslationItem(
|
||||
filename="test.md",
|
||||
content="# Test",
|
||||
relative_path="subdir"
|
||||
)
|
||||
|
||||
self.assertEqual(item.filename, "test.md")
|
||||
self.assertEqual(item.content, "# Test")
|
||||
self.assertEqual(item.relative_path, "subdir")
|
||||
|
||||
def test_create_item_defaults(self):
|
||||
"""Test creating MDTranslationItem with defaults"""
|
||||
item = MDTranslationItem(
|
||||
filename="test.md",
|
||||
content="# Test"
|
||||
)
|
||||
|
||||
self.assertEqual(item.filename, "test.md")
|
||||
self.assertEqual(item.content, "# Test")
|
||||
self.assertEqual(item.relative_path, "")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
56
tests/test_models.py
Normal file
56
tests/test_models.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Tests for data models
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from models import TranslationItem, TranslationBatch
|
||||
|
||||
|
||||
class TestTranslationItem(unittest.TestCase):
|
||||
"""Test cases for TranslationItem model"""
|
||||
|
||||
def test_translation_item_creation(self):
|
||||
"""Test creating a TranslationItem"""
|
||||
item = TranslationItem(name="test_key", value="Test value")
|
||||
self.assertEqual(item.name, "test_key")
|
||||
self.assertEqual(item.value, "Test value")
|
||||
self.assertIsNone(item.comment)
|
||||
|
||||
def test_translation_item_with_comment(self):
|
||||
"""Test creating a TranslationItem with comment"""
|
||||
item = TranslationItem(
|
||||
name="test_key",
|
||||
value="Test value",
|
||||
comment="Test comment"
|
||||
)
|
||||
self.assertEqual(item.name, "test_key")
|
||||
self.assertEqual(item.value, "Test value")
|
||||
self.assertEqual(item.comment, "Test comment")
|
||||
|
||||
|
||||
class TestTranslationBatch(unittest.TestCase):
|
||||
"""Test cases for TranslationBatch model"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures"""
|
||||
self.items = [
|
||||
TranslationItem(name="key1", value="Value 1"),
|
||||
TranslationItem(name="key2", value="Value 2")
|
||||
]
|
||||
|
||||
def test_translation_batch_creation(self):
|
||||
"""Test creating a TranslationBatch"""
|
||||
batch = TranslationBatch(
|
||||
items=self.items,
|
||||
target_language="values-de-rDE",
|
||||
target_file="strings.xml"
|
||||
)
|
||||
self.assertEqual(len(batch.items), 2)
|
||||
self.assertEqual(batch.target_language, "values-de-rDE")
|
||||
self.assertEqual(batch.target_file, "strings.xml")
|
||||
self.assertEqual(batch.items[0].name, "key1")
|
||||
self.assertEqual(batch.items[1].value, "Value 2")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
188
tests/test_xml_processor.py
Normal file
188
tests/test_xml_processor.py
Normal file
@@ -0,0 +1,188 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user