94 lines
5.3 KiB
Python
94 lines
5.3 KiB
Python
import unittest
|
|
from script_text import extract_display_literals, patch_display_calls
|
|
|
|
|
|
class ScriptTextTests(unittest.TestCase):
|
|
def test_numeric_percent_in_prose_is_not_a_printf_conversion(self):
|
|
source = b'SetMissionDescription("speed 0% is pause; %s %d");'
|
|
result = patch_display_calls(source, {'speed 0% is pause; %s %d': '速度 0% 等于暂停;%s %d'})
|
|
self.assertIn('速度 0%'.encode('gb2312'), result)
|
|
with self.assertRaises(ValueError):
|
|
patch_display_calls(source, {'speed 0% is pause; %s %d': '速度 0% 等于暂停'})
|
|
|
|
def test_stock_tutorial_unescaped_function_key_is_a_display_span(self):
|
|
text = '\fTo use a charged spell select it by pressing the "F" KEY marked under it'
|
|
source = b'SetMissionDescription("\\fTo use a charged spell select it by pressing the "F" KEY marked under it");'
|
|
self.assertEqual(extract_display_literals(source)[0].text, text)
|
|
self.assertEqual(patch_display_calls(source, {text: '\f按 F 键'}),
|
|
'SetMissionDescription("\\f按 F 键");'.encode('gb2312'))
|
|
self.assertEqual(extract_display_literals(b'SetMissionDescription("other "F" text");'), [])
|
|
|
|
def test_only_direct_display_literals_change(self):
|
|
source = b'DisplayMessage("Help", "Move");\r\nEnableEvent("Move");\r\n'
|
|
result = patch_display_calls(source, {'Help': '帮助', 'Move': '移动'})
|
|
self.assertEqual(result, 'DisplayMessage("帮助", "移动");\r\nEnableEvent("Move");\r\n'.encode('gb2312'))
|
|
|
|
def test_comments_and_non_display_strings_are_untouched(self):
|
|
source = (b'# DisplayMessage("Help", "Move");\r\n'
|
|
b'// SetMissionDescription("Move");\n'
|
|
b'/* DisplayMessage("Help", "Move"); */\n'
|
|
b'x="DisplayMessage(\\\"Help\\\", \\\"Move\\\")";\n'
|
|
b'SetMissionDescription("Move");')
|
|
result = patch_display_calls(source, {'Move': '移动'})
|
|
self.assertEqual(result, source[:-8] + '"移动");'.encode('gb2312'))
|
|
|
|
def test_function_definition_and_expressions_are_not_direct_literals(self):
|
|
source = (b'DisplayMessage(Caption, Text){MessageBox(Caption, Text);}\n'
|
|
b'DisplayMessage("Help" + suffix, getText("Move"));\n'
|
|
b'SetMissionDescription(text);')
|
|
self.assertEqual(extract_display_literals(source), [])
|
|
|
|
def test_duplicate_display_text_is_replaced_in_both_calls(self):
|
|
source = b'DisplayMessage("Title", "Move");SetMissionDescription("Move");'
|
|
self.assertEqual(patch_display_calls(source, {'Move': '移动'}),
|
|
'DisplayMessage("Title", "移动");SetMissionDescription("移动");'.encode('gb2312'))
|
|
|
|
def test_continuation_quotes_and_controls_round_trip(self):
|
|
source = b'DisplayMessage("Title", "\\fPress \\\"H\\\" \\\r\n\tfor help.\\n\\aDone.");'
|
|
entries = extract_display_literals(source)
|
|
self.assertEqual(entries[1].text, '\fPress "H" for help.\n\aDone.')
|
|
result = patch_display_calls(source, {entries[1].text: '\f按“H”键查看帮助。\n\a完成。'})
|
|
self.assertEqual(result, 'DisplayMessage("Title", "\\f按“H”键查看帮助。\\n\\a完成。");'.encode('gb2312'))
|
|
|
|
def test_literal_backslash_and_quote_are_escaped_on_output(self):
|
|
source = b'DisplayMessage("Title", "A\\\\B \\\"Q\\\"");'
|
|
self.assertEqual(patch_display_calls(source, {'A\\B "Q"': '甲\\乙 "Q"'}),
|
|
'DisplayMessage("Title", "甲\\\\乙 \\\"Q\\\"");'.encode('gb2312'))
|
|
|
|
def test_missing_mapping_key_is_rejected(self):
|
|
with self.assertRaisesRegex(ValueError, 'not found'):
|
|
patch_display_calls(b'SetMissionDescription("Move");', {'Wrong': '错误'})
|
|
|
|
def test_unencodable_translation_is_rejected(self):
|
|
with self.assertRaises(UnicodeEncodeError):
|
|
patch_display_calls(b'SetMissionDescription("Move");', {'Move': '移动🙂'})
|
|
|
|
def test_control_sequence_change_is_rejected(self):
|
|
with self.assertRaisesRegex(ValueError, 'control'):
|
|
patch_display_calls(b'SetMissionDescription("\\fMove\\nNow");', {'\fMove\nNow': '移动'})
|
|
|
|
def test_printf_sequence_change_is_rejected(self):
|
|
with self.assertRaisesRegex(ValueError, 'format'):
|
|
patch_display_calls(b'SetMissionDescription("Move %s %d");', {'Move %s %d': '移动 %d %s'})
|
|
|
|
def test_malformed_string_fails_before_output(self):
|
|
with self.assertRaisesRegex(ValueError, 'unterminated'):
|
|
patch_display_calls(b'SetMissionDescription("Move);', {'Move': '移动'})
|
|
|
|
def test_unknown_escape_is_not_silently_reinterpreted(self):
|
|
with self.assertRaisesRegex(ValueError, 'escape'):
|
|
extract_display_literals(b'SetMissionDescription("\\qMove");')
|
|
|
|
def test_empty_mapping_is_byte_identical(self):
|
|
source = b'#\xff\xfe\r\nDisplayMessage("Title", "Move");'
|
|
self.assertEqual(patch_display_calls(source, {}), source)
|
|
|
|
def test_allowed_call_nested_in_expression_is_found(self):
|
|
source = b'if (DisplayMessage("Help", "Move")) { EnableEvent("Move"); }'
|
|
self.assertEqual(patch_display_calls(source, {'Move': '移动'}),
|
|
'if (DisplayMessage("Help", "移动")) { EnableEvent("Move"); }'.encode('gb2312'))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|