internal/site/bdf_test.go
Ref: Size: 4.2 KiB History
package site
import (
"strings"
"testing"
)
// bitmapString renders a pixel grid for comparison against a literal, so a
// failure prints the glyph rather than a slice of booleans.
func bitmapString(pix [][]bool) string {
var b strings.Builder
for _, row := range pix {
for _, on := range row {
if on {
b.WriteByte('#')
} else {
b.WriteByte('.')
}
}
b.WriteByte('\n')
}
return b.String()
}
func TestParseBDFGlyphBitmap(t *testing.T) {
f, err := parseBDF(gohu11)
if err != nil {
t.Fatal(err)
}
g, ok := f.glyphs['E']
if !ok {
t.Fatal("no glyph for 'E'")
}
want := "#####\n#....\n#....\n####.\n#....\n#....\n#....\n#####\n"
if got := bitmapString(g.pix); got != want {
t.Errorf("glyph 'E':\ngot:\n%swant:\n%s", got, want)
}
if g.w != 5 || g.h != 8 || g.xoff != 0 || g.yoff != 0 {
t.Errorf("BBX = %d %d %d %d, want 5 8 0 0", g.w, g.h, g.xoff, g.yoff)
}
if g.advance != 6 {
t.Errorf("advance = %d, want 6", g.advance)
}
}
func TestParseBDFMetrics(t *testing.T) {
for _, tc := range []struct {
name string
src []byte
ascent, descent int
lineHeight int
}{
{"gohu11", gohu11, 9, 2, 11},
{"gohu14b", gohu14b, 11, 3, 14},
} {
f, err := parseBDF(tc.src)
if err != nil {
t.Fatalf("%s: %v", tc.name, err)
}
if f.ascent != tc.ascent || f.descent != tc.descent {
t.Errorf("%s: ascent/descent = %d/%d, want %d/%d",
tc.name, f.ascent, f.descent, tc.ascent, tc.descent)
}
if got := f.lineHeight(); got != tc.lineHeight {
t.Errorf("%s: lineHeight = %d, want %d", tc.name, got, tc.lineHeight)
}
}
}
// The published fonts must cover every character the site can put on a card.
func TestParseBDFCoversPrintableASCII(t *testing.T) {
for _, src := range [][]byte{gohu11, gohu14b} {
f, err := parseBDF(src)
if err != nil {
t.Fatal(err)
}
for r := rune(' '); r <= '~'; r++ {
if _, ok := f.glyphs[r]; !ok {
t.Errorf("%s: no glyph for %q", f.name, r)
}
}
}
}
func TestFontRunsPlacesInkBelowTheBaseline(t *testing.T) {
f, err := parseBDF(gohu11)
if err != nil {
t.Fatal(err)
}
// 'p' has a descender: its ink must reach past the ascent line, where a
// row index equal to the ascent is the first row below the baseline.
runs, err := f.runs("p")
if err != nil {
t.Fatal(err)
}
var maxY int
for _, r := range runs {
if r.Y > maxY {
maxY = r.Y
}
}
if maxY < f.ascent {
t.Errorf("'p' bottom row Y = %d, want >= ascent %d", maxY, f.ascent)
}
if maxY >= f.lineHeight() {
t.Errorf("'p' bottom row Y = %d, past the line box %d", maxY, f.lineHeight())
}
}
func TestFontRunsAdvancesEachGlyph(t *testing.T) {
f, err := parseBDF(gohu11)
if err != nil {
t.Fatal(err)
}
runs, err := f.runs("EE")
if err != nil {
t.Fatal(err)
}
var first, second bool
for _, r := range runs {
switch r.X {
case 0:
first = true
case 6:
second = true
}
}
if !first || !second {
t.Errorf("want runs at X=0 and X=6 (one advance apart), got %v", runs)
}
if got, err := f.width("EE"); err != nil || got != 12 {
t.Errorf("width(\"EE\") = %d, %v; want 12, nil", got, err)
}
}
func TestFontRunsRejectsUnknownRune(t *testing.T) {
f, err := parseBDF(gohu11)
if err != nil {
t.Fatal(err)
}
if _, err := f.runs("日"); err == nil {
t.Error("want an error for a rune the font has no glyph for")
}
if _, err := f.width("日"); err == nil {
t.Error("want an error from width for a rune the font has no glyph for")
}
}
func TestParseBDFRejectsBrokenFonts(t *testing.T) {
for name, src := range map[string]string{
"no glyphs": "STARTFONT 2.1\nFONT_ASCENT 9\nFONT_DESCENT 2\nENDFONT\n",
"no ascent": "STARTFONT 2.1\nSTARTCHAR E\nENCODING 69\nDWIDTH 6 0\nBBX 1 1 0 0\nBITMAP\n80\nENDCHAR\nENDFONT\n",
"bitmap w/o bbx": "STARTFONT 2.1\nFONT_ASCENT 9\nFONT_DESCENT 2\nSTARTCHAR E\nENCODING 69\nBITMAP\n80\nENDCHAR\nENDFONT\n",
"bad hex": "STARTFONT 2.1\nFONT_ASCENT 9\nFONT_DESCENT 2\nSTARTCHAR E\nENCODING 69\nDWIDTH 6 0\nBBX 1 1 0 0\nBITMAP\nzz\nENDCHAR\nENDFONT\n",
"short bitmap": "STARTFONT 2.1\nFONT_ASCENT 9\nFONT_DESCENT 2\nSTARTCHAR E\nENCODING 69\nDWIDTH 6 0\nBBX 1 2 0 0\nBITMAP\n80\nENDCHAR\nENDFONT\n",
} {
if _, err := parseBDF([]byte(src)); err == nil {
t.Errorf("%s: want an error, got none", name)
}
}
}