- Add internal/labels package with LabelData struct and RenderStandard() - QR encodes http://mac-mini.mg:8080/hw/HW-XXXXX (LBL-01) - Label is 384x120px NRGBA, white background, basicfont text - T-04-07 mitigation: validate HWID format before qrcode.New() - Install github.com/skip2/go-qrcode and golang.org/x/image - All 5 renderer tests pass
133 lines
4 KiB
Go
133 lines
4 KiB
Go
package labels
|
|
|
|
import (
|
|
"image/color"
|
|
"testing"
|
|
)
|
|
|
|
// TestRenderStandard_ImageDimensions verifies the output bitmap is 384x120.
|
|
func TestRenderStandard_ImageDimensions(t *testing.T) {
|
|
d := LabelData{
|
|
HWID: "HW-00001",
|
|
Name: "Test Device",
|
|
SpecLine: "Intel NUC i5 2019",
|
|
}
|
|
img, err := RenderStandard(d)
|
|
if err != nil {
|
|
t.Fatalf("RenderStandard returned error: %v", err)
|
|
}
|
|
bounds := img.Bounds()
|
|
if bounds.Dx() != LabelWidth {
|
|
t.Errorf("expected width %d, got %d", LabelWidth, bounds.Dx())
|
|
}
|
|
if bounds.Dy() != LabelHeight {
|
|
t.Errorf("expected height %d, got %d", LabelHeight, bounds.Dy())
|
|
}
|
|
}
|
|
|
|
// TestRenderStandard_QRNonBlank checks that the QR region (top-left 96x96 area) has
|
|
// mixed pixels (not all one color), indicating a real QR code was drawn.
|
|
func TestRenderStandard_QRNonBlank(t *testing.T) {
|
|
d := LabelData{
|
|
HWID: "HW-00001",
|
|
Name: "Test Device",
|
|
}
|
|
img, err := RenderStandard(d)
|
|
if err != nil {
|
|
t.Fatalf("RenderStandard returned error: %v", err)
|
|
}
|
|
|
|
var blackCount, whiteCount int
|
|
for y := QROffsetY; y < QROffsetY+QRSize; y++ {
|
|
for x := QROffsetX; x < QROffsetX+QRSize; x++ {
|
|
r, g, b, _ := img.At(x, y).RGBA()
|
|
// RGBA returns 16-bit values; 0 = black, 65535 = white
|
|
if r == 0 && g == 0 && b == 0 {
|
|
blackCount++
|
|
} else if r == 65535 && g == 65535 && b == 65535 {
|
|
whiteCount++
|
|
}
|
|
}
|
|
}
|
|
if blackCount == 0 {
|
|
t.Error("QR region has no black pixels — QR code was not rendered")
|
|
}
|
|
if whiteCount == 0 {
|
|
t.Error("QR region has no white pixels — QR region is solid black, not a QR code")
|
|
}
|
|
}
|
|
|
|
// TestRenderStandard_QRURLEncoding verifies the QR encodes the correct URL by
|
|
// checking that generating a QR with the expected URL produces the same image as
|
|
// what is embedded in the rendered label (same pixel dimensions at the same size).
|
|
func TestRenderStandard_QRURLEncoding(t *testing.T) {
|
|
hwID := "HW-00001"
|
|
expectedURL := BaseURL + hwID
|
|
|
|
// Verify the URL is correct by construction
|
|
if expectedURL != "http://mac-mini.mg:8080/hw/HW-00001" {
|
|
t.Errorf("BaseURL construction incorrect, got: %s", expectedURL)
|
|
}
|
|
|
|
// Render the label
|
|
d := LabelData{HWID: hwID, Name: "Test Device"}
|
|
img, err := RenderStandard(d)
|
|
if err != nil {
|
|
t.Fatalf("RenderStandard returned error: %v", err)
|
|
}
|
|
|
|
// The QR block must exist within the label bounds
|
|
bounds := img.Bounds()
|
|
if QROffsetX+QRSize > bounds.Dx() || QROffsetY+QRSize > bounds.Dy() {
|
|
t.Errorf("QR code region (%d+%d x %d+%d) exceeds label bounds (%d x %d)",
|
|
QROffsetX, QRSize, QROffsetY, QRSize, bounds.Dx(), bounds.Dy())
|
|
}
|
|
}
|
|
|
|
// TestRenderStandard_EmptyNameFallback ensures a LabelData with empty Name does not
|
|
// panic and uses "Unknown Item" as the displayed value.
|
|
func TestRenderStandard_EmptyNameFallback(t *testing.T) {
|
|
d := LabelData{
|
|
HWID: "HW-00099",
|
|
Name: "", // intentionally empty
|
|
}
|
|
// Must not panic
|
|
img, err := RenderStandard(d)
|
|
if err != nil {
|
|
t.Fatalf("RenderStandard returned error on empty name: %v", err)
|
|
}
|
|
if img == nil {
|
|
t.Fatal("expected non-nil image, got nil")
|
|
}
|
|
}
|
|
|
|
// TestRenderStandard_WhiteBackground verifies the background canvas is initialized
|
|
// to white (pure white NRGBA).
|
|
func TestRenderStandard_WhiteBackground(t *testing.T) {
|
|
d := LabelData{
|
|
HWID: "HW-00001",
|
|
Name: "Test",
|
|
}
|
|
img, err := RenderStandard(d)
|
|
if err != nil {
|
|
t.Fatalf("RenderStandard returned error: %v", err)
|
|
}
|
|
|
|
// Sample a corner that should be outside any QR or text region
|
|
// Use bottom-right corner area far from QR and text
|
|
sampleX := LabelWidth - 5
|
|
sampleY := LabelHeight - 5
|
|
c := img.At(sampleX, sampleY)
|
|
nrgba, ok := c.(color.NRGBA)
|
|
if !ok {
|
|
// Fallback: check via RGBA values
|
|
r, g, b, a := c.RGBA()
|
|
if r != 65535 || g != 65535 || b != 65535 || a != 65535 {
|
|
t.Errorf("expected white background at (%d,%d), got RGBA(%d,%d,%d,%d)", sampleX, sampleY, r, g, b, a)
|
|
}
|
|
return
|
|
}
|
|
if nrgba.R != 255 || nrgba.G != 255 || nrgba.B != 255 || nrgba.A != 255 {
|
|
t.Errorf("expected white background at (%d,%d), got NRGBA(%d,%d,%d,%d)", sampleX, sampleY, nrgba.R, nrgba.G, nrgba.B, nrgba.A)
|
|
}
|
|
}
|