148 lines
4.1 KiB
Go
148 lines
4.1 KiB
Go
package generator
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func fillFrame(value byte) FrameRenderer {
|
|
return func(dst []byte, _, _, _ int) error {
|
|
for i := range dst {
|
|
dst[i] = value
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func TestNewCPUGeneratorValidation(t *testing.T) {
|
|
renderer := fillFrame(0)
|
|
tests := []struct {
|
|
name string
|
|
width uint
|
|
height uint
|
|
renderer FrameRenderer
|
|
wantErrSub string
|
|
}{
|
|
{name: "zero width", height: 1, renderer: renderer, wantErrSub: "greater than zero"},
|
|
{name: "zero height", width: 6, renderer: renderer, wantErrSub: "greater than zero"},
|
|
{name: "odd width", width: 7, height: 1, renderer: renderer, wantErrSub: "even"},
|
|
{name: "nil renderer", width: 6, height: 1, wantErrSub: "renderer is nil"},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := NewCPUGenerator(tc.width, tc.height, tc.renderer, nil)
|
|
if err == nil || !strings.Contains(err.Error(), tc.wantErrSub) {
|
|
t.Fatalf("error = %v, want substring %q", err, tc.wantErrSub)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUGeneratorCopiesBaseAndRestoresBeforePatch(t *testing.T) {
|
|
patch := func(dst []byte, _, _, frameIndex int) error {
|
|
switch frameIndex {
|
|
case 1:
|
|
dst[0] = 0x22
|
|
case 2:
|
|
dst[16] = 0x33
|
|
}
|
|
return nil
|
|
}
|
|
g, err := NewCPUGenerator(12, 1, fillFrame(0x11), patch)
|
|
if err != nil {
|
|
t.Fatalf("NewCPUGenerator: %v", err)
|
|
}
|
|
|
|
frame := make([]byte, V210FrameSize(12, 1))
|
|
if err := g.GenerateFrame(frame, 1); err != nil {
|
|
t.Fatalf("GenerateFrame(1): %v", err)
|
|
}
|
|
if frame[0] != 0x22 {
|
|
t.Fatalf("frame 1 patch byte = %#x, want 0x22", frame[0])
|
|
}
|
|
|
|
if err := g.GenerateFrame(frame, 2); err != nil {
|
|
t.Fatalf("GenerateFrame(2): %v", err)
|
|
}
|
|
if frame[0] != 0x11 {
|
|
t.Fatalf("old patch byte = %#x, want restored base 0x11", frame[0])
|
|
}
|
|
if frame[16] != 0x33 {
|
|
t.Fatalf("frame 2 patch byte = %#x, want 0x33", frame[16])
|
|
}
|
|
}
|
|
|
|
func TestPackV210Block(t *testing.T) {
|
|
var pixels [6]YCbCr10
|
|
for i := range pixels {
|
|
pixels[i] = YCbCr10{
|
|
Y: uint32(100 + i),
|
|
Cb: uint32(200 + i),
|
|
Cr: uint32(300 + i),
|
|
}
|
|
}
|
|
frame := make([]byte, 16)
|
|
packV210Block(frame, pixels)
|
|
|
|
for x := range pixels {
|
|
y, cb, cr := sampleV210(frame, 6, x, 0)
|
|
chromaX := x - x%2
|
|
if y != pixels[x].Y || cb != pixels[chromaX].Cb || cr != pixels[chromaX].Cr {
|
|
t.Fatalf("pixel %d: got %d/%d/%d, want %d/%d/%d",
|
|
x, y, cb, cr, pixels[x].Y, pixels[chromaX].Cb, pixels[chromaX].Cr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPackV210BlockMasksComponents(t *testing.T) {
|
|
pixel := YCbCr10{Y: 0xC01, Cb: 0xC02, Cr: 0xC03}
|
|
frame := make([]byte, 16)
|
|
packV210Block(frame, [6]YCbCr10{pixel, pixel, pixel, pixel, pixel, pixel})
|
|
y, cb, cr := sampleV210(frame, 6, 0, 0)
|
|
if y != 1 || cb != 2 || cr != 3 {
|
|
t.Fatalf("masked components = %d/%d/%d, want 1/2/3", y, cb, cr)
|
|
}
|
|
}
|
|
|
|
func TestCPUGeneratorErrors(t *testing.T) {
|
|
wantErr := errors.New("patch failed")
|
|
g, err := NewCPUGenerator(6, 1, fillFrame(0), func([]byte, int, int, int) error {
|
|
return wantErr
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewCPUGenerator: %v", err)
|
|
}
|
|
if err := g.GenerateFrame(make([]byte, V210FrameSize(6, 1)-1), 0); err == nil || !strings.Contains(err.Error(), "too small") {
|
|
t.Fatalf("small destination error = %v", err)
|
|
}
|
|
if err := g.GenerateFrame(make([]byte, V210FrameSize(6, 1)), 4); !errors.Is(err, wantErr) {
|
|
t.Fatalf("patch error = %v, want wrapped %v", err, wantErr)
|
|
}
|
|
}
|
|
|
|
func TestCPUGeneratorUsesPaddedV210Rows(t *testing.T) {
|
|
const width, height = 100, 2
|
|
g, err := NewCPUPatternGenerator(width, height, "gray-ramp")
|
|
if err != nil {
|
|
t.Fatalf("NewCPUPatternGenerator: %v", err)
|
|
}
|
|
frame := make([]byte, V210FrameSize(width, height))
|
|
if err := g.GenerateFrame(frame, 0); err != nil {
|
|
t.Fatalf("GenerateFrame: %v", err)
|
|
}
|
|
|
|
for y := 0; y < height; y++ {
|
|
gotY, gotCb, gotCr := sampleV210(frame, width, 0, y)
|
|
if gotY != 64 || gotCb != 512 || gotCr != 512 {
|
|
t.Fatalf("row %d first pixel = %d/%d/%d, want 64/512/512", y, gotY, gotCb, gotCr)
|
|
}
|
|
padding := frame[y*V210LineSize(width)+V210ActiveLineSize(width) : (y+1)*V210LineSize(width)]
|
|
for i, b := range padding {
|
|
if b != 0 {
|
|
t.Fatalf("row %d padding byte %d = %#x, want 0", y, i, b)
|
|
}
|
|
}
|
|
}
|
|
}
|