Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,86 @@ func TestIsValider(t *testing.T) {
})
require.NoError(t, err)
}

// TestFilterFlags tests the filterFlags function
func TestFilterFlags(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "no flags",
input: "application/json",
expected: "application/json",
},
{
name: "with space",
input: "application/json charset=utf-8",
expected: "application/json",
},
{
name: "with semicolon",
input: "application/json; charset=utf-8",
expected: "application/json",
},
{
name: "space at start",
input: " application/json",
expected: "",
},
{
name: "empty string",
input: "",
expected: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := filterFlags(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}

// TestQueryBinding_Name tests queryBinding Name method
func TestQueryBinding_Name(t *testing.T) {
qb := queryBinding{}
assert.Equal(t, "query", qb.Name())
}

// TestQueryBinding_Bind tests queryBinding Bind method
func TestQueryBinding_Bind(t *testing.T) {
type QueryArgs struct {
Page int `query:"page"`
PageSize int `query:"page_size"`
Keyword string `query:"keyword"`
}

t.Run("successful binding", func(t *testing.T) {
req, _ := http.NewRequest(http.MethodGet, "/?page=1&page_size=20&keyword=test", nil)

var args QueryArgs
qb := queryBinding{}
err := qb.Bind(req, &args)

require.NoError(t, err)
assert.Equal(t, 1, args.Page)
assert.Equal(t, 20, args.PageSize)
assert.Equal(t, "test", args.Keyword)
})

t.Run("binding without keyword", func(t *testing.T) {
req, _ := http.NewRequest(http.MethodGet, "/?page=1&page_size=20", nil)

var args QueryArgs
qb := queryBinding{}
err := qb.Bind(req, &args)

require.NoError(t, err)
assert.Equal(t, 1, args.Page)
assert.Equal(t, 20, args.PageSize)
assert.Empty(t, args.Keyword)
})
}
148 changes: 148 additions & 0 deletions engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package fox_test
import (
"bytes"
"context"
"embed"
"encoding/json"
"errors"
"net/http"
Expand Down Expand Up @@ -384,3 +385,150 @@ func TestDefaultEnableContextWithFallback(t *testing.T) {
assert.Equal("no context value", w.Body.String())
})
}

// TestEngine_NotFound tests custom 404 handler
func TestEngine_NotFound(t *testing.T) {
router := fox.New()

router.NotFound(func(c *fox.Context) {
c.JSON(404, map[string]string{
"error": "custom not found",
})
})

router.GET("/exists", func() string {
return "exists"
})

t.Run("existing route", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/exists", nil)
router.ServeHTTP(w, req)

assert.Equal(t, 200, w.Code)
assert.Equal(t, "exists", w.Body.String())
})

t.Run("not found route", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/not-exists", nil)
router.ServeHTTP(w, req)

assert.Equal(t, 404, w.Code)
assert.JSONEq(t, `{"error":"custom not found"}`, w.Body.String())
})
}

// TestEngine_NoRoute tests NoRoute handler
func TestEngine_NoRoute(t *testing.T) {
router := fox.New()

router.NoRoute(func(c *fox.Context) {
c.JSON(404, map[string]string{
"message": "route not found",
})
})

w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/undefined", nil)
router.ServeHTTP(w, req)

assert.Equal(t, 404, w.Code)
assert.JSONEq(t, `{"message":"route not found"}`, w.Body.String())
}

// TestEngine_NoMethod tests NoMethod handler
func TestEngine_NoMethod(t *testing.T) {
router := fox.New()
router.HandleMethodNotAllowed = true

router.NoMethod(func(c *fox.Context) {
c.JSON(405, map[string]string{
"error": "method not allowed",
})
})

router.GET("/test", func() string {
return "get"
})

t.Run("allowed method", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
router.ServeHTTP(w, req)

assert.Equal(t, 200, w.Code)
assert.Equal(t, "get", w.Body.String())
})

t.Run("not allowed method", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/test", nil)
router.ServeHTTP(w, req)

assert.Equal(t, 405, w.Code)
assert.JSONEq(t, `{"error":"method not allowed"}`, w.Body.String())
})
}

// TestEngine_Load tests Load router config func
func TestEngine_Load(t *testing.T) {
router := fox.New()

configFunc := func(r *fox.Engine, embedFS ...embed.FS) {
r.GET("/loaded", func() string {
return "loaded"
})
}

router.Load(configFunc)

w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/loaded", nil)
router.ServeHTTP(w, req)

assert.Equal(t, 200, w.Code)
assert.Equal(t, "loaded", w.Body.String())
}

// TestHandlersChain_Last tests Last() method with edge cases
func TestHandlersChain_Last(t *testing.T) {
tests := []struct {
name string
chain fox.HandlersChain
expected fox.HandlerFunc
}{
{
name: "empty chain",
chain: fox.HandlersChain{},
expected: nil,
},
{
name: "single handler",
chain: fox.HandlersChain{
func() string { return "first" },
},
expected: func() string { return "first" },
},
{
name: "multiple handlers",
chain: fox.HandlersChain{
func() string { return "first" },
func() string { return "second" },
func() string { return "third" },
},
expected: func() string { return "third" },
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.chain.Last()
if tt.expected == nil {
assert.Nil(t, result)
} else {
assert.NotNil(t, result)
}
})
}
}
63 changes: 63 additions & 0 deletions routergroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,66 @@ func TestRouterGroup_Use(t *testing.T) {
assert.Equal("context value", w.Body.String())
})
}

// TestHTTPMethods tests all HTTP method shortcuts
func TestHTTPMethods(t *testing.T) {
router := fox.New()

// Test DELETE
router.DELETE("/delete", func() string {
return "deleted"
})

// Test PUT
router.PUT("/put", func() string {
return "updated"
})

// Test PATCH
router.PATCH("/patch", func() string {
return "patched"
})

// Test OPTIONS
router.OPTIONS("/options", func() string {
return "options"
})

// Test HEAD
router.HEAD("/head", func() {})

// Test Any
router.Any("/any", func() string {
return "any method"
})

tests := []struct {
name string
method string
path string
expectedStatus int
expectedBody string
}{
{"DELETE method", http.MethodDelete, "/delete", 200, "deleted"},
{"PUT method", http.MethodPut, "/put", 200, "updated"},
{"PATCH method", http.MethodPatch, "/patch", 200, "patched"},
{"OPTIONS method", http.MethodOptions, "/options", 200, "options"},
{"HEAD method", http.MethodHead, "/head", 200, ""},
{"Any - GET", http.MethodGet, "/any", 200, "any method"},
{"Any - POST", http.MethodPost, "/any", 200, "any method"},
{"Any - PUT", http.MethodPut, "/any", 200, "any method"},
{"Any - DELETE", http.MethodDelete, "/any", 200, "any method"},
{"Any - PATCH", http.MethodPatch, "/any", 200, "any method"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(tt.method, tt.path, nil)
router.ServeHTTP(w, req)

assert.Equal(t, tt.expectedStatus, w.Code)
assert.Equal(t, tt.expectedBody, w.Body.String())
})
}
}
Loading