Improve coverage for font_path and ignore coverage of difficult to test (platform-based) cases. Use pathlib for tests

This commit is contained in:
Jonathan Wagenet 2026-01-30 16:00:46 -05:00
parent bb80b11322
commit cb14f338e2
4 changed files with 76 additions and 45 deletions

View file

@ -85,7 +85,7 @@ class FontManager:
aliases = [aliases.Value(i).ToCString() for i in range(1, aliases.Length() + 1)]
if "singleline" not in aliases:
if platform.system() == "Windows":
if platform.system() == "Windows": # pragma: no cover
# OCCT doesnt add user fonts on Windows
self.register_system_fonts()
@ -135,7 +135,7 @@ class FontManager:
) -> list[str]:
"""Register all font faces in a font file and return font face names."""
_, ext = os.path.splitext(path)
if ext.strip(".") == "ttc":
if ext.strip(".") == "ttc": # pragma: no cover
fonts = ttCollection.TTCollection(path)
else:
fonts = [TTFont(path)]
@ -168,18 +168,18 @@ class FontManager:
"""Runner to (re)inititalize the OCCT FontMgr font list since user folder is
missing on Windows and some fonts may not be imported correctly."""
if platform.system() == "Windows":
if platform.system() == "Windows": # pragma: no cover
user = os.getlogin()
paths = [
"C:/Windows/Fonts",
f"C:/Users/{user}/AppData/Local/Microsoft/Windows/Fonts",
]
elif platform.system() == "Darwin":
elif platform.system() == "Darwin": # pragma: no cover
# macOS
paths = ["/System/Library/Fonts", "/Library/Fonts"]
else:
paths = [
"/system/fonts", # Android
"/system/fonts", # Android
"/usr/share/fonts",
"/usr/local/share/fonts",
]

View file

@ -383,12 +383,7 @@ class TestBuildSketchObjects(unittest.TestCase):
self.assertEqual(len(test.sketch.faces()), 4)
self.assertEqual(t.faces()[0].normal_at(), Vector(0, 0, 1))
with self.assertRaises(ValueError):
Text("test", 2, text_align=(TextAlign.BOTTOM, TextAlign.BOTTOM))
with self.assertRaises(ValueError):
Text("test", 2, text_align=(TextAlign.LEFT, TextAlign.LEFT))
def test_text_singleline(self):
font_size = 10
singleline = Text("test", font_size, "singleline")
self.assertTrue(all([isinstance(s, Face) for s in singleline.get_top_level_shapes()]))
@ -403,6 +398,12 @@ class TestBuildSketchObjects(unittest.TestCase):
with self.assertRaises(ValueError):
Text("the quick brown fox", font_size, "singleline", single_line_width=6)
def test_text_exceptions(self):
with self.assertRaises(ValueError):
Text("test", 2, text_align=(TextAlign.BOTTOM, TextAlign.BOTTOM))
with self.assertRaises(ValueError):
Text("test", 2, text_align=(TextAlign.LEFT, TextAlign.LEFT))
def test_trapezoid(self):
with BuildSketch() as test:

View file

@ -28,12 +28,14 @@ license:
import itertools
import unittest
from pathlib import Path
from build123d.build_common import GridLocations, PolarLocations
from build123d.build_enums import Align, CenterOf
from build123d.geometry import Location, Plane
from build123d.objects_part import Box
from build123d.objects_sketch import Circle
from build123d.text import FontManager
from build123d.topology import Compound, Edge, Face, ShapeList, Solid, Sketch
@ -55,6 +57,17 @@ class TestCompound(unittest.TestCase):
self.assertGreaterEqual(len(singleline.wires()), 4)
self.assertEqual(len(outline.faces()), 4)
def test_make_text_font_path(self):
manager = FontManager()
manager.manager.ClearFontDataBase()
working_path = Path(__file__).resolve().parent
src_path = Path("src/build123d")
font_name = manager.bundled_fonts[0][1]
font_path = (working_path / ".." / ".." / src_path / manager.bundled_path / font_name).resolve()
self.assertIsInstance(Compound.make_text("text", 10, font_path=str(font_path)), Compound)
def test_fuse(self):
box1 = Solid.make_box(1, 1, 1)
box2 = Solid.make_box(1, 1, 1, Plane((1, 0, 0)))

View file

@ -1,5 +1,5 @@
"""
build123d Helper Utilities tests
build123d Font and Text Utilities tests
name: test_text.py
by: jwagenet
@ -9,7 +9,7 @@ desc: Unit tests for the build123d font and text module
"""
import unittest
import os
from pathlib import Path
from OCP.TCollection import TCollection_AsciiString
@ -24,25 +24,30 @@ class TestFontManager(unittest.TestCase):
"""OCP FontMgr expected to persist db over multiple instances"""
instance1 = FontManager()
instance1.manager.ClearFontDataBase()
working_path = os.path.dirname(os.path.abspath(__file__))
src_path = "src/build123d"
font_path = instance1.bundled_fonts[0][1]
font_path = os.path.join(working_path, "..", src_path, instance1.bundled_path, font_path)
instance1.register_font(font_path)
working_path = Path(__file__).resolve().parent
src_path = Path("src/build123d")
font_name = instance1.bundled_fonts[0][1]
font_path = (working_path.parent / src_path / instance1.bundled_path / font_name)
instance1.register_font(str(font_path))
instance2 = FontManager()
self.assertEqual(instance1.available_fonts(), instance2.available_fonts())
def test_register_font(self):
"""Expected to return system font with matching name if it exists"""
manager = FontManager()
manager.manager.ClearFontDataBase()
working_path = os.path.dirname(os.path.abspath(__file__))
src_path = "src/build123d"
font_path = manager.bundled_fonts[0][1]
font_path = os.path.normpath(os.path.join(working_path, "..", src_path, manager.bundled_path, font_path))
font_names = manager.register_font(font_path)
working_path = Path(__file__).resolve().parent
src_path = Path("src/build123d")
font_name = manager.bundled_fonts[0][1]
font_path = (working_path.parent / src_path / manager.bundled_path / font_name).resolve()
font_names = manager.register_font(str(font_path))
result = manager.find_font(font_names[0], FontStyle.REGULAR)
self.assertEqual(font_names[0], result.FontName().ToCString())
@ -51,53 +56,63 @@ class TestFontManager(unittest.TestCase):
"""Expected to register fonts in folder"""
manager = FontManager()
manager.manager.ClearFontDataBase()
working_path = os.path.dirname(os.path.abspath(__file__))
src_path = "src/build123d"
working_path = Path(__file__).resolve().parent
src_path = Path("src/build123d")
font_name = manager.bundled_fonts[0][0]
font_path = os.path.dirname(manager.bundled_fonts[0][1])
folder_path = os.path.normpath(os.path.join(working_path, "..", src_path, manager.bundled_path, font_path))
font_names = manager.register_folder(folder_path)
font_file = Path(manager.bundled_fonts[0][1])
font_folder = font_file.parent
folder_path = (working_path.parent / src_path / manager.bundled_path / font_folder).resolve()
font_names = manager.register_folder(str(folder_path))
result = manager.find_font(font_names[0], FontStyle.REGULAR)
self.assertEqual(font_name, result.FontName().ToCString())
def test_register_system_fonts(self):
"""Expected to register at least as many fonts from before.
"""Expected to register at least as many fonts from before.
May find more on Windows
"""
manager = FontManager()
available_before = manager.available_fonts()
manager.manager.RemoveFontAlias(
TCollection_AsciiString("singleline"),
TCollection_AsciiString("Relief SingleLine CAD")
)
TCollection_AsciiString("singleline"),
TCollection_AsciiString("Relief SingleLine CAD"),
)
manager.manager.ClearFontDataBase()
manager.register_system_fonts()
# add bundled fonts back in
manager.__init__()
available_after = manager.available_fonts()
# register_system_fonts may add more fonts than InitFontDataBase() due to
# string naming rules
self.assertGreaterEqual(len(available_after), len(available_before))
def test_check_font(self):
"""Expected to return system font with matching path if it exists or None"""
manager = FontManager()
working_path = os.path.dirname(os.path.abspath(__file__))
font_path = manager.bundled_fonts[0][1]
src_path = "src/build123d"
good_path = os.path.normpath(os.path.join(working_path, "..", src_path, manager.bundled_path, font_path))
good_font = manager.check_font(good_path)
bad_font = manager.check_font(font_path)
working_path = Path(__file__).resolve().parent
src_path = Path("src/build123d")
font_name = manager.bundled_fonts[0][1]
good_path = (working_path.parent / src_path / manager.bundled_path / font_name).resolve()
good_font = manager.check_font(str(good_path))
bad_font = manager.check_font(font_name)
aspect = FONT_ASPECT[FontStyle.REGULAR]
self.assertEqual(good_path, good_font.FontPath(aspect).ToCString())
self.assertEqual(None, bad_font)
self.assertEqual(str(good_path), good_font.FontPath(aspect).ToCString())
self.assertIsNone(bad_font)
def test_find_font(self):
"""Expected to return font with matching name if it exists"""
manager = FontManager()
good_name = manager.bundled_fonts[0][0]
good_font = manager.find_font(good_name, FontStyle.REGULAR)
bad_font = manager.find_font("build123d", FontStyle.REGULAR)
@ -116,13 +131,15 @@ class TestFontHelpers(unittest.TestCase):
font = FontInfo(name, styles)
self.assertEqual(
repr(font), f"Font(name={name!r}, styles={tuple(s.name for s in styles)})"
repr(font),
f"Font(name={name!r}, styles={tuple(s.name for s in styles)})",
)
def test_available_fonts(self):
"""Test expected output for available fonts."""
fonts = available_fonts()
self.assertIsInstance(fonts, list)
for font in fonts:
self.assertIsInstance(font, FontInfo)
self.assertIsInstance(font.name, str)
@ -135,4 +152,4 @@ class TestFontHelpers(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
unittest.main()