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 (
"fmt"
2015-04-06 05:08:52 +02:00
"net/http"
2016-11-13 19:36:57 +02:00
"strings"
2015-04-01 17:05:54 +02:00
"testing"
2015-05-31 00:20:36 +02:00
"github.com/stretchr/testify/assert"
2015-04-01 17:05:54 +02:00
)
2015-03-01 19:45:13 +02:00
2015-04-09 23:59:31 +02:00
var (
2017-06-20 17:58:53 +02:00
staticRoutes = [ ] * Route {
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" , "" } ,
}
2017-06-20 17:58:53 +02:00
gitHubAPI = [ ] * Route {
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
2017-06-20 17:58:53 +02:00
parseAPI = [ ] * Route {
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" , "" } ,
}
2017-06-20 17:58:53 +02:00
googlePlusAPI = [ ] * Route {
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
2020-11-21 04:48:16 +02:00
paramAndAnyAPI = [ ] * Route {
{ "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/*" , "" } ,
}
paramAndAnyAPIToFind = [ ] * Route {
{ "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" , "" } ,
}
missesAPI = [ ] * Route {
{ "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 )
c . Set ( "path" , c . Path ( ) )
return nil
}
}
2021-03-06 01:43:59 +02:00
handlerFunc = func ( c Context ) error {
c . Set ( "path" , c . Path ( ) )
return nil
}
2015-04-09 23:59:31 +02:00
)
2015-04-06 05:08:52 +02:00
2021-03-06 01:43:59 +02:00
func checkUnusedParamValues ( t * testing . T , c * context , expectParam map [ string ] string ) {
for i , p := range c . pnames {
value := c . pvalues [ i ]
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 {
if _ , ok := expectParam [ p ] ; ! ok {
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-06-04 00:18:27 +02:00
e := New ( )
r := e . router
2015-04-12 22:04:41 +02:00
path := "/folders/a/files/echo.gif"
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , path , handlerFunc )
2016-10-11 02:31:26 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
2021-03-06 01:43:59 +02:00
2018-10-14 17:16:58 +02:00
r . Find ( http . MethodGet , path , c )
2016-04-09 23:00:23 +02:00
c . handler ( c )
2021-03-06 01:43:59 +02:00
2016-02-15 18:11:29 +02:00
assert . Equal ( t , path , c . Get ( "path" ) )
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 ( )
r := e . router
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users/:id" , handlerFunc )
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" } ,
} ,
{ // FIXME: this documents current implementation (slash at end is problematic)
name : "route /users/1/ to /users/:id" ,
whenURL : "/users/1/" ,
expectRoute : nil , // FIXME: should be "/users/:id",
expectParam : nil , // FIXME: should be map[string]string{"id": "1/"},
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
c . handler ( c )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2015-04-04 19:44:48 +02:00
}
func TestRouterTwoParam ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
r := e . router
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users/:uid/files/:fid" , handlerFunc )
2016-10-11 02:31:26 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
2015-04-24 16:44:30 +02:00
2018-10-14 17:16:58 +02:00
r . Find ( http . MethodGet , "/users/1/files/1" , c )
2021-03-06 01:43:59 +02:00
2016-10-11 03:18:09 +02:00
assert . Equal ( t , "1" , c . Param ( "uid" ) )
assert . Equal ( t , "1" , c . Param ( "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 ( )
r := e . router
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/a/:b/c/d/:e" , handlerFunc )
r . Add ( http . MethodGet , "/a/:b/c/:d/:f" , handlerFunc )
2016-03-07 09:24:51 +02:00
2021-03-06 01:43:59 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , "/a/1/c/d/2/3" , c ) // `2/3` should mapped to path `/a/:b/c/d/:e` and into `:e`
err := c . handler ( c )
assert . Equal ( t , nil , c . Get ( "path" ) ) // FIXME: should be "/a/:b/c/d/:e"
assert . EqualError ( t , err , "code=404, message=Not Found" ) // FIXME: should be .NoError()
}
// 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"
//
// +----------+
// +-----+ "/" root +--------------------+--------------------------+
// | +----------+ | |
// | | |
// +-------v-------+ +---v---------+ +-------v---+
// | "a/" (static) +---------------+ | ":" (param) | | "*" (any) |
// +-+----------+--+ | +-----------+-+ +-----------+
// | | | |
// +---------------v+ +-- ---v------+ +------v----+ +-----v-----------+
// | "c/d" (static) | | ":" (param) | | "*" (any) | | "/c/f" (static) |
// +---------+------+ +--------+----+ +----------++ +-----------------+
// | | |
// | | |
// +---------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 ( )
r := e . router
r . Add ( http . MethodGet , "/a/:b/c" , handlerHelper ( "case" , 1 ) )
r . Add ( http . MethodGet , "/a/c/d" , handlerHelper ( "case" , 2 ) )
r . Add ( http . MethodGet , "/a/c/df" , handlerHelper ( "case" , 3 ) )
r . Add ( http . MethodGet , "/a/*/f" , handlerHelper ( "case" , 4 ) )
r . Add ( http . MethodGet , "/:e/c/f" , handlerHelper ( "case" , 5 ) )
r . Add ( http . MethodGet , "/*" , handlerHelper ( "case" , 6 ) )
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
c . handler ( c )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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"
//
// +-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) |
// +---------------+
func TestRouteMultiLevelBacktracking2 ( t * testing . T ) {
e := New ( )
r := e . router
r . Add ( http . MethodGet , "/a/:b/c" , handlerFunc )
r . Add ( http . MethodGet , "/a/c/d" , handlerFunc )
r . Add ( http . MethodGet , "/a/c/df" , handlerFunc )
r . Add ( http . MethodGet , "/:e/c/f" , handlerFunc )
r . Add ( http . MethodGet , "/*" , handlerFunc )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
c . handler ( c )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
func TestRouterBacktrackingFromMultipleParamKinds ( t * testing . T ) {
e := New ( )
r := e . router
r . Add ( http . MethodGet , "/*" , handlerFunc ) // this can match only path that does not have slash in it
r . Add ( http . MethodGet , "/:1/second" , handlerFunc )
r . Add ( http . MethodGet , "/:1/:2" , handlerFunc ) // this acts as match ANY for all routes that have at least one slash
r . Add ( http . MethodGet , "/:1/:2/third" , handlerFunc )
r . Add ( http . MethodGet , "/:1/:2/:3/fourth" , handlerFunc )
r . Add ( http . MethodGet , "/:1/:2/:3/:4/fifth" , handlerFunc )
2016-03-07 09:24:51 +02:00
2016-10-11 02:31:26 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
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" ,
whenURL : "/first/second/" ,
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 ) {
r . Find ( http . MethodGet , tc . whenURL , c )
c . handler ( c )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
handler := func ( c Context ) error {
c . Set ( "path" , c . Path ( ) )
return nil
}
g := e . Group ( "/g" )
g . GET ( "/skills" , handler )
g . GET ( "/status" , handler )
g . GET ( "/:name" , handler )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2020-02-24 18:26:49 +02:00
2021-03-06 01:43:59 +02:00
r . Find ( http . MethodGet , tc . whenURL , c )
err := c . handler ( c )
assert . NoError ( t , err )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2020-02-24 18:26:49 +02:00
}
2015-04-29 08:09:30 +02:00
func TestRouterMatchAny ( t * testing . T ) {
2015-06-04 00:18:27 +02:00
e := New ( )
r := e . router
2015-09-17 04:28:09 +02:00
// Routes
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/" , handlerFunc )
r . Add ( http . MethodGet , "/*" , handlerFunc )
r . Add ( http . MethodGet , "/users/*" , handlerFunc )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2015-04-26 21:44:38 +02:00
2021-03-06 01:43:59 +02:00
r . Find ( http . MethodGet , tc . whenURL , c )
err := c . handler ( c )
2015-09-17 04:28:09 +02:00
2021-03-06 01:43:59 +02:00
assert . NoError ( t , err )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
r . Add ( http . MethodGet , "/users/*" , handlerHelper ( "case" , 1 ) )
r . Add ( http . MethodGet , "/users/*/action*" , handlerHelper ( "case" , 2 ) )
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , "/users/xxx/action/sea" , c )
c . handler ( c )
assert . Equal ( t , "/users/*/action*" , c . Get ( "path" ) )
assert . Equal ( t , "xxx/action/sea" , c . Param ( "*" ) )
// if we add another route then it is the last added and so it is matched
r . Add ( http . MethodGet , "/users/*/action/search" , handlerHelper ( "case" , 3 ) )
r . Find ( http . MethodGet , "/users/xxx/action/sea" , c )
c . handler ( c )
assert . Equal ( t , "/users/*/action/search" , c . Get ( "path" ) )
assert . Equal ( t , "xxx/action/sea" , c . Param ( "*" ) )
}
2021-01-03 20:35:00 +02:00
// Issue #1739
func TestRouterMatchAnyPrefixIssue ( t * testing . T ) {
e := New ( )
r := e . router
// Routes
r . Add ( http . MethodGet , "/*" , func ( c Context ) error {
c . Set ( "path" , c . Path ( ) )
return nil
} )
r . Add ( http . MethodGet , "/users/*" , func ( c Context ) error {
c . Set ( "path" , c . Path ( ) )
return nil
} )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2021-03-02 20:56:40 +02:00
2021-03-06 01:43:59 +02:00
r . Find ( http . MethodGet , tc . whenURL , c )
err := c . handler ( c )
2021-03-02 20:56:40 +02:00
2021-03-06 01:43:59 +02:00
assert . NoError ( t , err )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
// Routes
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users" , handlerFunc )
r . Add ( http . MethodGet , "/users/*" , handlerFunc )
r . Add ( http . MethodGet , "/img/*" , handlerFunc )
r . Add ( http . MethodGet , "/img/load" , handlerFunc )
r . Add ( http . MethodGet , "/img/load/*" , handlerFunc )
r . Add ( http . MethodGet , "/assets/*" , handlerFunc )
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/" ,
expectRoute : nil ,
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" ,
expectRoute : nil ,
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2020-05-06 23:01:28 +02:00
2021-03-06 01:43:59 +02:00
r . Find ( http . MethodGet , tc . whenURL , c )
err := c . handler ( c )
2020-05-06 23:01:28 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
// Routes
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/api/users/jack" , handlerFunc )
r . Add ( http . MethodGet , "/api/users/jill" , handlerFunc )
r . Add ( http . MethodGet , "/api/users/*" , handlerFunc )
r . Add ( http . MethodGet , "/api/*" , handlerFunc )
r . Add ( http . MethodGet , "/other/*" , handlerFunc )
r . Add ( http . MethodGet , "/*" , handlerFunc )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2019-10-03 19:30:46 +02:00
2021-03-06 01:43:59 +02:00
r . Find ( http . MethodGet , tc . whenURL , c )
err := c . handler ( c )
2019-10-03 19:30:46 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
// 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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2019-10-16 21:52:10 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2019-10-16 21:52:10 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
2018-10-14 17:16:58 +02:00
r . Add ( http . MethodGet , "/:a/:b/:c" , func ( c Context ) error {
2015-04-19 01:47:48 +02:00
return nil
2016-10-22 05:36:49 +02:00
} )
2016-10-11 02:31:26 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
2018-10-14 17:16:58 +02:00
r . Find ( http . MethodGet , "/1/2/3" , c )
2016-10-11 03:18:09 +02:00
assert . Equal ( t , "1" , c . Param ( "a" ) )
assert . Equal ( t , "2" , c . Param ( "b" ) )
assert . Equal ( t , "3" , c . Param ( "c" ) )
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 ( )
r := e . router
// Route
2018-10-14 17:16:58 +02:00
r . Add ( http . MethodGet , "/users/:id/*" , func ( c Context ) error {
2015-09-15 17:29:29 +02:00
return nil
2016-10-22 05:36:49 +02:00
} )
2016-10-11 02:31:26 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
2015-09-15 17:29:29 +02:00
2018-10-14 17:16:58 +02:00
r . Find ( http . MethodGet , "/users/joe/comments" , c )
2016-04-09 23:00:23 +02:00
c . handler ( c )
2016-10-11 03:18:09 +02:00
assert . Equal ( t , "joe" , c . Param ( "id" ) )
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 ( )
r := e . router
2015-04-12 22:04:41 +02:00
2015-04-13 22:12:30 +02:00
// Routes
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id" , handlerFunc )
var testCases = [ ] struct {
whenMethod string
whenURL string
expectRoute interface { }
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" ,
expectRoute : nil ,
expectParam : map [ string ] string { "*" : "" } ,
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
c := e . NewContext ( nil , nil ) . ( * context )
2015-04-12 22:04:41 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2015-04-12 22:04:41 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
2015-04-13 22:12:30 +02:00
// Routes
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users" , handlerFunc )
r . Add ( http . MethodGet , "/users/new" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id" , handlerFunc )
r . Add ( http . MethodGet , "/users/dew" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id/files" , handlerFunc )
r . Add ( http . MethodGet , "/users/newsee" , handlerFunc )
r . Add ( http . MethodGet , "/users/*" , handlerFunc )
r . Add ( http . MethodGet , "/users/new/*" , handlerFunc )
r . Add ( http . MethodGet , "/*" , handlerFunc )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
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
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2019-10-03 19:30:46 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
r . Add ( http . MethodGet , "/:lang/" , func ( c Context ) error {
return nil
} )
r . Add ( http . MethodGet , "/:lang/dupa" , func ( c Context ) error {
return nil
} )
}
2016-03-04 08:06:47 +02:00
// Issue #372
func TestRouterPriorityNotFound ( t * testing . T ) {
e := New ( )
r := e . router
// Add
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/a/foo" , handlerFunc )
r . Add ( http . MethodGet , "/a/bar" , handlerFunc )
var testCases = [ ] struct {
whenMethod string
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectError error
} {
{
whenURL : "/a/foo" ,
expectRoute : "/a/foo" ,
} ,
{
whenURL : "/a/bar" ,
expectRoute : "/a/bar" ,
} ,
{
whenURL : "/abc/def" ,
expectRoute : nil ,
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
c := e . NewContext ( nil , nil ) . ( * context )
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
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2016-03-04 08:06:47 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
2015-04-24 16:44:30 +02:00
// Routes
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id" , handlerFunc )
r . Add ( http . MethodGet , "/users/:uid/files/:fid" , handlerFunc )
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
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
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2015-04-24 16:44:30 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
2019-10-16 21:52:10 +02:00
r . Add ( http . MethodGet , "/dictionary/skills" , handlerHelper ( "a" , 1 ) )
r . Add ( http . MethodGet , "/dictionary/:name" , handlerHelper ( "b" , 2 ) )
r . Add ( http . MethodGet , "/users/new" , handlerHelper ( "d" , 4 ) )
r . Add ( http . MethodGet , "/users/:name" , handlerHelper ( "e" , 5 ) )
r . Add ( http . MethodGet , "/server" , handlerHelper ( "c" , 3 ) )
r . Add ( http . MethodGet , "/" , handlerHelper ( "f" , 6 ) )
2016-10-14 23:52:40 +02:00
2021-03-06 01:43:59 +02:00
var testCases = [ ] struct {
whenMethod string
whenURL string
expectRoute interface { }
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
2019-10-16 21:52:10 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2019-10-16 21:52:10 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
// Add
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/:param1" , handlerFunc )
r . Add ( http . MethodGet , "/:param1/foo" , handlerFunc )
r . Add ( http . MethodGet , "/:param1/bar" , handlerFunc )
r . Add ( http . MethodGet , "/:param1/bar/:param2" , handlerFunc )
var testCases = [ ] struct {
name string
whenMethod string
whenURL string
expectRoute interface { }
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" ,
expectRoute : nil ,
expectError : ErrNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
c := e . NewContext ( nil , nil ) . ( * context )
2019-07-25 22:39:03 +02:00
2021-03-06 01:43:59 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
2019-07-25 22:39:03 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectError != nil {
assert . Equal ( t , tc . expectError , err )
} else {
assert . NoError ( t , err )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2019-07-25 22:39:03 +02:00
}
2017-06-20 17:58:53 +02:00
func testRouterAPI ( t * testing . T , api [ ] * Route ) {
2015-06-04 00:18:27 +02:00
e := New ( )
r := e . router
2016-11-16 06:09:52 +02:00
for _ , route := range api {
2016-04-02 23:19:39 +02:00
r . Add ( route . Method , route . Path , func ( c Context ) error {
2015-04-19 01:47:48 +02:00
return nil
2016-10-22 05:36:49 +02:00
} )
2015-06-04 00:18:27 +02:00
}
2016-10-11 02:31:26 +02:00
c := e . NewContext ( nil , nil ) . ( * context )
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 ) {
r . Find ( route . Method , route . Path , c )
tokens := strings . Split ( route . Path [ 1 : ] , "/" )
for _ , token := range tokens {
if token [ 0 ] == ':' {
assert . Equal ( t , c . Param ( token [ 1 : ] ) , token )
}
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 )
}
// Issue #729
func TestRouterParamAlias ( t * testing . T ) {
2017-06-20 17:58:53 +02:00
api := [ ] * Route {
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 ) {
api := [ ] * Route {
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 )
api2 := [ ] * Route {
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 )
api3 := [ ] * Route {
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 ) {
api := [ ] * Route {
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 )
api2 := [ ] * Route {
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 ( )
r := e . router
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodPost , "/users/signup" , handlerFunc )
r . Add ( http . MethodPost , "/users/signup/bulk" , handlerFunc )
r . Add ( http . MethodPost , "/users/survey" , handlerFunc )
r . Add ( http . MethodGet , "/users/:username" , handlerFunc )
r . Add ( http . MethodGet , "/interests/:name/users" , handlerFunc )
r . Add ( http . MethodGet , "/skills/:name/users" , handlerFunc )
2020-01-24 02:13:18 +02:00
// Additional routes for Issue 1479
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users/:username/likes/projects/ids" , handlerFunc )
r . Add ( http . MethodGet , "/users/:username/profile" , handlerFunc )
r . Add ( http . MethodGet , "/users/:username/uploads/:type" , handlerFunc )
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
} {
{
whenURL : "/users/ajitem" ,
expectRoute : "/users/:username" ,
expectParam : map [ string ] string { "username" : "ajitem" } ,
} ,
{
whenURL : "/users/sharewithme" ,
expectRoute : "/users/:username" ,
expectParam : map [ string ] string { "username" : "sharewithme" } ,
} ,
{
whenURL : "/users/signup" ,
expectRoute : nil , // method not found as this route is for POST but request is for GET
expectParam : map [ string ] string { "username" : "" } ,
} ,
// 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" ,
expectRoute : nil , // not found
expectParam : map [ string ] string { "id" : "" } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
c . handler ( c )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
r := e . router
v0 := e . Group ( "/:version" )
v0 . GET ( "/admin" , func ( c Context ) error {
c . SetParamNames ( "version" )
c . SetParamValues ( "v1" )
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 ;) )
c := e . NewContext ( nil , nil )
r . Find ( http . MethodGet , "/v1/admin" , c )
c . Handler ( ) ( c )
assert . Equal ( t , "v1" , c . Param ( "version" ) )
//panic
c = e . NewContext ( nil , nil )
r . Find ( http . MethodGet , "/v1/view/same-data" , c )
c . Handler ( ) ( c )
assert . Equal ( t , "same-data" , c . Param ( "*" ) )
assert . Equal ( t , 1 , c . Get ( "v" ) )
//looping
c = e . NewContext ( nil , nil )
r . Find ( http . MethodGet , "/v1/images/view" , c )
c . Handler ( ) ( c )
assert . Equal ( t , "view" , c . Param ( "id" ) )
assert . Equal ( t , 1 , c . Get ( "i" ) )
}
2020-10-25 06:03:07 +02:00
// Issue #1653
func TestRouterPanicWhenParamNoRootOnlyChildsFailsFind ( t * testing . T ) {
e := New ( )
r := e . router
2021-03-06 01:43:59 +02:00
r . Add ( http . MethodGet , "/users/create" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id/edit" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id/active" , handlerFunc )
var testCases = [ ] struct {
whenURL string
expectRoute interface { }
expectParam map [ string ] string
expectStatus int
} {
{
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
{
whenURL : "/users/createNotFound" ,
expectStatus : http . StatusNotFound ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . whenURL , func ( t * testing . T ) {
c := e . NewContext ( nil , nil ) . ( * context )
2020-10-25 06:03:07 +02:00
2021-03-06 01:43:59 +02:00
r . Find ( http . MethodGet , tc . whenURL , c )
err := c . handler ( c )
2020-10-25 06:03:07 +02:00
2021-03-06 01:43:59 +02:00
if tc . expectStatus != 0 {
assert . Error ( t , err )
he := err . ( * HTTPError )
assert . Equal ( t , tc . expectStatus , he . Code )
}
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
2020-10-25 06:03:07 +02:00
}
2020-11-21 04:48:16 +02:00
func benchmarkRouterRoutes ( b * testing . B , routes [ ] * Route , routesToFind [ ] * Route ) {
2016-03-18 06:49:06 +02:00
e := New ( )
r := e . router
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 {
2016-04-02 23:19:39 +02:00
r . Add ( route . Method , route . Path , func ( c Context ) error {
2016-03-18 06:49:06 +02:00
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 {
2016-11-12 19:42:25 +02:00
c := e . pool . Get ( ) . ( * context )
2016-03-18 06:49:06 +02:00
r . Find ( route . Method , route . Path , c )
2016-11-12 19:42:25 +02:00
e . pool . Put ( c )
2016-03-18 06:49:06 +02:00
}
}
}
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
}
2015-04-01 17:05:54 +02:00
func ( n * node ) printTree ( pfx string , tail bool ) {
p := prefix ( tail , pfx , "└── " , "├── " )
2018-10-07 05:04:30 +02:00
fmt . Printf ( "%s%s, %p: type=%d, parent=%p, handler=%v, pnames=%v\n" , p , n . prefix , n , n . kind , n . parent , n . methodHandler , n . pnames )
2015-04-01 17:05:54 +02:00
p = prefix ( tail , pfx , " " , "│ " )
2020-11-21 04:48:16 +02:00
2021-03-06 01:43:59 +02:00
children := n . staticChildren
2020-11-21 04:48:16 +02:00
l := len ( children )
2021-03-06 01:43:59 +02:00
if n . paramChild != nil {
n . paramChild . printTree ( p , n . anyChild == nil && l == 0 )
2020-11-21 04:48:16 +02:00
}
2021-03-06 01:43:59 +02:00
if n . anyChild != nil {
n . anyChild . printTree ( p , l == 0 )
2020-11-21 04:48:16 +02:00
}
2015-04-01 17:05:54 +02:00
for i := 0 ; i < l - 1 ; i ++ {
2015-04-14 06:57:36 +02:00
children [ i ] . printTree ( p , false )
2015-04-01 17:05:54 +02:00
}
if l > 0 {
2015-04-14 06:57:36 +02:00
children [ l - 1 ] . printTree ( p , true )
2015-04-01 17:05:54 +02:00
}
}
func prefix ( tail bool , p , on , off string ) string {
if tail {
return fmt . Sprintf ( "%s%s" , p , on )
}
return fmt . Sprintf ( "%s%s" , p , off )
2015-03-31 17:26:00 +02:00
}