mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
refactor: simplify mocks
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
5c4df0912e
commit
7cd4a482c2
@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/navidrome/navidrome/tests"
|
"github.com/navidrome/navidrome/tests"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"golang.org/x/text/unicode/norm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Playlists", func() {
|
var _ = Describe("Playlists", func() {
|
||||||
@ -425,28 +424,6 @@ var _ = Describe("Playlists", func() {
|
|||||||
Expect(pls.Tracks[0].Path).To(Equal("abc/tEsT1.Mp3"))
|
Expect(pls.Tracks[0].Path).To(Equal("abc/tEsT1.Mp3"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("handles Unicode normalization when comparing paths", func() {
|
|
||||||
// Test case for Apple Music playlists that use NFC encoding vs macOS filesystem NFD
|
|
||||||
// The character "è" can be represented as NFC (single codepoint) or NFD (e + combining accent)
|
|
||||||
|
|
||||||
const pathWithAccents = "artist/Michèle Desrosiers/album/Noël.m4a"
|
|
||||||
|
|
||||||
// Simulate a database entry with NFD encoding (as stored by macOS filesystem)
|
|
||||||
nfdPath := norm.NFD.String(pathWithAccents)
|
|
||||||
repo.data = []string{nfdPath}
|
|
||||||
|
|
||||||
// Simulate an Apple Music M3U playlist entry with NFC encoding
|
|
||||||
nfcPath := norm.NFC.String("/music/" + pathWithAccents)
|
|
||||||
m3u := strings.Join([]string{
|
|
||||||
nfcPath,
|
|
||||||
}, "\n")
|
|
||||||
f := strings.NewReader(m3u)
|
|
||||||
|
|
||||||
pls, err := ps.ImportM3U(ctx, f)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Expect(pls.Tracks).To(HaveLen(1), "Should find the track despite Unicode normalization differences")
|
|
||||||
Expect(pls.Tracks[0].Path).To(Equal(nfdPath))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("InPlaylistsPath", func() {
|
Describe("InPlaylistsPath", func() {
|
||||||
@ -496,9 +473,8 @@ var _ = Describe("Playlists", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// mockedMediaFileRepo's FindByPaths method mimics the real implementation.
|
// mockedMediaFileRepo's FindByPaths method returns MediaFiles for the given paths.
|
||||||
// If data map is provided, it looks up files using the path as the key.
|
// If data map is provided, looks up files by key; otherwise creates them from paths.
|
||||||
// Otherwise, it creates MediaFile entries from the input paths.
|
|
||||||
type mockedMediaFileRepo struct {
|
type mockedMediaFileRepo struct {
|
||||||
model.MediaFileRepository
|
model.MediaFileRepository
|
||||||
data map[string]model.MediaFile
|
data map[string]model.MediaFile
|
||||||
@ -507,10 +483,9 @@ type mockedMediaFileRepo struct {
|
|||||||
func (r *mockedMediaFileRepo) FindByPaths(paths []string) (model.MediaFiles, error) {
|
func (r *mockedMediaFileRepo) FindByPaths(paths []string) (model.MediaFiles, error) {
|
||||||
var mfs model.MediaFiles
|
var mfs model.MediaFiles
|
||||||
|
|
||||||
// If data map is provided, use it to look up files
|
// If data map provided, look up files
|
||||||
if r.data != nil {
|
if r.data != nil {
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
// Look up by the path key (test should use "path:libraryID" format for keys)
|
|
||||||
if mf, ok := r.data[path]; ok {
|
if mf, ok := r.data[path]; ok {
|
||||||
mfs = append(mfs, mf)
|
mfs = append(mfs, mf)
|
||||||
}
|
}
|
||||||
@ -518,17 +493,18 @@ func (r *mockedMediaFileRepo) FindByPaths(paths []string) (model.MediaFiles, err
|
|||||||
return mfs, nil
|
return mfs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: create MediaFile entries from paths
|
// Otherwise, create MediaFiles from paths
|
||||||
// Parse library-qualified format: "libraryID:path"
|
|
||||||
for idx, path := range paths {
|
for idx, path := range paths {
|
||||||
libraryID := 1 // Default library ID
|
// Strip library qualifier if present (format: "libraryID:path")
|
||||||
actualPath := path
|
actualPath := path
|
||||||
|
libraryID := 1
|
||||||
if parts := strings.SplitN(path, ":", 2); len(parts) == 2 {
|
if parts := strings.SplitN(path, ":", 2); len(parts) == 2 {
|
||||||
if libID, err := strconv.Atoi(parts[0]); err == nil {
|
if id, err := strconv.Atoi(parts[0]); err == nil {
|
||||||
libraryID = libID
|
libraryID = id
|
||||||
actualPath = parts[1]
|
actualPath = parts[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mfs = append(mfs, model.MediaFile{
|
mfs = append(mfs, model.MediaFile{
|
||||||
ID: strconv.Itoa(idx),
|
ID: strconv.Itoa(idx),
|
||||||
Path: actualPath,
|
Path: actualPath,
|
||||||
@ -547,39 +523,24 @@ type mockedMediaFileFromListRepo struct {
|
|||||||
func (r *mockedMediaFileFromListRepo) FindByPaths(paths []string) (model.MediaFiles, error) {
|
func (r *mockedMediaFileFromListRepo) FindByPaths(paths []string) (model.MediaFiles, error) {
|
||||||
var mfs model.MediaFiles
|
var mfs model.MediaFiles
|
||||||
|
|
||||||
// Build a map of requested paths with their library IDs (handle both qualified and unqualified)
|
for idx, dataPath := range r.data {
|
||||||
type pathRequest struct {
|
for _, requestPath := range paths {
|
||||||
path string
|
// Strip library qualifier if present (format: "libraryID:path")
|
||||||
libraryID int
|
actualPath := requestPath
|
||||||
qualified bool
|
libraryID := 1
|
||||||
|
if parts := strings.SplitN(requestPath, ":", 2); len(parts) == 2 {
|
||||||
|
if id, err := strconv.Atoi(parts[0]); err == nil {
|
||||||
|
libraryID = id
|
||||||
|
actualPath = parts[1]
|
||||||
}
|
}
|
||||||
requests := make([]pathRequest, 0, len(paths))
|
|
||||||
for _, path := range paths {
|
|
||||||
req := pathRequest{path: path, libraryID: 1, qualified: false}
|
|
||||||
if parts := strings.SplitN(path, ":", 2); len(parts) == 2 {
|
|
||||||
if libID, err := strconv.Atoi(parts[0]); err == nil {
|
|
||||||
req.libraryID = libID
|
|
||||||
req.path = parts[1]
|
|
||||||
req.qualified = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requests = append(requests, req)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return files that match the requests
|
// Case-insensitive comparison (like SQL's "collate nocase")
|
||||||
// Need to use normalized comparison to handle Unicode normalization differences
|
if strings.EqualFold(actualPath, dataPath) {
|
||||||
normalizeForComparison := func(s string) string {
|
|
||||||
return strings.ToLower(norm.NFC.String(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx, path := range r.data {
|
|
||||||
normalizedPath := normalizeForComparison(path)
|
|
||||||
for _, req := range requests {
|
|
||||||
if normalizeForComparison(req.path) == normalizedPath {
|
|
||||||
mfs = append(mfs, model.MediaFile{
|
mfs = append(mfs, model.MediaFile{
|
||||||
ID: strconv.Itoa(idx),
|
ID: strconv.Itoa(idx),
|
||||||
Path: path,
|
Path: dataPath,
|
||||||
LibraryID: req.libraryID,
|
LibraryID: libraryID,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user