package main import ( "fmt" "os" "path/filepath" "strings" "testing" ) func TestExtractISO_SkipsExistingWAVs(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() called := false runAkaiutil = func(isoPath, commands string) (string, error) { called = true return "", nil } tmp := t.TempDir() isoOutDir := filepath.Join(tmp, sanitiseISOName(filepath.Base("/fake/test.iso"))) if err := os.MkdirAll(isoOutDir, 0755); err != nil { t.Fatal(err) } for _, name := range []string{"kick.wav", "snare.wav", "hihat.wav"} { fd, err := os.Create(filepath.Join(isoOutDir, name)) if err != nil { t.Fatal(err) } defer func() { _ = fd.Close() }() } result, err := extractISO("/fake/test.iso", tmp) if err != nil { t.Fatalf("expected no error, got %v", err) } if called { t.Fatal("runAkaiutil should not have been called for existing WAVs") } if result == "" { t.Fatal("expected non-empty result") } } func TestExtractISO_ProceedsWhenNoWAVs(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() calls := 0 runAkaiutil = func(isoPath, commands string) (string, error) { calls++ if commands == "df\nq\n" { return ` Disk /disk0 A - S1000 HD (3840 blocks) `, nil } return ` exported 3 file(s) `, nil } tmp := t.TempDir() result, err := extractISO("/fake/test.iso", tmp) if err != nil { t.Fatalf("expected no error, got %v", err) } if calls == 0 { t.Fatal("runAkaiutil should have been called") } if result == "" { t.Fatal("expected non-empty result") } } func TestListPartitions(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() runAkaiutil = func(isoPath, commands string) (string, error) { if commands != "df\nq\n" { t.Fatalf("unexpected commands: %q", commands) } return ` Disk /disk0 Total blocks: 12288 (8 KB each) 98304 KB Partition table: A - S1000 HD (3840 blocks) B - S1000 HD (5120 blocks) C - S1000 HD (3328 blocks) `, nil } parts, err := listPartitions("/fake/disk.iso") if err != nil { t.Fatal(err) } if len(parts) != 3 { t.Fatalf("expected 3 partitions, got %d: %v", len(parts), parts) } if parts[0] != "A" || parts[1] != "B" || parts[2] != "C" { t.Fatalf("unexpected partitions: %v", parts) } } func TestListPartitionsEmpty(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() runAkaiutil = func(isoPath, commands string) (string, error) { return "No partitions found\n", nil } parts, err := listPartitions("/fake/disk.iso") if err != nil { t.Fatal(err) } if len(parts) != 1 || parts[0] != "A" { t.Fatalf("expected fallback to [A], got %v", parts) } } func TestListVolumes(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() runAkaiutil = func(isoPath, commands string) (string, error) { return ` /disk0/A > cd /disk0/A /disk0/A > dir 1 DRUM KIT 1 - VOLUME (10 files) 2 BASS SAMPLES - VOLUME (5 files) /disk0/A > cd /disk0/B /disk0/B > dir 3 SYNTH PADS - VOLUME (20 files) /disk0/B > `, nil } vols, err := listVolumes("/fake/disk.iso", []string{"A", "B"}) if err != nil { t.Fatal(err) } if len(vols) != 3 { t.Fatalf("expected 3 volumes, got %d: %v", len(vols), vols) } if vols[0].Part != "A" || vols[0].Name != "DRUM KIT 1" { t.Fatalf("unexpected vol 0: %+v", vols[0]) } if vols[1].Part != "A" || vols[1].Name != "BASS SAMPLES" { t.Fatalf("unexpected vol 1: %+v", vols[1]) } if vols[2].Part != "B" || vols[2].Name != "SYNTH PADS" { t.Fatalf("unexpected vol 2: %+v", vols[2]) } } func TestRunExtractionCount(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() calls := 0 runAkaiutil = func(isoPath, commands string) (string, error) { calls++ return ` exported 10 file(s) exported 5 file(s) exported 0 file(s) `, nil } vols := []volInfo{ {Part: "A", Name: "DRUMS"}, {Part: "A", Name: "BASS"}, } total, err := runExtraction("/fake/disk.iso", "/tmp/out", vols) if err != nil { t.Fatal(err) } if total != 15 { t.Fatalf("expected 15 total WAVs, got %d", total) } if calls != 1 { t.Fatalf("expected 1 akaiutil call, got %d", calls) } } func TestExtractWAVs_Success(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() callCount := 0 runAkaiutil = func(isoPath, commands string) (string, error) { callCount++ if callCount == 1 { if commands != "df\nq\n" { t.Fatalf("first call: expected df\\q\\n, got %q", commands) } return ` Disk /disk0 A - S1000 HD (3840 blocks) `, nil } if callCount == 2 { return ` /disk0/A > cd /disk0/A /disk0/A > dir 1 DRUMS - VOLUME (10 files) /disk0/A > q `, nil } if callCount == 3 { return ` exported 10 file(s) `, nil } t.Fatalf("unexpected call #%d with commands: %q", callCount, commands) return "", nil } tmp := t.TempDir() total, err := extractWAVs("/fake/test.iso", tmp) if err != nil { t.Fatalf("expected no error, got %v", err) } if total != 10 { t.Fatalf("expected 10 WAVs, got %d", total) } if callCount != 3 { t.Fatalf("expected 3 akaiutil calls, got %d", callCount) } } func TestExtractWAVs_MultipleVolumes(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() calls := 0 runAkaiutil = func(isoPath, commands string) (string, error) { calls++ if calls == 1 { return ` Disk /disk0 A - S1000 HD (3840 blocks) B - S1000 HD (5120 blocks) `, nil } if calls == 2 { return ` /disk0/A > cd /disk0/A 1 VOL_A - VOLUME (5 files) /disk0/B > cd /disk0/B 2 VOL_B - VOLUME (8 files) `, nil } return ` exported 5 file(s) exported 8 file(s) `, nil } tmp := t.TempDir() total, err := extractWAVs("/fake/multivol.iso", tmp) if err != nil { t.Fatalf("expected no error, got %v", err) } if total != 13 { t.Fatalf("expected 13 WAVs, got %d", total) } if calls != 3 { t.Fatalf("expected 3 calls, got %d", calls) } } func TestExtractWAVs_NoVolumes(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() calls := 0 runAkaiutil = func(isoPath, commands string) (string, error) { calls++ if calls == 1 { return `Disk /disk0 A - S1000 HD (3840 blocks) `, nil } if calls == 2 { return `/disk0/A > cd /disk0/A /disk0/A > q `, nil } return ` exported 0 file(s) `, nil } tmp := t.TempDir() total, err := extractWAVs("/fake/empty.iso", tmp) if err != nil { t.Fatalf("expected no error, got %v", err) } if total != 0 { t.Fatalf("expected 0 WAVs, got %d", total) } } func TestExtractWAVs_ErrorInPartitionList(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() runAkaiutil = func(isoPath, commands string) (string, error) { return "", fmt.Errorf("simulated partition error") } tmp := t.TempDir() _, err := extractWAVs("/fake/error.iso", tmp) if err == nil { t.Fatal("expected error, got nil") } } func TestExtractWAVs_ErrorInVolumeList(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() calls := 0 runAkaiutil = func(isoPath, commands string) (string, error) { calls++ if calls == 1 { return ` Disk /disk0 A - S1000 HD (3840 blocks) `, nil } return "", fmt.Errorf("simulated volume list error") } tmp := t.TempDir() _, err := extractWAVs("/fake/error.iso", tmp) if err == nil { t.Fatal("expected error, got nil") } } func TestRunExtraction_CreatesVolumeDirs(t *testing.T) { orig := runAkaiutil defer func() { runAkaiutil = orig }() created := map[string]bool{} runAkaiutil = func(isoPath, commands string) (string, error) { for _, line := range strings.Split(commands, "\n") { if strings.HasPrefix(line, "lcd ") { dir := strings.TrimPrefix(line, "lcd ") created[dir] = true } } return ` exported 3 file(s) `, nil } tmp := t.TempDir() vols := []volInfo{ {Part: "A", Name: "Test Volume One"}, } baseDir := filepath.Join(tmp, "output") _, err := runExtraction("/fake/test.iso", baseDir, vols) if err != nil { t.Fatalf("expected no error, got %v", err) } if !created["/"] { t.Error("expected lcd / to be in commands") } } func TestParseTags(t *testing.T) { t.Run("parses basic tag list", func(t *testing.T) { out := ` tag name ----------------- 01 Drums 02 Bass 03 FX 04 Vox 05 Percussion ----------------- ` tags := parseTags(out) if len(tags) != 5 { t.Fatalf("expected 5 tags, got %d", len(tags)) } if tags[0].Index != 1 || tags[0].Name != "Drums" { t.Errorf("tag 0: got {%d %s}, want {1 Drums}", tags[0].Index, tags[0].Name) } if tags[4].Index != 5 || tags[4].Name != "Percussion" { t.Errorf("tag 4: got {%d %s}, want {5 Percussion}", tags[4].Index, tags[4].Name) } }) t.Run("parses tags with spaces in names", func(t *testing.T) { out := ` tag name ----------------- 01 Kick Drum 02 Hi Hat 03 Snare Drum ----------------- ` tags := parseTags(out) if len(tags) != 3 { t.Fatalf("expected 3 tags, got %d", len(tags)) } if tags[0].Name != "Kick Drum" { t.Errorf("got %q, want 'Kick Drum'", tags[0].Name) } }) t.Run("handles default tag names from akaiutil", func(t *testing.T) { out := ` tag name ----------------- 01 TAG A 02 TAG B 03 MyTag ----------------- ` tags := parseTags(out) if len(tags) != 3 { t.Fatalf("expected 3 tags, got %d", len(tags)) } }) t.Run("no tags present message returns empty", func(t *testing.T) { out := "no tags present\n" tags := parseTags(out) if len(tags) != 0 { t.Errorf("expected 0 tags, got %d", len(tags)) } }) t.Run("handles empty output", func(t *testing.T) { tags := parseTags("") if len(tags) != 0 { t.Errorf("expected 0 tags, got %d", len(tags)) } }) t.Run("handles no tags in partition type", func(t *testing.T) { out := "no tags in this partition type\n" tags := parseTags(out) if len(tags) != 0 { t.Errorf("expected 0 tags, got %d", len(tags)) } }) } func TestListTags_Integration(t *testing.T) { origRun := runAkaiutil defer func() { runAkaiutil = origRun }() runAkaiutil = func(isoPath, commands string) (string, error) { return ` /disk0/A > lstags tag name ----------------- 01 Drums 02 Bass 03 FX ----------------- `, nil } tags, err := listTags("fake.iso", "A", "SomeVolume") if err != nil { t.Fatalf("unexpected error: %v", err) } if len(tags) != 3 { t.Errorf("expected 3 tags, got %d", len(tags)) } if tags[0].Name != "Drums" { t.Errorf("expected Drums, got %s", tags[0].Name) } if tags[2].Index != 3 || tags[2].Name != "FX" { t.Errorf("tag 2: got {%d %s}, want {3 FX}", tags[2].Index, tags[2].Name) } }