2015-03-27 23:21:30 +02:00
package echo
2015-03-01 19:45:13 +02:00
2015-04-01 17:05:54 +02:00
import (
2021-07-15 22:34:01 +02:00
"github.com/stretchr/testify/assert"
2015-04-06 05:08:52 +02:00
"net/http"
2021-12-04 20:02:11 +02:00
"net/http/httptest"
2021-07-15 22:34:01 +02:00
"net/url"
2016-11-13 19:36:57 +02:00
"strings"
2015-04-01 17:05:54 +02:00
"testing"
)
2015-03-01 19:45:13 +02:00
2021-07-15 22:34:01 +02:00
type testRoute struct {
Method string
Path string
Handler string
}
2015-04-09 23:59:31 +02:00
var (
2021-07-15 22:34:01 +02:00
staticRoutes = [ ] testRoute {
2016-11-12 19:42:25 +02:00
{ "GET" , "/" , "" } ,
{ "GET" , "/cmd.html" , "" } ,
{ "GET" , "/code.html" , "" } ,
{ "GET" , "/contrib.html" , "" } ,
{ "GET" , "/contribute.html" , "" } ,
{ "GET" , "/debugging_with_gdb.html" , "" } ,
{ "GET" , "/docs.html" , "" } ,
{ "GET" , "/effective_go.html" , "" } ,
{ "GET" , "/files.log" , "" } ,
{ "GET" , "/gccgo_contribute.html" , "" } ,
{ "GET" , "/gccgo_install.html" , "" } ,
{ "GET" , "/go-logo-black.png" , "" } ,
{ "GET" , "/go-logo-blue.png" , "" } ,
{ "GET" , "/go-logo-white.png" , "" } ,
{ "GET" , "/go1.1.html" , "" } ,
{ "GET" , "/go1.2.html" , "" } ,
{ "GET" , "/go1.html" , "" } ,
{ "GET" , "/go1compat.html" , "" } ,
{ "GET" , "/go_faq.html" , "" } ,
{ "GET" , "/go_mem.html" , "" } ,
{ "GET" , "/go_spec.html" , "" } ,
{ "GET" , "/help.html" , "" } ,
{ "GET" , "/ie.css" , "" } ,
{ "GET" , "/install-source.html" , "" } ,
{ "GET" , "/install.html" , "" } ,
{ "GET" , "/logo-153x55.png" , "" } ,
{ "GET" , "/Makefile" , "" } ,
{ "GET" , "/root.html" , "" } ,
{ "GET" , "/share.png" , "" } ,
{ "GET" , "/sieve.gif" , "" } ,
{ "GET" , "/tos.html" , "" } ,
{ "GET" , "/articles/" , "" } ,
{ "GET" , "/articles/go_command.html" , "" } ,
{ "GET" , "/articles/index.html" , "" } ,
{ "GET" , "/articles/wiki/" , "" } ,
{ "GET" , "/articles/wiki/edit.html" , "" } ,
{ "GET" , "/articles/wiki/final-noclosure.go" , "" } ,
{ "GET" , "/articles/wiki/final-noerror.go" , "" } ,
{ "GET" , "/articles/wiki/final-parsetemplate.go" , "" } ,
{ "GET" , "/articles/wiki/final-template.go" , "" } ,
{ "GET" , "/articles/wiki/final.go" , "" } ,
{ "GET" , "/articles/wiki/get.go" , "" } ,
{ "GET" , "/articles/wiki/http-sample.go" , "" } ,
{ "GET" , "/articles/wiki/index.html" , "" } ,
{ "GET" , "/articles/wiki/Makefile" , "" } ,
{ "GET" , "/articles/wiki/notemplate.go" , "" } ,
{ "GET" , "/articles/wiki/part1-noerror.go" , "" } ,
{ "GET" , "/articles/wiki/part1.go" , "" } ,
{ "GET" , "/articles/wiki/part2.go" , "" } ,
{ "GET" , "/articles/wiki/part3-errorhandling.go" , "" } ,
{ "GET" , "/articles/wiki/part3.go" , "" } ,
{ "GET" , "/articles/wiki/test.bash" , "" } ,
{ "GET" , "/articles/wiki/test_edit.good" , "" } ,
{ "GET" , "/articles/wiki/test_Test.txt.good" , "" } ,
{ "GET" , "/articles/wiki/test_view.good" , "" } ,
{ "GET" , "/articles/wiki/view.html" , "" } ,
{ "GET" , "/codewalk/" , "" } ,
{ "GET" , "/codewalk/codewalk.css" , "" } ,
{ "GET" , "/codewalk/codewalk.js" , "" } ,
{ "GET" , "/codewalk/codewalk.xml" , "" } ,
{ "GET" , "/codewalk/functions.xml" , "" } ,
{ "GET" , "/codewalk/markov.go" , "" } ,
{ "GET" , "/codewalk/markov.xml" , "" } ,
{ "GET" , "/codewalk/pig.go" , "" } ,
{ "GET" , "/codewalk/popout.png" , "" } ,
{ "GET" , "/codewalk/run" , "" } ,
{ "GET" , "/codewalk/sharemem.xml" , "" } ,
{ "GET" , "/codewalk/urlpoll.go" , "" } ,
{ "GET" , "/devel/" , "" } ,
{ "GET" , "/devel/release.html" , "" } ,
{ "GET" , "/devel/weekly.html" , "" } ,
{ "GET" , "/gopher/" , "" } ,
{ "GET" , "/gopher/appenginegopher.jpg" , "" } ,
{ "GET" , "/gopher/appenginegophercolor.jpg" , "" } ,
{ "GET" , "/gopher/appenginelogo.gif" , "" } ,
{ "GET" , "/gopher/bumper.png" , "" } ,
{ "GET" , "/gopher/bumper192x108.png" , "" } ,
{ "GET" , "/gopher/bumper320x180.png" , "" } ,
{ "GET" , "/gopher/bumper480x270.png" , "" } ,
{ "GET" , "/gopher/bumper640x360.png" , "" } ,
{ "GET" , "/gopher/doc.png" , "" } ,
{ "GET" , "/gopher/frontpage.png" , "" } ,
{ "GET" , "/gopher/gopherbw.png" , "" } ,
{ "GET" , "/gopher/gophercolor.png" , "" } ,
{ "GET" , "/gopher/gophercolor16x16.png" , "" } ,
{ "GET" , "/gopher/help.png" , "" } ,
{ "GET" , "/gopher/pkg.png" , "" } ,
{ "GET" , "/gopher/project.png" , "" } ,
{ "GET" , "/gopher/ref.png" , "" } ,
{ "GET" , "/gopher/run.png" , "" } ,
{ "GET" , "/gopher/talks.png" , "" } ,
{ "GET" , "/gopher/pencil/" , "" } ,
{ "GET" , "/gopher/pencil/gopherhat.jpg" , "" } ,
{ "GET" , "/gopher/pencil/gopherhelmet.jpg" , "" } ,
{ "GET" , "/gopher/pencil/gophermega.jpg" , "" } ,
{ "GET" , "/gopher/pencil/gopherrunning.jpg" , "" } ,
{ "GET" , "/gopher/pencil/gopherswim.jpg" , "" } ,
{ "GET" , "/gopher/pencil/gopherswrench.jpg" , "" } ,
{ "GET" , "/play/" , "" } ,
{ "GET" , "/play/fib.go" , "" } ,
{ "GET" , "/play/hello.go" , "" } ,
{ "GET" , "/play/life.go" , "" } ,
{ "GET" , "/play/peano.go" , "" } ,
{ "GET" , "/play/pi.go" , "" } ,
{ "GET" , "/play/sieve.go" , "" } ,
{ "GET" , "/play/solitaire.go" , "" } ,
{ "GET" , "/play/tree.go" , "" } ,
{ "GET" , "/progs/" , "" } ,
{ "GET" , "/progs/cgo1.go" , "" } ,
{ "GET" , "/progs/cgo2.go" , "" } ,
{ "GET" , "/progs/cgo3.go" , "" } ,
{ "GET" , "/progs/cgo4.go" , "" } ,
{ "GET" , "/progs/defer.go" , "" } ,
{ "GET" , "/progs/defer.out" , "" } ,
{ "GET" , "/progs/defer2.go" , "" } ,
{ "GET" , "/progs/defer2.out" , "" } ,
{ "GET" , "/progs/eff_bytesize.go" , "" } ,
{ "GET" , "/progs/eff_bytesize.out" , "" } ,
{ "GET" , "/progs/eff_qr.go" , "" } ,
{ "GET" , "/progs/eff_sequence.go" , "" } ,
{ "GET" , "/progs/eff_sequence.out" , "" } ,
{ "GET" , "/progs/eff_unused1.go" , "" } ,
{ "GET" , "/progs/eff_unused2.go" , "" } ,
{ "GET" , "/progs/error.go" , "" } ,
{ "GET" , "/progs/error2.go" , "" } ,
{ "GET" , "/progs/error3.go" , "" } ,
{ "GET" , "/progs/error4.go" , "" } ,
{ "GET" , "/progs/go1.go" , "" } ,
{ "GET" , "/progs/gobs1.go" , "" } ,
{ "GET" , "/progs/gobs2.go" , "" } ,
{ "GET" , "/progs/image_draw.go" , "" } ,
{ "GET" , "/progs/image_package1.go" , "" } ,
{ "GET" , "/progs/image_package1.out" , "" } ,
{ "GET" , "/progs/image_package2.go" , "" } ,
{ "GET" , "/progs/image_package2.out" , "" } ,
{ "GET" , "/progs/image_package3.go" , "" } ,
{ "GET" , "/progs/image_package3.out" , "" } ,
{ "GET" , "/progs/image_package4.go" , "" } ,
{ "GET" , "/progs/image_package4.out" , "" } ,
{ "GET" , "/progs/image_package5.go" , "" } ,
{ "GET" , "/progs/image_package5.out" , "" } ,
{ "GET" , "/progs/image_package6.go" , "" } ,
{ "GET" , "/progs/image_package6.out" , "" } ,
{ "GET" , "/progs/interface.go" , "" } ,
{ "GET" , "/progs/interface2.go" , "" } ,
{ "GET" , "/progs/interface2.out" , "" } ,
{ "GET" , "/progs/json1.go" , "" } ,
{ "GET" , "/progs/json2.go" , "" } ,
{ "GET" , "/progs/json2.out" , "" } ,
{ "GET" , "/progs/json3.go" , "" } ,
{ "GET" , "/progs/json4.go" , "" } ,
{ "GET" , "/progs/json5.go" , "" } ,
{ "GET" , "/progs/run" , "" } ,
{ "GET" , "/progs/slices.go" , "" } ,
{ "GET" , "/progs/timeout1.go" , "" } ,
{ "GET" , "/progs/timeout2.go" , "" } ,
{ "GET" , "/progs/update.bash" , "" } ,
}
2021-07-15 22:34:01 +02:00
gitHubAPI = [ ] testRoute {
2015-04-09 23:59:31 +02:00
// OAuth Authorizations
2016-11-12 19:42:25 +02:00
{ "GET" , "/authorizations" , "" } ,
{ "GET" , "/authorizations/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/authorizations" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PUT" , "/authorizations/clients/:client_id" , "" } ,
{ "PATCH" , "/authorizations/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/authorizations/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/applications/:client_id/tokens/:access_token" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/applications/:client_id/tokens" , "" } ,
{ "DELETE" , "/applications/:client_id/tokens/:access_token" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Activity
2016-11-12 19:42:25 +02:00
{ "GET" , "/events" , "" } ,
{ "GET" , "/repos/:owner/:repo/events" , "" } ,
{ "GET" , "/networks/:owner/:repo/events" , "" } ,
{ "GET" , "/orgs/:org/events" , "" } ,
{ "GET" , "/users/:user/received_events" , "" } ,
{ "GET" , "/users/:user/received_events/public" , "" } ,
{ "GET" , "/users/:user/events" , "" } ,
{ "GET" , "/users/:user/events/public" , "" } ,
{ "GET" , "/users/:user/events/orgs/:org" , "" } ,
{ "GET" , "/feeds" , "" } ,
{ "GET" , "/notifications" , "" } ,
{ "GET" , "/repos/:owner/:repo/notifications" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/notifications" , "" } ,
{ "PUT" , "/repos/:owner/:repo/notifications" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/notifications/threads/:id" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/notifications/threads/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/notifications/threads/:id/subscription" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/notifications/threads/:id/subscription" , "" } ,
{ "DELETE" , "/notifications/threads/:id/subscription" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/stargazers" , "" } ,
{ "GET" , "/users/:user/starred" , "" } ,
{ "GET" , "/user/starred" , "" } ,
{ "GET" , "/user/starred/:owner/:repo" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/user/starred/:owner/:repo" , "" } ,
{ "DELETE" , "/user/starred/:owner/:repo" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/subscribers" , "" } ,
{ "GET" , "/users/:user/subscriptions" , "" } ,
{ "GET" , "/user/subscriptions" , "" } ,
{ "GET" , "/repos/:owner/:repo/subscription" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/repos/:owner/:repo/subscription" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/subscription" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/user/subscriptions/:owner/:repo" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/user/subscriptions/:owner/:repo" , "" } ,
{ "DELETE" , "/user/subscriptions/:owner/:repo" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Gists
2016-11-12 19:42:25 +02:00
{ "GET" , "/users/:user/gists" , "" } ,
{ "GET" , "/gists" , "" } ,
2020-11-21 04:48:16 +02:00
{ "GET" , "/gists/public" , "" } ,
{ "GET" , "/gists/starred" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/gists/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/gists" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/gists/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/gists/:id/star" , "" } ,
{ "DELETE" , "/gists/:id/star" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/gists/:id/star" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/gists/:id/forks" , "" } ,
{ "DELETE" , "/gists/:id" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Git Data
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/git/blobs/:sha" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/git/blobs" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/git/commits/:sha" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/git/commits" , "" } ,
2020-11-21 04:48:16 +02:00
{ "GET" , "/repos/:owner/:repo/git/refs/*ref" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/git/refs" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/git/refs" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/git/refs/*ref" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/git/refs/*ref" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/git/tags/:sha" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/git/tags" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/git/trees/:sha" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/git/trees" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Issues
2016-11-12 19:42:25 +02:00
{ "GET" , "/issues" , "" } ,
{ "GET" , "/user/issues" , "" } ,
{ "GET" , "/orgs/:org/issues" , "" } ,
{ "GET" , "/repos/:owner/:repo/issues" , "" } ,
{ "GET" , "/repos/:owner/:repo/issues/:number" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/issues" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/issues/:number" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/assignees" , "" } ,
{ "GET" , "/repos/:owner/:repo/assignees/:assignee" , "" } ,
{ "GET" , "/repos/:owner/:repo/issues/:number/comments" , "" } ,
2020-11-21 04:48:16 +02:00
{ "GET" , "/repos/:owner/:repo/issues/comments" , "" } ,
{ "GET" , "/repos/:owner/:repo/issues/comments/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/issues/:number/comments" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/issues/comments/:id" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/issues/comments/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/issues/:number/events" , "" } ,
2020-11-21 04:48:16 +02:00
{ "GET" , "/repos/:owner/:repo/issues/events" , "" } ,
{ "GET" , "/repos/:owner/:repo/issues/events/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/labels" , "" } ,
{ "GET" , "/repos/:owner/:repo/labels/:name" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/labels" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/labels/:name" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo/labels/:name" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/issues/:number/labels" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/issues/:number/labels" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/issues/:number/labels/:name" , "" } ,
{ "PUT" , "/repos/:owner/:repo/issues/:number/labels" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/issues/:number/labels" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/milestones/:number/labels" , "" } ,
{ "GET" , "/repos/:owner/:repo/milestones" , "" } ,
{ "GET" , "/repos/:owner/:repo/milestones/:number" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/milestones" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/milestones/:number" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo/milestones/:number" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Miscellaneous
2016-11-12 19:42:25 +02:00
{ "GET" , "/emojis" , "" } ,
{ "GET" , "/gitignore/templates" , "" } ,
{ "GET" , "/gitignore/templates/:name" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/markdown" , "" } ,
{ "POST" , "/markdown/raw" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/meta" , "" } ,
{ "GET" , "/rate_limit" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Organizations
2016-11-12 19:42:25 +02:00
{ "GET" , "/users/:user/orgs" , "" } ,
{ "GET" , "/user/orgs" , "" } ,
{ "GET" , "/orgs/:org" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/orgs/:org" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/orgs/:org/members" , "" } ,
{ "GET" , "/orgs/:org/members/:user" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/orgs/:org/members/:user" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/orgs/:org/public_members" , "" } ,
{ "GET" , "/orgs/:org/public_members/:user" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/orgs/:org/public_members/:user" , "" } ,
{ "DELETE" , "/orgs/:org/public_members/:user" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/orgs/:org/teams" , "" } ,
{ "GET" , "/teams/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/orgs/:org/teams" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/teams/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/teams/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/teams/:id/members" , "" } ,
{ "GET" , "/teams/:id/members/:user" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/teams/:id/members/:user" , "" } ,
{ "DELETE" , "/teams/:id/members/:user" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/teams/:id/repos" , "" } ,
{ "GET" , "/teams/:id/repos/:owner/:repo" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/teams/:id/repos/:owner/:repo" , "" } ,
{ "DELETE" , "/teams/:id/repos/:owner/:repo" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/user/teams" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Pull Requests
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/pulls" , "" } ,
{ "GET" , "/repos/:owner/:repo/pulls/:number" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/pulls" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/pulls/:number" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/pulls/:number/commits" , "" } ,
{ "GET" , "/repos/:owner/:repo/pulls/:number/files" , "" } ,
{ "GET" , "/repos/:owner/:repo/pulls/:number/merge" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/repos/:owner/:repo/pulls/:number/merge" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/pulls/:number/comments" , "" } ,
2020-11-21 04:48:16 +02:00
{ "GET" , "/repos/:owner/:repo/pulls/comments" , "" } ,
{ "GET" , "/repos/:owner/:repo/pulls/comments/:number" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/repos/:owner/:repo/pulls/:number/comments" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/pulls/comments/:number" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/pulls/comments/:number" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Repositories
2016-11-12 19:42:25 +02:00
{ "GET" , "/user/repos" , "" } ,
{ "GET" , "/users/:user/repos" , "" } ,
{ "GET" , "/orgs/:org/repos" , "" } ,
{ "GET" , "/repositories" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/user/repos" , "" } ,
{ "POST" , "/orgs/:org/repos" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/contributors" , "" } ,
{ "GET" , "/repos/:owner/:repo/languages" , "" } ,
{ "GET" , "/repos/:owner/:repo/teams" , "" } ,
{ "GET" , "/repos/:owner/:repo/tags" , "" } ,
{ "GET" , "/repos/:owner/:repo/branches" , "" } ,
{ "GET" , "/repos/:owner/:repo/branches/:branch" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/collaborators" , "" } ,
{ "GET" , "/repos/:owner/:repo/collaborators/:user" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/repos/:owner/:repo/collaborators/:user" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/collaborators/:user" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/comments" , "" } ,
{ "GET" , "/repos/:owner/:repo/commits/:sha/comments" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/commits/:sha/comments" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/comments/:id" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/comments/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo/comments/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/commits" , "" } ,
{ "GET" , "/repos/:owner/:repo/commits/:sha" , "" } ,
{ "GET" , "/repos/:owner/:repo/readme" , "" } ,
2020-11-21 04:48:16 +02:00
2016-11-12 19:42:25 +02:00
//{"GET", "/repos/:owner/:repo/contents/*path", ""},
2016-01-09 19:44:18 +02:00
//{"PUT", "/repos/:owner/:repo/contents/*path", ""},
//{"DELETE", "/repos/:owner/:repo/contents/*path", ""},
2020-11-21 04:48:16 +02:00
{ "GET" , "/repos/:owner/:repo/:archive_format/:ref" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/keys" , "" } ,
{ "GET" , "/repos/:owner/:repo/keys/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/keys" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/keys/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo/keys/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/downloads" , "" } ,
{ "GET" , "/repos/:owner/:repo/downloads/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo/downloads/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/forks" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/forks" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/hooks" , "" } ,
{ "GET" , "/repos/:owner/:repo/hooks/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/hooks" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/hooks/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/hooks/:id/tests" , "" } ,
{ "DELETE" , "/repos/:owner/:repo/hooks/:id" , "" } ,
{ "POST" , "/repos/:owner/:repo/merges" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/releases" , "" } ,
{ "GET" , "/repos/:owner/:repo/releases/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/releases" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/repos/:owner/:repo/releases/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/repos/:owner/:repo/releases/:id" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/repos/:owner/:repo/releases/:id/assets" , "" } ,
{ "GET" , "/repos/:owner/:repo/stats/contributors" , "" } ,
{ "GET" , "/repos/:owner/:repo/stats/commit_activity" , "" } ,
{ "GET" , "/repos/:owner/:repo/stats/code_frequency" , "" } ,
{ "GET" , "/repos/:owner/:repo/stats/participation" , "" } ,
{ "GET" , "/repos/:owner/:repo/stats/punch_card" , "" } ,
{ "GET" , "/repos/:owner/:repo/statuses/:ref" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/repos/:owner/:repo/statuses/:ref" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Search
2016-11-12 19:42:25 +02:00
{ "GET" , "/search/repositories" , "" } ,
{ "GET" , "/search/code" , "" } ,
{ "GET" , "/search/issues" , "" } ,
{ "GET" , "/search/users" , "" } ,
{ "GET" , "/legacy/issues/search/:owner/:repository/:state/:keyword" , "" } ,
{ "GET" , "/legacy/repos/search/:keyword" , "" } ,
{ "GET" , "/legacy/user/search/:keyword" , "" } ,
{ "GET" , "/legacy/user/email/:email" , "" } ,
2015-04-06 06:00:14 +02:00
2015-04-09 23:59:31 +02:00
// Users
2016-11-12 19:42:25 +02:00
{ "GET" , "/users/:user" , "" } ,
{ "GET" , "/user" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/user" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/users" , "" } ,
{ "GET" , "/user/emails" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/user/emails" , "" } ,
{ "DELETE" , "/user/emails" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/users/:user/followers" , "" } ,
{ "GET" , "/user/followers" , "" } ,
{ "GET" , "/users/:user/following" , "" } ,
{ "GET" , "/user/following" , "" } ,
{ "GET" , "/user/following/:user" , "" } ,
{ "GET" , "/users/:user/following/:target_user" , "" } ,
2016-01-09 19:44:18 +02:00
{ "PUT" , "/user/following/:user" , "" } ,
{ "DELETE" , "/user/following/:user" , "" } ,
2016-11-12 19:42:25 +02:00
{ "GET" , "/users/:user/keys" , "" } ,
{ "GET" , "/user/keys" , "" } ,
{ "GET" , "/user/keys/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "POST" , "/user/keys" , "" } ,
2020-11-21 04:48:16 +02:00
{ "PATCH" , "/user/keys/:id" , "" } ,
2016-01-09 19:44:18 +02:00
{ "DELETE" , "/user/keys/:id" , "" } ,
2015-04-09 23:59:31 +02:00
}
2016-11-12 19:42:25 +02:00
2021-07-15 22:34:01 +02:00
parseAPI = [ ] testRoute {
2016-11-12 19:42:25 +02:00
// Objects
{ "POST" , "/1/classes/:className" , "" } ,
{ "GET" , "/1/classes/:className/:objectId" , "" } ,
{ "PUT" , "/1/classes/:className/:objectId" , "" } ,
{ "GET" , "/1/classes/:className" , "" } ,
{ "DELETE" , "/1/classes/:className/:objectId" , "" } ,
// Users
{ "POST" , "/1/users" , "" } ,
{ "GET" , "/1/login" , "" } ,
{ "GET" , "/1/users/:objectId" , "" } ,
{ "PUT" , "/1/users/:objectId" , "" } ,
{ "GET" , "/1/users" , "" } ,
{ "DELETE" , "/1/users/:objectId" , "" } ,
{ "POST" , "/1/requestPasswordReset" , "" } ,
// Roles
{ "POST" , "/1/roles" , "" } ,
{ "GET" , "/1/roles/:objectId" , "" } ,
{ "PUT" , "/1/roles/:objectId" , "" } ,
{ "GET" , "/1/roles" , "" } ,
{ "DELETE" , "/1/roles/:objectId" , "" } ,
// Files
{ "POST" , "/1/files/:fileName" , "" } ,
// Analytics
{ "POST" , "/1/events/:eventName" , "" } ,
// Push Notifications
{ "POST" , "/1/push" , "" } ,
// Installations
{ "POST" , "/1/installations" , "" } ,
{ "GET" , "/1/installations/:objectId" , "" } ,
{ "PUT" , "/1/installations/:objectId" , "" } ,
{ "GET" , "/1/installations" , "" } ,
{ "DELETE" , "/1/installations/:objectId" , "" } ,
// Cloud Functions
{ "POST" , "/1/functions" , "" } ,
}
2021-07-15 22:34:01 +02:00
googlePlusAPI = [ ] testRoute {
2016-11-12 19:42:25 +02:00
// People
{ "GET" , "/people/:userId" , "" } ,
{ "GET" , "/people" , "" } ,
{ "GET" , "/activities/:activityId/people/:collection" , "" } ,
{ "GET" , "/people/:userId/people/:collection" , "" } ,
{ "GET" , "/people/:userId/openIdConnect" , "" } ,
// Activities
{ "GET" , "/people/:userId/activities/:collection" , "" } ,
{ "GET" , "/activities/:activityId" , "" } ,
{ "GET" , "/activities" , "" } ,
// Comments
{ "GET" , "/activities/:activityId/comments" , "" } ,
{ "GET" , "/comments/:commentId" , "" } ,
// Moments
{ "POST" , "/people/:userId/moments/:collection" , "" } ,
{ "GET" , "/people/:userId/moments/:collection" , "" } ,
{ "DELETE" , "/moments/:id" , "" } ,
}
2019-10-16 21:52:10 +02:00
2021-07-15 22:34:01 +02:00
paramAndAnyAPI = [ ] testRoute {
2020-11-21 04:48:16 +02:00
{ "GET" , "/root/:first/foo/*" , "" } ,
{ "GET" , "/root/:first/:second/*" , "" } ,
{ "GET" , "/root/:first/bar/:second/*" , "" } ,
{ "GET" , "/root/:first/qux/:second/:third/:fourth" , "" } ,
{ "GET" , "/root/:first/qux/:second/:third/:fourth/*" , "" } ,
{ "GET" , "/root/*" , "" } ,
{ "POST" , "/root/:first/foo/*" , "" } ,
{ "POST" , "/root/:first/:second/*" , "" } ,
{ "POST" , "/root/:first/bar/:second/*" , "" } ,
{ "POST" , "/root/:first/qux/:second/:third/:fourth" , "" } ,
{ "POST" , "/root/:first/qux/:second/:third/:fourth/*" , "" } ,
{ "POST" , "/root/*" , "" } ,
{ "PUT" , "/root/:first/foo/*" , "" } ,
{ "PUT" , "/root/:first/:second/*" , "" } ,
{ "PUT" , "/root/:first/bar/:second/*" , "" } ,
{ "PUT" , "/root/:first/qux/:second/:third/:fourth" , "" } ,
{ "PUT" , "/root/:first/qux/:second/:third/:fourth/*" , "" } ,
{ "PUT" , "/root/*" , "" } ,
{ "DELETE" , "/root/:first/foo/*" , "" } ,
{ "DELETE" , "/root/:first/:second/*" , "" } ,
{ "DELETE" , "/root/:first/bar/:second/*" , "" } ,
{ "DELETE" , "/root/:first/qux/:second/:third/:fourth" , "" } ,
{ "DELETE" , "/root/:first/qux/:second/:third/:fourth/*" , "" } ,
{ "DELETE" , "/root/*" , "" } ,
}
2021-07-15 22:34:01 +02:00
paramAndAnyAPIToFind = [ ] testRoute {
2020-11-21 04:48:16 +02:00
{ "GET" , "/root/one/foo/after/the/asterisk" , "" } ,
{ "GET" , "/root/one/foo/path/after/the/asterisk" , "" } ,
{ "GET" , "/root/one/two/path/after/the/asterisk" , "" } ,
{ "GET" , "/root/one/bar/two/after/the/asterisk" , "" } ,
{ "GET" , "/root/one/qux/two/three/four" , "" } ,
{ "GET" , "/root/one/qux/two/three/four/after/the/asterisk" , "" } ,
{ "POST" , "/root/one/foo/after/the/asterisk" , "" } ,
{ "POST" , "/root/one/foo/path/after/the/asterisk" , "" } ,
{ "POST" , "/root/one/two/path/after/the/asterisk" , "" } ,
{ "POST" , "/root/one/bar/two/after/the/asterisk" , "" } ,
{ "POST" , "/root/one/qux/two/three/four" , "" } ,
{ "POST" , "/root/one/qux/two/three/four/after/the/asterisk" , "" } ,
{ "PUT" , "/root/one/foo/after/the/asterisk" , "" } ,
{ "PUT" , "/root/one/foo/path/after/the/asterisk" , "" } ,
{ "PUT" , "/root/one/two/path/after/the/asterisk" , "" } ,
{ "PUT" , "/root/one/bar/two/after/the/asterisk" , "" } ,
{ "PUT" , "/root/one/qux/two/three/four" , "" } ,
{ "PUT" , "/root/one/qux/two/three/four/after/the/asterisk" , "" } ,
{ "DELETE" , "/root/one/foo/after/the/asterisk" , "" } ,
{ "DELETE" , "/root/one/foo/path/after/the/asterisk" , "" } ,
{ "DELETE" , "/root/one/two/path/after/the/asterisk" , "" } ,
{ "DELETE" , "/root/one/bar/two/after/the/asterisk" , "" } ,
{ "DELETE" , "/root/one/qux/two/three/four" , "" } ,
{ "DELETE" , "/root/one/qux/two/three/four/after/the/asterisk" , "" } ,
}
2021-07-15 22:34:01 +02:00
missesAPI = [ ] testRoute {
2020-11-21 04:48:16 +02:00
{ "GET" , "/missOne" , "" } ,
{ "GET" , "/miss/two" , "" } ,
{ "GET" , "/miss/three/levels" , "" } ,
{ "GET" , "/miss/four/levels/nooo" , "" } ,
{ "POST" , "/missOne" , "" } ,
{ "POST" , "/miss/two" , "" } ,
{ "POST" , "/miss/three/levels" , "" } ,
{ "POST" , "/miss/four/levels/nooo" , "" } ,
{ "PUT" , "/missOne" , "" } ,
{ "PUT" , "/miss/two" , "" } ,
{ "PUT" , "/miss/three/levels" , "" } ,
{ "PUT" , "/miss/four/levels/nooo" , "" } ,
{ "DELETE" , "/missOne" , "" } ,
{ "DELETE" , "/miss/two" , "" } ,
{ "DELETE" , "/miss/three/levels" , "" } ,
{ "DELETE" , "/miss/four/levels/nooo" , "" } ,
}
2019-10-16 21:52:10 +02:00
// handlerHelper created a function that will set a context key for assertion
handlerHelper = func ( key string , value int ) func ( c Context ) error {
return func ( c Context ) error {
c . Set ( key , value )
2021-07-15 22:34:01 +02:00
c . Set ( "path" , c . RouteInfo ( ) . Path ( ) )
2019-10-16 21:52:10 +02:00
return nil
}
}
2021-03-06 01:43:59 +02:00
handlerFunc = func ( c Context ) error {
2021-07-15 22:34:01 +02:00
c . Set ( "path" , c . RouteInfo ( ) . Path ( ) )
2021-03-06 01:43:59 +02:00
return nil
}
2015-04-09 23:59:31 +02:00
)
2015-04-06 05:08:52 +02:00
2021-07-15 22:34:01 +02:00
func checkUnusedParamValues ( t * testing . T , c * DefaultContext , expectParam map [ string ] string ) {
for _ , p := range c . PathParams ( ) {
value := p . Value
2021-03-06 01:43:59 +02:00
if value != "" {
if expectParam == nil {
t . Errorf ( "pValue '%v' is set for param name '%v' but we are not expecting it with expectParam" , value , p )
} else {
2021-07-15 22:34:01 +02:00
if _ , ok := expectParam [ p . Name ] ; ! ok {
2021-03-06 01:43:59 +02:00
t . Errorf ( "pValue '%v' is set for param name '%v' but we are not expecting it with expectParam" , value , p )
}
}
}
}
}
2015-03-19 08:51:32 +02:00
func TestRouterStatic ( t * testing . T ) {
2015-04-12 22:04:41 +02:00
path := "/folders/a/files/echo.gif"
2022-12-04 22:17:48 +02:00
req := httptest . NewRequest ( http . MethodGet , path , nil )
2021-07-15 22:34:01 +02:00
rec := httptest . NewRecorder ( )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
e := New ( )
e . GET ( path , handlerFunc )
c := e . NewContext ( req , rec ) . ( * DefaultContext )
_ = e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , path , c . Path ( ) )
assert . Equal ( t , 0 , cap ( * c . pathParams ) )
assert . Len ( t , * c . pathParams , 0 )
2015-03-01 19:45:13 +02:00
}
2015-03-19 08:51:32 +02:00
func TestRouterParam ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
e . GET ( "/users/:id" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
name string
whenURL string
expectRoute interface { }
expectParam map [ string ] string
} {
{
name : "route /users/1 to /users/:id" ,
whenURL : "/users/1" ,
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "1" } ,
} ,
2021-04-27 09:55:31 +02:00
{
2021-03-06 01:43:59 +02:00
name : "route /users/1/ to /users/:id" ,
whenURL : "/users/1/" ,
2021-04-27 09:55:31 +02:00
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "1/" } ,
2021-03-06 01:43:59 +02:00
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
c := e . NewContext ( nil , nil ) . ( * DefaultContext )
2022-12-04 22:17:48 +02:00
c . SetRequest ( httptest . NewRequest ( http . MethodGet , tc . whenURL , nil ) )
2021-07-15 22:34:01 +02:00
_ = e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2015-04-04 19:44:48 +02:00
}
2021-07-15 22:34:01 +02:00
func TestRouter_addAndMatchAllSupportedMethods ( t * testing . T ) {
var testCases = [ ] struct {
2022-12-04 22:17:48 +02:00
name string
givenNoAddRoute bool
whenMethod string
expectPath string
expectError string
2021-07-15 22:34:01 +02:00
} {
{ name : "ok, CONNECT" , whenMethod : http . MethodConnect } ,
{ name : "ok, DELETE" , whenMethod : http . MethodDelete } ,
{ name : "ok, GET" , whenMethod : http . MethodGet } ,
{ name : "ok, HEAD" , whenMethod : http . MethodHead } ,
{ name : "ok, OPTIONS" , whenMethod : http . MethodOptions } ,
{ name : "ok, PATCH" , whenMethod : http . MethodPatch } ,
{ name : "ok, POST" , whenMethod : http . MethodPost } ,
{ name : "ok, PROPFIND" , whenMethod : PROPFIND } ,
{ name : "ok, PUT" , whenMethod : http . MethodPut } ,
{ name : "ok, TRACE" , whenMethod : http . MethodTrace } ,
{ name : "ok, REPORT" , whenMethod : REPORT } ,
{ name : "ok, NON_TRADITIONAL_METHOD" , whenMethod : "NON_TRADITIONAL_METHOD" } ,
2022-12-04 22:17:48 +02:00
{
name : "ok, NOT_EXISTING_METHOD" ,
whenMethod : "NOT_EXISTING_METHOD" ,
givenNoAddRoute : true ,
expectPath : "/*" ,
expectError : "code=405, message=Method Not Allowed" ,
} ,
2021-07-15 22:34:01 +02:00
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . GET ( "/*" , handlerFunc )
2022-12-04 22:17:48 +02:00
if ! tc . givenNoAddRoute {
e . Add ( tc . whenMethod , "/my/*" , handlerFunc )
}
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( tc . whenMethod , "/my/some-url" , nil )
rec := httptest . NewRecorder ( )
c := e . NewContext ( req , rec ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2022-12-04 22:17:48 +02:00
if tc . expectError != "" {
assert . EqualError ( t , err , tc . expectError )
} else {
assert . NoError ( t , err )
}
expectPath := "/my/*"
if tc . expectPath != "" {
expectPath = tc . expectPath
}
assert . Equal ( t , expectPath , c . Path ( ) )
2021-07-15 22:34:01 +02:00
} )
}
}
2022-12-04 22:17:48 +02:00
func TestRouterAllowHeaderForAnyOtherMethodType ( t * testing . T ) {
e := New ( )
r := e . router
_ , err := r . Add ( Route { Method : http . MethodGet , Path : "/users" , Handler : handlerFunc } )
assert . NoError ( t , err )
_ , err = r . Add ( Route { Method : "COPY" , Path : "/users" , Handler : handlerFunc } )
assert . NoError ( t , err )
_ , err = r . Add ( Route { Method : "LOCK" , Path : "/users" , Handler : handlerFunc } )
assert . NoError ( t , err )
req := httptest . NewRequest ( "TEST" , "/users" , nil )
rec := httptest . NewRecorder ( )
//r.Find("TEST", "/users", c)
c := e . NewContext ( req , rec ) . ( * DefaultContext )
handler := e . router . Route ( c )
err = handler ( c )
assert . EqualError ( t , err , "code=405, message=Method Not Allowed" )
assert . ElementsMatch ( t , [ ] string { "COPY" , "GET" , "LOCK" , "OPTIONS" } , strings . Split ( c . Response ( ) . Header ( ) . Get ( HeaderAllow ) , ", " ) )
}
2021-04-27 09:55:31 +02:00
func TestMethodNotAllowedAndNotFound ( t * testing . T ) {
e := New ( )
// Routes
2021-07-15 22:34:01 +02:00
ri , err := e . AddRoute ( Route { Method : http . MethodGet , Path : "/*" , Handler : handlerFunc } )
assert . NoError ( t , err )
assert . Equal ( t , "GET:/*" , ri . Name ( ) )
ri , err = e . AddRoute ( Route { Method : http . MethodPost , Path : "/users/:id" , Handler : handlerFunc } )
assert . NoError ( t , err )
assert . Equal ( t , "POST:/users/:id" , ri . Name ( ) )
2021-04-27 09:55:31 +02:00
var testCases = [ ] struct {
2021-12-04 20:02:11 +02:00
name string
whenMethod string
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-12-04 20:02:11 +02:00
expectParam map [ string ] string
expectError error
expectAllowHeader string
2021-04-27 09:55:31 +02:00
} {
{
name : "exact match for route+method" ,
whenMethod : http . MethodPost ,
whenURL : "/users/1" ,
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "1" } ,
} ,
{
2021-12-04 20:02:11 +02:00
name : "matches node but not method. sends 405 from best match node" ,
whenMethod : http . MethodPut ,
whenURL : "/users/1" ,
2021-07-15 22:34:01 +02:00
expectRoute : "/users/:id" ,
2021-12-04 20:02:11 +02:00
expectError : ErrMethodNotAllowed ,
expectAllowHeader : "OPTIONS, POST" ,
2021-04-27 09:55:31 +02:00
} ,
{
name : "best match is any route up in tree" ,
whenMethod : http . MethodGet ,
whenURL : "/users/1" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "users/1" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
rec := httptest . NewRecorder ( )
c := e . NewContext ( req , rec ) . ( * DefaultContext )
handler := e . router . Route ( c )
2021-04-27 09:55:31 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
2021-04-27 09:55:31 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-04-27 09:55:31 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-04-27 09:55:31 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
2021-12-04 20:02:11 +02:00
assert . Equal ( t , tc . expectAllowHeader , c . Response ( ) . Header ( ) . Get ( HeaderAllow ) )
2021-04-27 09:55:31 +02:00
} )
}
}
2021-12-04 20:02:11 +02:00
func TestRouterOptionsMethodHandler ( t * testing . T ) {
e := New ( )
var keyInContext interface { }
e . Use ( func ( next HandlerFunc ) HandlerFunc {
return func ( c Context ) error {
err := next ( c )
keyInContext = c . Get ( ContextKeyHeaderAllow )
return err
}
} )
e . GET ( "/test" , func ( c Context ) error {
return c . String ( http . StatusOK , "Echo!" )
} )
req := httptest . NewRequest ( http . MethodOptions , "/test" , nil )
rec := httptest . NewRecorder ( )
e . ServeHTTP ( rec , req )
assert . Equal ( t , http . StatusNoContent , rec . Code )
assert . Equal ( t , "OPTIONS, GET" , rec . Header ( ) . Get ( HeaderAllow ) )
assert . Equal ( t , "OPTIONS, GET" , keyInContext )
}
2021-07-15 22:34:01 +02:00
func TestRouterHandleMethodOptions ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2021-07-15 22:34:01 +02:00
e . contextPathParamAllocSize = 1
2015-06-04 00:18:27 +02:00
r := e . router
2015-04-24 16:44:30 +02:00
2021-07-15 22:34:01 +02:00
r . Add ( Route { Method : http . MethodGet , Path : "/users" , Handler : handlerFunc } )
r . Add ( Route { Method : http . MethodPost , Path : "/users" , Handler : handlerFunc } )
r . Add ( Route { Method : http . MethodPut , Path : "/users/:id" , Handler : handlerFunc } )
r . Add ( Route { Method : http . MethodGet , Path : "/users/:id" , Handler : handlerFunc } )
var testCases = [ ] struct {
name string
whenMethod string
whenURL string
expectAllowHeader string
expectStatus int
} {
{
name : "allows GET and POST handlers" ,
whenMethod : http . MethodOptions ,
whenURL : "/users" ,
expectAllowHeader : "OPTIONS, GET, POST" ,
expectStatus : http . StatusNoContent ,
} ,
{
name : "allows GET and PUT handlers" ,
whenMethod : http . MethodOptions ,
whenURL : "/users/1" ,
expectAllowHeader : "OPTIONS, GET, PUT" ,
expectStatus : http . StatusNoContent ,
} ,
{
name : "GET does not have allows header" ,
whenMethod : http . MethodGet ,
whenURL : "/users" ,
expectAllowHeader : "" ,
expectStatus : http . StatusOK ,
} ,
{
name : "path with no handlers does not set Allows header" ,
whenMethod : http . MethodOptions ,
whenURL : "/notFound" ,
expectAllowHeader : "" ,
expectStatus : http . StatusNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
req := httptest . NewRequest ( tc . whenMethod , tc . whenURL , nil )
rec := httptest . NewRecorder ( )
c := e . NewContext ( req , rec ) . ( * DefaultContext )
h := r . Route ( c )
err := h ( c )
if tc . expectStatus >= 400 {
assert . Error ( t , err )
he := err . ( * HTTPError )
assert . Equal ( t , tc . expectStatus , he . Code )
} else {
assert . NoError ( t , err )
assert . Equal ( t , tc . expectStatus , rec . Code )
}
assert . Equal ( t , tc . expectAllowHeader , c . Response ( ) . Header ( ) . Get ( HeaderAllow ) )
} )
}
}
func TestRouterTwoParam ( t * testing . T ) {
e := New ( )
e . GET ( "/users/:uid/files/:fid" , handlerFunc )
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , "/users/1/files/1" , nil ) , nil ) . ( * DefaultContext )
_ = e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , "/users/:uid/files/:fid" , c . Path ( ) )
assert . Equal ( t , "1" , c . pathParams . Get ( "uid" , "" ) )
assert . Equal ( t , "1" , c . pathParams . Get ( "fid" , "" ) )
2015-03-01 19:45:13 +02:00
}
2016-03-07 09:24:51 +02:00
// Issue #378
func TestRouterParamWithSlash ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/a/:b/c/d/:e" , handlerFunc )
e . GET ( "/a/:b/c/:d/:f" , handlerFunc )
2016-03-07 09:24:51 +02:00
2021-07-15 22:34:01 +02:00
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , "/a/1/c/d/2/3" , nil ) , nil ) . ( * DefaultContext )
// `2/3` should mapped to path `/a/:b/c/d/:e` and into `:e`
handler := e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
assert . Equal ( t , "/a/:b/c/d/:e" , c . Path ( ) )
2021-04-27 09:55:31 +02:00
assert . NoError ( t , err )
2021-03-06 01:43:59 +02:00
}
// Issue #1754 - router needs to backtrack multiple levels upwards in tree to find the matching route
// route evaluation order
//
// Routes:
// 1) /a/:b/c
// 2) /a/c/d
// 3) /a/c/df
//
// 4) /a/*/f
// 5) /:e/c/f
//
// 6) /*
//
// Searching route for "/a/c/f" should match "/a/*/f"
// When route `4) /a/*/f` is not added then request for "/a/c/f" should match "/:e/c/f"
//
2022-12-04 22:17:48 +02:00
// +----------+
// +-----+ "/" root +--------------------+--------------------------+
// | +----------+ | |
// | | |
// +-------v-------+ +---v---------+ +-------v---+
// | "a/" (static) +---------------+ | ":" (param) | | "*" (any) |
// +-+----------+--+ | +-----------+-+ +-----------+
// | | | |
//
2021-03-06 01:43:59 +02:00
// +---------------v+ +-- ---v------+ +------v----+ +-----v-----------+
// | "c/d" (static) | | ":" (param) | | "*" (any) | | "/c/f" (static) |
// +---------+------+ +--------+----+ +----------++ +-----------------+
2022-12-04 22:17:48 +02:00
//
// | | |
// | | |
//
2021-03-06 01:43:59 +02:00
// +---------v----+ +------v--------+ +------v--------+
// | "f" (static) | | "/c" (static) | | "/f" (static) |
// +--------------+ +---------------+ +---------------+
func TestRouteMultiLevelBacktracking ( t * testing . T ) {
var testCases = [ ] struct {
name string
whenURL string
expectRoute interface { }
expectParam map [ string ] string
} {
{
name : "route /a/c/df to /a/c/df" ,
whenURL : "/a/c/df" ,
expectRoute : "/a/c/df" ,
} ,
{
name : "route /a/x/df to /a/:b/c" ,
whenURL : "/a/x/c" ,
expectRoute : "/a/:b/c" ,
expectParam : map [ string ] string { "b" : "x" } ,
} ,
{
name : "route /a/x/f to /a/*/f" ,
whenURL : "/a/x/f" ,
expectRoute : "/a/*/f" ,
expectParam : map [ string ] string { "*" : "x/f" } , // NOTE: `x` would be probably more suitable
} ,
{
name : "route /b/c/f to /:e/c/f" ,
whenURL : "/b/c/f" ,
expectRoute : "/:e/c/f" ,
expectParam : map [ string ] string { "e" : "b" } ,
} ,
{
name : "route /b/c/c to /*" ,
whenURL : "/b/c/c" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "b/c/c" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/a/:b/c" , handlerFunc )
e . GET ( "/a/c/d" , handlerFunc )
e . GET ( "/a/c/df" , handlerFunc )
e . GET ( "/a/*/f" , handlerFunc )
e . GET ( "/:e/c/f" , handlerFunc )
e . GET ( "/*" , handlerFunc )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , tc . whenURL , nil ) , nil ) . ( * DefaultContext )
_ = e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
// Issue #1754 - router needs to backtrack multiple levels upwards in tree to find the matching route
// route evaluation order
//
// Request for "/a/c/f" should match "/:e/c/f"
//
2022-12-04 22:17:48 +02:00
// +-0,7--------+
// | "/" (root) |----------------------------------+
// +------------+ |
// | | |
// | | |
// +-1,6-----------+ | | +-8-----------+ +------v----+
// | "a/" (static) +<--+ +--------->+ ":" (param) | | "*" (any) |
// +---------------+ +-------------+ +-----------+
// | | |
// +-2--------v-----+ +v-3,5--------+ +-9------v--------+
// | "c/d" (static) | | ":" (param) | | "/c/f" (static) |
// +----------------+ +-------------+ +-----------------+
// |
// +-4--v----------+
// | "/c" (static) |
// +---------------+
2021-03-06 01:43:59 +02:00
func TestRouteMultiLevelBacktracking2 ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/a/:b/c" , handlerFunc )
e . GET ( "/a/c/d" , handlerFunc )
e . GET ( "/a/c/df" , handlerFunc )
e . GET ( "/:e/c/f" , handlerFunc )
e . GET ( "/*" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
name string
whenURL string
expectRoute string
expectParam map [ string ] string
} {
{
name : "route /a/c/df to /a/c/df" ,
whenURL : "/a/c/df" ,
expectRoute : "/a/c/df" ,
} ,
{
name : "route /a/x/df to /a/:b/c" ,
whenURL : "/a/x/c" ,
expectRoute : "/a/:b/c" ,
expectParam : map [ string ] string { "b" : "x" } ,
} ,
{
name : "route /a/c/f to /:e/c/f" ,
whenURL : "/a/c/f" ,
expectRoute : "/:e/c/f" ,
expectParam : map [ string ] string { "e" : "a" } ,
} ,
{
name : "route /b/c/f to /:e/c/f" ,
whenURL : "/b/c/f" ,
expectRoute : "/:e/c/f" ,
expectParam : map [ string ] string { "e" : "b" } ,
} ,
{
name : "route /b/c/c to /*" ,
whenURL : "/b/c/c" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "b/c/c" } ,
} ,
{ // this traverses `/a/:b/c` and `/:e/c/f` branches and eventually backtracks to `/*`
name : "route /a/c/cf to /*" ,
whenURL : "/a/c/cf" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "a/c/cf" } ,
} ,
{
name : "route /anyMatch to /*" ,
whenURL : "/anyMatch" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "anyMatch" } ,
} ,
{
name : "route /anyMatch/withSlash to /*" ,
whenURL : "/anyMatch/withSlash" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "anyMatch/withSlash" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , tc . whenURL , nil ) , nil ) . ( * DefaultContext )
_ = e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
func TestRouterBacktrackingFromMultipleParamKinds ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/*" , handlerFunc ) // this can match only path that does not have slash in it
e . GET ( "/:1/second" , handlerFunc )
e . GET ( "/:1/:2" , handlerFunc ) // this acts as match ANY for all routes that have at least one slash
e . GET ( "/:1/:2/third" , handlerFunc )
e . GET ( "/:1/:2/:3/fourth" , handlerFunc )
e . GET ( "/:1/:2/:3/:4/fifth" , handlerFunc )
2016-03-07 09:24:51 +02:00
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
name string
whenURL string
expectRoute string
expectParam map [ string ] string
} {
{
name : "route /first to /*" ,
whenURL : "/first" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "first" } ,
} ,
{
name : "route /first/second to /:1/second" ,
whenURL : "/first/second" ,
expectRoute : "/:1/second" ,
expectParam : map [ string ] string { "1" : "first" } ,
} ,
{
name : "route /first/second-new to /:1/:2" ,
whenURL : "/first/second-new" ,
expectRoute : "/:1/:2" ,
expectParam : map [ string ] string {
"1" : "first" ,
"2" : "second-new" ,
} ,
} ,
{ // FIXME: should match `/:1/:2` when backtracking in tree. this 1 level backtracking fails even with old implementation
name : "route /first/second/ to /:1/:2" ,
2021-07-15 22:34:01 +02:00
whenURL : "/first/second/" , /// <-- slash at the end is problematic
2021-03-06 01:43:59 +02:00
expectRoute : "/*" , // "/:1/:2",
expectParam : map [ string ] string { "*" : "first/second/" } , // map[string]string{"1": "first", "2": "second/"},
} ,
{ // FIXME: should match `/:1/:2`. same backtracking problem. when backtracking is at `/:1/:2` during backtracking this node should be match as it has executable handler
name : "route /first/second/third/fourth/fifth/nope to /:1/:2" ,
whenURL : "/first/second/third/fourth/fifth/nope" ,
expectRoute : "/*" , // "/:1/:2",
expectParam : map [ string ] string { "*" : "first/second/third/fourth/fifth/nope" } , // map[string]string{"1": "first", "2": "second/third/fourth/fifth/nope"},
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , tc . whenURL , nil ) , nil ) . ( * DefaultContext )
_ = e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2016-03-07 09:24:51 +02:00
}
2020-02-24 18:26:49 +02:00
// Issue #1509
func TestRouterParamStaticConflict ( t * testing . T ) {
e := New ( )
g := e . Group ( "/g" )
2021-07-15 22:34:01 +02:00
g . GET ( "/skills" , handlerFunc )
g . GET ( "/status" , handlerFunc )
g . GET ( "/:name" , handlerFunc )
2020-02-24 18:26:49 +02:00
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
} {
{
whenURL : "/g/s" ,
expectRoute : "/g/:name" ,
expectParam : map [ string ] string { "name" : "s" } ,
} ,
{
whenURL : "/g/status" ,
expectRoute : "/g/status" ,
expectParam : map [ string ] string { "name" : "" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , tc . whenURL , nil ) , nil ) . ( * DefaultContext )
2020-02-24 18:26:49 +02:00
2021-07-15 22:34:01 +02:00
handler := e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2020-02-24 18:26:49 +02:00
}
2021-09-19 10:39:12 +02:00
func TestRouterParam_escapeColon ( t * testing . T ) {
// to allow Google cloud API like route paths with colon in them
// i.e. https://service.name/v1/some/resource/name:customVerb <- that `:customVerb` is not path param. It is just a string
e := New ( )
e . POST ( "/files/a/long/file\\:undelete" , handlerFunc )
2021-12-16 22:58:40 +02:00
e . POST ( "/multilevel\\:undelete/second\\:something" , handlerFunc )
e . POST ( "/mixed/:id/second\\:something" , handlerFunc )
2021-09-19 10:39:12 +02:00
e . POST ( "/v1/some/resource/name:customVerb" , handlerFunc )
var testCases = [ ] struct {
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-09-19 10:39:12 +02:00
expectParam map [ string ] string
expectError string
} {
{
2021-12-16 22:58:40 +02:00
whenURL : "/files/a/long/file:undelete" ,
2021-09-19 10:39:12 +02:00
expectRoute : "/files/a/long/file\\:undelete" ,
expectParam : map [ string ] string { } ,
} ,
{
2021-12-16 22:58:40 +02:00
whenURL : "/multilevel:undelete/second:something" ,
expectRoute : "/multilevel\\:undelete/second\\:something" ,
expectParam : map [ string ] string { } ,
} ,
{
whenURL : "/mixed/123/second:something" ,
expectRoute : "/mixed/:id/second\\:something" ,
expectParam : map [ string ] string { "id" : "123" } ,
} ,
{
whenURL : "/files/a/long/file:notMatching" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" ,
2021-09-19 10:39:12 +02:00
expectError : "code=404, message=Not Found" ,
expectParam : nil ,
} ,
{
whenURL : "/v1/some/resource/name:PATCH" ,
expectRoute : "/v1/some/resource/name:customVerb" ,
expectParam : map [ string ] string { "customVerb" : ":PATCH" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodPost , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2021-09-19 10:39:12 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
2021-09-19 10:39:12 +02:00
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-09-19 10:39:12 +02:00
if tc . expectError != "" {
assert . EqualError ( t , err , tc . expectError )
} else {
assert . NoError ( t , err )
}
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . PathParam ( param ) )
2021-09-19 10:39:12 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
2015-04-29 08:09:30 +02:00
func TestRouterMatchAny ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2015-09-17 04:28:09 +02:00
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/" , handlerFunc )
e . GET ( "/*" , handlerFunc )
e . GET ( "/users/*" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
} {
{
whenURL : "/" ,
expectRoute : "/" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/download" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "download" } ,
} ,
{
whenURL : "/users/joe" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "joe" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
c := e . NewContext ( httptest . NewRequest ( http . MethodGet , tc . whenURL , nil ) , nil ) . ( * DefaultContext )
2015-04-26 21:44:38 +02:00
2021-07-15 22:34:01 +02:00
handler := e . router . Route ( c )
2015-09-17 04:28:09 +02:00
2021-07-15 22:34:01 +02:00
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2015-03-07 07:55:51 +02:00
}
2021-03-02 20:56:40 +02:00
// NOTE: this is to document current implementation. Last added route with `*` asterisk is always the match and no
// backtracking or more precise matching is done to find more suitable match.
//
// Current behaviour might not be correct or expected.
// But this is where we are without well defined requirements/rules how (multiple) asterisks work in route
func TestRouterAnyMatchesLastAddedAnyRoute ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/users/*" , handlerFunc )
e . GET ( "/users/*/action*" , handlerFunc )
2021-03-02 20:56:40 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , "/users/xxx/action/sea" , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2021-03-02 20:56:40 +02:00
2021-07-15 22:34:01 +02:00
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , "/users/*/action*" , c . Path ( ) )
assert . Equal ( t , "xxx/action/sea" , c . pathParams . Get ( "*" , "" ) )
2021-03-02 20:56:40 +02:00
// if we add another route then it is the last added and so it is matched
2021-07-15 22:34:01 +02:00
e . GET ( "/users/*/action/search" , handlerFunc )
c2 := e . NewContext ( httptest . NewRequest ( http . MethodGet , "/users/xxx/action/sea" , nil ) , nil ) . ( * DefaultContext )
handler2 := e . router . Route ( c2 )
2021-03-02 20:56:40 +02:00
2021-07-15 22:34:01 +02:00
assert . NoError ( t , handler2 ( c2 ) )
assert . Equal ( t , "/users/*/action/search" , c2 . Path ( ) )
assert . Equal ( t , "xxx/action/sea" , c2 . pathParams . Get ( "*" , "" ) )
2021-03-02 20:56:40 +02:00
}
2021-01-03 20:35:00 +02:00
// Issue #1739
func TestRouterMatchAnyPrefixIssue ( t * testing . T ) {
e := New ( )
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/*" , handlerFunc )
e . GET ( "/users/*" , handlerFunc )
2021-01-03 20:35:00 +02:00
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
} {
{
whenURL : "/" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/users" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "users" } ,
} ,
{
whenURL : "/users/" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/users_prefix" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "users_prefix" } ,
} ,
{
whenURL : "/users_prefix/" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "users_prefix/" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2021-03-02 20:56:40 +02:00
2021-07-15 22:34:01 +02:00
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2021-03-02 20:56:40 +02:00
}
2020-05-06 23:01:28 +02:00
// TestRouterMatchAnySlash shall verify finding the best route
// for any routes with trailing slash requests
func TestRouterMatchAnySlash ( t * testing . T ) {
e := New ( )
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/users" , handlerFunc )
e . GET ( "/users/*" , handlerFunc )
e . GET ( "/img/*" , handlerFunc )
e . GET ( "/img/load" , handlerFunc )
e . GET ( "/img/load/*" , handlerFunc )
e . GET ( "/assets/*" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-03-06 01:43:59 +02:00
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" ,
2021-03-06 01:43:59 +02:00
expectParam : map [ string ] string { "*" : "" } ,
expectError : ErrNotFound ,
} ,
{ // Test trailing slash request for simple any route (see #1526)
whenURL : "/users/" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/users/joe" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "joe" } ,
} ,
// Test trailing slash request for nested any route (see #1526)
{
whenURL : "/img/load" ,
expectRoute : "/img/load" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/img/load/" ,
expectRoute : "/img/load/*" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/img/load/ben" ,
expectRoute : "/img/load/*" ,
expectParam : map [ string ] string { "*" : "ben" } ,
} ,
// Test /assets/* any route
{ // ... without trailing slash must not match
whenURL : "/assets" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" ,
2021-03-06 01:43:59 +02:00
expectParam : map [ string ] string { "*" : "" } ,
expectError : ErrNotFound ,
} ,
{ // ... with trailing slash must match
whenURL : "/assets/" ,
expectRoute : "/assets/*" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2020-05-06 23:01:28 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2020-05-06 23:01:28 +02:00
}
2017-06-15 01:30:53 +02:00
func TestRouterMatchAnyMultiLevel ( t * testing . T ) {
e := New ( )
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/api/users/jack" , handlerFunc )
e . GET ( "/api/users/jill" , handlerFunc )
e . GET ( "/api/users/*" , handlerFunc )
e . GET ( "/api/*" , handlerFunc )
e . GET ( "/other/*" , handlerFunc )
e . GET ( "/*" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/api/users/jack" ,
expectRoute : "/api/users/jack" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/api/users/jill" ,
expectRoute : "/api/users/jill" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/api/users/joe" ,
expectRoute : "/api/users/*" ,
expectParam : map [ string ] string { "*" : "joe" } ,
} ,
{
whenURL : "/api/nousers/joe" ,
expectRoute : "/api/*" ,
expectParam : map [ string ] string { "*" : "nousers/joe" } ,
} ,
{
whenURL : "/api/none" ,
expectRoute : "/api/*" ,
expectParam : map [ string ] string { "*" : "none" } ,
} ,
{
whenURL : "/api/none" ,
expectRoute : "/api/*" ,
expectParam : map [ string ] string { "*" : "none" } ,
} ,
{
whenURL : "/noapi/users/jim" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "noapi/users/jim" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2019-10-03 19:30:46 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2017-06-15 01:30:53 +02:00
}
2019-10-16 21:52:10 +02:00
func TestRouterMatchAnyMultiLevelWithPost ( t * testing . T ) {
e := New ( )
// Routes
2021-03-06 01:43:59 +02:00
e . POST ( "/api/auth/login" , handlerFunc )
e . POST ( "/api/auth/forgotPassword" , handlerFunc )
e . Any ( "/api/*" , handlerFunc )
e . Any ( "/*" , handlerFunc )
var testCases = [ ] struct {
whenMethod string
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectError error
} {
{ // POST /api/auth/login shall choose login method
whenURL : "/api/auth/login" ,
whenMethod : http . MethodPost ,
expectRoute : "/api/auth/login" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{ // POST /api/auth/logout shall choose nearest any route
whenURL : "/api/auth/logout" ,
whenMethod : http . MethodPost ,
expectRoute : "/api/*" ,
expectParam : map [ string ] string { "*" : "auth/logout" } ,
} ,
{ // POST to /api/other/test shall choose nearest any route
whenURL : "/api/other/test" ,
whenMethod : http . MethodPost ,
expectRoute : "/api/*" ,
expectParam : map [ string ] string { "*" : "other/test" } ,
} ,
{ // GET to /api/other/test shall choose nearest any route
whenURL : "/api/other/test" ,
whenMethod : http . MethodGet ,
expectRoute : "/api/*" ,
expectParam : map [ string ] string { "*" : "other/test" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2019-10-16 21:52:10 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2019-10-16 21:52:10 +02:00
}
2017-06-15 01:30:53 +02:00
2015-03-19 08:51:32 +02:00
func TestRouterMicroParam ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/:a/:b/:c" , handlerFunc )
req := httptest . NewRequest ( http . MethodGet , "/1/2/3" , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , "1" , c . pathParams . Get ( "a" , "---none---" ) )
assert . Equal ( t , "2" , c . pathParams . Get ( "b" , "---none---" ) )
assert . Equal ( t , "3" , c . pathParams . Get ( "c" , "---none---" ) )
2015-03-01 19:45:13 +02:00
}
2015-03-31 17:26:00 +02:00
2015-09-15 17:29:29 +02:00
func TestRouterMixParamMatchAny ( t * testing . T ) {
e := New ( )
// Route
2021-07-15 22:34:01 +02:00
e . GET ( "/users/:id/*" , handlerFunc )
2015-09-15 17:29:29 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , "/users/joe/comments" , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , "/users/:id/*" , c . Path ( ) )
assert . Equal ( t , "joe" , c . pathParams . Get ( "id" , "---none---" ) )
assert . Equal ( t , "comments" , c . pathParams . Get ( "*" , "---none---" ) )
2015-09-15 17:29:29 +02:00
}
2015-04-13 22:12:30 +02:00
func TestRouterMultiRoute ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2015-04-12 22:04:41 +02:00
2015-04-13 22:12:30 +02:00
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/users" , handlerFunc )
e . GET ( "/users/:id" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenMethod string
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-03-06 01:43:59 +02:00
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/users" ,
expectRoute : "/users" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/users/1" ,
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "1" } ,
} ,
{
whenURL : "/user" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" ,
2021-03-06 01:43:59 +02:00
expectParam : map [ string ] string { "*" : "" } ,
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2015-04-12 22:04:41 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2015-04-13 22:12:30 +02:00
}
2015-05-10 07:06:13 +02:00
func TestRouterPriority ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2015-04-13 22:12:30 +02:00
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/users" , handlerFunc )
e . GET ( "/users/new" , handlerFunc )
e . GET ( "/users/:id" , handlerFunc )
e . GET ( "/users/dew" , handlerFunc )
e . GET ( "/users/:id/files" , handlerFunc )
e . GET ( "/users/newsee" , handlerFunc )
e . GET ( "/users/*" , handlerFunc )
e . GET ( "/users/new/*" , handlerFunc )
e . GET ( "/*" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenMethod string
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/users" ,
expectRoute : "/users" ,
} ,
{
whenURL : "/users/new" ,
expectRoute : "/users/new" ,
} ,
{
whenURL : "/users/1" ,
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "1" } ,
} ,
{
whenURL : "/users/dew" ,
expectRoute : "/users/dew" ,
} ,
{
whenURL : "/users/1/files" ,
expectRoute : "/users/:id/files" ,
expectParam : map [ string ] string { "id" : "1" } ,
} ,
{
whenURL : "/users/new" ,
expectRoute : "/users/new" ,
} ,
{
whenURL : "/users/news" ,
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "news" } ,
} ,
{
whenURL : "/users/newsee" ,
expectRoute : "/users/newsee" ,
} ,
{
whenURL : "/users/joe/books" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "joe/books" } ,
} ,
{
whenURL : "/users/new/someone" ,
expectRoute : "/users/new/*" ,
expectParam : map [ string ] string { "*" : "someone" } ,
} ,
{
whenURL : "/users/dew/someone" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "dew/someone" } ,
} ,
{ // Route > /users/* should be matched although /users/dew exists
whenURL : "/users/notexists/someone" ,
expectRoute : "/users/*" ,
expectParam : map [ string ] string { "*" : "notexists/someone" } ,
} ,
{
whenURL : "/nousers" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "nousers" } ,
} ,
{
whenURL : "/nousers/new" ,
expectRoute : "/*" ,
expectParam : map [ string ] string { "*" : "nousers/new" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2019-10-03 19:30:46 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2019-10-03 19:30:46 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2015-04-11 22:52:40 +02:00
}
2019-07-18 06:18:56 +02:00
func TestRouterIssue1348 ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/:lang/" , handlerFunc )
e . GET ( "/:lang/dupa" , handlerFunc )
2019-07-18 06:18:56 +02:00
}
2016-03-04 08:06:47 +02:00
// Issue #372
func TestRouterPriorityNotFound ( t * testing . T ) {
e := New ( )
// Add
2021-07-15 22:34:01 +02:00
e . GET ( "/a/foo" , handlerFunc )
e . GET ( "/a/bar" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenMethod string
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-03-06 01:43:59 +02:00
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/a/foo" ,
expectRoute : "/a/foo" ,
} ,
{
whenURL : "/a/bar" ,
expectRoute : "/a/bar" ,
} ,
{
whenURL : "/abc/def" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" ,
2021-03-06 01:43:59 +02:00
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2016-03-04 08:06:47 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2016-03-04 08:06:47 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2016-03-04 08:06:47 +02:00
}
2015-04-24 16:44:30 +02:00
func TestRouterParamNames ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2015-04-24 16:44:30 +02:00
// Routes
2021-07-15 22:34:01 +02:00
e . GET ( "/users" , handlerFunc )
e . GET ( "/users/:id" , handlerFunc )
e . GET ( "/users/:uid/files/:fid" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenMethod string
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/users" ,
expectRoute : "/users" ,
} ,
{
whenURL : "/users/1" ,
expectRoute : "/users/:id" ,
expectParam : map [ string ] string { "id" : "1" } ,
} ,
{
whenURL : "/users/1/files/1" ,
expectRoute : "/users/:uid/files/:fid" ,
expectParam : map [ string ] string {
"uid" : "1" ,
"fid" : "1" ,
} ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2015-04-24 16:44:30 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2015-04-24 16:44:30 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2015-04-24 16:44:30 +02:00
}
2019-10-16 21:52:10 +02:00
// Issue #623 and #1406
2016-10-14 23:52:40 +02:00
func TestRouterStaticDynamicConflict ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/dictionary/skills" , handlerFunc )
e . GET ( "/dictionary/:name" , handlerFunc )
e . GET ( "/users/new" , handlerFunc )
e . GET ( "/users/:name" , handlerFunc )
e . GET ( "/server" , handlerFunc )
e . GET ( "/" , handlerFunc )
2016-10-14 23:52:40 +02:00
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenMethod string
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-03-06 01:43:59 +02:00
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/dictionary/skills" ,
expectRoute : "/dictionary/skills" ,
expectParam : map [ string ] string { "*" : "" } ,
} ,
{
whenURL : "/dictionary/skillsnot" ,
expectRoute : "/dictionary/:name" ,
expectParam : map [ string ] string { "name" : "skillsnot" } ,
} ,
{
whenURL : "/dictionary/type" ,
expectRoute : "/dictionary/:name" ,
expectParam : map [ string ] string { "name" : "type" } ,
} ,
{
whenURL : "/server" ,
expectRoute : "/server" ,
} ,
{
whenURL : "/users/new" ,
expectRoute : "/users/new" ,
} ,
{
whenURL : "/users/new2" ,
expectRoute : "/users/:name" ,
expectParam : map [ string ] string { "name" : "new2" } ,
} ,
{
whenURL : "/" ,
expectRoute : "/" ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2019-10-16 21:52:10 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2016-10-14 23:52:40 +02:00
}
2019-07-25 22:39:03 +02:00
// Issue #1348
func TestRouterParamBacktraceNotFound ( t * testing . T ) {
e := New ( )
// Add
2021-07-15 22:34:01 +02:00
e . GET ( "/:param1" , handlerFunc )
e . GET ( "/:param1/foo" , handlerFunc )
e . GET ( "/:param1/bar" , handlerFunc )
e . GET ( "/:param1/bar/:param2" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
name string
whenMethod string
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-03-06 01:43:59 +02:00
expectParam map [ string ] string
expectError error
} {
{
name : "route /a to /:param1" ,
whenURL : "/a" ,
expectRoute : "/:param1" ,
expectParam : map [ string ] string { "param1" : "a" } ,
} ,
{
name : "route /a/foo to /:param1/foo" ,
whenURL : "/a/foo" ,
expectRoute : "/:param1/foo" ,
expectParam : map [ string ] string { "param1" : "a" } ,
} ,
{
name : "route /a/bar to /:param1/bar" ,
whenURL : "/a/bar" ,
expectRoute : "/:param1/bar" ,
expectParam : map [ string ] string { "param1" : "a" } ,
} ,
{
name : "route /a/bar/b to /:param1/bar/:param2" ,
whenURL : "/a/bar/b" ,
expectRoute : "/:param1/bar/:param2" ,
expectParam : map [ string ] string {
"param1" : "a" ,
"param2" : "b" ,
} ,
} ,
{
name : "route /a/bbbbb should return 404" ,
whenURL : "/a/bbbbb" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" ,
2021-03-06 01:43:59 +02:00
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
2019-07-25 22:39:03 +02:00
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( method , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
err := handler ( c )
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2019-07-25 22:39:03 +02:00
}
2021-07-15 22:34:01 +02:00
func testRouterAPI ( t * testing . T , api [ ] testRoute ) {
2015-06-04 00:18:27 +02:00
e := New ( )
2016-11-16 06:09:52 +02:00
for _ , route := range api {
2021-07-15 22:34:01 +02:00
ri , err := e . AddRoute ( Route {
Method : route . Method ,
Path : route . Path ,
Handler : func ( c Context ) error {
return nil
} ,
2016-10-22 05:36:49 +02:00
} )
2021-07-15 22:34:01 +02:00
assert . NoError ( t , err )
assert . NotNil ( t , ri )
2015-06-04 00:18:27 +02:00
}
2021-07-15 22:34:01 +02:00
c := e . NewContext ( nil , nil ) . ( * DefaultContext )
2016-11-16 06:09:52 +02:00
for _ , route := range api {
2021-03-06 01:43:59 +02:00
t . Run ( route . Path , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
c . SetRequest ( httptest . NewRequest ( route . Method , route . Path , nil ) )
e . router . Route ( c )
2021-03-06 01:43:59 +02:00
tokens := strings . Split ( route . Path [ 1 : ] , "/" )
for _ , token := range tokens {
if token [ 0 ] == ':' {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , c . pathParams . Get ( token [ 1 : ] , "---none---" ) , token )
2021-03-06 01:43:59 +02:00
}
2015-06-06 00:08:32 +02:00
}
2021-03-06 01:43:59 +02:00
} )
2015-04-06 06:00:14 +02:00
}
2015-04-06 05:08:52 +02:00
}
2016-11-16 06:09:52 +02:00
func TestRouterGitHubAPI ( t * testing . T ) {
testRouterAPI ( t , gitHubAPI )
}
2021-07-15 22:34:01 +02:00
func TestRouter_Match_DifferentParamNamesForSamePlace ( t * testing . T ) {
var testCases = [ ] struct {
name string
whenURL string
whenMethod string
expectRoute string
expectParam map [ string ] string
expectError error
} {
{
name : "ok, 1=id + 2=file" ,
whenURL : "/users/123/file/payroll.csv" ,
whenMethod : http . MethodGet ,
expectRoute : "/users/:id/file/:file" ,
expectParam : map [ string ] string { "id" : "123" , "file" : "payroll.csv" } ,
} ,
{
name : "ok, 1=id2 + 2=file2" ,
whenURL : "/users/123/file/payroll.csv" ,
whenMethod : http . MethodPost ,
expectRoute : "/users/:id2/file/:file2" ,
expectParam : map [ string ] string { "id2" : "123" , "file2" : "payroll.csv" } ,
} ,
{
name : "ok, 1=uid" ,
whenURL : "/users/999/files" ,
whenMethod : http . MethodGet ,
expectRoute : "/users/:uid/files" ,
expectParam : map [ string ] string { "uid" : "999" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . GET ( "/users/create" , handlerFunc )
e . GET ( "/users/:id/file/:file" , handlerFunc )
e . POST ( "/users/:id2/file/:file2" , handlerFunc )
e . GET ( "/users/:uid/files" , handlerFunc )
req := httptest . NewRequest ( tc . whenMethod , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2022-05-04 13:32:09 +02:00
err := handler ( c )
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
// Issue #2164 - this test is meant to document path parameter behaviour when request url has empty value in place
// of the path parameter. As tests show the result is different depending on where parameter exists in the route path.
func TestDefaultRouter_PathParamsCanMatchEmptyValues ( t * testing . T ) {
var testCases = [ ] struct {
name string
whenURL string
expectRoute string
expectParam map [ string ] string
expectError error
} {
{
name : "ok, route is matched with even empty param is in the middle and between slashes" ,
whenURL : "/a//b" ,
expectRoute : "/a/:id/b" ,
expectParam : map [ string ] string { "id" : "" } ,
} ,
{
name : "ok, route is matched with even empty param is in the middle" ,
whenURL : "/a2/b" ,
expectRoute : "/a2:id/b" ,
expectParam : map [ string ] string { "id" : "" } ,
} ,
{
name : "ok, route is NOT matched with even empty param is at the end" ,
whenURL : "/a3/" ,
expectRoute : "" ,
expectParam : map [ string ] string { } ,
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . GET ( "/a/:id/b" , handlerFunc )
e . GET ( "/a2:id/b" , handlerFunc )
e . GET ( "/a3/:id" , handlerFunc )
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2021-07-15 22:34:01 +02:00
err := handler ( c )
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
2016-11-16 06:09:52 +02:00
// Issue #729
func TestRouterParamAlias ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
api := [ ] testRoute {
2018-10-14 17:16:58 +02:00
{ http . MethodGet , "/users/:userID/following" , "" } ,
{ http . MethodGet , "/users/:userID/followedBy" , "" } ,
{ http . MethodGet , "/users/:userID/follow" , "" } ,
2016-11-16 06:09:52 +02:00
}
testRouterAPI ( t , api )
}
2018-10-07 05:04:30 +02:00
// Issue #1052
func TestRouterParamOrdering ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
api := [ ] testRoute {
2018-10-14 17:16:58 +02:00
{ http . MethodGet , "/:a/:b/:c/:id" , "" } ,
{ http . MethodGet , "/:a/:id" , "" } ,
{ http . MethodGet , "/:a/:e/:id" , "" } ,
2018-10-07 05:04:30 +02:00
}
testRouterAPI ( t , api )
2021-07-15 22:34:01 +02:00
api2 := [ ] testRoute {
2018-10-14 17:16:58 +02:00
{ http . MethodGet , "/:a/:id" , "" } ,
{ http . MethodGet , "/:a/:e/:id" , "" } ,
{ http . MethodGet , "/:a/:b/:c/:id" , "" } ,
2018-10-07 05:04:30 +02:00
}
testRouterAPI ( t , api2 )
2021-07-15 22:34:01 +02:00
api3 := [ ] testRoute {
2018-10-14 17:16:58 +02:00
{ http . MethodGet , "/:a/:b/:c/:id" , "" } ,
{ http . MethodGet , "/:a/:e/:id" , "" } ,
{ http . MethodGet , "/:a/:id" , "" } ,
2018-10-07 05:04:30 +02:00
}
testRouterAPI ( t , api3 )
}
// Issue #1139
func TestRouterMixedParams ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
api := [ ] testRoute {
2018-10-14 17:16:58 +02:00
{ http . MethodGet , "/teacher/:tid/room/suggestions" , "" } ,
{ http . MethodGet , "/teacher/:id" , "" } ,
2018-10-07 05:04:30 +02:00
}
testRouterAPI ( t , api )
2021-07-15 22:34:01 +02:00
api2 := [ ] testRoute {
2018-10-14 17:16:58 +02:00
{ http . MethodGet , "/teacher/:id" , "" } ,
{ http . MethodGet , "/teacher/:tid/room/suggestions" , "" } ,
2018-10-07 05:04:30 +02:00
}
testRouterAPI ( t , api2 )
}
2020-01-01 18:57:00 +02:00
// Issue #1466
func TestRouterParam1466 ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . POST ( "/users/signup" , handlerFunc )
e . POST ( "/users/signup/bulk" , handlerFunc )
e . POST ( "/users/survey" , handlerFunc )
e . GET ( "/users/:username" , handlerFunc )
e . GET ( "/interests/:name/users" , handlerFunc )
e . GET ( "/skills/:name/users" , handlerFunc )
2020-01-24 02:13:18 +02:00
// Additional routes for Issue 1479
2021-07-15 22:34:01 +02:00
e . GET ( "/users/:username/likes/projects/ids" , handlerFunc )
e . GET ( "/users/:username/profile" , handlerFunc )
e . GET ( "/users/:username/uploads/:type" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenURL string
2021-07-15 22:34:01 +02:00
expectRoute string
2021-03-06 01:43:59 +02:00
expectParam map [ string ] string
2021-07-15 22:34:01 +02:00
expectError error
2021-03-06 01:43:59 +02:00
} {
{
whenURL : "/users/ajitem" ,
expectRoute : "/users/:username" ,
expectParam : map [ string ] string { "username" : "ajitem" } ,
} ,
{
whenURL : "/users/sharewithme" ,
expectRoute : "/users/:username" ,
expectParam : map [ string ] string { "username" : "sharewithme" } ,
} ,
2021-04-27 09:55:31 +02:00
{ // route `/users/signup` is registered for POST. so param route `/users/:username` (lesser priority) is matched as it has GET handler
2021-03-06 01:43:59 +02:00
whenURL : "/users/signup" ,
2021-04-27 09:55:31 +02:00
expectRoute : "/users/:username" ,
expectParam : map [ string ] string { "username" : "signup" } ,
2021-03-06 01:43:59 +02:00
} ,
// Additional assertions for #1479
{
whenURL : "/users/sharewithme/likes/projects/ids" ,
expectRoute : "/users/:username/likes/projects/ids" ,
expectParam : map [ string ] string { "username" : "sharewithme" } ,
} ,
{
whenURL : "/users/ajitem/likes/projects/ids" ,
expectRoute : "/users/:username/likes/projects/ids" ,
expectParam : map [ string ] string { "username" : "ajitem" } ,
} ,
{
whenURL : "/users/sharewithme/profile" ,
expectRoute : "/users/:username/profile" ,
expectParam : map [ string ] string { "username" : "sharewithme" } ,
} ,
{
whenURL : "/users/ajitem/profile" ,
expectRoute : "/users/:username/profile" ,
expectParam : map [ string ] string { "username" : "ajitem" } ,
} ,
{
whenURL : "/users/sharewithme/uploads/self" ,
expectRoute : "/users/:username/uploads/:type" ,
expectParam : map [ string ] string {
"username" : "sharewithme" ,
"type" : "self" ,
} ,
} ,
{
whenURL : "/users/ajitem/uploads/self" ,
expectRoute : "/users/:username/uploads/:type" ,
expectParam : map [ string ] string {
"username" : "ajitem" ,
"type" : "self" ,
} ,
} ,
{
whenURL : "/users/tree/free" ,
2021-07-15 22:34:01 +02:00
expectRoute : "" , // not found
2021-03-06 01:43:59 +02:00
expectParam : map [ string ] string { "id" : "" } ,
2021-07-15 22:34:01 +02:00
expectError : ErrNotFound ,
2021-03-06 01:43:59 +02:00
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
2021-03-06 01:43:59 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2020-01-01 18:57:00 +02:00
}
2020-10-28 06:30:41 +02:00
// Issue #1655
func TestRouterFindNotPanicOrLoopsWhenContextSetParamValuesIsCalledWithLessValuesThanEchoMaxParam ( t * testing . T ) {
e := New ( )
v0 := e . Group ( "/:version" )
v0 . GET ( "/admin" , func ( c Context ) error {
2021-07-15 22:34:01 +02:00
c . SetPathParams ( PathParams { {
Name : "version" ,
Value : "v1" ,
} } )
2020-10-28 06:30:41 +02:00
return nil
} )
v0 . GET ( "/images/view/:id" , handlerHelper ( "iv" , 1 ) )
v0 . GET ( "/images/:id" , handlerHelper ( "i" , 1 ) )
v0 . GET ( "/view/*" , handlerHelper ( "v" , 1 ) )
//If this API is called before the next two one panic the other loops ( of course without my fix ;) )
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , "/v1/admin" , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := e . router . Route ( c )
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , "v1" , c . PathParam ( "version" ) )
2020-10-28 06:30:41 +02:00
//panic
2021-07-15 22:34:01 +02:00
req = httptest . NewRequest ( http . MethodGet , "/v1/view/same-data" , nil )
c = e . NewContext ( req , nil ) . ( * DefaultContext )
handler = e . router . Route ( c )
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , "same-data" , c . PathParam ( "*" ) )
2020-10-28 06:30:41 +02:00
assert . Equal ( t , 1 , c . Get ( "v" ) )
//looping
2021-07-15 22:34:01 +02:00
req = httptest . NewRequest ( http . MethodGet , "/v1/images/view" , nil )
c = e . NewContext ( req , nil ) . ( * DefaultContext )
handler = e . router . Route ( c )
assert . NoError ( t , handler ( c ) )
assert . Equal ( t , "view" , c . PathParam ( "id" ) )
2020-10-28 06:30:41 +02:00
assert . Equal ( t , 1 , c . Get ( "i" ) )
}
2020-10-25 06:03:07 +02:00
// Issue #1653
func TestRouterPanicWhenParamNoRootOnlyChildsFailsFind ( t * testing . T ) {
e := New ( )
2021-07-15 22:34:01 +02:00
e . GET ( "/users/create" , handlerFunc )
e . GET ( "/users/:id/edit" , handlerFunc )
e . GET ( "/users/:id/active" , handlerFunc )
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
2021-07-15 22:34:01 +02:00
whenURL string
expectRoute string
expectParam map [ string ] string
expectError error
2021-03-06 01:43:59 +02:00
} {
{
whenURL : "/users/alice/edit" ,
expectRoute : "/users/:id/edit" ,
expectParam : map [ string ] string { "id" : "alice" } ,
} ,
{
whenURL : "/users/bob/active" ,
expectRoute : "/users/:id/active" ,
expectParam : map [ string ] string { "id" : "bob" } ,
} ,
{
whenURL : "/users/create" ,
expectRoute : "/users/create" ,
expectParam : nil ,
} ,
//This panic before the fix for Issue #1653
{
2021-07-15 22:34:01 +02:00
whenURL : "/users/createNotFound" ,
expectError : ErrNotFound ,
2021-03-06 01:43:59 +02:00
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
2020-10-25 06:03:07 +02:00
2021-07-15 22:34:01 +02:00
handler := e . router . Route ( c )
2020-10-25 06:03:07 +02:00
2021-07-15 22:34:01 +02:00
err := handler ( c )
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
2021-03-06 01:43:59 +02:00
}
2021-07-15 22:34:01 +02:00
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
2021-03-06 01:43:59 +02:00
for param , expectedValue := range tc . expectParam {
2021-07-15 22:34:01 +02:00
assert . Equal ( t , expectedValue , c . pathParams . Get ( param , "---none---" ) )
2021-03-06 01:43:59 +02:00
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2020-10-25 06:03:07 +02:00
}
2021-07-15 22:34:01 +02:00
func TestRoutes_ReverseHandlerName ( t * testing . T ) {
static := func ( Context ) error { return nil }
getUser := func ( Context ) error { return nil }
getAny := func ( Context ) error { return nil }
getFile := func ( Context ) error { return nil }
2021-12-04 20:02:11 +02:00
var testCases = [ ] struct {
2021-07-15 22:34:01 +02:00
name string
when string
whenArgs [ ] interface { }
expect string
expectErr string
2021-12-04 20:02:11 +02:00
} {
{
2021-07-15 22:34:01 +02:00
name : "ok, HandlerName + args" ,
when : HandlerName ( getFile ) ,
whenArgs : [ ] interface { } { "1" } ,
expect : "/group/users/1/files/:fid" ,
2021-12-04 20:02:11 +02:00
} ,
{
2021-07-15 22:34:01 +02:00
name : "ok, HandlerName" ,
when : HandlerName ( getFile ) ,
expect : "/group/users/:uid/files/:fid" ,
2021-12-04 20:02:11 +02:00
} ,
{
2021-07-15 22:34:01 +02:00
name : "ok, unnamed fixed name" ,
when : "GET:/static/file" ,
expect : "/static/file" ,
2021-12-04 20:02:11 +02:00
} ,
{
2021-07-15 22:34:01 +02:00
name : "ok, unnamed fixed name" ,
when : "GET:/users/:id" ,
expect : "/users/:id" ,
} ,
{
name : "ok, unnamed any route" ,
when : "POST:/documents/*" ,
expect : "/documents/*" ,
} ,
{
name : "ok, unnamed any route + args" ,
when : "GET:/documents/*" ,
whenArgs : [ ] interface { } { "index.html" } ,
expect : "/documents/index.html" ,
} ,
{
name : "ok, named route + args" ,
when : HandlerName ( getFile ) ,
whenArgs : [ ] interface { } { "1" , "abc" } ,
expect : "/group/users/1/files/abc" ,
2021-12-04 20:02:11 +02:00
} ,
}
2021-07-15 22:34:01 +02:00
2021-12-04 20:02:11 +02:00
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
2021-07-15 22:34:01 +02:00
e := New ( )
e . GET ( "/static/file" , static )
e . GET ( "/users/:id" , getUser )
e . Any ( "/documents/*" , getAny )
2021-12-04 20:02:11 +02:00
2021-07-15 22:34:01 +02:00
g := e . Group ( "/group" )
g . GET ( "/roles/:rid/files/:fid" , getFile )
g . AddRoute ( Route { Method : http . MethodGet , Path : "/users/:uid/files/:fid" , Handler : getFile , Name : HandlerName ( getFile ) } )
2021-12-04 20:02:11 +02:00
2021-07-15 22:34:01 +02:00
reversed , err := e . Router ( ) . Routes ( ) . Reverse ( tc . when , tc . whenArgs ... )
assert . Equal ( t , tc . expect , reversed )
if tc . expectErr != "" {
assert . EqualError ( t , err , tc . expectErr )
2021-12-04 20:02:11 +02:00
} else {
assert . NoError ( t , err )
}
} )
}
}
2021-07-15 22:34:01 +02:00
func TestRoutes_Reverse ( t * testing . T ) {
var testCases = [ ] struct {
name string
when string
whenArgs [ ] interface { }
expect string
expectErr string
} {
{
name : "ok, static" ,
when : "/static" ,
expect : "/static" ,
} ,
{
name : "ok, static + args" ,
when : "/static" ,
whenArgs : [ ] interface { } { "missing param" } ,
expect : "/static" ,
} ,
{
name : "ok, static/*" ,
when : "/static/*" ,
expect : "/static/*" ,
} ,
{
name : "ok, static/*" ,
when : "/static/*" ,
whenArgs : [ ] interface { } { "foo.txt" } ,
expect : "/static/foo.txt" ,
} ,
{
name : "ok, /params/:foo" ,
when : "/params/:foo" ,
expect : "/params/:foo" ,
} ,
{
name : "ok, /params/:foo + args" ,
when : "/params/:foo" ,
whenArgs : [ ] interface { } { "one" } ,
expect : "/params/one" ,
} ,
{
name : "ok, /params/:foo/bar/:qux" ,
when : "/params/:foo/bar/:qux" ,
expect : "/params/:foo/bar/:qux" ,
} ,
{
name : "ok, /params/:foo/bar/:qux + args1" ,
when : "/params/:foo/bar/:qux" ,
whenArgs : [ ] interface { } { "one" } ,
expect : "/params/one/bar/:qux" ,
} ,
{
name : "ok, /params/:foo/bar/:qux + args2" ,
when : "/params/:foo/bar/:qux" ,
whenArgs : [ ] interface { } { "one" , "two" } ,
expect : "/params/one/bar/two" ,
} ,
{
name : "ok, /params/:foo/bar/:qux/* + args3" ,
when : "/params/:foo/bar/:qux/*" ,
whenArgs : [ ] interface { } { "one" , "two" , "three" } ,
expect : "/params/one/bar/two/three" ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
dummyHandler := func ( Context ) error { return nil }
router := NewRouter ( RouterConfig { } )
router . Add ( Route { Path : "/static" , Name : "/static" , Method : http . MethodGet , Handler : dummyHandler } )
router . Add ( Route { Path : "/static/*" , Name : "/static/*" , Method : http . MethodGet , Handler : dummyHandler } )
router . Add ( Route { Path : "/params/:foo" , Name : "/params/:foo" , Method : http . MethodGet , Handler : dummyHandler } )
router . Add ( Route { Path : "/params/:foo/bar/:qux" , Name : "/params/:foo/bar/:qux" , Method : http . MethodGet , Handler : dummyHandler } )
router . Add ( Route { Path : "/params/:foo/bar/:qux/*" , Name : "/params/:foo/bar/:qux/*" , Method : http . MethodGet , Handler : dummyHandler } )
reversed , err := router . Routes ( ) . Reverse ( tc . when , tc . whenArgs ... )
assert . Equal ( t , tc . expect , reversed )
if tc . expectErr != "" {
assert . EqualError ( t , err , tc . expectErr )
} else {
assert . NoError ( t , err )
}
} )
}
}
func TestRouter_Routes ( t * testing . T ) {
routes := [ ] * Route {
{ Method : http . MethodGet , Path : "/users/:user/events" } ,
{ Method : http . MethodGet , Path : "/users/:user/events/public" } ,
{ Method : http . MethodPost , Path : "/repos/:owner/:repo/git/refs" } ,
{ Method : http . MethodPost , Path : "/repos/:owner/:repo/git/tags" } ,
}
router := NewRouter ( RouterConfig { } )
for _ , r := range routes {
_ , err := router . Add ( Route {
Method : r . Method ,
Path : r . Path ,
Handler : func ( c Context ) error {
return c . String ( http . StatusOK , "OK" )
} ,
} )
if err != nil {
t . Fatal ( err )
}
}
assert . Equal ( t , len ( routes ) , len ( router . Routes ( ) ) )
for _ , r := range router . Routes ( ) {
found := false
for _ , rr := range routes {
if r . Method ( ) == rr . Method && r . Path ( ) == rr . Path {
found = true
break
}
}
if ! found {
t . Errorf ( "Route %s %s not found" , r . Method ( ) , r . Path ( ) )
}
}
}
2023-02-28 22:12:14 +02:00
func TestRouterNoRoutablePath ( t * testing . T ) {
e := New ( )
e . router . Add ( Route { Path : "/static" , Name : "/static" , Method : http . MethodGet , Handler : func ( Context ) error { return nil } } )
req := httptest . NewRequest ( http . MethodGet , "/notFound" , nil )
c := e . NewContext ( req , nil )
e . router . Route ( c . ( RoutableContext ) )
// No routable path, don't set Path.
assert . Equal ( t , "" , c . Path ( ) )
}
2021-07-15 22:34:01 +02:00
func benchmarkRouterRoutes ( b * testing . B , routes [ ] testRoute , routesToFind [ ] testRoute ) {
2016-03-18 06:49:06 +02:00
e := New ( )
r := e . router
2022-12-04 22:17:48 +02:00
req := httptest . NewRequest ( http . MethodGet , "/" , nil )
2016-03-18 17:47:03 +02:00
b . ReportAllocs ( )
2016-03-18 06:49:06 +02:00
// Add routes
2016-11-12 19:42:25 +02:00
for _ , route := range routes {
2021-07-15 22:34:01 +02:00
e . AddRoute ( Route {
Method : route . Method ,
Path : route . Path ,
Handler : func ( c Context ) error {
return nil
} ,
2016-10-22 05:36:49 +02:00
} )
2016-03-18 06:49:06 +02:00
}
2020-11-21 04:48:16 +02:00
// Routes adding are performed just once, so it doesn't make sense to see that in the benchmark
b . ResetTimer ( )
2016-03-18 06:49:06 +02:00
// Find routes
for i := 0 ; i < b . N ; i ++ {
2020-11-21 04:48:16 +02:00
for _ , route := range routesToFind {
2021-07-15 22:34:01 +02:00
c := e . contextPool . Get ( ) . ( * DefaultContext )
c . request = req
req . Method = route . Method
req . URL . Path = route . Path
_ = r . Route ( c )
e . contextPool . Put ( c )
2016-03-18 06:49:06 +02:00
}
}
}
2021-07-15 22:34:01 +02:00
func TestDefaultRouter_Remove ( t * testing . T ) {
var testCases = [ ] struct {
name string
givenPaths [ ] string
whenMethod string
whenPath string
expectErr string
} {
{
name : "ok, static" ,
whenPath : "/users" ,
} ,
{
name : "ok, static without slash" ,
whenPath : "users" ,
} ,
{
name : "ok, multilevel static" ,
whenPath : "/users/newsee" ,
} ,
{
name : "ok, static with path params" ,
whenPath : "/users/:id/files" ,
} ,
{
name : "ok, path params" ,
whenPath : "/users/:id" ,
} ,
{
name : "ok, any" ,
whenPath : "/users/new/*" ,
} ,
{
name : "ok, any root" ,
whenPath : "/*" ,
} ,
{
name : "ok, multilevel any" ,
whenPath : "/users/dew/*" ,
} ,
{
name : "ok, single root" ,
givenPaths : [ ] string { "/users" } ,
whenPath : "/users" ,
} ,
{
name : "nok, no routes, nothing to remove" ,
givenPaths : [ ] string { } ,
whenPath : "/users/" ,
expectErr : "router has no routes to remove" ,
} ,
{
name : "nok, route not found (matches partial node)" ,
whenPath : "/users/" ,
expectErr : "could not find route to remove by given path" ,
} ,
{
name : "nok, route not found (matches partial node)" ,
whenPath : "" ,
expectErr : "could not find route to remove by given path" ,
} ,
{
name : "nok, route not found" ,
whenPath : "/this_is_not_existent" ,
expectErr : "could not find route to remove by given path" ,
} ,
{
name : "nok, multilevel static but different method" ,
whenPath : "/users/newsee" ,
whenMethod : http . MethodPost ,
expectErr : "could not find route to remove by given path and method" ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
paths := [ ] string {
"/users" ,
"/users/new" ,
"/users/:id" ,
"/users/dew" ,
"/users/dew/*" ,
"/users/:id/files" ,
"/users/newsee" ,
"/users/new/new" ,
"/users/new/*" ,
"/*" ,
}
if tc . givenPaths != nil {
paths = tc . givenPaths
}
index := - 1
for i , p := range paths {
e . GET ( p , handlerFunc )
if p == tc . whenPath {
index = i
}
}
var toCheckPaths [ ] string
if index != - 1 {
toCheckPaths = append ( paths [ : index ] , paths [ index + 1 : ] ... )
}
method := tc . whenMethod
if method == "" {
method = http . MethodGet
}
err := e . Router ( ) . Remove ( method , tc . whenPath )
if tc . expectErr != "" {
assert . EqualError ( t , err , tc . expectErr )
} else {
assert . NoError ( t , err )
}
for _ , p := range toCheckPaths {
req := httptest . NewRequest ( http . MethodGet , p , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
_ = e . Router ( ) . Route ( c )
assert . Equal ( t , p , c . Path ( ) , "after removing %v we matched wrong route. when matching: %v, got: %v" , tc . whenPath , p , c . Path ( ) )
}
} )
}
}
func TestDefaultRouter_AddWithoutHandler ( t * testing . T ) {
router := NewRouter ( RouterConfig { } )
ri , err := router . Add ( Route { Method : http . MethodGet , Path : "/info" , Handler : nil } )
assert . EqualError ( t , err , "GET /info: adding route without handler function" )
assert . Nil ( t , ri )
}
func TestDefaultRouter_AddDuplicateRouteNotAllowed ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig { } )
e . router = router
ri , err := router . Add ( Route {
Method : http . MethodGet ,
Path : "/info" ,
Handler : func ( c Context ) error {
return c . String ( http . StatusTeapot , "OLD" )
} ,
Name : "old" ,
} )
assert . NoError ( t , err )
assert . NotNil ( t , ri )
ri , err = router . Add ( Route { Method : http . MethodGet , Path : "/info" , Handler : handlerFunc , Name : "new" } )
assert . Nil ( t , ri )
assert . EqualError ( t , err , "GET /info: adding duplicate route (same method+path) is not allowed" )
assert . Len ( t , router . Routes ( ) , 1 )
status , body := request ( http . MethodGet , "/info" , e )
assert . Equal ( t , http . StatusTeapot , status )
assert . Equal ( t , "OLD" , body )
}
func TestName ( t * testing . T ) {
}
// See issue #1531, #1258 - there are cases when path parameter need to be unescaped
func TestDefaultRouter_UnescapePathParamValues ( t * testing . T ) {
var testCases = [ ] struct {
name string
givenUnescapePathParamValues bool
whenURL string
expectPath string
expectPathParams PathParams
} {
{
name : "ok, unescape = true" ,
givenUnescapePathParamValues : true ,
whenURL : "/first/value%20with%20space" ,
expectPath : "/first/:raw" ,
expectPathParams : PathParams {
{
Name : "raw" ,
Value : "value with space" ,
} ,
} ,
} ,
{
name : "ok, multiple, unescape = true" ,
givenUnescapePathParamValues : true ,
whenURL : "/second/%20/with%20space" ,
expectPath : "/second/:id/:fileName" ,
expectPathParams : PathParams {
{ Name : "id" , Value : " " } ,
{ Name : "fileName" , Value : "with space" } ,
} ,
} ,
{
name : "ok, any route, unescape = true" ,
givenUnescapePathParamValues : true ,
whenURL : "/third/%20%2Fwith%20space" ,
expectPath : "/third/*" ,
expectPathParams : PathParams {
{ Name : "*" , Value : " /with space" } ,
} ,
} ,
2023-07-22 22:25:34 +02:00
{
name : "ok, ending with static node, unescape = true" ,
givenUnescapePathParamValues : true ,
whenURL : "/fourth/%20%2Fwith%20space/static" ,
expectPath : "/fourth/:id/static" ,
expectPathParams : PathParams {
{ Name : "id" , Value : " /with space" } ,
} ,
} ,
2021-07-15 22:34:01 +02:00
{
name : "ok, unescape = false" ,
givenUnescapePathParamValues : false ,
whenURL : "/first/value%20with%20space" ,
expectPath : "/first/:raw" ,
expectPathParams : PathParams {
{
Name : "raw" ,
Value : "value%20with%20space" ,
} ,
} ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig { UnescapePathParamValues : tc . givenUnescapePathParamValues } )
e . router = router
e . contextPathParamAllocSize = 2
_ , err := router . Add ( Route { Method : http . MethodGet , Path : "/first/:raw" , Handler : handlerFunc } )
assert . NoError ( t , err )
_ , err = router . Add ( Route { Method : http . MethodGet , Path : "/second/:id/:fileName" , Handler : handlerFunc } )
assert . NoError ( t , err )
_ , err = router . Add ( Route { Method : http . MethodGet , Path : "/third/*" , Handler : handlerFunc } )
assert . NoError ( t , err )
2023-07-22 22:25:34 +02:00
_ , err = router . Add ( Route { Method : http . MethodGet , Path : "/fourth/:id/static" , Handler : handlerFunc } )
assert . NoError ( t , err )
2021-07-15 22:34:01 +02:00
target , _ := url . Parse ( tc . whenURL )
req := httptest . NewRequest ( http . MethodGet , target . String ( ) , nil )
req . URL . RawPath = tc . whenURL
c := e . NewContext ( req , nil ) . ( * DefaultContext )
_ = e . Router ( ) . Route ( c )
assert . Equal ( t , tc . expectPath , c . Path ( ) )
assert . Equal ( t , tc . expectPathParams , c . PathParams ( ) )
} )
}
}
func TestDefaultRouter_AddDuplicateRouteAllowed ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig { AllowOverwritingRoute : true } )
e . router = router
ri , err := router . Add ( Route { Method : http . MethodGet , Path : "/info" , Handler : handlerFunc , Name : "old" } )
assert . NoError ( t , err )
assert . Equal ( t , ri , routeInfo {
method : http . MethodGet ,
path : "/info" ,
name : "old" ,
} )
ri , err = router . Add ( Route {
Method : http . MethodGet ,
Path : "/info" ,
Handler : func ( c Context ) error {
return c . String ( http . StatusTeapot , "NEW" )
} ,
Name : "new" ,
} )
assert . NoError ( t , err )
assert . Equal ( t , ri , routeInfo {
method : http . MethodGet ,
path : "/info" ,
name : "new" ,
} )
routes := router . Routes ( )
assert . Len ( t , routes , 1 )
assert . Equal ( t , "new" , routes [ 0 ] . Name ( ) )
status , body := request ( http . MethodGet , "/info" , e )
assert . Equal ( t , http . StatusTeapot , status )
assert . Equal ( t , "NEW" , body )
}
func TestDefaultRouter_UseEscapedPathForRouting ( t * testing . T ) {
var testCases = [ ] struct {
name string
givenDoNotUseEscapedPathForRouting bool
whenRawPath string
expectBody string
expectStatus int
} {
{
name : "ok, static route" ,
whenRawPath : "/what's%20up" ,
expectBody : "/what's up" ,
expectStatus : http . StatusTeapot ,
} ,
{
name : "nok, rawPath does not match with route path" ,
givenDoNotUseEscapedPathForRouting : true ,
whenRawPath : "/what's%20up" , // route is "/what's up"
expectBody : "{\"message\":\"Not Found\"}\n" ,
expectStatus : http . StatusNotFound ,
} ,
{
name : "ok, match path param" ,
whenRawPath : "/test/what's%20up" ,
expectBody : "/test/:param|what's up" ,
expectStatus : http . StatusTeapot ,
} ,
{
name : "ok, path param is unescaped as it is in rawPath" ,
givenDoNotUseEscapedPathForRouting : true ,
whenRawPath : "/test/what's%20up" ,
expectBody : "/test/:param|what's%20up" ,
expectStatus : http . StatusTeapot ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig { UseEscapedPathForMatching : ! tc . givenDoNotUseEscapedPathForRouting } )
e . router = router
e . contextPathParamAllocSize = 1
ri , err := router . Add ( Route {
Method : http . MethodGet ,
Path : "/what's up" ,
Handler : func ( c Context ) error {
return c . String ( http . StatusTeapot , c . RouteInfo ( ) . Path ( ) )
} ,
} )
assert . NoError ( t , err )
assert . NotNil ( t , ri )
ri , err = router . Add ( Route {
Method : http . MethodGet ,
Path : "/test/:param" ,
Handler : func ( c Context ) error {
return c . String ( http . StatusTeapot , c . RouteInfo ( ) . Path ( ) + "|" + c . PathParam ( "param" ) )
} ,
} )
assert . NoError ( t , err )
assert . NotNil ( t , ri )
status , body := request ( http . MethodGet , tc . whenRawPath , e )
assert . Equal ( t , tc . expectStatus , status )
assert . Equal ( t , tc . expectBody , body )
} )
}
}
func TestDefaultRouter_NotFoundHandler ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig {
NotFoundHandler : func ( c Context ) error {
return c . String ( http . StatusTeapot , "404" )
} ,
} )
e . router = router
e . GET ( "/test" , func ( c Context ) error {
return c . String ( http . StatusOK , "OK" )
} )
status , body := request ( http . MethodGet , "/noFound" , e )
assert . Equal ( t , http . StatusTeapot , status )
assert . Equal ( t , "404" , body )
}
func TestDefaultRouter_MethodNotAllowedHandler ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig {
MethodNotAllowedHandler : func ( c Context ) error {
return c . String ( http . StatusTeapot , "405" )
} ,
} )
e . router = router
e . GET ( "/test" , func ( c Context ) error {
return c . String ( http . StatusOK , "OK" )
} )
status , body := request ( http . MethodPost , "/test" , e )
assert . Equal ( t , http . StatusTeapot , status )
assert . Equal ( t , "405" , body )
}
func TestDefaultRouter_OptionsMethodHandler ( t * testing . T ) {
e := New ( )
router := NewRouter ( RouterConfig {
OptionsMethodHandler : func ( c Context ) error {
return c . String ( http . StatusBadRequest , "not empty" )
} ,
} )
e . router = router
e . GET ( "/test" , func ( c Context ) error {
return c . String ( http . StatusOK , "OK" )
} )
status , body := request ( http . MethodOptions , "/test" , e )
assert . Equal ( t , http . StatusBadRequest , status )
assert . Equal ( t , "not empty" , body )
}
2022-07-17 21:19:09 +02:00
func TestRouter_RouteWhenNotFoundRouteWithNodeSplitting ( t * testing . T ) {
e := New ( )
r := e . router
hf := func ( c Context ) error {
return c . String ( http . StatusOK , c . RouteInfo ( ) . Name ( ) )
}
r . Add ( Route { Method : http . MethodGet , Path : "/test*" , Handler : hf , Name : "0" } )
r . Add ( Route { Method : RouteNotFound , Path : "/test*" , Handler : hf , Name : "1" } )
r . Add ( Route { Method : RouteNotFound , Path : "/test" , Handler : hf , Name : "2" } )
// Tree before:
// 1 `/`
// 1.1 `*` (any) ID=1
// 1.2 `test` (static) ID=2
// 1.2.1 `*` (any) ID=0
// node with path `test` has routeNotFound handler from previous Add call. Now when we insert `/te/st*` into router tree
// This means that node `test` is split into `te` and `st` nodes and new node `/st*` is inserted.
// On that split `/test` routeNotFound handler must not be lost.
r . Add ( Route { Method : http . MethodGet , Path : "/te/st*" , Handler : hf , Name : "3" } )
// Tree after:
// 1 `/`
// 1.1 `*` (any) ID=1
// 1.2 `te` (static)
// 1.2.1 `st` (static) ID=2
// 1.2.1.1 `*` (any) ID=0
// 1.2.2 `/st` (static)
// 1.2.2.1 `*` (any) ID=3
_ , body := request ( http . MethodPut , "/test" , e )
assert . Equal ( t , "2" , body )
}
func TestRouter_RouteWhenNotFoundRouteAnyKind ( t * testing . T ) {
var testCases = [ ] struct {
name string
whenURL string
expectRoute interface { }
expectID int
expectParam map [ string ] string
} {
{
name : "route not existent /xx to not found handler /*" ,
whenURL : "/xx" ,
expectRoute : "/*" ,
expectID : 4 ,
expectParam : map [ string ] string { "*" : "xx" } ,
} ,
{
name : "route not existent /a/xx to not found handler /a/*" ,
whenURL : "/a/xx" ,
expectRoute : "/a/*" ,
expectID : 5 ,
expectParam : map [ string ] string { "*" : "xx" } ,
} ,
{
name : "route not existent /a/c/dxxx to not found handler /a/c/d*" ,
whenURL : "/a/c/dxxx" ,
expectRoute : "/a/c/d*" ,
expectID : 6 ,
expectParam : map [ string ] string { "*" : "xxx" } ,
} ,
{
name : "route /a/c/df to /a/c/df" ,
whenURL : "/a/c/df" ,
expectRoute : "/a/c/df" ,
expectID : 1 ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . contextPathParamAllocSize = 1
r := e . router
r . Add ( Route { Method : http . MethodGet , Path : "/" , Handler : handlerHelper ( "ID" , 0 ) , Name : "0" } )
r . Add ( Route { Method : http . MethodGet , Path : "/a/c/df" , Handler : handlerHelper ( "ID" , 1 ) , Name : "1" } )
r . Add ( Route { Method : http . MethodGet , Path : "/a/b*" , Handler : handlerHelper ( "ID" , 2 ) , Name : "2" } )
r . Add ( Route { Method : http . MethodPut , Path : "/*" , Handler : handlerHelper ( "ID" , 3 ) , Name : "3" } )
r . Add ( Route { Method : RouteNotFound , Path : "/a/c/d*" , Handler : handlerHelper ( "ID" , 6 ) , Name : "6" } )
r . Add ( Route { Method : RouteNotFound , Path : "/a/*" , Handler : handlerHelper ( "ID" , 5 ) , Name : "5" } )
r . Add ( Route { Method : RouteNotFound , Path : "/*" , Handler : handlerHelper ( "ID" , 4 ) , Name : "4" } )
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := r . Route ( c )
handler ( c )
testValue , _ := c . Get ( "ID" ) . ( int )
assert . Equal ( t , tc . expectID , testValue )
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . PathParam ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
func TestRouter_RouteWhenNotFoundRouteParamKind ( t * testing . T ) {
var testCases = [ ] struct {
name string
whenURL string
expectRoute interface { }
expectID int
expectParam map [ string ] string
} {
{
name : "route not existent /xx to not found handler /:file" ,
whenURL : "/xx" ,
expectRoute : "/:file" ,
expectID : 4 ,
expectParam : map [ string ] string { "file" : "xx" } ,
} ,
{
name : "route not existent /a/xx to not found handler /a/:file" ,
whenURL : "/a/xx" ,
expectRoute : "/a/:file" ,
expectID : 5 ,
expectParam : map [ string ] string { "file" : "xx" } ,
} ,
{
name : "route not existent /a/c/dxxx to not found handler /a/c/d:file" ,
whenURL : "/a/c/dxxx" ,
expectRoute : "/a/c/d:file" ,
expectID : 6 ,
expectParam : map [ string ] string { "file" : "xxx" } ,
} ,
{
name : "route /a/c/df to /a/c/df" ,
whenURL : "/a/c/df" ,
expectRoute : "/a/c/df" ,
expectID : 1 ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . contextPathParamAllocSize = 1
r := e . router
r . Add ( Route { Method : http . MethodGet , Path : "/" , Handler : handlerHelper ( "ID" , 0 ) , Name : "0" } )
r . Add ( Route { Method : http . MethodGet , Path : "/a/c/df" , Handler : handlerHelper ( "ID" , 1 ) , Name : "1" } )
r . Add ( Route { Method : http . MethodGet , Path : "/a/b*" , Handler : handlerHelper ( "ID" , 2 ) , Name : "2" } )
r . Add ( Route { Method : http . MethodPut , Path : "/*" , Handler : handlerHelper ( "ID" , 3 ) , Name : "3" } )
r . Add ( Route { Method : RouteNotFound , Path : "/a/c/d:file" , Handler : handlerHelper ( "ID" , 6 ) , Name : "6" } )
r . Add ( Route { Method : RouteNotFound , Path : "/a/:file" , Handler : handlerHelper ( "ID" , 5 ) , Name : "5" } )
r . Add ( Route { Method : RouteNotFound , Path : "/:file" , Handler : handlerHelper ( "ID" , 4 ) , Name : "4" } )
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := r . Route ( c )
handler ( c )
testValue , _ := c . Get ( "ID" ) . ( int )
assert . Equal ( t , tc . expectID , testValue )
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . PathParam ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
func TestRouter_RouteWhenNotFoundRouteStaticKind ( t * testing . T ) {
// note: static not found handler is quite silly thing to have but we still support it
var testCases = [ ] struct {
name string
whenURL string
expectRoute interface { }
expectID int
expectParam map [ string ] string
} {
{
name : "route not existent / to not found handler /" ,
whenURL : "/" ,
expectRoute : "/" ,
expectID : 3 ,
expectParam : map [ string ] string { } ,
} ,
{
name : "route /a to /a" ,
whenURL : "/a" ,
expectRoute : "/a" ,
expectID : 1 ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . contextPathParamAllocSize = 1
r := e . router
r . Add ( Route { Method : http . MethodPut , Path : "/" , Handler : handlerHelper ( "ID" , 0 ) , Name : "0" } )
r . Add ( Route { Method : http . MethodGet , Path : "/a" , Handler : handlerHelper ( "ID" , 1 ) , Name : "1" } )
r . Add ( Route { Method : http . MethodPut , Path : "/*" , Handler : handlerHelper ( "ID" , 2 ) , Name : "2" } )
r . Add ( Route { Method : RouteNotFound , Path : "/" , Handler : handlerHelper ( "ID" , 3 ) , Name : "3" } )
req := httptest . NewRequest ( http . MethodGet , tc . whenURL , nil )
c := e . NewContext ( req , nil ) . ( * DefaultContext )
handler := r . Route ( c )
handler ( c )
testValue , _ := c . Get ( "ID" ) . ( int )
assert . Equal ( t , tc . expectID , testValue )
assert . Equal ( t , tc . expectRoute , c . Path ( ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . PathParam ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
2021-07-15 22:34:01 +02:00
type mySimpleRouter struct {
route Route
}
func ( m * mySimpleRouter ) Add ( addRoute Routable ) ( RouteInfo , error ) {
route := addRoute . ToRoute ( )
h := route . Handler
route . Handler = func ( c Context ) error {
c . Set ( "router" , "mySimpleRouter" )
return h ( c )
}
m . route = route
return route . ToRouteInfo ( [ ] string { /* no values */ } ) , nil
}
func ( m * mySimpleRouter ) Remove ( method string , path string ) error {
return nil
}
func ( m * mySimpleRouter ) Routes ( ) Routes {
return Routes { m . route . ToRouteInfo ( nil ) }
}
func ( m * mySimpleRouter ) Route ( c RoutableContext ) HandlerFunc {
c . SetPath ( m . route . Path )
return m . route . Handler
}
func TestCustomRouter_defaultAndVHostRouting ( t * testing . T ) {
e := New ( )
e . ResetRouterCreator ( func ( e * Echo ) Router {
return & mySimpleRouter { }
} )
e . GET ( "/info" , func ( c Context ) error {
return c . String ( http . StatusTeapot , "default from " + c . Get ( "router" ) . ( string ) )
} )
g := e . Host ( "my.vhost.test" )
g . GET ( "/info" , func ( c Context ) error {
return c . String ( http . StatusTeapot , "my.vhost.test default from " + c . Get ( "router" ) . ( string ) )
} )
// see if default router was our mySimpleRouter
req := httptest . NewRequest ( http . MethodGet , "/info" , nil )
rec := httptest . NewRecorder ( )
e . ServeHTTP ( rec , req )
assert . Equal ( t , http . StatusTeapot , rec . Code )
assert . Equal ( t , "default from mySimpleRouter" , rec . Body . String ( ) )
// see if vhost router was our mySimpleRouter
req = httptest . NewRequest ( http . MethodGet , "/info" , nil )
req . Host = "my.vhost.test"
rec = httptest . NewRecorder ( )
e . ServeHTTP ( rec , req )
assert . Equal ( t , http . StatusTeapot , rec . Code )
assert . Equal ( t , "my.vhost.test default from mySimpleRouter" , rec . Body . String ( ) )
}
2016-11-16 06:09:52 +02:00
func BenchmarkRouterStaticRoutes ( b * testing . B ) {
2020-11-21 04:48:16 +02:00
benchmarkRouterRoutes ( b , staticRoutes , staticRoutes )
}
func BenchmarkRouterStaticRoutesMisses ( b * testing . B ) {
benchmarkRouterRoutes ( b , staticRoutes , missesAPI )
2016-11-12 19:42:25 +02:00
}
2016-11-16 06:09:52 +02:00
func BenchmarkRouterGitHubAPI ( b * testing . B ) {
2020-11-21 04:48:16 +02:00
benchmarkRouterRoutes ( b , gitHubAPI , gitHubAPI )
}
func BenchmarkRouterGitHubAPIMisses ( b * testing . B ) {
benchmarkRouterRoutes ( b , gitHubAPI , missesAPI )
2016-11-12 19:42:25 +02:00
}
2016-11-16 06:09:52 +02:00
func BenchmarkRouterParseAPI ( b * testing . B ) {
2020-11-21 04:48:16 +02:00
benchmarkRouterRoutes ( b , parseAPI , parseAPI )
}
func BenchmarkRouterParseAPIMisses ( b * testing . B ) {
benchmarkRouterRoutes ( b , parseAPI , missesAPI )
2016-11-12 19:42:25 +02:00
}
2016-11-16 06:09:52 +02:00
func BenchmarkRouterGooglePlusAPI ( b * testing . B ) {
2020-11-21 04:48:16 +02:00
benchmarkRouterRoutes ( b , googlePlusAPI , googlePlusAPI )
}
func BenchmarkRouterGooglePlusAPIMisses ( b * testing . B ) {
benchmarkRouterRoutes ( b , googlePlusAPI , missesAPI )
}
func BenchmarkRouterParamsAndAnyAPI ( b * testing . B ) {
benchmarkRouterRoutes ( b , paramAndAnyAPI , paramAndAnyAPIToFind )
2016-11-12 19:42:25 +02:00
}