package ginext import ( "net/http" "net/http/httptest" "testing" "time" "git.blackforestbytes.com/BlackForestBytes/goext/langext" "github.com/gin-gonic/gin" ) func TestNewEngine_DefaultsApplied(t *testing.T) { w := NewEngine(Options{}) if w == nil { t.Fatalf("expected non-nil wrapper") } if w.engine == nil { t.Fatalf("expected gin engine") } if w.allowCors { t.Fatalf("expected allowCors default false") } if w.bufferBody { t.Fatalf("expected bufferBody default false") } if !w.ginDebug { t.Fatalf("expected ginDebug default true") } if w.requestTimeout != 24*time.Hour { t.Fatalf("expected default 24h timeout, got %s", w.requestTimeout) } } func TestNewEngine_OptionsHonored(t *testing.T) { allowCors := true bufferBody := true suppress := true debug := false timeout := 5 * time.Second w := NewEngine(Options{ AllowCors: &allowCors, BufferBody: &bufferBody, SuppressGinLogs: &suppress, GinDebug: &debug, Timeout: &timeout, CorsAllowHeader: &[]string{"X-Custom"}, }) if !w.allowCors { t.Fatalf("allowCors") } if !w.bufferBody { t.Fatalf("bufferBody") } if !w.suppressGinLogs { t.Fatalf("suppressGinLogs") } if w.ginDebug { t.Fatalf("ginDebug should be false") } if w.requestTimeout != timeout { t.Fatalf("timeout mismatch") } if !langext.ArrEqualsExact(w.corsAllowHeader, []string{"X-Custom"}) { t.Fatalf("expected custom allow header") } } func TestNewEngine_BuildRequestBindError_DefaultIsErrorWrapper(t *testing.T) { w := NewEngine(Options{}) if w.buildRequestBindError == nil { t.Fatalf("expected default builder") } resp := w.buildRequestBindError(nil, "URI", http.ErrAbortHandler) if resp == nil { t.Fatalf("expected response") } if resp.IsSuccess() { t.Fatalf("expected error response, not success") } } func TestNewEngine_BuildRequestBindError_Custom(t *testing.T) { called := false custom := func(c *gin.Context, fieldtype string, err error) HTTPResponse { called = true return Status(http.StatusTeapot) } _ = custom // referenced below to avoid unused warning if signature mismatch w := NewEngine(Options{BuildRequestBindError: custom}) resp := w.buildRequestBindError(nil, "URI", http.ErrAbortHandler) if !called { t.Fatalf("expected custom builder to be invoked") } if resp.(InspectableHTTPResponse).Statuscode() != http.StatusTeapot { t.Fatalf("expected 418 from custom builder") } } func TestServeHTTP_RoundTrip(t *testing.T) { w := NewEngine(Options{}) w.Routes().GET("/hello").Handle(func(p PreContext) HTTPResponse { return Text(http.StatusOK, "world") }) req := httptest.NewRequest(http.MethodGet, "/hello", nil) rec := w.ServeHTTP(req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d", rec.Code) } if rec.Body.String() != "world" { t.Fatalf("expected world, got %q", rec.Body.String()) } } func TestForwardRequest(t *testing.T) { w := NewEngine(Options{}) w.Routes().GET("/fwd").Handle(func(p PreContext) HTTPResponse { return Text(http.StatusOK, "ok") }) req := httptest.NewRequest(http.MethodGet, "/fwd", nil) rec := httptest.NewRecorder() w.ForwardRequest(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d", rec.Code) } } func TestListRoutes(t *testing.T) { w := NewEngine(Options{}) w.Routes().GET("/a").Handle(func(p PreContext) HTTPResponse { return Status(200) }) w.Routes().POST("/b").Handle(func(p PreContext) HTTPResponse { return Status(200) }) rs := w.ListRoutes() if len(rs) < 2 { t.Fatalf("expected at least 2 routes, got %d", len(rs)) } } func TestDebugPrintRoutes_NoPanic(t *testing.T) { w := NewEngine(Options{}) w.Routes().GET("/x").Handle(func(p PreContext) HTTPResponse { return Status(200) }) // just verify it doesn't panic w.DebugPrintRoutes() } func TestCleanMiddlewareName(t *testing.T) { w := NewEngine(Options{ DebugTrimHandlerPrefixes: []string{"customprefix."}, DebugReplaceHandlerNames: map[string]string{"BadName": "GoodName"}, }) cases := []struct { in, want string }{ {"ginext.BodyBuffer", "[BodyBuffer]"}, {"foo.(*GinRoutesWrapper).WithJSONFilter", "[JSONFilter]"}, {"ginext.someThing", "someThing"}, {"api.someThing", "someThing"}, {"customprefix.thing", "thing"}, {"BadName", "GoodName"}, {"badname", "GoodName"}, {"some.pkg.Func.func1", "some.pkg.Func"}, {"some.pkg.Func.func1.2", "some.pkg.Func"}, } for _, tc := range cases { if got := w.cleanMiddlewareName(tc.in); got != tc.want { t.Errorf("cleanMiddlewareName(%q) = %q, want %q", tc.in, got, tc.want) } } }