SpotiFLAC-Mobile/go_backend/cue_duplicate_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

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")
}
}