Files
xlgo-core/router/router_test.go
T
2026-07-08 12:05:26 +08:00

460 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package router_test
import (
"net/http/httptest"
"testing"
"github.com/EthanCodeCraft/xlgo-core/router"
"github.com/gin-gonic/gin"
)
func setupTestRouter() *gin.Engine {
gin.SetMode(gin.TestMode)
return gin.New()
}
func TestNewRegistry(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
if registry == nil {
t.Error("NewRegistry should not return nil")
}
}
func TestRegistryUse(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
result := registry.Use(func(c *gin.Context) { c.Next() })
if result == nil {
t.Error("Use should return registry for chaining")
}
}
func TestRegisterModule(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
module := &testModule{name: "test"}
result := registry.RegisterModule(module)
if result == nil {
t.Error("RegisterModule should return registry for chaining")
}
}
func TestRegisterModuleFunc(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
result := registry.RegisterModuleFunc("test", func(r *gin.RouterGroup) {
r.GET("/test", func(c *gin.Context) { c.JSON(200, gin.H{}) })
})
if result == nil {
t.Error("RegisterModuleFunc should return registry for chaining")
}
}
func TestNewVersion(t *testing.T) {
v := router.NewVersion("v1", "/api/v1")
if v.Version != "v1" {
t.Errorf("Version = %s, want v1", v.Version)
}
if v.BasePath != "/api/v1" {
t.Errorf("BasePath = %s, want /api/v1", v.BasePath)
}
}
func TestVersionAddModule(t *testing.T) {
v := router.NewVersion("v1", "/api/v1")
module := &testModule{name: "user"}
result := v.AddModule(module)
if result == nil {
t.Error("AddModule should return VersionedAPI for chaining")
}
}
func TestVersionAddModuleFunc(t *testing.T) {
v := router.NewVersion("v1", "/api/v1")
result := v.AddModuleFunc("user", func(r *gin.RouterGroup) {
r.GET("/users", func(c *gin.Context) {})
})
if result == nil {
t.Error("AddModuleFunc should return VersionedAPI for chaining")
}
}
func TestRegisterVersion(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
v := router.NewVersion("v1", "/api/v1")
result := registry.RegisterVersion(v)
if result == nil {
t.Error("RegisterVersion should return registry for chaining")
}
}
func TestNewMiddlewareGroup(t *testing.T) {
group := router.NewMiddlewareGroup("auth", func(c *gin.Context) { c.Next() })
if group.Name != "auth" {
t.Errorf("Name = %s, want auth", group.Name)
}
if len(group.Middlewares) != 1 {
t.Errorf("Middlewares length = %d, want 1", len(group.Middlewares))
}
}
func TestRegisterMiddlewareGroup(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
group := router.NewMiddlewareGroup("auth")
result := registry.RegisterMiddlewareGroup(group)
if result == nil {
t.Error("RegisterMiddlewareGroup should return registry for chaining")
}
}
func TestGetMiddlewareGroup(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
middleware := func(c *gin.Context) { c.Next() }
group := router.NewMiddlewareGroup("auth", middleware)
registry.RegisterMiddlewareGroup(group)
mws := registry.GetMiddlewareGroup("auth")
if len(mws) != 1 {
t.Errorf("GetMiddlewareGroup length = %d, want 1", len(mws))
}
// 不存在的分组
mws2 := registry.GetMiddlewareGroup("nonexistent")
if mws2 != nil {
t.Error("GetMiddlewareGroup nonexistent should return nil")
}
}
func TestApply(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
registry.RegisterModuleFunc("test", func(r *gin.RouterGroup) {
r.GET("/hello", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "hello"})
})
})
registry.Apply()
// 测试路由是否生效
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/hello", nil)
engine.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("Apply route status = %d, want 200", w.Code)
}
}
func TestApplyWithVersion(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
v1 := router.NewVersion("v1", "/api/v1")
v1.AddModuleFunc("user", func(r *gin.RouterGroup) {
r.GET("/users", func(c *gin.Context) {
c.JSON(200, gin.H{"version": "v1"})
})
})
registry.RegisterVersion(v1)
registry.Apply()
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/v1/users", nil)
engine.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("Versioned route status = %d, want 200", w.Code)
}
}
func TestApplyWithMiddleware(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
// 全局中间件
registry.Use(func(c *gin.Context) {
c.Set("global", true)
c.Next()
})
registry.RegisterModuleFunc("test", func(r *gin.RouterGroup) {
r.GET("/test", func(c *gin.Context) {
val, _ := c.Get("global")
c.JSON(200, gin.H{"global": val})
})
})
registry.Apply()
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/test", nil)
engine.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("Middleware route status = %d", w.Code)
}
}
func TestVersionMiddleware(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
v1 := router.NewVersion("v1", "/api/v1", func(c *gin.Context) {
c.Set("version", "v1")
c.Next()
})
v1.AddModuleFunc("user", func(r *gin.RouterGroup) {
r.GET("/users", func(c *gin.Context) {
val, _ := c.Get("version")
c.JSON(200, gin.H{"version": val})
})
})
registry.RegisterVersion(v1)
registry.Apply()
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/v1/users", nil)
engine.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("Version middleware route status = %d", w.Code)
}
}
func TestMultipleVersions(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
v1 := router.NewVersion("v1", "/api/v1")
v1.AddModuleFunc("user", func(r *gin.RouterGroup) {
r.GET("/users", func(c *gin.Context) { c.JSON(200, gin.H{"version": "v1"}) })
})
v2 := router.NewVersion("v2", "/api/v2")
v2.AddModuleFunc("user", func(r *gin.RouterGroup) {
r.GET("/users", func(c *gin.Context) { c.JSON(200, gin.H{"version": "v2"}) })
})
registry.RegisterVersion(v1)
registry.RegisterVersion(v2)
registry.Apply()
// 测试 v1
w1 := httptest.NewRecorder()
req1 := httptest.NewRequest("GET", "/api/v1/users", nil)
engine.ServeHTTP(w1, req1)
// 测试 v2
w2 := httptest.NewRecorder()
req2 := httptest.NewRequest("GET", "/api/v2/users", nil)
engine.ServeHTTP(w2, req2)
if w1.Code != 200 || w2.Code != 200 {
t.Error("Multiple versions should both work")
}
}
func TestInitAndGetRegistry(t *testing.T) {
engine := setupTestRouter()
registry := router.Init(engine)
if registry == nil {
t.Error("Init should return registry")
}
registry2 := router.GetRegistry()
if registry2 != registry {
t.Error("GetRegistry should return same registry")
}
}
func TestGlobalFunctions(t *testing.T) {
engine := setupTestRouter()
router.Init(engine)
router.Use(func(c *gin.Context) { c.Next() })
router.RegisterModule(&testModule{name: "test"})
router.RegisterVersion(router.NewVersion("v1", "/api/v1"))
registry := router.GetRegistry()
if registry == nil {
t.Error("Global functions should work")
}
}
func TestGlobalApply(t *testing.T) {
engine := setupTestRouter()
router.Init(engine)
router.RegisterModuleFunc("hello", func(r *gin.RouterGroup) {
r.GET("/hello", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "hello"})
})
})
router.Apply()
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/hello", nil)
engine.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("Global Apply status = %d, want 200", w.Code)
}
}
func TestModuleFunc(t *testing.T) {
var mf router.ModuleFunc = func(r *gin.RouterGroup) {
r.GET("/test", func(c *gin.Context) {})
}
// 验证实现了 Module 接口
var _ router.Module = mf
}
func TestRESTfulRoute(t *testing.T) {
engine := setupTestRouter()
group := engine.Group("/api")
rest := router.NewRESTful(group, "/users")
rest.GET(func(c *gin.Context) { c.JSON(200, gin.H{}) })
rest.POST(func(c *gin.Context) { c.JSON(201, gin.H{}) })
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/users", nil)
engine.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("RESTful GET status = %d", w.Code)
}
}
func TestRESTfulCRUD(t *testing.T) {
engine := setupTestRouter()
group := engine.Group("/api")
rest := router.NewRESTful(group, "/items")
rest.CRUD(
func(c *gin.Context) { c.JSON(200, gin.H{"action": "list"}) },
func(c *gin.Context) { c.JSON(200, gin.H{"action": "detail"}) },
func(c *gin.Context) { c.JSON(201, gin.H{"action": "create"}) },
func(c *gin.Context) { c.JSON(200, gin.H{"action": "update"}) },
func(c *gin.Context) { c.JSON(204, gin.H{}) },
)
tests := []struct {
method string
path string
code int
}{
{"GET", "/api/items", 200},
{"GET", "/api/items/1", 200},
{"POST", "/api/items", 201},
{"PUT", "/api/items/1", 200},
{"DELETE", "/api/items/1", 204},
}
for _, tt := range tests {
w := httptest.NewRecorder()
req := httptest.NewRequest(tt.method, tt.path, nil)
engine.ServeHTTP(w, req)
if w.Code != tt.code {
t.Errorf("%s %s status = %d, want %d", tt.method, tt.path, w.Code, tt.code)
}
}
}
func TestRESTfulPartialCRUD(t *testing.T) {
engine := setupTestRouter()
group := engine.Group("/api")
rest := router.NewRESTful(group, "/items")
// 只注册 list 和 create
rest.CRUD(
func(c *gin.Context) { c.JSON(200, gin.H{}) }, // list
nil, // no detail
func(c *gin.Context) { c.JSON(201, gin.H{}) }, // create
nil, // no update
nil, // no delete
)
// list 存在
w1 := httptest.NewRecorder()
req1 := httptest.NewRequest("GET", "/api/items", nil)
engine.ServeHTTP(w1, req1)
if w1.Code != 200 {
t.Error("Partial CRUD list should work")
}
// detail 不存在(404
w2 := httptest.NewRecorder()
req2 := httptest.NewRequest("GET", "/api/items/1", nil)
engine.ServeHTTP(w2, req2)
if w2.Code != 404 {
t.Errorf("Partial CRUD detail should be 404, got %d", w2.Code)
}
}
func TestGroup(t *testing.T) {
engine := setupTestRouter()
group := router.Group(engine, "/api", func(c *gin.Context) { c.Next() })
if group == nil {
t.Error("Group should not return nil")
}
}
func TestGroupWithMiddlewareGroup(t *testing.T) {
engine := setupTestRouter()
registry := router.NewRegistry(engine)
registry.RegisterMiddlewareGroup(router.NewMiddlewareGroup("auth", func(c *gin.Context) { c.Next() }))
group := registry.GroupWithMiddlewareGroup(engine, "/api", "auth")
if group == nil {
t.Error("GroupWithMiddlewareGroup should not return nil")
}
}
func TestModuleInterface(t *testing.T) {
module := &testModule{name: "test"}
// 测试 Name 方法
if module.Name() != "test" {
t.Error("Module Name failed")
}
// 测试实现了接口
var _ router.Module = module
}
// 测试模块实现
type testModule struct {
name string
}
func (m *testModule) Name() string { return m.name }
func (m *testModule) Register(r *gin.RouterGroup) {
r.GET("/"+m.name, func(c *gin.Context) { c.JSON(200, gin.H{"module": m.name}) })
}