package api import ( "encoding/json" "testing" "github.com/jackc/pgx/v5/pgtype" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) // These tests pin the wire-format keys for /api/library/sync upserts. // Without them, sqlc model field-name drift or accidental // `json.Marshal(rawStruct)` regressions would silently break the // Flutter client (which reads snake_case keys via _*FromJson helpers // in flutter_client/lib/cache/sync_controller.dart). // validUUID is a deterministic test UUID — not a real value, just // something that pgtype.UUID.Valid will accept. var validUUID = pgtype.UUID{ Bytes: [16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}, Valid: true, } func assertJSONKeys(t *testing.T, label string, b []byte, want []string) { t.Helper() var m map[string]json.RawMessage if err := json.Unmarshal(b, &m); err != nil { t.Fatalf("%s: invalid json: %v\nbody: %s", label, err, b) } for _, k := range want { if _, ok := m[k]; !ok { t.Errorf("%s: missing key %q in %s", label, k, b) } } } func TestArtistSyncView_WireKeys(t *testing.T) { a := dbq.Artist{ID: validUUID, Name: "Aphex Twin", SortName: "Aphex Twin"} b, err := json.Marshal(toArtistSyncView(a)) if err != nil { t.Fatal(err) } assertJSONKeys(t, "artist", b, []string{ "id", "name", "sort_name", "mbid", "artist_thumb_path", "artist_fanart_path", }) } func TestAlbumSyncView_WireKeys(t *testing.T) { a := dbq.Album{ID: validUUID, ArtistID: validUUID, Title: "Drukqs", SortTitle: "Drukqs"} b, err := json.Marshal(toAlbumSyncView(a)) if err != nil { t.Fatal(err) } assertJSONKeys(t, "album", b, []string{ "id", "artist_id", "title", "sort_title", "release_date", "cover_art_path", "mbid", }) } func TestTrackSyncView_WireKeys(t *testing.T) { tr := dbq.Track{ ID: validUUID, AlbumID: validUUID, ArtistID: validUUID, Title: "Avril 14th", DurationMs: 121_000, FilePath: "x", FileFormat: "flac", } b, err := json.Marshal(toTrackSyncView(tr)) if err != nil { t.Fatal(err) } assertJSONKeys(t, "track", b, []string{ "id", "album_id", "artist_id", "title", "duration_ms", "track_number", "disc_number", "file_path", "file_format", "genre", }) } func TestPlaylistSyncView_WireKeys(t *testing.T) { variant := "discover" p := dbq.Playlist{ ID: validUUID, UserID: validUUID, Name: "Test", IsPublic: true, TrackCount: 5, DurationSec: 600, SystemVariant: &variant, } b, err := json.Marshal(toPlaylistSyncView(p)) if err != nil { t.Fatal(err) } assertJSONKeys(t, "playlist", b, []string{ "id", "user_id", "name", "description", "is_public", "cover_path", "track_count", "duration_sec", "system_variant", }) // Sanity: system_variant carries the value, not just present. var m map[string]any _ = json.Unmarshal(b, &m) if got := m["system_variant"]; got != "discover" { t.Errorf("system_variant: want 'discover', got %v", got) } }