[🤖] Add Unit-Tests
Build Docker and Deploy / Run goext test-suite (push) Successful in 1m34s

This commit is contained in:
2026-04-27 10:46:08 +02:00
parent dad0e3240d
commit 02d6894ec6
116 changed files with 18795 additions and 1 deletions
+278
View File
@@ -0,0 +1,278 @@
package ginext
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
func TestJoinPaths(t *testing.T) {
cases := []struct {
abs, rel, want string
}{
{"", "", ""},
{"/api", "", "/api"},
{"/api", "users", "/api/users"},
{"/api/", "users", "/api/users"},
{"/api", "/users", "/api/users"},
{"/api/", "/users/", "/api/users/"},
{"/api", "users/", "/api/users/"},
{"", "/users", "/users"},
{"/", "/", "/"},
}
for _, tc := range cases {
got := joinPaths(tc.abs, tc.rel)
if got != tc.want {
t.Errorf("joinPaths(%q,%q)=%q want %q", tc.abs, tc.rel, got, tc.want)
}
}
}
func TestLastChar(t *testing.T) {
if lastChar("hello") != 'o' {
t.Fatalf("expected 'o'")
}
if lastChar("/") != '/' {
t.Fatalf("expected '/'")
}
}
func TestLastChar_PanicsOnEmpty(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatalf("expected panic on empty string")
}
}()
lastChar("")
}
func sampleHandler(_ *gin.Context) {}
func TestNameOfFunction(t *testing.T) {
name := nameOfFunction(sampleHandler)
if name == "" {
t.Fatalf("expected non-empty name")
}
// nameOfFunction strips path prefix, expecting form "ginext.sampleHandler" or similar
if name != "ginext.sampleHandler" {
t.Errorf("expected ginext.sampleHandler, got %q", name)
}
}
type sampleStruct struct{}
func (s sampleStruct) Method(_ *gin.Context) {}
func TestNameOfFunction_StripsFmSuffix(t *testing.T) {
s := sampleStruct{}
// Method values get a "-fm" suffix that nameOfFunction should strip
name := nameOfFunction(s.Method)
if name == "" {
t.Fatalf("expected non-empty name")
}
if got := name; got[len(got)-3:] == "-fm" {
t.Errorf("expected -fm suffix to be stripped, got %q", name)
}
}
func TestRoutes_GroupAndAbsPath(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes()
if rw.absPath != "" {
t.Fatalf("expected empty absPath")
}
g1 := rw.Group("/api")
if g1.absPath != "/api" {
t.Fatalf("expected /api, got %q", g1.absPath)
}
g2 := g1.Group("/v1")
if g2.absPath != "/api/v1" {
t.Fatalf("expected /api/v1, got %q", g2.absPath)
}
}
func TestRoutes_UseAccumulatesMiddleware(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes()
mw1 := func(c *gin.Context) {}
mw2 := func(c *gin.Context) {}
r1 := rw.Use(mw1)
if len(r1.defaultHandler) != 1 {
t.Fatalf("expected 1 handler after Use, got %d", len(r1.defaultHandler))
}
r2 := r1.Use(mw2)
if len(r2.defaultHandler) != 2 {
t.Fatalf("expected 2 handlers, got %d", len(r2.defaultHandler))
}
// Original parent should be unchanged
if len(rw.defaultHandler) != 0 {
t.Fatalf("expected parent to remain unchanged, got %d", len(rw.defaultHandler))
}
}
func TestRoutes_GroupCopiesMiddleware(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes().Use(func(c *gin.Context) {})
g := rw.Group("/x")
if len(g.defaultHandler) != 1 {
t.Fatalf("expected group to inherit middleware")
}
}
func TestRoutes_MethodBuilders(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes()
cases := []struct {
name string
build func(string) *GinRouteBuilder
want string
}{
{"GET", rw.GET, http.MethodGet},
{"POST", rw.POST, http.MethodPost},
{"PUT", rw.PUT, http.MethodPut},
{"PATCH", rw.PATCH, http.MethodPatch},
{"DELETE", rw.DELETE, http.MethodDelete},
{"HEAD", rw.HEAD, http.MethodHead},
{"OPTIONS", rw.OPTIONS, http.MethodOptions},
{"COUNT", rw.COUNT, "COUNT"},
{"Any", rw.Any, "*"},
}
for _, tc := range cases {
b := tc.build("/foo")
if b.method != tc.want {
t.Errorf("%s: expected method %q, got %q", tc.name, tc.want, b.method)
}
if b.relPath != "/foo" {
t.Errorf("%s: expected relPath /foo, got %q", tc.name, b.relPath)
}
}
}
func TestRoutes_RouteBuilderUseAppends(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes()
b := rw.GET("/x")
startCount := len(b.handlers)
b.Use(func(c *gin.Context) {})
if len(b.handlers) != startCount+1 {
t.Fatalf("expected handlers to grow by 1")
}
}
func TestRoutes_RouteBuilderInheritsDefaultHandlers(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes().Use(func(c *gin.Context) {})
b := rw.GET("/x")
if len(b.handlers) != 1 {
t.Fatalf("expected route to inherit default handler")
}
}
func TestRoutes_WithJSONFilter_AddsHandler(t *testing.T) {
w := NewEngine(Options{})
rw := w.Routes().WithJSONFilter("xyz")
if len(rw.defaultHandler) != 1 {
t.Fatalf("expected json filter middleware to be added")
}
// invoke it to verify it sets the key
rec := httptest.NewRecorder()
c, _ := gin.CreateTestContext(rec)
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
rw.defaultHandler[0](c)
if c.GetString(jsonFilterKey) != "xyz" {
t.Fatalf("expected jsonFilterKey to be set to xyz")
}
}
func TestRoutes_RouteBuilderWithJSONFilter(t *testing.T) {
w := NewEngine(Options{})
b := w.Routes().GET("/x").WithJSONFilter("abc")
if len(b.handlers) != 1 {
t.Fatalf("expected handler to be added")
}
}
func TestRoutes_HandleRegistersAndStoresSpec(t *testing.T) {
w := NewEngine(Options{})
w.Routes().GET("/foo").Handle(func(p PreContext) HTTPResponse {
return Status(http.StatusOK)
})
if len(w.routeSpecs) != 1 {
t.Fatalf("expected 1 route spec, got %d", len(w.routeSpecs))
}
spec := w.routeSpecs[0]
if spec.Method != http.MethodGet {
t.Fatalf("expected GET, got %s", spec.Method)
}
if spec.URL != "/foo" {
t.Fatalf("expected /foo, got %s", spec.URL)
}
// Hitting the route should serve our handler
req := httptest.NewRequest(http.MethodGet, "/foo", nil)
rec := w.ServeHTTP(req)
if rec.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", rec.Code)
}
}
func TestRoutes_AnyRegistersAllMethods(t *testing.T) {
w := NewEngine(Options{})
w.Routes().Any("/wild").Handle(func(p PreContext) HTTPResponse {
return Status(http.StatusOK)
})
for _, m := range anyMethods {
req := httptest.NewRequest(m, "/wild", nil)
rec := w.ServeHTTP(req)
if rec.Code != http.StatusOK {
t.Errorf("method %s: expected 200, got %d", m, rec.Code)
}
}
if w.routeSpecs[0].Method != "ANY" {
t.Fatalf("expected method label ANY, got %s", w.routeSpecs[0].Method)
}
}
func TestRoutes_GroupedRoutes(t *testing.T) {
w := NewEngine(Options{})
api := w.Routes().Group("/api")
api.GET("/ping").Handle(func(p PreContext) HTTPResponse {
return Text(http.StatusOK, "pong")
})
req := httptest.NewRequest(http.MethodGet, "/api/ping", nil)
rec := w.ServeHTTP(req)
if rec.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", rec.Code)
}
if rec.Body.String() != "pong" {
t.Fatalf("expected pong, got %q", rec.Body.String())
}
if w.routeSpecs[0].URL != "/api/ping" {
t.Fatalf("expected absPath /api/ping in spec, got %s", w.routeSpecs[0].URL)
}
}
func TestRoutes_NoRoute(t *testing.T) {
w := NewEngine(Options{})
w.NoRoute(func(p PreContext) HTTPResponse {
return Status(http.StatusTeapot)
})
req := httptest.NewRequest(http.MethodGet, "/missing", nil)
rec := w.ServeHTTP(req)
if rec.Code != http.StatusTeapot {
t.Fatalf("expected 418, got %d", rec.Code)
}
if len(w.routeSpecs) != 1 || w.routeSpecs[0].URL != "[NO_ROUTE]" {
t.Fatalf("expected NO_ROUTE spec to be recorded")
}
}