SpotiFLAC-Mobile/go_backend/exports_songlink_lyrics_supplement_test.go
zarzet 5bdaa35ced test: add comprehensive Go backend and Dart model test suites
- Add 16 Go supplement test files covering extension runtime, providers,
  health checks, lyrics, metadata, HTTP utils, library scan, and more
- Add Dart model/utils test suite (test/models_and_utils_test.dart)
- Update settings.g.dart with deduplicateDownloads serialization
2026-05-04 02:21:17 +07:00

158 lines
8.3 KiB
Go

package gobackend
import (
"context"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestLyricsExportWrappersWithoutNetwork(t *testing.T) {
dir := t.TempDir()
audioPath := filepath.Join(dir, "sidecar.mp3")
if err := os.WriteFile(audioPath, []byte("audio"), 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "sidecar.lrc"), []byte("[00:00.00]Sidecar lyric"), 0600); err != nil {
t.Fatal(err)
}
if jsonText, err := FetchLyrics("spotify-1", "Song Instrumental", "Artist", 180000); err != nil || !strings.Contains(jsonText, `"instrumental":true`) {
t.Fatalf("FetchLyrics instrumental = %q/%v", jsonText, err)
}
if lrc, err := GetLyricsLRC("spotify-1", "Song Instrumental", "Artist", "", 180000); err != nil || lrc != "[instrumental:true]" {
t.Fatalf("GetLyricsLRC instrumental = %q/%v", lrc, err)
}
if jsonText, err := GetLyricsLRCWithSource("spotify-1", "Song Instrumental", "Artist", "", 180000); err != nil || !strings.Contains(jsonText, `"instrumental":true`) {
t.Fatalf("GetLyricsLRCWithSource instrumental = %q/%v", jsonText, err)
}
if lrc, err := GetLyricsLRC("", "", "", audioPath, 0); err != nil || !strings.Contains(lrc, "Sidecar lyric") {
t.Fatalf("GetLyricsLRC sidecar = %q/%v", lrc, err)
}
if jsonText, err := GetLyricsLRCWithSource("", "", "", audioPath, 0); err != nil || !strings.Contains(jsonText, "Sidecar lyric") {
t.Fatalf("GetLyricsLRCWithSource sidecar = %q/%v", jsonText, err)
}
outPath := filepath.Join(dir, "lyrics.lrc")
if err := FetchAndSaveLyrics("Song", "Artist", "", 0, outPath, audioPath); err != nil {
t.Fatalf("FetchAndSaveLyrics sidecar: %v", err)
}
if data := string(mustReadFile(t, outPath)); !strings.Contains(data, "Sidecar lyric") {
t.Fatalf("saved lyrics = %q", data)
}
if response, err := EmbedLyricsToFile(filepath.Join(dir, "not-flac.mp3"), "lyrics"); err != nil || !strings.Contains(response, `"success":false`) {
t.Fatalf("EmbedLyricsToFile error = %q/%v", response, err)
}
if response, err := RewriteSplitArtistTagsExport(filepath.Join(dir, "not-flac.mp3"), "A;B", "A"); err != nil || !strings.Contains(response, `"success":false`) {
t.Fatalf("RewriteSplitArtistTagsExport error = %q/%v", response, err)
}
}
func TestSongLinkExportWrappersWithFakeClient(t *testing.T) {
origClient := globalSongLinkClient
origRetryConfig := songLinkRetryConfig
origSearchByISRC := songLinkSearchByISRC
origCheckFromDeezer := songLinkCheckAvailabilityFromDeezer
defer func() {
globalSongLinkClient = origClient
songLinkRetryConfig = origRetryConfig
songLinkSearchByISRC = origSearchByISRC
songLinkCheckAvailabilityFromDeezer = origCheckFromDeezer
SetSongLinkNetworkOptions(false, false)
}()
songLinkRetryConfig = func() RetryConfig {
return RetryConfig{MaxRetries: 0, InitialDelay: 0, MaxDelay: 0, BackoffFactor: 1}
}
globalSongLinkClient = &SongLinkClient{client: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
var body string
if req.URL.Host == "api.zarz.moe" {
body = `{"success":true,"songUrls":{"Spotify":"https://open.spotify.com/track/spotify-1","Deezer":"https://www.deezer.com/track/101","Tidal":"https://listen.tidal.com/track/202","YouTube":"https://youtu.be/yt1","AmazonMusic":"https://music.amazon.com/tracks/amz1","Qobuz":"https://open.qobuz.com/track/303"}}`
} else if req.URL.Host == "api.song.link" {
body = `{"linksByPlatform":{"spotify":{"url":"https://open.spotify.com/track/spotify-1"},"deezer":{"url":"https://www.deezer.com/track/101"},"tidal":{"url":"https://listen.tidal.com/track/202"},"youtubeMusic":{"url":"https://music.youtube.com/watch?v=ytm1"},"amazonMusic":{"url":"https://music.amazon.com/tracks/amz1"},"qobuz":{"url":"https://open.qobuz.com/track/303"}}}`
} else {
t.Fatalf("unexpected SongLink request: %s", req.URL.String())
}
return &http.Response{StatusCode: http.StatusOK, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(body)), Request: req}, nil
})}}
songLinkClientOnce.Do(func() {})
SetSongLinkNetworkOptions(true, true)
if availabilityJSON, err := CheckAvailability("spotify-1", ""); err != nil || !strings.Contains(availabilityJSON, `"deezer_id":"101"`) {
t.Fatalf("CheckAvailability = %q/%v", availabilityJSON, err)
}
if availabilityJSON, err := CheckAvailabilityFromDeezerID("101"); err != nil || !strings.Contains(availabilityJSON, `"spotify_id":"spotify-1"`) {
t.Fatalf("CheckAvailabilityFromDeezerID = %q/%v", availabilityJSON, err)
}
if availabilityJSON, err := CheckAvailabilityByPlatformID("deezer", "song", "101"); err != nil || !strings.Contains(availabilityJSON, `"tidal_url"`) {
t.Fatalf("CheckAvailabilityByPlatformID = %q/%v", availabilityJSON, err)
}
if spotifyID, err := GetSpotifyIDFromDeezerTrack("101"); err != nil || spotifyID != "spotify-1" {
t.Fatalf("GetSpotifyIDFromDeezerTrack = %q/%v", spotifyID, err)
}
if tidalURL, err := GetTidalURLFromDeezerTrack("101"); err != nil || !strings.Contains(tidalURL, "tidal") {
t.Fatalf("GetTidalURLFromDeezerTrack = %q/%v", tidalURL, err)
}
if urls, err := NewSongLinkClient().GetStreamingURLs("spotify-1"); err != nil || urls["tidal"] == "" || urls["amazon"] == "" {
t.Fatalf("GetStreamingURLs = %#v/%v", urls, err)
}
if youtubeURL, err := NewSongLinkClient().GetYouTubeURLFromSpotify("spotify-1"); err != nil || !strings.Contains(youtubeURL, "youtu") {
t.Fatalf("GetYouTubeURLFromSpotify = %q/%v", youtubeURL, err)
}
if amazonURL, err := NewSongLinkClient().GetAmazonURLFromDeezer("101"); err != nil || !strings.Contains(amazonURL, "amazon") {
t.Fatalf("GetAmazonURLFromDeezer = %q/%v", amazonURL, err)
}
if youtubeURL, err := NewSongLinkClient().GetYouTubeURLFromDeezer("101"); err != nil || !strings.Contains(youtubeURL, "youtube") {
t.Fatalf("GetYouTubeURLFromDeezer = %q/%v", youtubeURL, err)
}
if deezerID, err := NewSongLinkClient().GetDeezerIDFromSpotify("spotify-1"); err != nil || deezerID != "101" {
t.Fatalf("GetDeezerIDFromSpotify = %q/%v", deezerID, err)
}
if album, err := NewSongLinkClient().CheckAlbumAvailability("album-1"); err != nil || !album.Deezer || album.DeezerID == "" {
t.Fatalf("CheckAlbumAvailability = %#v/%v", album, err)
}
if albumID, err := NewSongLinkClient().GetDeezerAlbumIDFromSpotify("album-1"); err != nil || albumID == "" {
t.Fatalf("GetDeezerAlbumIDFromSpotify = %q/%v", albumID, err)
}
if availability, err := NewSongLinkClient().CheckAvailabilityFromURL("https://www.deezer.com/track/101"); err != nil || !availability.Deezer {
t.Fatalf("CheckAvailabilityFromURL = %#v/%v", availability, err)
}
songLinkSearchByISRC = func(ctx context.Context, isrc string) (*TrackMetadata, error) {
return &TrackMetadata{SpotifyID: "deezer:101", ExternalURL: "https://www.deezer.com/track/101"}, nil
}
songLinkCheckAvailabilityFromDeezer = func(s *SongLinkClient, deezerTrackID string) (*TrackAvailability, error) {
return &TrackAvailability{SpotifyID: "spotify-1", Deezer: true, DeezerID: deezerTrackID}, nil
}
if availabilityJSON, err := CheckAvailability("", "USRC17607839"); err != nil || !strings.Contains(availabilityJSON, `"deezer_id":"101"`) {
t.Fatalf("CheckAvailability by ISRC = %q/%v", availabilityJSON, err)
}
if songLinkExtractDeezerTrackID(nil) != "" || songLinkExtractDeezerTrackID(&TrackMetadata{ExternalURL: "https://www.deezer.com/track/202"}) != "202" {
t.Fatal("songLinkExtractDeezerTrackID mismatch")
}
deezerClient = &DeezerClient{
httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
body := fakeDeezerResponse(req.URL.Path, req.URL.RawQuery)
if body == "" {
body = `{"error":"missing"}`
}
return &http.Response{StatusCode: http.StatusOK, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(body)), Request: req}, nil
})},
searchCache: map[string]*cacheEntry{},
albumCache: map[string]*cacheEntry{},
artistCache: map[string]*cacheEntry{},
isrcCache: map[string]string{},
cacheCleanupInterval: time.Hour,
}
deezerClientOnce.Do(func() {})
if jsonText, err := ConvertSpotifyToDeezer("track", "spotify-1"); err != nil || !strings.Contains(jsonText, `"spotify_id":"deezer:101"`) {
t.Fatalf("ConvertSpotifyToDeezer track = %q/%v", jsonText, err)
}
if jsonText, err := ConvertSpotifyToDeezer("album", "album-1"); err != nil || jsonText == "" {
t.Fatalf("ConvertSpotifyToDeezer album = %q/%v", jsonText, err)
}
}