test(quick-19): add multi-root path resolution tests
- Add TestResolveM3UPath with 7 cases: abs, relative, second root, no match, empty roots, nil knownPaths - Add TestToRelativePathMultiRoot with 5 cases: first root, second root, no root, empty roots, empty string - Add TestRemoveM3UEntriesMultiRoot: entries from different roots removed correctly - Add TestFindM3UEntryMultiRoot: entry relative to second root found - Add TestReplaceM3UEntryPathsMultiRoot: replacement under second root applied
This commit is contained in:
@@ -866,3 +866,275 @@ func TestFindM3UEntry(t *testing.T) {
|
||||
t.Errorf("expected index -1, got %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveM3UPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
relativePath string
|
||||
libraryRoots []string
|
||||
knownPaths map[string]struct{}
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "absolute path returned as-is",
|
||||
relativePath: "/music/song.flac",
|
||||
libraryRoots: []string{"/other"},
|
||||
knownPaths: nil,
|
||||
expected: "/music/song.flac",
|
||||
},
|
||||
{
|
||||
name: "relative path resolves against first root",
|
||||
relativePath: "Artist/song.flac",
|
||||
libraryRoots: []string{"/music", "/archive"},
|
||||
knownPaths: map[string]struct{}{
|
||||
"/music/Artist/song.flac": {},
|
||||
},
|
||||
expected: "/music/Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "relative path resolves against second root",
|
||||
relativePath: "Artist/song.flac",
|
||||
libraryRoots: []string{"/music", "/archive"},
|
||||
knownPaths: map[string]struct{}{
|
||||
"/archive/Artist/song.flac": {},
|
||||
},
|
||||
expected: "/archive/Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "no match falls back to first root",
|
||||
relativePath: "Artist/song.flac",
|
||||
libraryRoots: []string{"/music", "/archive"},
|
||||
knownPaths: map[string]struct{}{},
|
||||
expected: "/music/Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "empty roots returns path unchanged",
|
||||
relativePath: "Artist/song.flac",
|
||||
libraryRoots: nil,
|
||||
knownPaths: nil,
|
||||
expected: "Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "nil knownPaths falls back to first root",
|
||||
relativePath: "Artist/song.flac",
|
||||
libraryRoots: []string{"/music"},
|
||||
knownPaths: nil,
|
||||
expected: "/music/Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "absolute path in knownPaths returned",
|
||||
relativePath: "/music/Artist/song.flac",
|
||||
libraryRoots: []string{"/other"},
|
||||
knownPaths: map[string]struct{}{
|
||||
"/music/Artist/song.flac": {},
|
||||
},
|
||||
expected: "/music/Artist/song.flac",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result := resolveM3UPath(
|
||||
tt.relativePath,
|
||||
tt.libraryRoots,
|
||||
tt.knownPaths,
|
||||
)
|
||||
if result != tt.expected {
|
||||
t.Errorf(
|
||||
"resolveM3UPath(%q, %v, ...) = %q, want %q",
|
||||
tt.relativePath,
|
||||
tt.libraryRoots,
|
||||
result, tt.expected,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToRelativePathMultiRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
absolutePath string
|
||||
libraryRoots []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "path under first root",
|
||||
absolutePath: "/music/Artist/song.flac",
|
||||
libraryRoots: []string{"/music", "/archive"},
|
||||
expected: "Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "path under second root",
|
||||
absolutePath: "/archive/Artist/song.flac",
|
||||
libraryRoots: []string{"/music", "/archive"},
|
||||
expected: "Artist/song.flac",
|
||||
},
|
||||
{
|
||||
name: "path under no root returns absolute",
|
||||
absolutePath: "/other/song.flac",
|
||||
libraryRoots: []string{"/music", "/archive"},
|
||||
expected: "/other/song.flac",
|
||||
},
|
||||
{
|
||||
name: "empty roots returns absolute",
|
||||
absolutePath: "/music/song.flac",
|
||||
libraryRoots: nil,
|
||||
expected: "/music/song.flac",
|
||||
},
|
||||
{
|
||||
name: "empty root string skipped",
|
||||
absolutePath: "/music/song.flac",
|
||||
libraryRoots: []string{"", "/music"},
|
||||
expected: "song.flac",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result := toRelativePathMultiRoot(
|
||||
tt.absolutePath, tt.libraryRoots,
|
||||
)
|
||||
if result != tt.expected {
|
||||
t.Errorf(
|
||||
"toRelativePathMultiRoot(%q, %v) = %q, want %q",
|
||||
tt.absolutePath,
|
||||
tt.libraryRoots,
|
||||
result, tt.expected,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveM3UEntriesMultiRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
entries := []m3uEntry{
|
||||
{RelativePath: "Artist/Song1.flac"},
|
||||
{RelativePath: "Band/Song2.flac"},
|
||||
{RelativePath: "Artist/Song3.flac"},
|
||||
}
|
||||
|
||||
// Song1 is under /music, Song2 is under /archive.
|
||||
// Both should be found and removed.
|
||||
targets := map[string]struct{}{
|
||||
"/music/Artist/Song1.flac": {},
|
||||
"/archive/Band/Song2.flac": {},
|
||||
}
|
||||
|
||||
result := removeM3UEntries(
|
||||
entries, targets, []string{"/music", "/archive"},
|
||||
)
|
||||
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("expected 1 entry, got %d", len(result))
|
||||
}
|
||||
|
||||
if result[0].RelativePath != "Artist/Song3.flac" {
|
||||
t.Errorf(
|
||||
"entry[0] = %q, want %q",
|
||||
result[0].RelativePath,
|
||||
"Artist/Song3.flac",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindM3UEntryMultiRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
entries := []m3uEntry{
|
||||
{RelativePath: "Artist/Song1.flac"},
|
||||
{RelativePath: "Band/Song2.flac"},
|
||||
}
|
||||
|
||||
// Song2 is under the second root /archive.
|
||||
entry, idx := findM3UEntry(
|
||||
entries, "/archive/Band/Song2.flac",
|
||||
[]string{"/music", "/archive"},
|
||||
)
|
||||
|
||||
if idx != 1 {
|
||||
t.Errorf("expected index 1, got %d", idx)
|
||||
}
|
||||
|
||||
if entry.RelativePath != "Band/Song2.flac" {
|
||||
t.Errorf(
|
||||
"entry.RelativePath = %q, want %q",
|
||||
entry.RelativePath,
|
||||
"Band/Song2.flac",
|
||||
)
|
||||
}
|
||||
|
||||
// Not found in any root.
|
||||
_, idx = findM3UEntry(
|
||||
entries, "/other/Missing.flac",
|
||||
[]string{"/music", "/archive"},
|
||||
)
|
||||
|
||||
if idx != -1 {
|
||||
t.Errorf("expected index -1, got %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceM3UEntryPathsMultiRoot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
entries := []m3uEntry{
|
||||
{
|
||||
RelativePath: "old/path/song.flac",
|
||||
DurationSec: 180,
|
||||
DisplayTitle: "Song",
|
||||
},
|
||||
{
|
||||
RelativePath: "other/track.mp3",
|
||||
DurationSec: 240,
|
||||
DisplayTitle: "Track",
|
||||
},
|
||||
}
|
||||
|
||||
// The old path resolves under /archive, not /music.
|
||||
replacements := map[string]string{
|
||||
"/archive/old/path/song.flac": "new/path/song.flac",
|
||||
}
|
||||
|
||||
result := replaceM3UEntryPaths(
|
||||
entries, replacements,
|
||||
[]string{"/music", "/archive"},
|
||||
)
|
||||
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("expected 2 entries, got %d", len(result))
|
||||
}
|
||||
|
||||
if result[0].RelativePath != "new/path/song.flac" {
|
||||
t.Errorf(
|
||||
"entry[0].RelativePath = %q, want %q",
|
||||
result[0].RelativePath,
|
||||
"new/path/song.flac",
|
||||
)
|
||||
}
|
||||
|
||||
if result[0].DurationSec != 180 {
|
||||
t.Errorf(
|
||||
"entry[0].DurationSec = %d, want 180",
|
||||
result[0].DurationSec,
|
||||
)
|
||||
}
|
||||
|
||||
if result[1].RelativePath != "other/track.mp3" {
|
||||
t.Errorf(
|
||||
"entry[1].RelativePath = %q, want %q",
|
||||
result[1].RelativePath,
|
||||
"other/track.mp3",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user