Files
strans/tests/mkemoji_test.py
Hojun-Cho abff5ed122 emoji: search the dictionary by prefix in the engine, not in the data
mkemoji wrote a row for every prefix of every alias, so that a query
matched as it was typed; the trie is a prefix index already, and with a
real emoji list those rows would be four times the aliases themselves.
Now emoji.dict has one row per alias, trienode() names a key's node, and
dictlookup walks the entries at and below it, the key's own first, up to
Maxkouho.  Trie children are appended rather than pushed, so the walk
keeps the file's order and a bare digit still picks the superscript or
subscript it always did.

The hand-written symbol rows move to symbol.src; emoji.src is left to
the emoji.  mkemoji reads both by default, or the files it is given.
2026-08-17 01:07:10 +09:00

93 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
MKEMOJI = ROOT / "map" / "mkemoji"
TIMEOUT = 10
def generate(*sources):
args = [sys.executable, "-B", str(MKEMOJI)] + [str(s) for s in sources]
return subprocess.run(
args, capture_output=True, text=True, check=False, timeout=TIMEOUT
)
def table(output):
return dict(line.split("\t", 1) for line in output.splitlines())
class MkemojiTest(unittest.TestCase):
def source(self, text):
tmp = tempfile.TemporaryDirectory()
path = Path(tmp.name) / "emoji.src"
path.write_text(text, encoding="utf-8")
self.addCleanup(tmp.cleanup)
return path
def test_production_digit_slots(self):
result = generate()
self.assertEqual(result.returncode, 0, result.stderr)
data = table(result.stdout)
keys = list(data)
self.assertEqual([k for k in keys if k[:1] == "^"][:9],
[f"^{d}" for d in range(1, 10)])
self.assertEqual([k for k in keys if k[:1] == "_"][:9],
[f"_{d}" for d in range(1, 10)])
self.assertEqual([k for k in keys if k[:1] == "<"][2], "<3")
self.assertEqual(data["^1"], "¹")
self.assertEqual(data["_2"], "")
self.assertEqual(data["<3"].split()[0], "")
self.assertIn("😀", data["smile"].split())
self.assertIn("😀", data["웃음"].split())
def test_fold_normalize_and_source_order(self):
source = self.source(
"β\tALPHABET\talpha\n"
"α\talpha\n"
"\t\n"
"#\thash\n"
)
first = generate(source)
second = generate(source, source)
self.assertEqual(first.returncode, 0, first.stderr)
self.assertEqual(first.stdout, second.stdout)
data = table(first.stdout)
self.assertEqual(list(data), ["alphabet", "alpha", "é", "hash"])
self.assertEqual(data["alpha"].split(), ["β", "α"])
self.assertEqual(data["é"], "é")
self.assertEqual(data["hash"], "#")
def test_rejects_malformed_and_oversized_rows(self):
bad = [
"x\n",
"bad result\ta\n",
"x\t\n",
"x\t a\n",
"\0\ta\n",
"x\ta\0b\n",
"x\t;hidden\n",
"x" * 65 + "\ta\n",
"x\t" + "a" * 65 + "\n",
]
for text in bad:
with self.subTest(text=repr(text)):
result = generate(self.source(text))
self.assertEqual(result.returncode, 1)
def test_accepts_runtime_boundary(self):
source = self.source("x" * 64 + "\t" + "a" * 64 + "\n")
result = generate(source)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("a" * 64 + "\t" + "x" * 64, result.stdout)
if __name__ == "__main__":
unittest.main()