a73x

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)
		}
	}
}