feat(api): GET /api/artists with alpha/newest sort and paging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -254,3 +254,172 @@ func TestHandleGetArtist_NotFound(t *testing.T) {
|
||||
t.Errorf("status = %d, want 404", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_DefaultAlpha(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
seedArtist(t, pool, "Beatles")
|
||||
seedArtist(t, pool, "ABBA")
|
||||
seedArtist(t, pool, "Zeppelin")
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d body = %s", w.Code, w.Body.String())
|
||||
}
|
||||
var got Page[ArtistRef]
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if got.Total != 3 {
|
||||
t.Errorf("total = %d, want 3", got.Total)
|
||||
}
|
||||
if got.Limit != 50 || got.Offset != 0 {
|
||||
t.Errorf("pagination defaults = limit=%d offset=%d, want 50/0", got.Limit, got.Offset)
|
||||
}
|
||||
if len(got.Items) != 3 {
|
||||
t.Fatalf("items len = %d", len(got.Items))
|
||||
}
|
||||
if got.Items[0].Name != "ABBA" || got.Items[2].Name != "Zeppelin" {
|
||||
t.Errorf("alpha order wrong: %q, %q, %q", got.Items[0].Name, got.Items[1].Name, got.Items[2].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_SortNewest(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
// Seeded in this order; created_at DESC means Third first.
|
||||
seedArtist(t, pool, "First")
|
||||
seedArtist(t, pool, "Second")
|
||||
seedArtist(t, pool, "Third")
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists?sort=newest", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", w.Code)
|
||||
}
|
||||
var got Page[ArtistRef]
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &got)
|
||||
if len(got.Items) != 3 {
|
||||
t.Fatalf("items len = %d", len(got.Items))
|
||||
}
|
||||
if got.Items[0].Name != "Third" || got.Items[2].Name != "First" {
|
||||
t.Errorf("newest order wrong: %q, %q, %q", got.Items[0].Name, got.Items[1].Name, got.Items[2].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_InvalidSort(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
seedArtist(t, pool, "Only")
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists?sort=garbage", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("status = %d, want 400", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_Pagination(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
for _, n := range []string{"A", "B", "C", "D", "E"} {
|
||||
seedArtist(t, pool, n)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists?limit=2&offset=2", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", w.Code)
|
||||
}
|
||||
var got Page[ArtistRef]
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &got)
|
||||
if got.Total != 5 {
|
||||
t.Errorf("total = %d, want 5", got.Total)
|
||||
}
|
||||
if got.Limit != 2 || got.Offset != 2 {
|
||||
t.Errorf("page = limit=%d offset=%d", got.Limit, got.Offset)
|
||||
}
|
||||
if len(got.Items) != 2 {
|
||||
t.Fatalf("items len = %d", len(got.Items))
|
||||
}
|
||||
if got.Items[0].Name != "C" || got.Items[1].Name != "D" {
|
||||
t.Errorf("slice = %q, %q", got.Items[0].Name, got.Items[1].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_LimitClamped(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
seedArtist(t, pool, "One")
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists?limit=9999", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", w.Code)
|
||||
}
|
||||
var got Page[ArtistRef]
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &got)
|
||||
if got.Limit != 200 {
|
||||
t.Errorf("limit = %d, want 200 (max clamp)", got.Limit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_LimitNonNumeric(t *testing.T) {
|
||||
h, _ := testHandlers(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists?limit=abc", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("status = %d, want 400", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_AlbumCount(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
artist := seedArtist(t, pool, "A")
|
||||
seedAlbum(t, pool, artist.ID, "X", 0)
|
||||
seedAlbum(t, pool, artist.ID, "Y", 0)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
var got Page[ArtistRef]
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &got)
|
||||
if len(got.Items) != 1 || got.Items[0].AlbumCount != 2 {
|
||||
t.Errorf("items = %+v", got.Items)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleListArtists_EmptyDB(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/artists", nil)
|
||||
w := httptest.NewRecorder()
|
||||
newLibraryRouter(h).ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", w.Code)
|
||||
}
|
||||
var got Page[ArtistRef]
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &got)
|
||||
if got.Items == nil {
|
||||
t.Error("items = nil, want []")
|
||||
}
|
||||
if got.Total != 0 {
|
||||
t.Errorf("total = %d", got.Total)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user