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