fixtures

package module
v0.0.0-...-841adf0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: GPL-3.0 Imports: 25 Imported by: 0

README

fixtures

Test-media generator for WaxDeck. The repository policy is no binary media in git: every audio file a test needs is synthesized at test-setup from a Spec: a deterministic sine tone (440 Hz per channel, times the channel index) encoded into the requested codec/container through WaxFlow's own encoders and muxers. No external tools are involved, and the same spec always produces the same bytes.

It is a Go module usable as a library and as a CLI.

Library

import "github.com/colespringer/waxdeck/fixtures"

// The full supported matrix.
paths, err := fixtures.Generate(dir, fixtures.DefaultLibrary()...)

// One custom file.
paths, err = fixtures.Generate(dir, fixtures.Spec{
    Codec:      fixtures.CodecFLAC,
    Duration:   2 * time.Second,
    SampleRate: 48000,
    Channels:   1,
    Tags:       map[string]string{"TITLE": "Fixture"},
})

Spec fields: Codec, Container (empty picks the codec's default), Duration (default 1 s, capped at 10 s), SampleRate (default 44100; Opus 48000), Channels (default 2), Corrupt, Tags, Chapters, Name. Spec.Filename() is the deterministic name Generate writes.

CLI

go run ./cmd/fixturegen -out testdata/media                # codec/container matrix
go run ./cmd/fixturegen -out testdata/media -preset demo   # titled demo album
go run ./cmd/fixturegen -out testdata/media -preset all    # both

The written paths print to stdout, one per line. The demo preset (DemoLibrary()) is a small tagged album with human-findable titles; end-to-end harnesses scan it alongside the matrix.

Coverage

Route Codec / container
Valid PCM in WAV, PCM in AIFF, FLAC, FLAC in Matroska, MP3, AAC in ADTS, AAC in MP4, ALAC in MP4, Opus in Ogg, Vorbis in Ogg
Corrupt CorruptTruncated (valid encode cut at half), CorruptGarbage (deterministic junk bytes)

The MP4 routes use WaxFlow's progressive container override, producing flat moov+mdat files its format registry demuxes back; the default MP4 form is fragmented CMAF, which exists for streaming rather than for files. The vendored WMA/APE/WavPack samples the plan of record allows as the one binary-media exception are deferred for now.

Tests

go test ./... generates the library into temp dirs, decodes every valid file back through WaxFlow's format registry (asserting container, codec, rate, channels, and decoded length), checks byte-determinism across two generations, and asserts the corrupt flavors fail the way robustness tests rely on.

Documentation

Overview

Package fixtures synthesizes the tiny audio files WaxDeck's tests run against. The repository policy is "no binary media in git": every test asset is generated at test-setup from a Spec: a deterministic sine tone encoded through WaxFlow's own encoders and muxers. No external tools are involved. Output is byte-deterministic: the same Spec always yields the same file.

Library use:

paths, err := fixtures.Generate(dir, fixtures.DefaultLibrary()...)

CLI use:

go run ./cmd/fixturegen -out testdata/media

Index

Constants

View Source
const (
	ExoticCoverWidth  = 240
	ExoticCoverHeight = 180
)

ExoticCoverWidth and ExoticCoverHeight are what a test asserts the catalog measured. Not square, so a cover reported as 240 x 180 proves the dimensions were read rather than guessed from one number.

View Source
const ExoticCoverName = "sleeve.tiff"

ExoticCoverName is the file GenerateExoticCover writes. The extension is what a picker filters on, so it has to be one the app offers.

View Source
const MaxDuration = 10 * time.Second

MaxDuration bounds a Spec's synthesized audio, silence included. Fixtures exist to be tiny; anything longer is a misuse this package refuses.

Variables

This section is empty.

Functions

func Generate

func Generate(dir string, specs ...Spec) ([]string, error)

Generate synthesizes each spec into dir (created if absent) and returns the written paths, in spec order. It stops at the first failure, returning the paths written so far alongside the error.

func GenerateBook

func GenerateBook(dir string) (string, error)

GenerateBook writes a three-part audiobook under dir using the conventional Author/Title layout: "Ada Author/The Fixture Book" holding parts "01 - Part One.m4b" through "03 - Part Three.m4b". The parts share ALBUM and ALBUMARTIST and carry track numbers, so a WaxBin scan groups them into one book item with three files in reading order. Tone durations are distinct per part so fingerprint dedup cannot merge them. It returns the book's directory.

func GenerateChapteredBook

func GenerateChapteredBook(dir string) (string, error)

GenerateChapteredBook writes a single-file audiobook into dir: one .m4b whose MP4 container embeds three chapter markers, with book tags (album is the book title, album-artist the author). The tone duration differs from every GenerateBook part so the two books never share an essence. It returns the file's path.

func GenerateExoticCover

func GenerateExoticCover(dir string) (string, error)

GenerateExoticCover writes a TIFF cover into dir and returns its path.

TIFF is the useful format to test with: it is the one the catalog decodes and the Go standard library does not, so a cover that reaches the slot measured proves the artwork guard asked the catalog's own recognizer rather than http.DetectContentType.

func GeneratePodcastFeed

func GeneratePodcastFeed(dir string, feed FeedSpec, baseURL string) (string, error)

GeneratePodcastFeed writes the feed's episode audio (through the same Generate machinery every fixture uses), any transcript (<guid>.vtt) and chapter (<guid>.chapters.json) sidecar documents, and a feed.xml tying them together: RSS 2.0 with the itunes and podcast namespaces, enclosure URLs rooted at baseURL. It returns the path of feed.xml.

Types

type Chapter

type Chapter struct {
	Start time.Duration
	End   time.Duration
	Title string
}

Chapter is one chapter marker to embed where the container supports them (MP4 today).

type Codec

type Codec string

Codec names an audio codec a Spec can ask for.

const (
	CodecPCM    Codec = "pcm"
	CodecFLAC   Codec = "flac"
	CodecMP3    Codec = "mp3"
	CodecAAC    Codec = "aac"
	CodecALAC   Codec = "alac"
	CodecOpus   Codec = "opus"
	CodecVorbis Codec = "vorbis"
)

type Container

type Container string

Container names the file container a Spec's codec is muxed into.

const (
	// ContainerDefault selects the codec's default container: WAV for
	// PCM, ADTS for AAC, MP4 for ALAC, Ogg for Opus and Vorbis, and
	// the codec's own stream form for FLAC and MP3.
	ContainerDefault  Container = ""
	ContainerWAV      Container = "wav"
	ContainerAIFF     Container = "aiff"
	ContainerFLAC     Container = "flac"
	ContainerMP3      Container = "mp3"
	ContainerMP4      Container = "mp4"
	ContainerADTS     Container = "adts"
	ContainerOgg      Container = "ogg"
	ContainerMatroska Container = "mka"
)

type Corruption

type Corruption string

Corruption selects a deliberately malformed flavor of a Spec, for robustness tests. Corrupt fixtures are synthesized like everything else; no binary media is vendored.

const (
	// CorruptNone produces a valid file.
	CorruptNone Corruption = ""
	// CorruptTruncated produces the valid encode cut off at half its
	// length: headers survive, the stream ends mid-file.
	CorruptTruncated Corruption = "truncated"
	// CorruptGarbage produces deterministic junk bytes under the spec's
	// file extension: no valid magic, no parsable structure. Garbage
	// needs no encoder, so it never requires ffmpeg.
	CorruptGarbage Corruption = "garbage"
)

type EpisodeSpec

type EpisodeSpec struct {
	Title         string
	GUID          string
	Spec          Spec
	PubDate       time.Time
	Description   string
	TranscriptVTT string
	ChaptersJSON  string
}

EpisodeSpec describes one podcast episode: its synthesized audio plus the feed-level fields an aggregator reads. TranscriptVTT and ChaptersJSON are optional; when set, the sidecar documents are written next to the audio and the feed advertises them via the podcast namespace.

type FeedSpec

type FeedSpec struct {
	Title       string
	Author      string
	Description string
	Link        string
	Episodes    []EpisodeSpec
}

FeedSpec describes one podcast feed: channel fields plus its episodes. Link is the channel's home URL; empty falls back to the base URL the feed is generated against.

func DefaultPodcastFeed

func DefaultPodcastFeed(baseURL string) FeedSpec

DefaultPodcastFeed is the preset feed the end-to-end harness serves: three MP3 episodes with silence-padded audio and distinct tone lengths (so essence dedup cannot merge them), descending publish dates from a fixed base so goldens stay stable, and a transcript plus chapters document on the first episode. baseURL becomes the channel link; the enclosure URLs come from the baseURL passed to GeneratePodcastFeed.

type Spec

type Spec struct {
	// Name overrides the generated file's base name (without the
	// extension). Empty derives a deterministic name from the fields.
	Name string
	// Codec selects the audio codec. Required.
	Codec Codec
	// Container selects the file container; ContainerDefault picks the
	// codec's native one.
	Container Container
	// Duration is the length of the synthesized tone, capped at
	// MaxDuration to keep fixtures tiny; 0 means 1 second.
	Duration time.Duration
	// LeadSilence prepends literal zero samples before the tone. Zero
	// means none; the output is then byte-identical to a spec without
	// the field. LeadSilence + Duration + TrailSilence must stay within
	// MaxDuration.
	LeadSilence time.Duration
	// TrailSilence appends literal zero samples after the tone. Zero
	// means none.
	TrailSilence time.Duration
	// SampleRate is in Hz; 0 means 44100 (48000 for Opus, which always
	// runs at 48 kHz anyway).
	SampleRate int
	// Channels is the channel count; 0 means 2 (stereo).
	Channels int
	// Corrupt selects a malformed flavor; the zero value is a valid file.
	Corrupt Corruption
	// Tags are metadata fields (TITLE, ARTIST, ...) embedded where the
	// container has a stream form for them. Keys are written in sorted
	// order so tagged output stays deterministic.
	Tags map[string]string
	// Chapters are chapter markers, embedded where the container
	// supports them.
	Chapters []Chapter
}

Spec describes one fixture file to synthesize.

func ConformanceMedia

func ConformanceMedia() []Spec

ConformanceMedia returns the single tone the audio-engine conformance suite plays against real engines: long enough that mid-file seek targets are meaningfully far apart, still under the duration cap.

func DefaultLibrary

func DefaultLibrary() []Spec

DefaultLibrary is the preset covering the full supported codec/container matrix (PCM in WAV and AIFF, FLAC in its stream form and in Matroska, MP3, AAC in ADTS and MP4, ALAC in MP4, Opus in Ogg, and Vorbis in Ogg), plus one truncated and one garbage flavor. Specs are fully spelled out (no zero-value defaults) so callers can read expected properties off them.

func DemoLibrary

func DemoLibrary() []Spec

DemoLibrary is a small tagged album: one track per commonly streamed codec, titled so tests and humans can find them by name. End-to-end harnesses scan it alongside DefaultLibrary. Durations are distinct on purpose: a catalog's fingerprint dedup would otherwise merge these with the matrix files, which synthesize the same tone at the same length.

func UploadFolderSources

func UploadFolderSources() []Spec

UploadFolderSources is the folder-pick journey's source material, which has to be its own album: the folder test and the file test run against one server, and reusing UploadSources would have each one importing the other's release and racing it for the destination. Distinct durations again, for the fingerprint-dedup reason.

Written under a disc subdirectory by the e2e stack, so what the pick walks is a tree rather than a flat folder - which is the half of a folder upload a flat one would never prove.

func UploadSources

func UploadSources() []Spec

UploadSources is the manual-upload journey's source material: a two-track album plus a standalone single, whose artists, albums, and titles appear in no other preset, so an end-to-end import can assert them uniquely against the scanned library. The single is the declined-identify journey's own file - declining imports on arrival, so a file another upload test imports would race it for the destination and flag it as a duplicate. Durations are distinct from every other preset for the same fingerprint-dedup reason as DemoLibrary.

func UploadWorkbenchSources

func UploadWorkbenchSources() []Spec

UploadWorkbenchSources is the release-workbench journey's own album, its own for the UploadFolderSources reason: that journey imports and then renames a release, and had it reused the lantern album its import would hold the destination the manual-upload journey's own import needs (the rename regroups the catalog but moves no files). Distinct durations, same fingerprint-dedup reason as everywhere.

func (Spec) Filename

func (s Spec) Filename() string

Filename is the deterministic base name Generate writes the spec to, extension included. An unsupported codec/container pair yields a ".bin" placeholder name; Generate rejects such specs with an error.

Directories

Path Synopsis
cmd
corpusgen command
Command corpusgen synthesizes a large catalog corpus for performance gates: real audio files, each carrying a cue sheet that carves it into first-class virtual tracks at scan.
Command corpusgen synthesizes a large catalog corpus for performance gates: real audio files, each carrying a cue sheet that carves it into first-class virtual tracks at scan.
feedserv command
Command feedserv serves a directory of podcast-feed fixtures over HTTP for the end-to-end harness: feed.xml, episode audio, transcript and chapter documents, with correct content types, Range support, and ETag/Last-Modified conditional GETs so feed polling behaves like it does against a real host.
Command feedserv serves a directory of podcast-feed fixtures over HTTP for the end-to-end harness: feed.xml, episode audio, transcript and chapter documents, with correct content types, Range support, and ETag/Last-Modified conditional GETs so feed polling behaves like it does against a real host.
fixturegen command
Command fixturegen writes a synthesized fixture library to a directory and prints the file list, one path per line.
Command fixturegen writes a synthesized fixture library to a directory and prints the file list, one path per line.
sourceserv command
Command sourceserv serves a canned acquisition source for the end-to-end harness: a playlist manifest at /playlist and the entry audio at /audio/<id>, synthesized at startup with -generate.
Command sourceserv serves a canned acquisition source for the end-to-end harness: a playlist manifest at /playlist and the entry audio at /audio/<id>, synthesized at startup with -generate.
testidp command
Command testidp is a minimal OIDC identity provider for the end-to-end harness: discovery, JWKS, an interactive login form on the authorization endpoint, and a token endpoint that enforces PKCE (S256) and single-use codes.
Command testidp is a minimal OIDC identity provider for the end-to-end harness: discovery, JWKS, an interactive login form on the authorization endpoint, and a token endpoint that enforces PKCE (S256) and single-use codes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL