package fa import ( "context" "fmt" "net/http" "net/http/httptest" "strings" "sync/atomic" "testing" ) // fakeGalleryPage builds a minimal gallery-page response with two figures. // hasNext controls whether the "Next" anchor is included so detectNextPage // flips. func fakeGalleryPage(startID int, hasNext bool) string { var b strings.Builder b.WriteString(``) for i := 0; i < 2; i++ { id := startID + i fmt.Fprintf(&b, `

Sub %d

someartist
`, id, id, id, id, id) } if hasNext { b.WriteString(`Next`) } b.WriteString(``) return b.String() } func TestGalleryPage_HasNextPropagates(t *testing.T) { var requests atomic.Int32 mux := http.NewServeMux() mux.HandleFunc("/gallery/u/", func(w http.ResponseWriter, _ *http.Request) { requests.Add(1) _, _ = w.Write([]byte(fakeGalleryPage(1000, true))) }) mux.HandleFunc("/gallery/u/2/", func(w http.ResponseWriter, _ *http.Request) { requests.Add(1) _, _ = w.Write([]byte(fakeGalleryPage(2000, false))) }) srv := httptest.NewServer(mux) defer srv.Close() client := newE2EClient(t, srv) first, err := client.GalleryPage(context.Background(), "u", 1) if err != nil { t.Fatalf("GalleryPage(1): %v", err) } if first.Page != 1 { t.Errorf("first.Page = %d; want 1", first.Page) } if !first.HasNext { t.Error("first.HasNext = false; want true") } if len(first.Items) != 2 { t.Fatalf("first.Items len = %d; want 2", len(first.Items)) } if first.Items[0].ID != 1000 { t.Errorf("first.Items[0].ID = %d; want 1000", first.Items[0].ID) } // data-tags routed through to the page method too. if len(first.Items[0].Tags) == 0 || len(first.Items[0].CategorizedTags.Species) == 0 { t.Errorf("first.Items[0]: tags not populated from data-tags: %+v", first.Items[0]) } last, err := client.GalleryPage(context.Background(), "u", 2) if err != nil { t.Fatalf("GalleryPage(2): %v", err) } if last.HasNext { t.Error("last.HasNext = true; want false (last page)") } if last.Page != 2 { t.Errorf("last.Page = %d; want 2", last.Page) } if requests.Load() != 2 { t.Errorf("requests = %d; want 2", requests.Load()) } } func TestGalleryPage_ZeroPageDefaultsToOne(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/gallery/u/", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(fakeGalleryPage(1, false))) }) srv := httptest.NewServer(mux) defer srv.Close() client := newE2EClient(t, srv) page, err := client.GalleryPage(context.Background(), "u", 0) if err != nil { t.Fatalf("GalleryPage(0): %v", err) } if page.Page != 1 { t.Errorf("page.Page = %d; want 1 (zero should normalise)", page.Page) } } func TestScrapsPage_HitsScrapsRoute(t *testing.T) { var gotPath string mux := http.NewServeMux() mux.HandleFunc("/scraps/u/", func(w http.ResponseWriter, r *http.Request) { gotPath = r.URL.Path _, _ = w.Write([]byte(fakeGalleryPage(1, false))) }) srv := httptest.NewServer(mux) defer srv.Close() client := newE2EClient(t, srv) if _, err := client.ScrapsPage(context.Background(), "u", 1); err != nil { t.Fatalf("ScrapsPage: %v", err) } if gotPath != "/scraps/u/" { t.Errorf("gotPath = %q; want /scraps/u/", gotPath) } } func TestFavoritesPage_HitsFavoritesRoute(t *testing.T) { var gotPath string mux := http.NewServeMux() mux.HandleFunc("/favorites/u/", func(w http.ResponseWriter, r *http.Request) { gotPath = r.URL.Path _, _ = w.Write([]byte(fakeGalleryPage(1, true))) }) srv := httptest.NewServer(mux) defer srv.Close() client := newE2EClient(t, srv) p, err := client.FavoritesPage(context.Background(), "u", 1) if err != nil { t.Fatalf("FavoritesPage: %v", err) } if gotPath != "/favorites/u/" { t.Errorf("gotPath = %q; want /favorites/u/", gotPath) } if !p.HasNext { t.Error("p.HasNext = false; want true") } }