#!/usr/bin/env python3 """Focused safeguards for the 40250/Longju locale merge.""" import importlib.util import json import tempfile import unittest from pathlib import Path SPEC = importlib.util.spec_from_file_location("build_zh_locale", Path(__file__).with_name("build_zh_locale.py")) MODULE = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(MODULE) class LocaleBuildTest(unittest.TestCase): def test_preserves_40250_keys_formats_and_proto(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) en, zh, client, output = (root / name for name in ("en", "zh", "client", "out/Client")) for path in (en, zh, client): path.mkdir() (en / "locale_game.txt").write_bytes(b"GOOD\tValue %d\tSA\nBAD\t%s at %d\tSA\nONLY_EN\tFallback\n") (zh / "locale_game.txt").write_bytes("GOOD\t中文 %d\nBAD\t中文 %d 和 %s\n".encode("gbk")) (en / "locale_interface.txt").write_bytes(b"ACCEPT\tAccept\n") (zh / "locale_interface.txt").write_bytes("ACCEPT\t确定\n".encode("gbk")) (en / "item_proto").write_bytes(b"40250-proto") (zh / "item_proto").write_bytes(b"old-proto") (client / "pack").mkdir() (client / "pack/Index").write_bytes(b"PACK\r\nlocale/de/\r\nlocale_de\r\nlocale/en/\r\nlocale_en\r\n") (client / "pack/locale_en.eix").write_bytes(b"en") # Stands in for eterpack_pack: records its arguments as the .eix. pack_tool = root / "eterpack_pack" pack_tool.write_text("#!/bin/sh\necho \"$2 $3\" > \"$1.eix\"\n") pack_tool.chmod(0o755) report_path = MODULE.build(en, zh, output, client, pack_tool=pack_tool) staged = output.parent / "locale-src/zh" merged = (staged / "locale_game.txt").read_bytes().decode("gbk") self.assertIn("GOOD\t中文 %d\tSA", merged) self.assertIn("BAD\t%s at %d\tSA", merged) self.assertIn("ONLY_EN\tFallback", merged) self.assertEqual((staged / "item_proto").read_bytes(), b"40250-proto") self.assertEqual((output / "locale.cfg").read_text(), "10002 936 zh\n") self.assertEqual((output / "locale_zh.cfg").read_text(), "10002 936 zh\n") # A pack/ of its own: original packs linked, locale_zh packed from the staging dir and registered. self.assertFalse((output / "pack").is_symlink()) self.assertFalse((output / "locale/zh").exists()) self.assertTrue((output / "pack/locale_en.eix").is_symlink()) self.assertEqual((output / "pack/locale_zh.eix").read_text(), f"{staged} locale/zh/\n") self.assertEqual((output / "pack/Index").read_bytes(), b"PACK\r\nlocale/de/\r\nlocale_de\r\nlocale/zh/\r\nlocale_zh\r\n" b"locale/en/\r\nlocale_en\r\n") self.assertEqual((client / "pack/Index").read_bytes()[:4], b"PACK") self.assertFalse((client / "pack/locale_zh.eix").exists()) report = json.loads(report_path.read_text()) self.assertEqual(report["files"]["locale_game.txt"]["incompatible_format_keys"], ["BAD"]) # Reviewed overlay: fills an English-only key and replaces a format-incompatible Longju value. names = root / "names" names.mkdir() (names / "locale_game_zh_overlay.txt").write_text("KEY\tVALUE\nBAD\t%s 于 %d\nONLY_EN\t备用\n") report_path = MODULE.build(en, zh, output, client, names_dir=names, pack_tool=pack_tool) merged = (staged / "locale_game.txt").read_bytes().decode("gbk") self.assertIn("BAD\t%s 于 %d\tSA", merged) self.assertIn("ONLY_EN\t备用", merged) game = json.loads(report_path.read_text())["files"]["locale_game.txt"] self.assertEqual((game["english_fallback_keys"], game["incompatible_format_keys"]), ([], [])) def test_name_overlay_replaces_snapshot_rows(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) (root / "names.txt").write_text("VNUM\tLOCALE_NAME\n1\tYang\n2\t剑\n") (root / "overlay.txt").write_text("VNUM\tLOCALE_NAME\n1\t金币\n99\t不存在\n") result = MODULE.convert_names(root / "names.txt", root / "out.txt", root / "overlay.txt") self.assertEqual((root / "out.txt").read_bytes().decode("gbk"), "1\t金币\n2\t剑\n") self.assertEqual(result["overlaid"], 1) if __name__ == "__main__": unittest.main()