package generator import ( "errors" "strings" "testing" ) type fakeFrameGenerator struct { generateErr error closeErr error closed bool calls int } func (g *fakeFrameGenerator) GenerateFrame(dst []byte, frameIndex int) error { g.calls++ if g.generateErr != nil { return g.generateErr } for i := range dst { dst[i] = byte(frameIndex) } return nil } func (g *fakeFrameGenerator) Close() error { g.closed = true return g.closeErr } func TestV210AGeneratorLayoutAndAlpha(t *testing.T) { const width, height = 304, 200 fill := &fakeFrameGenerator{} g, err := NewV210AGenerator(fill, width, height) if err != nil { t.Fatalf("NewV210AGenerator: %v", err) } dst := make([]byte, V210AFrameSize(width, height)) if err := g.GenerateFrame(dst, 7); err != nil { t.Fatalf("GenerateFrame: %v", err) } fillSize := V210FrameSize(width, height) for i, b := range dst[:fillSize] { if b != 7 { t.Fatalf("fill byte %d = %#x, want 0x07", i, b) } } alpha := dst[fillSize:] if got := sampleAlpha(alpha, width, width/2, height/2); got != alphaTransparent { t.Errorf("square center = %d, want transparent %d", got, alphaTransparent) } if got := sampleAlpha(alpha, width, 10, height/2); got != alphaOpaque { t.Errorf("outside square = %d, want opaque %d", got, alphaOpaque) } } func TestV210AGeneratorRestoresAlphaBase(t *testing.T) { const width, height = 304, 200 g, err := NewV210AGenerator(&fakeFrameGenerator{}, width, height) if err != nil { t.Fatalf("NewV210AGenerator: %v", err) } dst := make([]byte, V210AFrameSize(width, height)) if err := g.GenerateFrame(dst, 0); err != nil { t.Fatalf("GenerateFrame(0): %v", err) } alpha := dst[V210FrameSize(width, height):] if got := sampleAlpha(alpha, width, width/2, height/2); got != alphaTransparent { t.Fatalf("frame 0 center = %d, want transparent %d", got, alphaTransparent) } if err := g.GenerateFrame(dst, 79); err != nil { t.Fatalf("GenerateFrame(79): %v", err) } if got := sampleAlpha(alpha, width, width/2, height/2); got != alphaOpaque { t.Errorf("old square position = %d, want restored opaque %d", got, alphaOpaque) } if got := sampleAlpha(alpha, width, 250, height/2); got != alphaTransparent { t.Errorf("new square position = %d, want transparent %d", got, alphaTransparent) } } func TestV210AGeneratorErrors(t *testing.T) { if _, err := NewV210AGenerator(nil, 1920, 1080); err == nil || !strings.Contains(err.Error(), "nil") { t.Fatalf("nil fill error = %v", err) } fillErr := errors.New("fill failed") g, err := NewV210AGenerator(&fakeFrameGenerator{generateErr: fillErr}, 100, 20) if err != nil { t.Fatalf("NewV210AGenerator: %v", err) } if err := g.GenerateFrame(make([]byte, V210AFrameSize(100, 20)-1), 0); err == nil || !strings.Contains(err.Error(), "too small") { t.Fatalf("small destination error = %v", err) } if err := g.GenerateFrame(make([]byte, V210AFrameSize(100, 20)), 3); !errors.Is(err, fillErr) { t.Fatalf("fill error = %v, want wrapped %v", err, fillErr) } } func TestV210AGeneratorClosesFill(t *testing.T) { closeErr := errors.New("close failed") fill := &fakeFrameGenerator{closeErr: closeErr} g, err := NewV210AGenerator(fill, 100, 20) if err != nil { t.Fatalf("NewV210AGenerator: %v", err) } if err := g.Close(); !errors.Is(err, closeErr) { t.Fatalf("Close = %v, want %v", err, closeErr) } if !fill.closed { t.Fatal("wrapped fill generator was not closed") } }