Files
epub_bilingual_translator/tests/reproduce_misalignment.py
T
2026-01-19 09:51:07 +08:00

111 lines
3.8 KiB
Python

from bs4 import BeautifulSoup
from unittest.mock import MagicMock
from src.bilingual_builder import BilingualEPUBBuilder
from src.chinese_builder import ChineseEPUBBuilder
# Mock classes to avoid full EPUB dependencies
class MockItem:
def __init__(self, name, content):
self.name = name
self.content = content
self.title = "Mock Title"
self.id = "item_1"
def get_name(self): return self.name
def get_content(self): return self.content.encode('utf-8')
def get_type(self): return 9 # ITEM_DOCUMENT
def test_bilingual_builder_misalignment():
"""
Reproduces the off-by-one misalignment bug.
Scenario:
1. HTML contains: [Para1], [Nav], [Para2]
2. Ordered IDs passed to builder: [ID1, ID2] (assuming Nav is validly ignored by extractor logic but maybe ID list is different?
Actually, let's trace the bug logic:
Extractor:
- Para1 -> Clean -> Valid -> Added to Manifest (Status: Pending) -> ID1
- Nav -> Clean -> Valid -> Added to Manifest (Status: Ignored) -> ID2
- Para2 -> Clean -> Valid -> Added to Manifest (Status: Pending) -> ID3
Builder Input:
- translation_map: {ID1: "Trans1", ID3: "Trans3"} (Nav ignored so no trans)
- paragraph_map: {ID1: ..., ID2: ..., ID3: ...}
- ordered_ids: [ID1, ID2, ID3] (All items in file)
Builder Loop (Current Broken Logic):
- Scans Para1: Valid, Not Nav.
- Match with ordered_ids[0] (ID1). OK.
- Incr index -> 1.
- Scans Nav: is_navigation_element() == True -> CONTINUE
- Index remains 1.
- Scans Para2: Valid, Not Nav.
- Match with ordered_ids[1] (ID2).
- ID2 is the Nav item!
- translation_map.get(ID2) -> None (or wrong if ID2 had a translation).
- Result: Para2 gets NO translation or WRONG translation.
- Expected: Para2 should match ID3.
"""
# Setup
html_content = """
<html>
<body>
<p>Paragraph 1</p>
<div class="nav">Navigation Content</div>
<p>Paragraph 2</p>
</body>
</html>
"""
mock_item = MockItem("test.xhtml", html_content)
# IDs corresponding to the elements as they would be in Manifest
# ID1: Para1, ID2: Nav, ID3: Para2
ordered_ids = ["p_001", "p_002", "p_003"]
translation_map = {
"p_001": "翻译1",
"p_003": "翻译2" # p_002 is ignored, so no translation
}
# Config
config = {'output': {}}
mock_book = MagicMock()
mock_book.get_metadata.return_value = None
builder = BilingualEPUBBuilder(mock_book, config)
# Execute private method directly for testing
# We mock _add_style_link to do nothing
builder._add_style_link = MagicMock()
new_item = builder._create_bilingual_document(mock_item, ordered_ids, translation_map)
new_content = new_item.get_content().decode('utf-8')
soup = BeautifulSoup(new_content, 'html.parser')
# Analyze results
paragraphs = soup.find_all('p', class_='translation-text')
print(f"Generated Paragraphs: {len(paragraphs)}")
for p in paragraphs:
print(f" - {p.get_text()}")
# Assertions
# We expect 2 translated paragraphs.
# Current BUG: Likely only 1 found (Para1), and Para2 missed because it matched with p_002 which has no translation.
assert len(paragraphs) == 2, f"Expected 2 translated paragraphs, found {len(paragraphs)}"
assert paragraphs[0].get_text() == "翻译1"
assert paragraphs[1].get_text() == "翻译2"
if __name__ == "__main__":
try:
test_bilingual_builder_misalignment()
print("Test PASSED")
except AssertionError as e:
print(f"Test FAILED: {e}")
except Exception as e:
print(f"Test ERROR: {e}")