- 系统候选补上 glyf 轮廓的 CJK 字体(文泉驿正黑/微米黑、DroidSansFallback、 AR PL UMing),并把 Noto Sans CJK 压到最后:它是 CFF/OTTO,freetype 必定解析失败, 排前面只会白白多读十几 MB - static/fonts 同时按当前工作目录与可执行文件目录查找,systemd 没配 WorkingDirectory 时也能找到(原先只按 CWD,文件在却报「没有可用字体」) - 启动时探一次字体:命中打 Info 带路径,缺失打 WARN 并给出补救命令 (apt install fonts-wqy-zenhei / 放 static/fonts/ / 配 font_path) - .ttc 先提取首个字面再用(仅对 glyf 轮廓的集合有效,如文泉驿); 失败结果缓存 1 分钟,避免公开端点被「每请求重新解析十几 MB」放大 实测:本地实例 apt install fonts-wqy-zenhei 后无需任何配置,启动即打出 font=/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc,/share-card 与单题分享图 从 500 变为 200 image/jpeg,中文与二维码渲染正常。
72 lines
2.7 KiB
Go
72 lines
2.7 KiB
Go
package question
|
||
|
||
import (
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/stretchr/testify/require"
|
||
|
||
"github.com/tamakyi/TamaBox/internal/conf"
|
||
)
|
||
|
||
// TestFontCandidatesOrder 锁住候选字体的优先级。
|
||
//
|
||
// 顺序错了不会报错,只会让线上多花几秒去解析一个注定失败的 19 MB CFF 字体
|
||
// (Noto Sans CJK 是 OTTO 轮廓,freetype 不支持),甚至在缺字体时把排障引向
|
||
// 「配了 font_path 却仍失败」的错误方向。
|
||
func TestFontCandidatesOrder(t *testing.T) {
|
||
old := conf.App.FontPath
|
||
t.Cleanup(func() { conf.App.FontPath = old })
|
||
conf.App.FontPath = "/opt/fonts/mine.ttf"
|
||
|
||
got := fontCandidates()
|
||
require.NotEmpty(t, got)
|
||
require.Equal(t, "/opt/fonts/mine.ttf", got[0], "配置项必须排在最前")
|
||
|
||
idxWQY, idxNoto := -1, -1
|
||
for i, p := range got {
|
||
if strings.Contains(p, "wqy-zenhei") {
|
||
idxWQY = i
|
||
}
|
||
if strings.Contains(p, "NotoSansCJK") && idxNoto < 0 {
|
||
idxNoto = i
|
||
}
|
||
}
|
||
require.NotEqual(t, -1, idxWQY, "系统 glyf 候选(文泉驿)应保留")
|
||
require.NotEqual(t, -1, idxNoto, "CFF 兜底候选应保留")
|
||
require.Less(t, idxWQY, idxNoto, "glyf 轮廓的系统字体必须排在 Noto(CFF) 之前")
|
||
}
|
||
|
||
// TestStaticFontDirs 校验两条不变式:返回的目录一定真实存在、且不重复。
|
||
// 存在性很重要 —— 把不存在的目录交给 Glob 不会报错,只会静默返回空,
|
||
// 于是「字体明明放在 static/fonts 却找不到」这种问题查起来毫无线索。
|
||
func TestStaticFontDirs(t *testing.T) {
|
||
seen := make(map[string]struct{})
|
||
for _, d := range staticFontDirs() {
|
||
st, err := os.Stat(d)
|
||
require.NoError(t, err, "候选目录必须存在:%s", d)
|
||
require.True(t, st.IsDir(), "候选必须是目录:%s", d)
|
||
_, dup := seen[d]
|
||
require.False(t, dup, "目录重复:%s", d)
|
||
seen[d] = struct{}{}
|
||
}
|
||
}
|
||
|
||
// TestLoadFontWithPathReportsTried 确认失败信息里列出实际尝试过的路径 ——
|
||
// 缺字体时这条文案就是唯一线索(分享卡是公开端点,没人看得到 console)。
|
||
func TestLoadFontWithPathReportsTried(t *testing.T) {
|
||
old := conf.App.FontPath
|
||
t.Cleanup(func() { conf.App.FontPath = old })
|
||
conf.App.FontPath = filepath.Join(t.TempDir(), "definitely-missing.ttf")
|
||
|
||
// 环境里可能偏偏装着可用系统字体,那就只能跳过(不断言失败)。
|
||
if _, path, err := loadFontWithPath(); err == nil {
|
||
t.Skipf("本机存在可用系统字体 %q,跳过失败路径断言", path)
|
||
} else {
|
||
require.Contains(t, err.Error(), "definitely-missing.ttf", "错误信息必须列出尝试过的路径")
|
||
require.Contains(t, err.Error(), "TrueType 轮廓", "错误信息必须点明需要 glyf 轮廓")
|
||
}
|
||
}
|