package generator import ( "encoding/binary" "strings" "testing" ) func TestPackAlphaBlock(t *testing.T) { var dst [4]byte packAlphaBlock(dst[:], [3]uint32{64, 512, 940}) word := binary.LittleEndian.Uint32(dst[:]) if got := word & 0x3ff; got != 64 { t.Errorf("sample 0 = %d, want 64", got) } if got := (word >> 10) & 0x3ff; got != 512 { t.Errorf("sample 1 = %d, want 512", got) } if got := (word >> 20) & 0x3ff; got != 940 { t.Errorf("sample 2 = %d, want 940", got) } if got := word >> 30; got != 0 { t.Errorf("unused bits = %d, want 0", got) } } func TestPackAlphaBlockMasksSamples(t *testing.T) { var dst [4]byte packAlphaBlock(dst[:], [3]uint32{0x401, 0x802, 0xc03}) word := binary.LittleEndian.Uint32(dst[:]) if got := word & 0x3ff; got != 1 { t.Errorf("sample 0 = %d, want 1", got) } if got := (word >> 10) & 0x3ff; got != 2 { t.Errorf("sample 1 = %d, want 2", got) } if got := (word >> 20) & 0x3ff; got != 3 { t.Errorf("sample 2 = %d, want 3", got) } } func TestFillAlphaPlaneCompleteBlocks(t *testing.T) { const width, height = 6, 2 dst := make([]byte, AlphaFrameSize(width, height)) if err := fillAlphaPlane(dst, width, height, alphaOpaque); err != nil { t.Fatalf("fillAlphaPlane: %v", err) } for y := 0; y < height; y++ { for x := 0; x < width; x++ { if got := sampleAlpha(dst, width, x, y); got != alphaOpaque { t.Errorf("sample (%d,%d) = %d, want %d", x, y, got, alphaOpaque) } } } } func TestFillAlphaPlaneZerosPartialBlockPadding(t *testing.T) { const width, height = 4, 2 dst := make([]byte, AlphaFrameSize(width, height)) if err := fillAlphaPlane(dst, width, height, alphaTransparent); err != nil { t.Fatalf("fillAlphaPlane: %v", err) } stride := AlphaLineSize(width) for y := 0; y < height; y++ { for x := 0; x < width; x++ { if got := sampleAlpha(dst, width, x, y); got != alphaTransparent { t.Errorf("sample (%d,%d) = %d, want %d", x, y, got, alphaTransparent) } } lastWord := binary.LittleEndian.Uint32(dst[y*stride+4:]) if got := (lastWord >> 10) & 0x3ff; got != 0 { t.Errorf("row %d padding sample 1 = %d, want 0", y, got) } if got := (lastWord >> 20) & 0x3ff; got != 0 { t.Errorf("row %d padding sample 2 = %d, want 0", y, got) } if got := lastWord >> 30; got != 0 { t.Errorf("row %d unused bits = %d, want 0", y, got) } } } func TestFillAlphaPlaneRejectsSmallDestination(t *testing.T) { const width, height = 6, 2 dst := make([]byte, AlphaFrameSize(width, height)-1) err := fillAlphaPlane(dst, width, height, alphaOpaque) if err == nil || !strings.Contains(err.Error(), "destination is too small") { t.Fatalf("error = %v, want destination size error", err) } } func TestPatchAlphaMovingSquare(t *testing.T) { const width, height = 304, 200 dst := make([]byte, AlphaFrameSize(width, height)) if err := fillAlphaPlane(dst, width, height, alphaOpaque); err != nil { t.Fatalf("fillAlphaPlane: %v", err) } if err := patchAlphaMovingSquare(dst, width, height, 0); err != nil { t.Fatalf("patchAlphaMovingSquare: %v", err) } if got := sampleAlpha(dst, width, width/2, height/2); got != alphaTransparent { t.Errorf("square center = %d, want transparent %d", got, alphaTransparent) } if got := sampleAlpha(dst, width, 10, height/2); got != alphaOpaque { t.Errorf("outside square = %d, want opaque %d", got, alphaOpaque) } // At frame zero the square begins at x=77. Its first three-sample word // therefore contains two opaque samples followed by one transparent sample. for x, want := range []uint32{alphaOpaque, alphaOpaque, alphaTransparent} { if got := sampleAlpha(dst, width, 75+x, height/2); got != want { t.Errorf("boundary sample x=%d = %d, want %d", 75+x, got, want) } } } func TestPatchAlphaMovingSquarePreservesPartialBlockPadding(t *testing.T) { const width, height = 100, 200 dst := make([]byte, AlphaFrameSize(width, height)) if err := fillAlphaPlane(dst, width, height, alphaOpaque); err != nil { t.Fatalf("fillAlphaPlane: %v", err) } if err := patchAlphaMovingSquare(dst, width, height, 0); err != nil { t.Fatalf("patchAlphaMovingSquare: %v", err) } lastWordOffset := height/2*AlphaLineSize(width) + (width/3)*4 lastWord := binary.LittleEndian.Uint32(dst[lastWordOffset:]) if got := lastWord & 0x3ff; got != alphaTransparent { t.Errorf("last visible sample = %d, want %d", got, alphaTransparent) } if got := lastWord >> 10; got != 0 { t.Errorf("partial-block padding bits = %#x, want 0", got) } } func TestPatchAlphaMovingSquareRejectsSmallDestination(t *testing.T) { const width, height = 100, 200 err := patchAlphaMovingSquare( make([]byte, AlphaFrameSize(width, height)-1), width, height, 0, ) if err == nil || !strings.Contains(err.Error(), "destination is too small") { t.Fatalf("error = %v, want destination size error", err) } } func sampleAlpha(buf []byte, width, x, y int) uint32 { offset := y*AlphaLineSize(width) + x/3*4 word := binary.LittleEndian.Uint32(buf[offset:]) return (word >> uint(x%3*10)) & 0x3ff }