1
0
Fork 0
mirror of https://github.com/imjasonh/dots synced 2026-07-07 00:22:55 +00:00
dots/braille_test.go
Jason Hall 40cc74ad03 golangci-lint, remove image creation from tests
Signed-off-by: Jason Hall <jason@chainguard.dev>
2025-11-14 16:18:30 -05:00

210 lines
5.2 KiB
Go
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package dots
import (
"image"
"image/color"
"image/png"
"os"
"testing"
)
func TestBlockToBraille(t *testing.T) {
for _, tt := range []struct {
desc string
block [8]color.Color
threshold uint8
want rune
}{
{
desc: "all white (all dots on)",
block: [8]color.Color{color.White, color.White, color.White, color.White, color.White, color.White, color.White, color.White},
threshold: 128,
want: '⣿', // U+28FF - all 8 dots
},
{
desc: "all black (no dots)",
block: [8]color.Color{color.Black, color.Black, color.Black, color.Black, color.Black, color.Black, color.Black, color.Black},
threshold: 128,
want: '', // U+2800 - empty braille
},
{
desc: "first dot only",
block: [8]color.Color{color.White, color.Black, color.Black, color.Black, color.Black, color.Black, color.Black, color.Black},
threshold: 128,
want: '⠁', // U+2801 - dot 1
},
{
desc: "last dot only",
block: [8]color.Color{color.Black, color.Black, color.Black, color.Black, color.Black, color.Black, color.Black, color.White},
threshold: 128,
want: '⢀', // U+2880 - dot 8
},
} {
t.Run(tt.desc, func(t *testing.T) {
got := blockToBraille(tt.block, tt.threshold)
if got != tt.want {
t.Errorf("blockToBraille() = %U (%c), want %U (%c)", got, got, tt.want, tt.want)
}
})
}
}
func TestQuantizeRGB(t *testing.T) {
for _, tt := range []struct {
desc string
r, g, b uint8
want uint8
}{
{
desc: "black to grayscale",
r: 0, g: 0, b: 0,
want: 16, // Black from RGB cube
},
{
desc: "white to grayscale",
r: 255, g: 255, b: 255,
want: 231, // White from RGB cube
},
{
desc: "pure red",
r: 255, g: 0, b: 0,
want: 196, // 16 + 36*5 + 6*0 + 0
},
{
desc: "pure green",
r: 0, g: 255, b: 0,
want: 46, // 16 + 36*0 + 6*5 + 0
},
{
desc: "pure blue",
r: 0, g: 0, b: 255,
want: 21, // 16 + 36*0 + 6*0 + 5
},
{
desc: "mid gray",
r: 128, g: 128, b: 128,
want: 244, // Grayscale ramp
},
} {
t.Run(tt.desc, func(t *testing.T) {
got := quantizeRGB(tt.r, tt.g, tt.b)
if got != tt.want {
t.Errorf("quantizeRGB(%d, %d, %d) = %d, want %d", tt.r, tt.g, tt.b, got, tt.want)
}
})
}
}
func TestConvert(t *testing.T) {
for _, tt := range []struct {
desc string
imgPath string
opts Options
validate func(t *testing.T, lines []string)
}{
{
desc: "white image produces all-dots braille",
imgPath: "testdata/white.png",
opts: Options{Width: 4, Height: 4, Threshold: 128, NoColor: true},
validate: func(t *testing.T, lines []string) {
if len(lines) != 4 {
t.Errorf("got %d lines, want 4", len(lines))
}
// Each line should have 4 characters, all should be ⣿ (all dots on)
for i, line := range lines {
runes := []rune(line)
if len(runes) != 4 {
t.Errorf("line %d: got %d chars, want 4", i, len(runes))
}
for j, r := range runes {
if r != '⣿' {
t.Errorf("line %d, char %d: got %c, want ⣿", i, j, r)
}
}
}
},
},
{
desc: "black image produces empty braille",
imgPath: "testdata/black.png",
opts: Options{Width: 4, Height: 4, Threshold: 128, NoColor: true},
validate: func(t *testing.T, lines []string) {
if len(lines) != 4 {
t.Errorf("got %d lines, want 4", len(lines))
}
// Each line should have 4 characters, all should be (no dots)
for i, line := range lines {
runes := []rune(line)
if len(runes) != 4 {
t.Errorf("line %d: got %d chars, want 4", i, len(runes))
}
for j, r := range runes {
if r != '' {
t.Errorf("line %d, char %d: got %c, want ", i, j, r)
}
}
}
},
},
{
desc: "checkerboard produces varied braille",
imgPath: "testdata/checkerboard.png",
opts: Options{Width: 4, Height: 4, Threshold: 128, NoColor: true},
validate: func(t *testing.T, lines []string) {
if len(lines) != 4 {
t.Errorf("got %d lines, want 4", len(lines))
}
// Should have a mix of different braille characters
uniqueChars := make(map[rune]bool)
for _, line := range lines {
for _, r := range line {
uniqueChars[r] = true
}
}
if len(uniqueChars) < 2 {
t.Errorf("checkerboard should produce at least 2 different braille chars, got %d", len(uniqueChars))
}
},
},
} {
t.Run(tt.desc, func(t *testing.T) {
// Load image
f, err := os.Open(tt.imgPath)
if err != nil {
t.Fatalf("failed to open test image: %v", err)
}
defer func() { _ = f.Close() }()
img, err := png.Decode(f)
if err != nil {
t.Fatalf("failed to decode test image: %v", err)
}
// Convert
lines := Convert(img, tt.opts)
// Validate
tt.validate(t, lines)
})
}
}
func TestResize(t *testing.T) {
// Create a simple test image
src := image.NewRGBA(image.Rect(0, 0, 100, 100))
for y := 0; y < 100; y++ {
for x := 0; x < 100; x++ {
src.Set(x, y, color.White)
}
}
// Resize to smaller dimensions
resized := resize(src, 10, 10)
if resized.Bounds().Dx() != 10 {
t.Errorf("resized width = %d, want 10", resized.Bounds().Dx())
}
if resized.Bounds().Dy() != 10 {
t.Errorf("resized height = %d, want 10", resized.Bounds().Dy())
}
}