Permalink
package lion | |
import ( | |
"fmt" | |
"net/http" | |
"net/http/httptest" | |
"testing" | |
"github.com/stretchr/testify/assert" | |
"golang.org/x/net/context" | |
) | |
var ( | |
emptyParams = map[string]string{} | |
) | |
func TestRouteMatching(t *testing.T) { | |
helloHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
helloNameHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
helloNameTweetsHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
helloNameGetTweetHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
cartsHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
getCartHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
helloContactHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
helloContactByPersonHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
extensionHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
usernameHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
wildcardHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {}) | |
routes := []struct { | |
Method string | |
Pattern string | |
Handler Handler | |
}{ | |
{ | |
Method: "GET", | |
Pattern: "/hello", | |
Handler: helloHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/hello/contact", | |
Handler: helloContactHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/hello/:name", | |
Handler: helloNameHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/hello/:name/tweets", | |
Handler: helloNameTweetsHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/hello/:name/tweets/:id", | |
Handler: helloNameGetTweetHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/carts", | |
Handler: cartsHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/carts/:cartid", | |
Handler: getCartHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/hello/contact/:dest", | |
Handler: helloContactByPersonHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/extension/:file.:ext", | |
Handler: extensionHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/@:username", | |
Handler: usernameHandler, | |
}, | |
{ | |
Method: "GET", | |
Pattern: "/*", | |
Handler: wildcardHandler, | |
}, | |
} | |
tests := []struct { | |
Input string | |
ExpectedHandler Handler | |
ExpectedParams map[string]string | |
}{ | |
{ | |
Input: "/hello", | |
ExpectedHandler: helloHandler, | |
ExpectedParams: emptyParams, | |
}, | |
{ | |
Input: "/hello/batman", | |
ExpectedHandler: helloNameHandler, | |
ExpectedParams: map[string]string{"name": "batman"}, | |
}, | |
{ | |
Input: "/hello/dot.inthemiddle", | |
ExpectedHandler: helloNameHandler, | |
ExpectedParams: map[string]string{"name": "dot.inthemiddle"}, | |
}, | |
{ | |
Input: "/hello/batman/tweets", | |
ExpectedHandler: helloNameTweetsHandler, | |
ExpectedParams: map[string]string{"name": "batman"}, | |
}, | |
{ | |
Input: "/hello/batman/tweets/123", | |
ExpectedHandler: helloNameGetTweetHandler, | |
ExpectedParams: map[string]string{"name": "batman", "id": "123"}, | |
}, | |
{ | |
Input: "/carts", | |
ExpectedHandler: cartsHandler, | |
ExpectedParams: emptyParams, | |
}, | |
{ | |
Input: "/carts/123456", | |
ExpectedHandler: getCartHandler, | |
ExpectedParams: map[string]string{"cartid": "123456"}, | |
}, | |
{ | |
Input: "/hello/contact", | |
ExpectedHandler: helloContactHandler, | |
ExpectedParams: emptyParams, | |
}, | |
{ | |
Input: "/hello/contact/batman", | |
ExpectedHandler: helloContactByPersonHandler, | |
ExpectedParams: map[string]string{"dest": "batman"}, | |
}, | |
{ | |
Input: "/extension/batman.jpg", | |
ExpectedHandler: extensionHandler, | |
ExpectedParams: map[string]string{"file": "batman", "ext": "jpg"}, | |
}, | |
{ | |
Input: "/@celrenheit", | |
ExpectedHandler: usernameHandler, | |
ExpectedParams: map[string]string{"username": "celrenheit"}, | |
}, | |
{ | |
Input: "/unkownpath/subfolder", | |
ExpectedHandler: wildcardHandler, | |
ExpectedParams: map[string]string{"*": "unkownpath/subfolder"}, | |
}, | |
} | |
mux := New() | |
for _, r := range routes { | |
mux.Handle(r.Method, r.Pattern, r.Handler) | |
} | |
for _, test := range tests { | |
req, _ := http.NewRequest("GET", test.Input, nil) | |
c, h := mux.rm.Match(&Context{ | |
parent: context.TODO(), | |
}, req) | |
// Compare params | |
for k, v := range test.ExpectedParams { | |
assert.NotNil(t, c.Value(k)) | |
actual := c.Value(k).(string) | |
if actual != v { | |
t.Errorf("Expected %s but got %s for url: %s", green(v), red(actual), test.Input) | |
} | |
} | |
// Compare handlers | |
if fmt.Sprintf("%v", h) != fmt.Sprintf("%v", test.ExpectedHandler) { | |
t.Errorf("Handler not match for %s", test.Input) | |
} | |
w := httptest.NewRecorder() | |
mux.ServeHTTP(w, req) | |
// Compare response code | |
if w.Code != http.StatusOK { | |
t.Errorf("Response should be 200 OK for %s", test.Input) | |
} | |
} | |
} | |
type testmw struct{} | |
func (m testmw) ServeNext(next Handler) Handler { | |
return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Test-Key", "Test-Value") | |
next.ServeHTTPC(c, w, r) | |
}) | |
} | |
func TestMiddleware(t *testing.T) { | |
mux := New() | |
mux.Use(testmw{}) | |
mux.Get("/hi", HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("Hi!")) | |
})) | |
expectHeader(t, mux, "GET", "/hi", "Test-Key", "Test-Value") | |
} | |
func TestMiddlewareFunc(t *testing.T) { | |
mux := New() | |
mux.UseFunc(func(next Handler) Handler { | |
return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Test-Key", "Test-Value") | |
next.ServeHTTPC(c, w, r) | |
}) | |
}) | |
mux.Get("/hi", HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("Hi!")) | |
})) | |
expectHeader(t, mux, "GET", "/hi", "Test-Key", "Test-Value") | |
} | |
func TestMiddlewareChain(t *testing.T) { | |
mux := New() | |
mux.UseFunc(func(next Handler) Handler { | |
return nil | |
}) | |
} | |
func TestMountingSubrouter(t *testing.T) { | |
mux := New() | |
adminrouter := New() | |
adminrouter.GetFunc("/:id", func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("admin", "id") | |
}) | |
mux.Mount("/admin", adminrouter) | |
expectHeader(t, mux, "GET", "/admin/123", "admin", "id") | |
} | |
func TestGroupSubGroup(t *testing.T) { | |
s := New() | |
admin := s.Group("/admin") | |
sub := admin.Group("/") | |
sub.UseFunc(func(next Handler) Handler { | |
return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Test-Key", "Get") | |
next.ServeHTTPC(c, w, r) | |
}) | |
}) | |
sub.GetFunc("/", func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("Get")) | |
}) | |
sub2 := admin.Group("/") | |
sub2.UseFunc(func(next Handler) Handler { | |
return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Test-Key", "Put") | |
next.ServeHTTPC(c, w, r) | |
}) | |
}) | |
sub2.PutFunc("/", func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("Put")) | |
}) | |
expectHeader(t, s, "GET", "/admin", "Test-Key", "Get") | |
expectHeader(t, s, "PUT", "/admin", "Test-Key", "Put") | |
} | |
func TestNamedMiddlewares(t *testing.T) { | |
l := New() | |
l.DefineFunc("admin", func(next Handler) Handler { | |
return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Test-Key", "admin") | |
next.ServeHTTPC(c, w, r) | |
}) | |
}) | |
l.DefineFunc("public", func(next Handler) Handler { | |
return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Test-Key", "public") | |
next.ServeHTTPC(c, w, r) | |
}) | |
}) | |
g := l.Group("/admin") | |
g.UseNamed("admin") | |
g.GetFunc("/test", func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("admintest")) | |
}) | |
p := l.Group("/public") | |
p.UseNamed("public") | |
p.GetFunc("/test", func(c context.Context, w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("publictest")) | |
}) | |
expectHeader(t, l, "GET", "/admin/test", "Test-Key", "admin") | |
expectHeader(t, l, "GET", "/public/test", "Test-Key", "public") | |
expectBody(t, l, "GET", "/admin/test", "admintest") | |
expectBody(t, l, "GET", "/public/test", "publictest") | |
} | |
func TestEmptyRouter(t *testing.T) { | |
l := New() | |
expectStatus(t, l, "GET", "/", http.StatusNotFound) | |
} | |
func expectStatus(t *testing.T, mux http.Handler, method, path string, status int) { | |
req, _ := http.NewRequest(method, path, nil) | |
w := httptest.NewRecorder() | |
mux.ServeHTTP(w, req) | |
if w.Code != status { | |
t.Errorf("Expected status code to be %d but got %d for request: %s %s", status, w.Code, method, path) | |
} | |
} | |
func expectHeader(t *testing.T, mux http.Handler, method, path, k, v string) { | |
req, _ := http.NewRequest(method, path, nil) | |
w := httptest.NewRecorder() | |
mux.ServeHTTP(w, req) | |
if w.Header().Get(k) != v { | |
t.Errorf("Expected header to be %s but got %s for request: %s %s", v, w.Header().Get(k), method, path) | |
} | |
} | |
func expectBody(t *testing.T, mux http.Handler, method, path, v string) { | |
req, _ := http.NewRequest(method, path, nil) | |
w := httptest.NewRecorder() | |
mux.ServeHTTP(w, req) | |
if w.Body.String() != v { | |
t.Errorf("Expected body to be %s but got %s for request: %s %s", v, w.Body.String(), method, path) | |
} | |
} |