package api import ( "context" "os" "path/filepath" "strings" "testing" "time" "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) // truncateLibrary clears the music tables between tests. Sessions/users are // cleared by testHandlers. CASCADE covers tracks→albums→artists FK chain. func truncateLibrary(t *testing.T, pool *pgxpool.Pool) { t.Helper() if _, err := pool.Exec(context.Background(), "TRUNCATE tracks, albums, artists RESTART IDENTITY CASCADE"); err != nil { t.Fatalf("truncate: %v", err) } } // seedArtist inserts an artist with deterministic sort_name = name. func seedArtist(t *testing.T, pool *pgxpool.Pool, name string) dbq.Artist { t.Helper() a, err := dbq.New(pool).UpsertArtist(context.Background(), dbq.UpsertArtistParams{ Name: name, SortName: name, Mbid: nil, }) if err != nil { t.Fatalf("UpsertArtist(%s): %v", name, err) } return a } // seedAlbum inserts an album belonging to artistID. releaseYear=0 leaves // release_date unset. func seedAlbum(t *testing.T, pool *pgxpool.Pool, artistID pgtype.UUID, title string, releaseYear int) dbq.Album { t.Helper() var rel pgtype.Date if releaseYear > 0 { rel = pgtype.Date{Time: time.Date(releaseYear, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true} } a, err := dbq.New(pool).UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{ Title: title, SortTitle: title, ArtistID: artistID, ReleaseDate: rel, Mbid: nil, CoverArtPath: nil, }) if err != nil { t.Fatalf("UpsertAlbum(%s): %v", title, err) } return a } // seedTrack inserts a track. trackNumber<=0 leaves it NULL. filePath is // synthesized from title to stay unique across seeds. func seedTrack(t *testing.T, pool *pgxpool.Pool, albumID, artistID pgtype.UUID, title string, trackNumber int, durationMs int32) dbq.Track { t.Helper() var tn *int32 if trackNumber > 0 { v := int32(trackNumber) tn = &v } tr, err := dbq.New(pool).UpsertTrack(context.Background(), dbq.UpsertTrackParams{ Title: title, AlbumID: albumID, ArtistID: artistID, TrackNumber: tn, DiscNumber: nil, DurationMs: durationMs, FilePath: "/seed/" + title + ".flac", FileSize: 1024, FileFormat: "flac", Bitrate: nil, Mbid: nil, Genre: nil, }) if err != nil { t.Fatalf("UpsertTrack(%s): %v", title, err) } return tr } // seedTrackWithFile creates a fresh temp directory, writes fileBody to // /.<ext>, and inserts a Track row whose file_path points at it. // Returns the inserted Track and the directory (callers drop sidecar covers // into this dir when a test needs them). FileFormat is ext lowercased. func seedTrackWithFile(t *testing.T, pool *pgxpool.Pool, albumID, artistID pgtype.UUID, title string, fileBody []byte, ext string) (dbq.Track, string) { t.Helper() dir := t.TempDir() path := filepath.Join(dir, title+"."+ext) if err := os.WriteFile(path, fileBody, 0o644); err != nil { t.Fatalf("WriteFile(%s): %v", path, err) } one := int32(1) tr, err := dbq.New(pool).UpsertTrack(context.Background(), dbq.UpsertTrackParams{ Title: title, AlbumID: albumID, ArtistID: artistID, TrackNumber: &one, DiscNumber: nil, // DurationMs: arbitrary non-zero; tests don't assert on it. DurationMs: int32(len(fileBody)), FilePath: path, FileSize: int64(len(fileBody)), FileFormat: strings.ToLower(ext), Bitrate: nil, Mbid: nil, Genre: nil, }) if err != nil { t.Fatalf("UpsertTrack(%s): %v", title, err) } return tr, dir }