test(tray): add pngToIco + toWindowsIcon structure tests

Overlooked when the tray dir was gitignored by theta-agent-*; the negation in
.gitignore now lets the test be tracked.
This commit is contained in:
2026-08-09 19:07:12 -07:00
parent 016a8fc6b6
commit d18de7d109
2 changed files with 83 additions and 0 deletions
+2
View File
@@ -6,5 +6,7 @@ dist/
agent.yml
!cmd/theta-agent-helper/
!cmd/theta-agent-helper/main.go
!cmd/theta-agent-tray/
!cmd/theta-agent-tray/main_test.go
# Fetched by scripts/setup-build-env.ps1, pinned in installer/windows/vendor-manifest.json
installer/windows/vendor/
+81
View File
@@ -0,0 +1,81 @@
package main
import (
"bytes"
"runtime"
"testing"
)
// pngToIco wraps a PNG in a Windows ICO with BMP (not PNG-compressed) entries,
// because LoadImage cannot read PNG-in-ICO. Verify the container is well-formed
// and every entry's DIB is a valid 32bpp bitmap with an AND mask.
func TestPNGToIco(t *testing.T) {
ico := pngToIco(iconGreen)
if len(ico) < 6+16 {
t.Fatal("ico too short")
}
// ICONDIR
if ico[0] != 0 || ico[1] != 0 {
t.Errorf("reserved must be 0")
}
if ico[2] != 1 || ico[3] != 0 {
t.Errorf("type must be 1 (icon)")
}
count := int(ico[4]) | int(ico[5])<<8
if count != 3 {
t.Fatalf("expected 3 icon entries, got %d", count)
}
// Each ICONDIRENTRY: valid size, planes=1, bpp=32, DIB with BITMAPINFOHEADER.
for i := 0; i < count; i++ {
e := 6 + i*16
w := int(ico[e])
h := int(ico[e+1])
if w == 0 {
w = 256
}
if h == 0 {
h = 256
}
planes := int(ico[e+4]) | int(ico[e+5])<<8
bpp := int(ico[e+6]) | int(ico[e+7])<<8
size := int(ico[e+8]) | int(ico[e+9])<<8 | int(ico[e+10])<<16 | int(ico[e+11])<<24
offset := int(ico[e+12]) | int(ico[e+13])<<8 | int(ico[e+14])<<16 | int(ico[e+15])<<24
if planes != 1 || bpp != 32 {
t.Errorf("entry %d: want planes=1 bpp=32, got %d/%d", i, planes, bpp)
}
if offset+size > len(ico) {
t.Fatalf("entry %d: DIB out of range", i)
}
dib := ico[offset : offset+size]
// BITMAPINFOHEADER: biSize=40, biHeight = 2x for XOR+AND.
biSize := int(dib[0]) | int(dib[1])<<8 | int(dib[2])<<16 | int(dib[3])<<24
biW := int(dib[4]) | int(dib[5])<<8 | int(dib[6])<<16 | int(dib[7])<<24
biH := int(dib[8]) | int(dib[9])<<8 | int(dib[10])<<16 | int(dib[11])<<24
if biSize != 40 {
t.Errorf("entry %d: expected BITMAPINFOHEADER (40), got %d", i, biSize)
}
if biW != w || biH != h*2 {
t.Errorf("entry %d: DIB dims %dx%d, want %dx%d", i, biW, biH, w, h*2)
}
}
}
// toWindowsIcon passes the PNG through untouched on non-Windows and returns an
// ICO on Windows (whose validity TestPNGToIco covers).
func TestToWindowsIcon(t *testing.T) {
pngMagic := []byte{0x89, 'P', 'N', 'G'}
if runtime.GOOS == "windows" {
if bytes.HasPrefix(toWindowsIcon(iconRed), pngMagic) {
t.Error("windows must not receive a raw PNG")
}
} else {
if !bytes.HasPrefix(toWindowsIcon(iconRed), pngMagic) {
t.Error("non-windows must receive the PNG unchanged")
}
}
}