package server_test import ( "io" "net/http" "net/http/httptest" "testing" "git.codelab.vc/pkg/httpx/server" ) func TestRouter(t *testing.T) { t.Run("basic route", func(t *testing.T) { r := server.NewRouter() r.HandleFunc("GET /hello", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("world")) }) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/hello", nil) r.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("got status %d, want %d", w.Code, http.StatusOK) } if body := w.Body.String(); body != "world" { t.Fatalf("got body %q, want %q", body, "world") } }) t.Run("Handle with http.Handler", func(t *testing.T) { r := server.NewRouter() r.Handle("GET /ping", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("pong")) })) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/ping", nil) r.ServeHTTP(w, req) if body := w.Body.String(); body != "pong" { t.Fatalf("got body %q, want %q", body, "pong") } }) t.Run("path parameter", func(t *testing.T) { r := server.NewRouter() r.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, req *http.Request) { _, _ = w.Write([]byte("user:" + req.PathValue("id"))) }) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/users/42", nil) r.ServeHTTP(w, req) if body := w.Body.String(); body != "user:42" { t.Fatalf("got body %q, want %q", body, "user:42") } }) } func TestRouterGroup(t *testing.T) { t.Run("prefix is applied", func(t *testing.T) { r := server.NewRouter() api := r.Group("/api/v1") api.HandleFunc("GET /users", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("users")) }) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/users", nil) r.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("got status %d, want %d", w.Code, http.StatusOK) } if body := w.Body.String(); body != "users" { t.Fatalf("got body %q, want %q", body, "users") } }) t.Run("nested groups", func(t *testing.T) { r := server.NewRouter() api := r.Group("/api") v1 := api.Group("/v1") v1.HandleFunc("GET /items", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("items")) }) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/items", nil) r.ServeHTTP(w, req) if body := w.Body.String(); body != "items" { t.Fatalf("got body %q, want %q", body, "items") } }) t.Run("group middleware", func(t *testing.T) { var mwCalled bool mw := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mwCalled = true next.ServeHTTP(w, r) }) } r := server.NewRouter() g := r.Group("/admin", mw) g.HandleFunc("GET /dashboard", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("ok")) }) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/admin/dashboard", nil) r.ServeHTTP(w, req) if !mwCalled { t.Fatal("group middleware was not called") } }) } func TestRouterMount(t *testing.T) { t.Run("mounts sub-handler with prefix stripping", func(t *testing.T) { sub := http.NewServeMux() sub.HandleFunc("GET /info", func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("info")) }) r := server.NewRouter() r.Mount("/sub", sub) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/sub/info", nil) r.ServeHTTP(w, req) body, _ := io.ReadAll(w.Body) if string(body) != "info" { t.Fatalf("got body %q, want %q", body, "info") } }) }