"""Execute real option-title call sites, coordinate transform and font metrics.""" import argparse import unittest from unicorn import UC_HOOK_CODE from unicorn.x86_const import UC_X86_REG_EAX, UC_X86_REG_ECX, UC_X86_REG_EDI, UC_X86_REG_ESP, UC_X86_REG_EIP import test_cjk_layout as engine # From the source string's lookup return to the original draw return. TITLE_SITES = [(0x4de8b7, 0x4de8e7), (0x4d747b, 0x4d74ab), (0x4ddaa3, 0x4ddad3), (0x4d9a0b, 0x4d9a3b)] def title_position(site, text, resolution): uc, put, ints, font, stack, string, stop = engine.make_machine() manager = font - 0x3a8 put(0x65af70, 0x2001000) put(0x2001008, 0x2002000) put(0x200105c, manager) put(0x2002514, *resolution) uc.mem_write(string, text.encode('gb2312') + b'\0') uc.reg_write(UC_X86_REG_ESP, stack) uc.reg_write(UC_X86_REG_EAX, string) uc.reg_write(UC_X86_REG_EDI, manager) uc.reg_write(UC_X86_REG_ECX, manager) # The caller pushed justification=0 before looking up its title. put(stack, 0) positions = [] def draw(machine, address, size, data): sp = machine.reg_read(UC_X86_REG_ESP) ret, point = ints(sp, 2) positions.append(ints(point, 2)) machine.reg_write(UC_X86_REG_ESP, sp + 24) machine.reg_write(UC_X86_REG_EIP, ret) uc.hook_add(UC_HOOK_CODE, draw, begin=0x4eab70, end=0x4eab70) uc.emu_start(site[0], site[1], count=10000) assert uc.reg_read(UC_X86_REG_EIP) == site[1] return positions class TitleTests(unittest.TestCase): def test_all_option_titles_share_panel_center(self): for site in TITLE_SITES: for label, x in [('操作', 628), ('游戏选项', 616), ('Controls', 608)]: with self.subTest(site=hex(site[0]), label=label): self.assertEqual(title_position(site, label, (800, 600)), [(x, 60)]) def test_title_center_tracks_resolution_without_scaling_font_width(self): for resolution, expected in [((1280, 720), (1012, 72)), ((1920, 1080), (1524, 108))]: with self.subTest(resolution=resolution): self.assertEqual(title_position(TITLE_SITES[0], '操作', resolution), [expected]) if __name__ == '__main__': p = argparse.ArgumentParser() p.add_argument('--exe', default=engine.DEFAULT_EXE) args, rest = p.parse_known_args() engine.EXE_PATH = args.exe unittest.main(argv=[__file__] + rest)