Files
david cf53912a33 feat: Audio Preview Player — browse and play WAV samples via Web Audio API
Issue: #9

Backend:
- GET /api/list-wavs?dir=<path> — lists .wav files in a directory
- GET /wavs/<file> — static file serving from ./output/wavs

Web UI:
- WAV Browser section with path input + Browse button
- AudioContext-based playback (zero deps) — progress bar, time display
- WAV file grid with Play buttons, active item highlighting

Tests:
- 3 new tests for handleListWavs (wav files, empty dir, nonexistent dir)
- Fix TestFindAkaiutil: add t.Chdir(tmp) so relative path lookups don't
  accidentally find the repo's third_party/akaiutil/akaiutil binary
2026-06-22 00:01:15 -07:00

205 lines
4.8 KiB
Go

package main
import (
"os"
"path/filepath"
"testing"
)
func TestSanitiseISOName(t *testing.T) {
cases := []struct {
input string
expected string
}{
{"ZERO-G - Deepest India", "ZERO-G_-_Deepest_India"},
{"SYNTH PAD COLLECTION.iso", "SYNTH_PAD_COLLECTION"},
{"vocal.loops", "vocal"},
{"DRUM KIT #1", "DRUM_KIT_1"},
{"simple", "simple"},
{"no-extension", "no-extension"},
{"multiple spaces", "multiple_spaces"},
{"UPPERCASE", "UPPERCASE"},
{"MiXeD CaSe", "MiXeD_CaSe"},
{"with-dash", "with-dash"},
{"with_underscore", "with_underscore"},
{"with.dots.in.name", "with.dots.in"},
{".hidden", ""},
{"trailing_", "trailing"},
{"__leading__", "leading"},
{"spaces everywhere", "spaces_everywhere"},
{"", ""},
{" ", ""},
{".iso", ""},
{"a", "a"},
}
for _, c := range cases {
got := sanitiseISOName(c.input)
if got != c.expected {
t.Errorf("sanitiseISOName(%q) = %q, want %q", c.input, got, c.expected)
}
}
}
func TestTruncate(t *testing.T) {
cases := []struct {
s string
n int
expect string
}{
{"hello", 10, "hello"},
{"hello", 5, "hello"},
{"hello", 4, "h..."},
{"hello", 3, "..."},
{"hello", 2, "he"},
{"hello", 1, "h"},
{"hello", 0, ""},
{"", 5, ""},
{"abcdef", 4, "a..."},
{"ab", 4, "ab"},
{"abc", 3, "abc"},
{"abcd", 2, "ab"},
}
for _, c := range cases {
got := truncate(c.s, c.n)
if got != c.expect {
t.Errorf("truncate(%q, %d) = %q, want %q", c.s, c.n, got, c.expect)
}
}
}
func TestHumanSize(t *testing.T) {
cases := []struct {
bytes int64
expect string
}{
{0, "0B"},
{500, "500B"},
{1024, "1.0 KB"},
{1536, "1.5 KB"},
{10240, "10.0 KB"},
{1048576, "1.0 MB"},
{1572864, "1.5 MB"},
{1073741824, "1.0 GB"},
{2147483648, "2.0 GB"},
}
for _, c := range cases {
got := humanSize(c.bytes)
if got != c.expect {
t.Errorf("humanSize(%d) = %q, want %q", c.bytes, got, c.expect)
}
}
}
func TestFindAkaiutil(t *testing.T) {
origEnv := os.Getenv("AKAIUTIL")
origArg0 := os.Args[0]
defer func() {
_ = os.Setenv("AKAIUTIL", origEnv)
os.Args[0] = origArg0
}()
t.Run("env var set to missing file", func(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
_ = os.Setenv("AKAIUTIL", "/nonexistent/akaiutil")
os.Args[0] = "/some/binary"
_, err := findAkaiutil()
if err == nil {
t.Fatal("expected error for missing env var path")
}
})
t.Run("env var set to existing file", func(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
f := tmp + "/myutil"
fd, _ := os.Create(f)
defer func() { _ = fd.Close() }()
_ = os.Setenv("AKAIUTIL", f)
got, err := findAkaiutil()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if got != f {
t.Errorf("got %q, want %q", got, f)
}
})
t.Run("finds binary next to argv[0]", func(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
exe := tmp + "/mybinary"
fd, _ := os.Create(exe)
defer func() { _ = fd.Close() }()
sideBySide := tmp + "/akaiutil"
fd2, _ := os.Create(sideBySide)
defer func() { _ = fd2.Close() }()
_ = os.Setenv("AKAIUTIL", "")
os.Args[0] = exe
got, err := findAkaiutil()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if got != sideBySide {
t.Errorf("got %q, want %q", got, sideBySide)
}
})
t.Run("finds binary in third_party relative to argv[0]", func(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
exe := tmp + "/somebin"
fd, _ := os.Create(exe)
defer func() { _ = fd.Close() }()
thirdParty := filepath.Join(tmp, "third_party", "akaiutil")
if err := os.MkdirAll(thirdParty, 0755); err != nil {
t.Fatal(err)
}
akaiutilInThirdParty := filepath.Join(thirdParty, "akaiutil")
fd2, _ := os.Create(akaiutilInThirdParty)
defer func() { _ = fd2.Close() }()
_ = os.Setenv("AKAIUTIL", "")
os.Args[0] = exe
got, err := findAkaiutil()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if got != akaiutilInThirdParty {
t.Errorf("got %q, want %q", got, akaiutilInThirdParty)
}
})
t.Run("env var takes priority over path candidates", func(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
envFile := tmp + "/envutil"
pathFile := tmp + "/pathutil"
fd1, _ := os.Create(envFile)
defer func() { _ = fd1.Close() }()
fd2, _ := os.Create(pathFile)
defer func() { _ = fd2.Close() }()
_ = os.Setenv("AKAIUTIL", envFile)
os.Args[0] = pathFile
got, err := findAkaiutil()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if got != envFile {
t.Errorf("got %q, want env var path %q", got, envFile)
}
})
t.Run("no akaiutil found returns error", func(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
exe := tmp + "/nobinaryhere"
fd, _ := os.Create(exe)
defer func() { _ = fd.Close() }()
_ = os.Setenv("AKAIUTIL", "")
os.Args[0] = exe
_, err := findAkaiutil()
if err == nil {
t.Fatal("expected error when no akaiutil found")
}
})
}