Files

129 lines
3.2 KiB
Go

// ABOUTME: Tests for the FLAC streaming decoder
// ABOUTME: Lifecycle tests — create with header, error without, close cleanly
package decode
import (
"testing"
"github.com/Sendspin/sendspin-go/pkg/audio"
)
// buildMinimalFLACHeader creates a syntactically valid FLAC codec_header
// (fLaC marker + STREAMINFO metadata block) for testing decoder lifecycle.
// The header is valid enough for mewkiz/flac to parse STREAMINFO, though
// no frames follow it.
func buildMinimalFLACHeader(sampleRate, channels, bitDepth, blockSize int) []byte {
header := make([]byte, 0, 42)
// fLaC marker
header = append(header, 'f', 'L', 'a', 'C')
// Metadata block header: last=1 (0x80), type=0 (STREAMINFO), length=34
header = append(header, 0x80, 0x00, 0x00, 34)
// STREAMINFO (34 bytes)
streamInfo := make([]byte, 34)
// min block size (bytes 0-1)
streamInfo[0] = byte(blockSize >> 8)
streamInfo[1] = byte(blockSize)
// max block size (bytes 2-3)
streamInfo[2] = byte(blockSize >> 8)
streamInfo[3] = byte(blockSize)
// min/max frame size (bytes 4-9): 0 = unknown
// sample rate (20 bits) | channels-1 (3 bits) | bps-1 (5 bits) | total samples (36 bits)
// packed into bytes 10-17
packed := uint64(sampleRate)<<44 | uint64(channels-1)<<41 | uint64(bitDepth-1)<<36
for i := 0; i < 8; i++ {
streamInfo[10+i] = byte(packed >> (56 - 8*i))
}
// MD5 (bytes 18-33): zeros
header = append(header, streamInfo...)
return header
}
func TestNewFLAC_RequiresCodecHeader(t *testing.T) {
format := audio.Format{
Codec: "flac",
SampleRate: 48000,
Channels: 2,
BitDepth: 24,
}
_, err := NewFLAC(format)
if err == nil {
t.Error("expected error when CodecHeader is nil")
}
}
func TestNewFLAC_InvalidCodec(t *testing.T) {
format := audio.Format{
Codec: "opus",
SampleRate: 48000,
Channels: 2,
BitDepth: 24,
}
_, err := NewFLAC(format)
if err == nil {
t.Fatal("expected error for invalid codec")
}
}
func TestNewFLAC_ValidHeader(t *testing.T) {
codecHeader := buildMinimalFLACHeader(48000, 2, 24, 4096)
format := audio.Format{
Codec: "flac",
SampleRate: 48000,
Channels: 2,
BitDepth: 24,
CodecHeader: codecHeader,
}
dec, err := NewFLAC(format)
if err != nil {
t.Fatalf("NewFLAC: %v", err)
}
defer dec.Close()
}
func TestFLACDecoder_CloseWithoutDecode(t *testing.T) {
codecHeader := buildMinimalFLACHeader(48000, 2, 24, 4096)
format := audio.Format{
Codec: "flac",
SampleRate: 48000,
Channels: 2,
BitDepth: 24,
CodecHeader: codecHeader,
}
dec, err := NewFLAC(format)
if err != nil {
t.Fatalf("NewFLAC: %v", err)
}
if err := dec.Close(); err != nil {
t.Errorf("Close: %v", err)
}
// Double close should not panic
if err := dec.Close(); err != nil {
t.Errorf("double Close: %v", err)
}
}
func TestFLACDecoder_DecodeAfterClose(t *testing.T) {
codecHeader := buildMinimalFLACHeader(48000, 2, 24, 4096)
format := audio.Format{
Codec: "flac",
SampleRate: 48000,
Channels: 2,
BitDepth: 24,
CodecHeader: codecHeader,
}
dec, err := NewFLAC(format)
if err != nil {
t.Fatalf("NewFLAC: %v", err)
}
dec.Close()
_, err = dec.Decode([]byte{0x00})
if err == nil {
t.Error("expected error after Close")
}
}