mirror of
https://github.com/spotiflacapp/SpotiFLAC-Mobile.git
synced 2026-06-01 03:15:17 +07:00
- 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
171 lines
5.6 KiB
Go
171 lines
5.6 KiB
Go
package gobackend
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestCueParserEndToEnd(t *testing.T) {
|
|
dir := t.TempDir()
|
|
audioPath := filepath.Join(dir, "album.wav")
|
|
if err := os.WriteFile(audioPath, []byte("audio"), 0600); err != nil {
|
|
t.Fatalf("write audio: %v", err)
|
|
}
|
|
cuePath := filepath.Join(dir, "album.cue")
|
|
cue := "\ufeffREM GENRE \"Pop\"\n" +
|
|
"REM DATE 2026\n" +
|
|
"REM COMMENT \"comment\"\n" +
|
|
"REM COMPOSER \"Album Composer\"\n" +
|
|
"PERFORMER \"Album Artist\"\n" +
|
|
"TITLE \"Album Title\"\n" +
|
|
"FILE \"album.wav\" WAVE\n" +
|
|
" TRACK 01 AUDIO\n" +
|
|
" TITLE \"First\"\n" +
|
|
" PERFORMER \"Track Artist\"\n" +
|
|
" ISRC USRC17607839\n" +
|
|
" INDEX 01 00:00:00\n" +
|
|
" TRACK 02 AUDIO\n" +
|
|
" TITLE \"Second\"\n" +
|
|
" SONGWRITER \"Track Composer\"\n" +
|
|
" INDEX 00 03:00:00\n" +
|
|
" INDEX 01 03:05:00\n"
|
|
if err := os.WriteFile(cuePath, []byte(cue), 0600); err != nil {
|
|
t.Fatalf("write cue: %v", err)
|
|
}
|
|
|
|
sheet, err := ParseCueFile(cuePath)
|
|
if err != nil {
|
|
t.Fatalf("ParseCueFile: %v", err)
|
|
}
|
|
if sheet.Performer != "Album Artist" || sheet.Title != "Album Title" || len(sheet.Tracks) != 2 {
|
|
t.Fatalf("sheet = %#v", sheet)
|
|
}
|
|
if got := parseCueTimestamp("01:02:37"); got <= 62 || got >= 63 {
|
|
t.Fatalf("timestamp = %f", got)
|
|
}
|
|
if got := formatCueTimestamp(3723.5); got != "01:02:03.500" {
|
|
t.Fatalf("format timestamp = %q", got)
|
|
}
|
|
if got := unquoteCue(" \"quoted\" "); got != "quoted" {
|
|
t.Fatalf("unquote = %q", got)
|
|
}
|
|
fileName, fileType := parseCueFileLine("unquoted album.flac FLAC")
|
|
if fileName != "unquoted album.flac" || fileType != "FLAC" {
|
|
t.Fatalf("file line = %q/%q", fileName, fileType)
|
|
}
|
|
|
|
if resolved := ResolveCueAudioPath(cuePath, "album.flac"); resolved != audioPath {
|
|
t.Fatalf("resolved = %q want %q", resolved, audioPath)
|
|
}
|
|
info, err := BuildCueSplitInfo(cuePath, sheet, "")
|
|
if err != nil {
|
|
t.Fatalf("BuildCueSplitInfo: %v", err)
|
|
}
|
|
if info.Tracks[0].EndSec != 180 || info.Tracks[1].Composer != "Track Composer" {
|
|
t.Fatalf("split info = %#v", info.Tracks)
|
|
}
|
|
|
|
jsonText, err := ParseCueFileJSON(cuePath, "")
|
|
if err != nil {
|
|
t.Fatalf("ParseCueFileJSON: %v", err)
|
|
}
|
|
var decoded CueSplitInfo
|
|
if err := json.Unmarshal([]byte(jsonText), &decoded); err != nil {
|
|
t.Fatalf("decode cue json: %v", err)
|
|
}
|
|
if decoded.AudioPath != audioPath {
|
|
t.Fatalf("decoded audio path = %q", decoded.AudioPath)
|
|
}
|
|
|
|
results, err := ScanCueFileForLibraryExt(cuePath, "", "virtual/album.cue", 1234, "scan-time")
|
|
if err != nil {
|
|
t.Fatalf("ScanCueFileForLibraryExt: %v", err)
|
|
}
|
|
if len(results) != 2 || results[0].TrackName != "First" || results[0].Duration != 180 {
|
|
t.Fatalf("scan results = %#v", results)
|
|
}
|
|
if results[0].FilePath != "virtual/album.cue#track01" || results[0].Format != "cue+wav" {
|
|
t.Fatalf("scan path/format = %q/%q", results[0].FilePath, results[0].Format)
|
|
}
|
|
|
|
if _, err := ParseCueFile(filepath.Join(dir, "missing.cue")); err == nil {
|
|
t.Fatal("expected missing cue error")
|
|
}
|
|
emptyCue := filepath.Join(dir, "empty.cue")
|
|
if err := os.WriteFile(emptyCue, []byte("TITLE \"No tracks\""), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := ParseCueFile(emptyCue); err == nil {
|
|
t.Fatal("expected no tracks error")
|
|
}
|
|
missingDir := t.TempDir()
|
|
missingCuePath := filepath.Join(missingDir, "missing.cue")
|
|
if err := os.WriteFile(missingCuePath, []byte(cue), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := BuildCueSplitInfo(missingCuePath, &CueSheet{FileName: "missing.wav"}, ""); err == nil {
|
|
t.Fatal("expected missing audio error")
|
|
}
|
|
if _, err := resolveCueAudioPathForLibrary(cuePath, nil, ""); err == nil {
|
|
t.Fatal("expected nil sheet error")
|
|
}
|
|
if _, err := scanCueSheetForLibrary(cuePath, nil, audioPath, "", 0, "", ""); err == nil {
|
|
t.Fatal("expected nil scan sheet error")
|
|
}
|
|
}
|
|
|
|
func TestDuplicateIndexAndParallelExistence(t *testing.T) {
|
|
dir := t.TempDir()
|
|
filePath := filepath.Join(dir, "song.flac")
|
|
if err := os.WriteFile(filePath, []byte("audio"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
idx := &ISRCIndex{index: map[string]string{}, outputDir: dir, buildTime: time.Now()}
|
|
idx.Add("usrc17607839", filePath)
|
|
if got, ok := idx.lookup("USRC17607839"); !ok || got != filePath {
|
|
t.Fatalf("lookup = %q/%v", got, ok)
|
|
}
|
|
if got, err := idx.Lookup("usrc17607839"); err != nil || got != filePath {
|
|
t.Fatalf("Lookup = %q/%v", got, err)
|
|
}
|
|
idx.remove("usrc17607839")
|
|
if _, ok := idx.lookup("usrc17607839"); ok {
|
|
t.Fatal("expected removed ISRC")
|
|
}
|
|
|
|
isrcIndexCacheMu.Lock()
|
|
isrcIndexCache[dir] = idx
|
|
isrcIndexCacheMu.Unlock()
|
|
defer InvalidateISRCCache(dir)
|
|
|
|
AddToISRCIndex(dir, "USRC17607839", filePath)
|
|
if found, err := CheckISRCExists(dir, "USRC17607839"); err != nil || found != filePath {
|
|
t.Fatalf("CheckISRCExists = %q/%v", found, err)
|
|
}
|
|
if !CheckFileExists(filePath) || CheckFileExists(dir) || CheckFileExists(filepath.Join(dir, "missing.flac")) {
|
|
t.Fatal("unexpected file existence result")
|
|
}
|
|
|
|
tracksJSON := `[{"isrc":"USRC17607839","track_name":"Song","artist_name":"Artist"},{"isrc":"MISSING","track_name":"Other","artist_name":"Artist"}]`
|
|
resultJSON, err := CheckFilesExistParallel(dir, tracksJSON)
|
|
if err != nil {
|
|
t.Fatalf("CheckFilesExistParallel: %v", err)
|
|
}
|
|
var results []FileExistenceResult
|
|
if err := json.Unmarshal([]byte(resultJSON), &results); err != nil {
|
|
t.Fatalf("decode results: %v", err)
|
|
}
|
|
if !results[0].Exists || results[0].FilePath != filePath || results[1].Exists {
|
|
t.Fatalf("results = %#v", results)
|
|
}
|
|
if _, err := CheckFilesExistParallel(dir, `not-json`); err == nil {
|
|
t.Fatal("expected invalid json error")
|
|
}
|
|
if err := PreBuildISRCIndex(""); err == nil {
|
|
t.Fatal("expected empty dir error")
|
|
}
|
|
}
|