package storage import ( "path/filepath" "os" "testing" "time" "gitea.mrixs.me/Mrixs/yandex-music-api-go/yandexmusic" ) func TestStorageNew(t *testing.T) { tmpDir := t.TempDir() s, err := NewStorage(tmpDir, true) if err != nil { t.Fatalf("NewStorage failed: %v", err) } if s == nil { t.Fatal("expected non-nil storage") } } func TestStorageSaveAndLoadTrack(t *testing.T) { tmpDir := t.TempDir() s, err := NewStorage(tmpDir, true) if err != nil { t.Fatalf("NewStorage failed: %v", err) } meta := TrackMeta{ TrackID: "123", AlbumID: "456", ArtistID: "789", Title: "Test Track", ArtistName: "Test Artist", AlbumTitle: "Test Album", TrackNumber: 1, DiscNumber: 1, DurationMs: 180000, Bitrate: 320, Codec: "mp3", DownloadedAt: time.Now().Format(time.RFC3339), } data := []byte("fake audio data") if err := s.SaveTrack(meta, data, nil); err != nil { t.Fatalf("SaveTrack failed: %v", err) } // Check index if !s.IsTrackDownloaded("123") { t.Error("track not marked as downloaded") } loadedMeta, ok := s.GetTrackMeta("123") if !ok { t.Fatal("track not found in index") } if loadedMeta.Title != "Test Track" { t.Errorf("expected title 'Test Track', got '%s'", loadedMeta.Title) } if loadedMeta.FileSize != int64(len(data)) { t.Errorf("expected file size %d, got %d", len(data), loadedMeta.FileSize) } // Check file exists using the stored path if _, err := os.Stat(loadedMeta.FilePath); os.IsNotExist(err) { t.Error("track file not created") } } func TestStorageIdempotent(t *testing.T) { tmpDir := t.TempDir() s, err := NewStorage(tmpDir, true) if err != nil { t.Fatalf("NewStorage failed: %v", err) } meta := TrackMeta{ TrackID: "123", Title: "Test Track", ArtistName: "Test Artist", AlbumTitle: "Test Album", TrackNumber: 1, Codec: "mp3", } data := []byte("fake audio data") // Save first time if err := s.SaveTrack(meta, data, nil); err != nil { t.Fatalf("first SaveTrack failed: %v", err) } firstPath := meta.FilePath // Save second time (should not create duplicate) if err := s.SaveTrack(meta, data, nil); err != nil { t.Fatalf("second SaveTrack failed: %v", err) } if meta.FilePath != firstPath { t.Errorf("file path changed on second save: %s vs %s", meta.FilePath, firstPath) } // Verify only one file exists files, _ := os.ReadDir(filepath.Join(tmpDir, "Test Artist", "Test Album")) count := 0 for _, f := range files { if !f.IsDir() { count++ } } if count != 1 { t.Errorf("expected 1 file, found %d", count) } } func TestStorageOrganizeFalse(t *testing.T) { tmpDir := t.TempDir() s, err := NewStorage(tmpDir, false) if err != nil { t.Fatalf("NewStorage failed: %v", err) } meta := TrackMeta{ TrackID: "123", Title: "Test Track", ArtistName: "Test Artist", AlbumTitle: "Test Album", TrackNumber: 1, Codec: "mp3", DownloadedAt: time.Now().Format(time.RFC3339), } data := []byte("fake audio data") if err := s.SaveTrack(meta, data, nil); err != nil { t.Fatalf("SaveTrack failed: %v", err) } // Should be flat structure - get the saved meta from index loadedMeta, ok := s.GetTrackMeta("123") if !ok { t.Fatal("track not found in index") } expectedDir := tmpDir if filepath.Dir(loadedMeta.FilePath) != expectedDir { t.Errorf("expected flat structure in %s, got %s", expectedDir, filepath.Dir(loadedMeta.FilePath)) } } func TestStorageSanitizeFilename(t *testing.T) { tests := []struct { input string expected string }{ {"normal", "normal"}, {"with/slash", "with_slash"}, {"with\\backslash", "with_backslash"}, {"with:colon", "with_colon"}, {"with*star", "with_star"}, {"with?question", "with_question"}, {"with\"quote", "with_quote"}, {"withgt", "with_gt"}, {"with|pipe", "with_pipe"}, } for _, tc := range tests { result := sanitizeFilename(tc.input) if result != tc.expected { t.Errorf("sanitizeFilename(%q) = %q, want %q", tc.input, result, tc.expected) } } } func TestStorageBuildTrackMetaFromYandex(t *testing.T) { track := &yandexmusic.Track{ ID: "123", Title: "Test Track", Genre: "Pop", DurationMs: 180000, Artists: []yandexmusic.Artist{ {ID: "789", Name: "Test Artist"}, }, Albums: []yandexmusic.Album{ {ID: "456", Title: "Test Album"}, }, } album := &yandexmusic.Album{ ID: "456", Title: "Test Album", Genre: "Album Pop", Year: 2023, ReleaseDate: "2023-05-15", Label: "Test Label", Description: "Test album description", CatalogNumber: "TC-001", Artists: []yandexmusic.Artist{ {ID: "789", Name: "Test Artist"}, }, } downloadInfo := yandexmusic.DownloadInfo{ Bitrate: 320, Codec: "mp3", } meta := BuildTrackMetaFromYandex(track, album, 1, 1, downloadInfo) if meta.TrackID != "123" { t.Errorf("expected track ID 123, got %s", meta.TrackID) } if meta.Title != "Test Track" { t.Errorf("expected title 'Test Track', got '%s'", meta.Title) } if meta.ArtistName != "Test Artist" { t.Errorf("expected artist 'Test Artist', got '%s'", meta.ArtistName) } if meta.AlbumTitle != "Test Album" { t.Errorf("expected album 'Test Album', got '%s'", meta.AlbumTitle) } if meta.Bitrate != 320 { t.Errorf("expected bitrate 320, got %d", meta.Bitrate) } if meta.Codec != "mp3" { t.Errorf("expected codec mp3, got %s", meta.Codec) } // Extended metadata checks if meta.Genre != "Pop" { t.Errorf("expected genre 'Pop', got '%s'", meta.Genre) } if meta.Comment != "Test album description" { t.Errorf("expected comment 'Test album description', got '%s'", meta.Comment) } if meta.Lyrics != "" { t.Errorf("expected empty lyrics (no lyrics in track), got '%s'", meta.Lyrics) } if meta.Publisher != "Test Label" { t.Errorf("expected publisher 'Test Label', got '%s'", meta.Publisher) } if meta.EncodedBy != "ym-dl" { t.Errorf("expected encoded_by 'ym-dl', got '%s'", meta.EncodedBy) } if meta.OriginalYear != "2023" { t.Errorf("expected original_year '2023', got '%s'", meta.OriginalYear) } if meta.Copyright != "TC-001" { t.Errorf("expected copyright 'TC-001', got '%s'", meta.Copyright) } } func TestStorageBuildAlbumMetaFromYandex(t *testing.T) { album := &yandexmusic.Album{ ID: "456", Title: "Test Album", Artists: []yandexmusic.Artist{ {ID: "789", Name: "Test Artist"}, }, Year: 2023, } tracks := []TrackMeta{ {TrackID: "1", Title: "Track 1"}, {TrackID: "2", Title: "Track 2"}, } meta := BuildAlbumMetaFromYandex(album, tracks) if meta.AlbumID != "456" { t.Errorf("expected album ID 456, got %s", meta.AlbumID) } if meta.Title != "Test Album" { t.Errorf("expected title 'Test Album', got '%s'", meta.Title) } if meta.ArtistName != "Test Artist" { t.Errorf("expected artist 'Test Artist', got '%s'", meta.ArtistName) } if meta.Year != 2023 { t.Errorf("expected year 2023, got %d", meta.Year) } if meta.TrackCount != 2 { t.Errorf("expected track count 2, got %d", meta.TrackCount) } }