package router import ( "net/http" "net/http/httptest" "strings" "testing" "github.com/gin-gonic/gin" ) func TestContentPagesOnlyRegisterPathParameterRoutes(t *testing.T) { engine := gin.New() registerRoutes(engine) routes := engine.Routes() registered := make(map[string]bool, len(routes)) handlers := make(map[string]string, len(routes)) for _, route := range routes { key := route.Method + " " + route.Path registered[key] = true handlers[key] = route.Handler } for _, route := range []string{ "GET /detail/:slug", "GET /play/:slug", "GET /play/:slug/:chapterId", "GET /topic", "GET /topic/page/:page", "GET /topic/:slug", "GET /topic/:slug/page/:page", "GET /tag", "GET /tag/page/:page", "GET /tag/:slug", "GET /tag/:slug/page/:page", "GET /series", "GET /series/page/:page", "GET /series/:filter", "GET /series/:filter/page/:page", "GET /category/:slug", "GET /category/:slug/page/:page", "GET /home-road", } { if !registered[route] { t.Fatalf("missing path parameter route %s", route) } } for _, route := range []string{ "POST /api/auth/resetPassword", "POST /api/contactus/add", "GET /api/playlet/chapter/list", "GET /api/playlet/operate/list", "GET /api/playlet/hot-like", "GET /api/app/playlet/hot-like", } { if !registered[route] { t.Fatalf("missing documented API route %s", route) } } for _, route := range []string{"GET /detail", "GET /play"} { if registered[route] { t.Fatalf("legacy query route should not be registered: %s", route) } } for route, handlerSuffix := range map[string]string{ "GET /topic": ".ThemeIndex", "GET /topic/page/:page": ".ThemeIndex", "GET /topic/:slug": ".More", "GET /tag": ".TagList", "GET /tag/:slug": ".TagList", "GET /category/:slug": ".CategoryDetail", } { if !strings.HasSuffix(handlers[route], handlerSuffix) { t.Fatalf("handler for %s = %q, want suffix %q", route, handlers[route], handlerSuffix) } } } func TestLegacyTagListRouteRedirectsToSemanticTagRoute(t *testing.T) { engine := gin.New() registerRoutes(engine) recorder := httptest.NewRecorder() request := httptest.NewRequest(http.MethodGet, "/tag-list/fantasy/page/2", nil) engine.ServeHTTP(recorder, request) if recorder.Code != http.StatusMovedPermanently { t.Fatalf("status = %d, want %d", recorder.Code, http.StatusMovedPermanently) } if location := recorder.Header().Get("Location"); location != "/tag/fantasy/page/2" { t.Fatalf("Location = %q, want %q", location, "/tag/fantasy/page/2") } } func TestLegacyAISeriesListRedirectsToSeriesPage(t *testing.T) { engine := gin.New() registerRoutes(engine) recorder := httptest.NewRecorder() request := httptest.NewRequest(http.MethodGet, "/list/ai-series/1/page/3", nil) engine.ServeHTTP(recorder, request) if recorder.Code != http.StatusMovedPermanently { t.Fatalf("status = %d, want %d", recorder.Code, http.StatusMovedPermanently) } if location := recorder.Header().Get("Location"); location != "/series/popular/page/3" { t.Fatalf("Location = %q, want %q", location, "/series/popular/page/3") } } func TestCrawlerHeadersNoIndexNonHTMLRoutes(t *testing.T) { engine := gin.New() engine.Use(crawlerHeaders()) engine.GET("/healthz", func(c *gin.Context) { c.Status(http.StatusOK) }) recorder := httptest.NewRecorder() request := httptest.NewRequest(http.MethodGet, "/healthz", nil) engine.ServeHTTP(recorder, request) if got := recorder.Header().Get("X-Robots-Tag"); got != "noindex, nofollow" { t.Fatalf("X-Robots-Tag = %q, want noindex, nofollow", got) } } func TestChromeDevToolsDiscoveryReturnsNoContent(t *testing.T) { engine := gin.New() registerBrowserDiscoveryRoutes(engine) recorder := httptest.NewRecorder() request := httptest.NewRequest(http.MethodGet, "/.well-known/appspecific/com.chrome.devtools.json", nil) engine.ServeHTTP(recorder, request) if recorder.Code != http.StatusNoContent { t.Fatalf("status = %d, want %d", recorder.Code, http.StatusNoContent) } if got := recorder.Header().Get("X-Robots-Tag"); got != "noindex, nofollow" { t.Fatalf("X-Robots-Tag = %q, want noindex, nofollow", got) } }