diff --git a/gin_test.go b/gin_test.go index be076537..cee1f3cc 100644 --- a/gin_test.go +++ b/gin_test.go @@ -913,3 +913,102 @@ func TestMethodNotAllowedNoRoute(t *testing.T) { assert.NotPanics(t, func() { g.ServeHTTP(resp, req) }) assert.Equal(t, http.StatusNotFound, resp.Code) } + +// Test the fix for https://github.com/gin-gonic/gin/pull/4415 +func TestLiteralColonWithRun(t *testing.T) { + SetMode(TestMode) + router := New() + + router.GET(`/test\:action`, func(c *Context) { + c.JSON(http.StatusOK, H{"path": "literal_colon"}) + }) + + router.updateRouteTrees() + + w := httptest.NewRecorder() + + req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Contains(t, w.Body.String(), "literal_colon") +} + +func TestLiteralColonWithDirectServeHTTP(t *testing.T) { + SetMode(TestMode) + router := New() + + router.GET(`/test\:action`, func(c *Context) { + c.JSON(http.StatusOK, H{"path": "literal_colon"}) + }) + + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Contains(t, w.Body.String(), "literal_colon") +} + +func TestLiteralColonWithHandler(t *testing.T) { + SetMode(TestMode) + router := New() + + router.GET(`/test\:action`, func(c *Context) { + c.JSON(http.StatusOK, H{"path": "literal_colon"}) + }) + + handler := router.Handler() + + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) + handler.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Contains(t, w.Body.String(), "literal_colon") +} + +func TestLiteralColonWithHTTPServer(t *testing.T) { + SetMode(TestMode) + router := New() + + router.GET(`/test\:action`, func(c *Context) { + c.JSON(http.StatusOK, H{"path": "literal_colon"}) + }) + + router.GET("/test/:param", func(c *Context) { + c.JSON(http.StatusOK, H{"param": c.Param("param")}) + }) + + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Contains(t, w.Body.String(), "literal_colon") + + w2 := httptest.NewRecorder() + req2, _ := http.NewRequest(http.MethodGet, "/test/foo", nil) + router.ServeHTTP(w2, req2) + + assert.Equal(t, http.StatusOK, w2.Code) + assert.Contains(t, w2.Body.String(), "foo") +} + +// Test that updateRouteTrees is called only once +func TestUpdateRouteTreesCalledOnce(t *testing.T) { + SetMode(TestMode) + router := New() + + router.GET(`/test\:action`, func(c *Context) { + c.String(http.StatusOK, "ok") + }) + + for range 5 { + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) + router.ServeHTTP(w, req) + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "ok", w.Body.String()) + } +} diff --git a/literal_colon_test.go b/literal_colon_test.go deleted file mode 100644 index f6cfba28..00000000 --- a/literal_colon_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package gin - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLiteralColonWithRun(t *testing.T) { - SetMode(TestMode) - router := New() - - router.GET(`/test\:action`, func(c *Context) { - c.JSON(http.StatusOK, H{"path": "literal_colon"}) - }) - - router.updateRouteTrees() - - w := httptest.NewRecorder() - - req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, w.Body.String(), "literal_colon") -} - -func TestLiteralColonWithDirectServeHTTP(t *testing.T) { - SetMode(TestMode) - router := New() - - router.GET(`/test\:action`, func(c *Context) { - c.JSON(http.StatusOK, H{"path": "literal_colon"}) - }) - - w := httptest.NewRecorder() - req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, w.Body.String(), "literal_colon") -} - -func TestLiteralColonWithHandler(t *testing.T) { - SetMode(TestMode) - router := New() - - router.GET(`/test\:action`, func(c *Context) { - c.JSON(http.StatusOK, H{"path": "literal_colon"}) - }) - - handler := router.Handler() - - w := httptest.NewRecorder() - req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) - handler.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, w.Body.String(), "literal_colon") -} - -func TestLiteralColonWithHTTPServer(t *testing.T) { - SetMode(TestMode) - router := New() - - router.GET(`/test\:action`, func(c *Context) { - c.JSON(http.StatusOK, H{"path": "literal_colon"}) - }) - - router.GET("/test/:param", func(c *Context) { - c.JSON(http.StatusOK, H{"param": c.Param("param")}) - }) - - w := httptest.NewRecorder() - req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, w.Body.String(), "literal_colon") - - w2 := httptest.NewRecorder() - req2, _ := http.NewRequest(http.MethodGet, "/test/foo", nil) - router.ServeHTTP(w2, req2) - - assert.Equal(t, http.StatusOK, w2.Code) - assert.Contains(t, w2.Body.String(), "foo") -} - -// Test that updateRouteTrees is called only once -func TestUpdateRouteTreesCalledOnce(t *testing.T) { - SetMode(TestMode) - router := New() - - router.GET(`/test\:action`, func(c *Context) { - c.String(http.StatusOK, "ok") - }) - - for range 5 { - w := httptest.NewRecorder() - req, _ := http.NewRequest(http.MethodGet, "/test:action", nil) - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusOK, w.Code) - assert.Equal(t, "ok", w.Body.String()) - } -}