Skip to content

Commit 6654591

Browse files
mpcabdclaude
andcommitted
Strengthen font config tests; gitignore fonts/
- Add fonts/ to .gitignore so local test fonts are never committed - Skip tests gracefully when fonts/ is absent or contains no .otf files - Replace smoke tests with correctness tests: _expected_config() independently reads the font's cmap via fonttools and computes the expected config, then asserts config_for_true_type_font() == expected — catches any mis-detection of glyph support rather than just checking the function doesn't crash - Add fonttools to dev dependency group so the tests run out of the box Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6a6a504 commit 6654591

4 files changed

Lines changed: 59 additions & 1 deletion

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ venv/
4747
# ignore
4848
.ignore/
4949
.DS_Store
50+
51+
# local test fonts — not committed
52+
fonts/
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import pytest
2+
from pathlib import Path
3+
4+
pytest.importorskip('fontTools', reason='fonttools not installed')
5+
6+
from fontTools.ttLib import TTFont
7+
from arabic_reshaper import ArabicReshaper
8+
from arabic_reshaper.letters import LETTERS_ARABIC, ISOLATED
9+
from arabic_reshaper.ligatures import LIGATURES
10+
from arabic_reshaper.reshaper_config import config_for_true_type_font
11+
12+
_FONTS_DIR = Path(__file__).parent.parent.parent / 'fonts'
13+
_FONT_FILES = sorted(_FONTS_DIR.rglob('*.otf')) if _FONTS_DIR.is_dir() else []
14+
15+
16+
def _expected_config(font_path: Path) -> dict:
17+
"""Independently compute the config config_for_true_type_font should return.
18+
19+
Uses fonttools directly to build the expected output so that the test is a
20+
genuine check of correctness, not just a smoke test.
21+
"""
22+
ttfont = TTFont(str(font_path))
23+
cmap_chars: set[int] = set()
24+
for table in ttfont['cmap'].tables:
25+
cmap_chars.update(table.cmap.keys())
26+
27+
has_isolated = all(
28+
ord(v[ISOLATED]) in cmap_chars
29+
for v in LETTERS_ARABIC.values()
30+
)
31+
32+
expected: dict = {'use_unshaped_instead_of_isolated': not has_isolated}
33+
34+
for name, (_, forms_tuple) in LIGATURES:
35+
forms = [f for f in forms_tuple if f]
36+
# A ligature is enabled when every non-empty form glyph is in the font.
37+
# If there are no non-empty forms (degenerate entry), treat as enabled.
38+
expected[name] = not forms or all(ord(f) in cmap_chars for f in forms)
39+
40+
return expected
41+
42+
43+
@pytest.mark.skipif(not _FONT_FILES, reason='No .otf files found under fonts/')
44+
class TestFontConfig:
45+
@pytest.mark.parametrize('font_path', _FONT_FILES, ids=lambda p: p.stem)
46+
def test_config_matches_font_capabilities(self, font_path):
47+
assert config_for_true_type_font(str(font_path)) == _expected_config(font_path)
48+
49+
@pytest.mark.parametrize('font_path', _FONT_FILES, ids=lambda p: p.stem)
50+
def test_config_produces_working_reshaper(self, font_path):
51+
config = config_for_true_type_font(str(font_path))
52+
reshaper = ArabicReshaper(configuration=config)
53+
assert reshaper.reshape('السلام عليكم')

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Homepage = "https://github.com/mpcabd/python-arabic-reshaper/"
3535
Repository = "https://github.com/mpcabd/python-arabic-reshaper/"
3636

3737
[dependency-groups]
38-
dev = ["pytest>=8", "pytest-cov"]
38+
dev = ["pytest>=8", "pytest-cov", "fonttools>=4.0"]
3939

4040
[tool.hatch.build]
4141
exclude = ["arabic_reshaper/tests"]

uv.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)