32 hid the tail of common readings: きょう has 41 kanji, 구 has 352 hanja. 128 covers every kanji entry and the hanja dictionary now keeps that many per reading.
141 lines
4.5 KiB
Python
141 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
IMPORT = ROOT / "map" / "libhangul2hanja"
|
|
GENERATE = ROOT / "map" / "mkhanja"
|
|
TIMEOUT = 10
|
|
|
|
|
|
def run(program, source=None, stdin=None, hostile=False):
|
|
command = [sys.executable, "-B", str(program)]
|
|
if source is not None:
|
|
command.append(str(source))
|
|
env = None
|
|
if hostile:
|
|
env = os.environ.copy()
|
|
env.update(LC_ALL="C", LANG="C", PYTHONCOERCECLOCALE="0", PYTHONUTF8="0")
|
|
env.pop("PYTHONIOENCODING", None)
|
|
return subprocess.run(
|
|
command,
|
|
input=stdin,
|
|
capture_output=True,
|
|
encoding="utf-8",
|
|
env=env,
|
|
check=False,
|
|
timeout=TIMEOUT,
|
|
)
|
|
|
|
|
|
class MkhanjaTest(unittest.TestCase):
|
|
def source(self, text):
|
|
tmp = tempfile.TemporaryDirectory()
|
|
path = Path(tmp.name) / "hanja.txt"
|
|
path.write_text(text, encoding="utf-8")
|
|
self.addCleanup(tmp.cleanup)
|
|
return path
|
|
|
|
def test_imports_single_bmp_hanja_rows(self):
|
|
result = run(
|
|
IMPORT,
|
|
self.source(
|
|
"# Copyright holder\n"
|
|
"# BSD license\n"
|
|
"한:漢:first\n"
|
|
"가:㐀:extension A\n"
|
|
"김:金:compatibility\n"
|
|
"방학:放:word reading\n"
|
|
"학:學校:word value\n"
|
|
"한:𠀀:astral\n"
|
|
"ㄱ:加:jamo\n"
|
|
),
|
|
)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
lines = result.stdout.splitlines()
|
|
self.assertEqual(lines[:2], ["# Copyright holder", "# BSD license"])
|
|
self.assertEqual(lines[2:], ["", "漢\t한", "㐀\t가", "金\t김"])
|
|
|
|
def test_import_rejects_malformed_and_duplicate_rows(self):
|
|
bad = [
|
|
"한 漢\n",
|
|
"한:漢:first\n한:漢:again\n",
|
|
]
|
|
for text in bad:
|
|
with self.subTest(text=repr(text)):
|
|
self.assertEqual(run(IMPORT, self.source(text)).returncode, 1)
|
|
|
|
def test_import_uses_utf8_without_locale(self):
|
|
text = "# 저작권\n한:漢:first\n"
|
|
expected = "# 저작권\n\n漢\t한\n"
|
|
for source, stdin in ((self.source(text), None), (None, text)):
|
|
with self.subTest(source=source):
|
|
result = run(IMPORT, source, stdin, hostile=True)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(result.stdout, expected)
|
|
|
|
def test_groups_readings_and_preserves_order(self):
|
|
result = run(
|
|
GENERATE,
|
|
self.source(
|
|
"# Copyright holder\n"
|
|
"# BSD license\n"
|
|
"漢\t한\n"
|
|
"韓\t한\n"
|
|
"㐀\t가\n"
|
|
"家\t가\n"
|
|
"金\t금\n"
|
|
),
|
|
)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(
|
|
result.stdout.splitlines(),
|
|
[
|
|
";; Copyright holder",
|
|
";; BSD license",
|
|
"",
|
|
"한\t漢 韓",
|
|
"가\t㐀 家",
|
|
"금\t金",
|
|
],
|
|
)
|
|
|
|
def test_generator_rejects_bad_rows(self):
|
|
bad = [
|
|
"漢韓\t한\n",
|
|
"漢\t한자\n",
|
|
"𠀀\t한\n",
|
|
"漢\t한\n漢\t한\n",
|
|
"漢 한\n",
|
|
]
|
|
for text in bad:
|
|
with self.subTest(text=repr(text)):
|
|
self.assertEqual(run(GENERATE, self.source(text)).returncode, 1)
|
|
|
|
def test_generator_uses_utf8_without_locale(self):
|
|
result = run(GENERATE, self.source("# 저작권\n漢\t한\n"), hostile=True)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(result.stdout, ";; 저작권\n\n한\t漢\n")
|
|
|
|
result = run(GENERATE, hostile=True)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertIn("한\t", result.stdout)
|
|
|
|
def test_generator_keeps_runtime_candidate_limit(self):
|
|
rows = "".join(f"{chr(0x4E00 + n)}\t한\n" for n in range(129))
|
|
result = run(GENERATE, self.source(rows))
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
candidates = result.stdout.rstrip().split("\t", 1)[1].split()
|
|
self.assertEqual(len(candidates), 128)
|
|
self.assertEqual(candidates[-1], chr(0x4E00 + 127))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|