diff --git a/routes_test.go b/routes_test.go index 1cae3fce..2cc39446 100644 --- a/routes_test.go +++ b/routes_test.go @@ -789,3 +789,107 @@ func TestEngineHandleMethodNotAllowedCornerCase(t *testing.T) { w := PerformRequest(r, http.MethodGet, "/base/v1/user/groups") assert.Equal(t, http.StatusNotFound, w.Code) } + +func TestRouterGoogleAIPCustomVerbRoutes(t *testing.T) { + router := New() + + router.POST("/users:batchGet", func(c *Context) { + assert.Equal(t, "/users:batchGet", c.FullPath()) + c.String(http.StatusOK, "batch-get") + }) + router.POST("/users:go", func(c *Context) { + assert.Equal(t, "/users:go", c.FullPath()) + assert.Empty(t, c.Param("go")) + c.String(http.StatusOK, "go") + }) + router.POST("/users:batchCreate", func(c *Context) { + assert.Equal(t, "/users:batchCreate", c.FullPath()) + c.String(http.StatusOK, "batch-create") + }) + + w := PerformRequest(router, http.MethodPost, "/users:batchGet") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "batch-get", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/users:batchCreate") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "batch-create", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/users:go") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "go", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/users:anything") + assert.Equal(t, http.StatusNotFound, w.Code) +} + +func TestRouterGoogleAIPCustomVerbAfterParam(t *testing.T) { + router := New() + + router.POST("/customers/:customer_id", func(c *Context) { + assert.Equal(t, "/customers/:customer_id", c.FullPath()) + assert.Equal(t, "123", c.Param("customer_id")) + c.String(http.StatusOK, "get") + }) + router.POST("/customers/:customer_id:mutate", func(c *Context) { + assert.Equal(t, "/customers/:customer_id:mutate", c.FullPath()) + assert.Equal(t, "123", c.Param("customer_id")) + c.String(http.StatusOK, "mutate") + }) + router.POST("/customers/:customer_id:mutate/static", func(c *Context) { + assert.Equal(t, "/customers/:customer_id:mutate/static", c.FullPath()) + assert.Equal(t, "123", c.Param("customer_id")) + c.String(http.StatusOK, "static") + }) + router.POST("/customers/:customer_id:mutate/:name", func(c *Context) { + assert.Equal(t, "/customers/:customer_id:mutate/:name", c.FullPath()) + assert.Equal(t, "123", c.Param("customer_id")) + c.String(http.StatusOK, c.Param("name")) + }) + router.POST("/customers/:customer_id/devices", func(c *Context) { + assert.Equal(t, "/customers/:customer_id/devices", c.FullPath()) + assert.Equal(t, "123", c.Param("customer_id")) + c.String(http.StatusOK, "devices") + }) + + w := PerformRequest(router, http.MethodPost, "/customers/123") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "get", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/customers/123:mutate") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "mutate", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/customers/123:mutate/static") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "static", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/customers/123:mutate/details") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "details", w.Body.String()) + + w = PerformRequest(router, http.MethodPost, "/customers/123/devices") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "devices", w.Body.String()) +} + +func TestRouterPrefixParamRoutesRemainSupported(t *testing.T) { + router := New() + + router.GET("/id:id", func(c *Context) { + assert.Equal(t, "/id:id", c.FullPath()) + c.String(http.StatusOK, c.Param("id")) + }) + router.GET("/v:version", func(c *Context) { + assert.Equal(t, "/v:version", c.FullPath()) + c.String(http.StatusOK, c.Param("version")) + }) + + w := PerformRequest(router, http.MethodGet, "/id123") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "123", w.Body.String()) + + w = PerformRequest(router, http.MethodGet, "/v1") + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "1", w.Body.String()) +} diff --git a/tree_test.go b/tree_test.go index 23339af4..527b982f 100644 --- a/tree_test.go +++ b/tree_test.go @@ -93,6 +93,18 @@ func TestCountParams(t *testing.T) { if countParams("/path/:param1/static/*catch-all") != 2 { t.Fail() } + if countParams("/users:batchGet") != 0 { + t.Fail() + } + if countParams("/users:go") != 0 { + t.Fail() + } + if countParams("/v:version") != 1 { + t.Fail() + } + if countParams("/customers/:customer_id:mutate") != 1 { + t.Fail() + } if countParams(strings.Repeat("/:param", 256)) != 256 { t.Fail() } @@ -496,8 +508,6 @@ func TestEmptyWildcardName(t *testing.T) { tree := &node{} routes := [...]string{ - "/user:", - "/user:/", "/cmd/:/", "/src/*", } @@ -540,9 +550,9 @@ func TestTreeDoubleWildcard(t *testing.T) { const panicMsg = "only one wildcard per path segment is allowed" routes := [...]string{ - "/:foo:bar", - "/:foo:bar/", "/:foo*bar", + "/:foo*bar:baz", + "/*foo:bar", } for _, route := range routes { @@ -557,6 +567,49 @@ func TestTreeDoubleWildcard(t *testing.T) { } } +func TestTreeCustomVerb(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/user:", + "/user:/", + "/users:batchGet", + "/users:batchCreate", + "/customers/:customer_id", + "/customers/:customer_id:mutate", + } + for _, route := range routes { + tree.addRoute(route, fakeHandler(route)) + } + + checkRequests(t, tree, testRequests{ + {"/user:", false, "/user:", nil}, + {"/user:/", false, "/user:/", nil}, + {"/users:batchGet", false, "/users:batchGet", nil}, + {"/users:batchCreate", false, "/users:batchCreate", nil}, + {"/customers/123", false, "/customers/:customer_id", Params{Param{Key: "customer_id", Value: "123"}}}, + {"/customers/123:mutate", false, "/customers/:customer_id:mutate", Params{Param{Key: "customer_id", Value: "123"}}}, + {"/customers/123:mutatex", false, "/customers/:customer_id", Params{Param{Key: "customer_id", Value: "123:mutatex"}}}, + }) +} + +func TestTreeCustomVerbBeforeBaseParam(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/customers/:customer_id:mutate", + "/customers/:customer_id", + } + for _, route := range routes { + tree.addRoute(route, fakeHandler(route)) + } + + checkRequests(t, tree, testRequests{ + {"/customers/123", false, "/customers/:customer_id", Params{Param{Key: "customer_id", Value: "123"}}}, + {"/customers/123:mutate", false, "/customers/:customer_id:mutate", Params{Param{Key: "customer_id", Value: "123"}}}, + }) +} + /*func TestTreeDuplicateWildcard(t *testing.T) { tree := &node{} routes := [...]string{ @@ -721,6 +774,8 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) { "/hi", "/b/", "/ABC/", + "/users:batchGet", + "/customers/:customer_id:mutate", "/search/:query", "/cmd/:tool/", "/src/*filepath", @@ -798,6 +853,8 @@ func TestTreeFindCaseInsensitivePath(t *testing.T) { {"/aBc/", "/ABC/", true, false}, {"/abC", "/ABC/", true, true}, {"/abC/", "/ABC/", true, false}, + {"/USERS:BATCHGET", "/users:batchGet", true, false}, + {"/USERS:BATCHGET/", "/users:batchGet", true, true}, {"/SEARCH/QUERY", "/search/QUERY", true, false}, {"/SEARCH/QUERY/", "/search/QUERY", true, true}, {"/CMD/TOOL/", "/cmd/TOOL/", true, false}, @@ -949,7 +1006,6 @@ func TestTreeWildcardConflictEx(t *testing.T) { {"/who/are/foo", "/foo", `/who/are/\*you`, `/\*you`}, {"/who/are/foo/", "/foo/", `/who/are/\*you`, `/\*you`}, {"/who/are/foo/bar", "/foo/bar", `/who/are/\*you`, `/\*you`}, - {"/con:nection", ":nection", `/con:tact`, `:tact`}, } for _, conflict := range conflicts {