mirror of
https://github.com/tiennm99/monkeyd-crawler.git
synced 2026-08-18 05:24:52 +00:00
PDF rendering failed on Linux with "stat usr/share/fonts/...: no such file or directory": fpdf joins the font path onto its own font directory, which it defaults to ".", so path.Join turns an absolute path into a working-directory-relative one. It only resolved when the process happened to run from the filesystem root, which is why Windows was unaffected. Font data is now read by pdfout and handed over as bytes. LoadFont also falls back to a bundled DejaVu Sans, so a host with no fonts installed still renders. An explicitly requested font remains a hard error when unreadable rather than being silently substituted. Tests verify the bundled font parses and covers Vietnamese, which is the reason it exists.
94 lines
2.8 KiB
Go
94 lines
2.8 KiB
Go
package pdfout
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"golang.org/x/image/font/sfnt"
|
|
)
|
|
|
|
func TestLoadFontUsesExplicitPath(t *testing.T) {
|
|
// Any readable file is enough: LoadFont does not parse, it only reads.
|
|
path := filepath.Join(t.TempDir(), "custom.ttf")
|
|
want := []byte("not really a font")
|
|
if err := os.WriteFile(path, want, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
font, err := LoadFont(path)
|
|
if err != nil {
|
|
t.Fatalf("LoadFont: %v", err)
|
|
}
|
|
if font.Name != path {
|
|
t.Errorf("Name = %q, want %q", font.Name, path)
|
|
}
|
|
if string(font.Data) != string(want) {
|
|
t.Errorf("Data = %q, want %q", font.Data, want)
|
|
}
|
|
}
|
|
|
|
// A caller that names a font wants that font; silently substituting another
|
|
// would produce a PDF that does not match the request.
|
|
func TestLoadFontFailsOnUnreadableExplicitPath(t *testing.T) {
|
|
font, err := LoadFont(filepath.Join(t.TempDir(), "missing.ttf"))
|
|
if err == nil {
|
|
t.Fatalf("LoadFont = %+v, want an error", font)
|
|
}
|
|
}
|
|
|
|
// With no path given, LoadFont must always produce something usable — that is
|
|
// the whole point of the bundled font.
|
|
func TestLoadFontFallsBackWithoutExplicitPath(t *testing.T) {
|
|
font, err := LoadFont("")
|
|
if err != nil {
|
|
t.Fatalf("LoadFont(\"\") = %v, want no error", err)
|
|
}
|
|
if len(font.Data) == 0 {
|
|
t.Error("resolved font carries no data")
|
|
}
|
|
if font.Name == "" {
|
|
t.Error("resolved font has no name")
|
|
}
|
|
// On a host with fonts installed this is a system path; on one without, it
|
|
// is the bundled font. Either is fine, but it must be one of them.
|
|
if system, err := FindFont(); err == nil {
|
|
if font.Name != system && font.Name != BundledFontName {
|
|
t.Errorf("Name = %q, want %q or %q", font.Name, system, BundledFontName)
|
|
}
|
|
} else if font.Name != BundledFontName {
|
|
t.Errorf("Name = %q, want %q when no system font exists", font.Name, BundledFontName)
|
|
}
|
|
}
|
|
|
|
func TestBundledFontIsParseable(t *testing.T) {
|
|
font := BundledFont()
|
|
if font.Name != BundledFontName {
|
|
t.Errorf("Name = %q, want %q", font.Name, BundledFontName)
|
|
}
|
|
if _, err := sfnt.Parse(font.Data); err != nil {
|
|
t.Fatalf("bundled font does not parse as a TrueType font: %v", err)
|
|
}
|
|
}
|
|
|
|
// The bundled font exists to render Vietnamese. A replacement that lacks these
|
|
// glyphs would silently emit blanks, so check before trusting it.
|
|
func TestBundledFontCoversVietnamese(t *testing.T) {
|
|
parsed, err := sfnt.Parse(BundledFont().Data)
|
|
if err != nil {
|
|
t.Fatalf("parse bundled font: %v", err)
|
|
}
|
|
var buf sfnt.Buffer
|
|
for _, r := range []rune{'ư', 'ơ', 'đ', 'ạ', 'ế', 'ộ', 'ữ', 'ằ', 'ỷ', 'ỹ', 'Ọ', 'Ế', 'Ư', 'Đ'} {
|
|
index, err := parsed.GlyphIndex(&buf, r)
|
|
if err != nil {
|
|
t.Errorf("GlyphIndex(%q): %v", r, err)
|
|
continue
|
|
}
|
|
// Glyph 0 is .notdef — the character is absent from the font.
|
|
if index == 0 {
|
|
t.Errorf("bundled font has no glyph for %q (U+%04X)", r, r)
|
|
}
|
|
}
|
|
}
|