support for parameters, middleware, and route groups.
This commit is contained in:
329
sux_test.go
Normal file
329
sux_test.go
Normal file
@@ -0,0 +1,329 @@
|
||||
package sux
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBasicRouting(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("home"))
|
||||
})
|
||||
|
||||
router.GET("/about", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("about"))
|
||||
})
|
||||
|
||||
// Test home route
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "home" {
|
||||
t.Errorf("Expected body 'home', got '%s'", w.Body.String())
|
||||
}
|
||||
|
||||
// Test about route
|
||||
req = httptest.NewRequest("GET", "/about", nil)
|
||||
w = httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "about" {
|
||||
t.Errorf("Expected body 'about', got '%s'", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestParameterRouting(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
|
||||
params := ParamsFromContext(r)
|
||||
if params == nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
id := params["id"]
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("user " + id))
|
||||
})
|
||||
|
||||
// Test parameter route
|
||||
req := httptest.NewRequest("GET", "/users/123", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "user 123" {
|
||||
t.Errorf("Expected body 'user 123', got '%s'", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestWildcardRouting(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/files/*path", func(w http.ResponseWriter, r *http.Request) {
|
||||
params := ParamsFromContext(r)
|
||||
if params == nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
path := params["path"]
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("file: " + path))
|
||||
})
|
||||
|
||||
// Test wildcard route
|
||||
req := httptest.NewRequest("GET", "/files/docs/readme.txt", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "file: docs/readme.txt" {
|
||||
t.Errorf("Expected body 'file: docs/readme.txt', got '%s'", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMethodNotAllowed(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/resource", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("GET resource"))
|
||||
})
|
||||
|
||||
// Test POST to GET-only route
|
||||
req := httptest.NewRequest("POST", "/resource", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("Expected status 405, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotFound(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/existing", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
// Test non-existent route
|
||||
req := httptest.NewRequest("GET", "/nonexistent", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("Expected status 404, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMiddleware(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
// Add middleware that sets a header
|
||||
router.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Middleware", "applied")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/test", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("test"))
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Header().Get("X-Middleware") != "applied" {
|
||||
t.Errorf("Expected middleware header, got '%s'", w.Header().Get("X-Middleware"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouteGroups(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
// Create API group with middleware
|
||||
api := router.Group("/api", func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-API-Version", "v1")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
})
|
||||
|
||||
api.GET("/users", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("users list"))
|
||||
})
|
||||
|
||||
// Test grouped route
|
||||
req := httptest.NewRequest("GET", "/api/users", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "users list" {
|
||||
t.Errorf("Expected body 'users list', got '%s'", w.Body.String())
|
||||
}
|
||||
if w.Header().Get("X-API-Version") != "v1" {
|
||||
t.Errorf("Expected API version header, got '%s'", w.Header().Get("X-API-Version"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomHandlers(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
// Custom 404 handler
|
||||
router.NotFound(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte("custom 404"))
|
||||
})
|
||||
|
||||
// Custom 405 handler
|
||||
router.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
w.Write([]byte("custom 405"))
|
||||
})
|
||||
|
||||
router.GET("/existing", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
// Test custom 404
|
||||
req := httptest.NewRequest("GET", "/nonexistent", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("Expected status 404, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "custom 404" {
|
||||
t.Errorf("Expected body 'custom 404', got '%s'", w.Body.String())
|
||||
}
|
||||
|
||||
// Test custom 405
|
||||
req = httptest.NewRequest("POST", "/existing", nil)
|
||||
w = httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("Expected status 405, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "custom 405" {
|
||||
t.Errorf("Expected body 'custom 405', got '%s'", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleParameters(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/users/:userId/posts/:postId", func(w http.ResponseWriter, r *http.Request) {
|
||||
params := ParamsFromContext(r)
|
||||
if params == nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
userId := params["userId"]
|
||||
postId := params["postId"]
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("user " + userId + " post " + postId))
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/users/123/posts/456", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
if w.Body.String() != "user 123 post 456" {
|
||||
t.Errorf("Expected body 'user 123 post 456', got '%s'", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestThreadSafety(t *testing.T) {
|
||||
router := New()
|
||||
|
||||
router.GET("/test", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("test"))
|
||||
})
|
||||
|
||||
// Create multiple goroutines to test concurrent access
|
||||
done := make(chan bool, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
for j := 0; j < 100; j++ {
|
||||
req := httptest.NewRequest("GET", "/test", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for all goroutines to complete
|
||||
for i := 0; i < 10; i++ {
|
||||
<-done
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterInstanceIsolation(t *testing.T) {
|
||||
// Create two separate router instances
|
||||
router1 := New()
|
||||
router2 := New()
|
||||
|
||||
router1.GET("/route", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("router1"))
|
||||
})
|
||||
|
||||
router2.GET("/route", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("router2"))
|
||||
})
|
||||
|
||||
// Test router1
|
||||
req := httptest.NewRequest("GET", "/route", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router1.ServeHTTP(w, req)
|
||||
|
||||
if w.Body.String() != "router1" {
|
||||
t.Errorf("Expected body 'router1', got '%s'", w.Body.String())
|
||||
}
|
||||
|
||||
// Test router2
|
||||
w = httptest.NewRecorder()
|
||||
router2.ServeHTTP(w, req)
|
||||
|
||||
if w.Body.String() != "router2" {
|
||||
t.Errorf("Expected body 'router2', got '%s'", w.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user