This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user