2024-03-09 11:21:24 +02:00
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
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 (
2015-04-06 05:08:52 +02:00
"net/http"
2021-12-04 20:02:11 +02:00
"net/http/httptest"
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
}
2023-01-27 22:58:54 +02:00
func TestRouterNoRoutablePath ( t * testing . T ) {
e := New ( )
r := e . router
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , "/notfound" , c )
c . handler ( c )
// No routable path, don't set Path.
assert . Equal ( t , "" , c . Path ( ) )
}
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" } ,
} ,
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 ) {
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
}
2022-08-06 22:25:43 +02:00
func TestRouter_addAndMatchAllSupportedMethods ( t * testing . T ) {
var testCases = [ ] struct {
name string
givenNoAddRoute bool
whenMethod string
expectPath string
expectError string
} {
{ 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" } ,
{
name : "ok, NOT_EXISTING_METHOD" ,
whenMethod : "NOT_EXISTING_METHOD" ,
givenNoAddRoute : true ,
expectPath : "/*" ,
expectError : "code=405, message=Method Not Allowed" ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
e := New ( )
e . GET ( "/*" , handlerFunc )
if ! tc . givenNoAddRoute {
e . Add ( tc . whenMethod , "/my/*" , handlerFunc )
}
req := httptest . NewRequest ( tc . whenMethod , "/my/some-url" , nil )
rec := httptest . NewRecorder ( )
c := e . NewContext ( req , rec ) . ( * context )
e . router . Find ( tc . whenMethod , "/my/some-url" , c )
err := c . handler ( c )
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-04-27 09:55:31 +02:00
func TestMethodNotAllowedAndNotFound ( t * testing . T ) {
e := New ( )
r := e . router
// Routes
r . Add ( http . MethodGet , "/*" , handlerFunc )
r . Add ( http . MethodPost , "/users/:id" , handlerFunc )
var testCases = [ ] struct {
2021-12-04 20:02:11 +02:00
name string
whenMethod string
whenURL string
expectRoute interface { }
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" ,
expectRoute : nil ,
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 ) {
2021-12-04 20:02:11 +02:00
req := httptest . NewRequest ( tc . whenMethod , tc . whenURL , nil )
rec := httptest . NewRecorder ( )
c := e . NewContext ( req , rec ) . ( * context )
2021-04-27 09:55:31 +02:00
method := http . MethodGet
if tc . whenMethod != "" {
method = tc . whenMethod
}
r . Find ( method , tc . whenURL , c )
err := c . handler ( c )
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 )
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 )
}
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 )
2021-04-27 09:55:31 +02:00
assert . Equal ( t , "/a/:b/c/d/:e" , c . Get ( "path" ) )
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-11-12 18:35:19 +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-11-12 18:35:19 +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 ( )
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"
//
2022-11-12 18:35:19 +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 ( )
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
}
2022-07-12 20:53:41 +02:00
func TestNotFoundRouteAnyKind ( 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 ( )
r := e . router
r . Add ( http . MethodGet , "/" , handlerHelper ( "ID" , 0 ) )
r . Add ( http . MethodGet , "/a/c/df" , handlerHelper ( "ID" , 1 ) )
r . Add ( http . MethodGet , "/a/b*" , handlerHelper ( "ID" , 2 ) )
r . Add ( http . MethodPut , "/*" , handlerHelper ( "ID" , 3 ) )
r . Add ( RouteNotFound , "/a/c/d*" , handlerHelper ( "ID" , 6 ) )
r . Add ( RouteNotFound , "/a/*" , handlerHelper ( "ID" , 5 ) )
r . Add ( RouteNotFound , "/*" , handlerHelper ( "ID" , 4 ) )
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
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 . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
func TestNotFoundRouteParamKind ( 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 ( )
r := e . router
r . Add ( http . MethodGet , "/" , handlerHelper ( "ID" , 0 ) )
r . Add ( http . MethodGet , "/a/c/df" , handlerHelper ( "ID" , 1 ) )
r . Add ( http . MethodGet , "/a/b*" , handlerHelper ( "ID" , 2 ) )
r . Add ( http . MethodPut , "/*" , handlerHelper ( "ID" , 3 ) )
r . Add ( RouteNotFound , "/a/c/d:file" , handlerHelper ( "ID" , 6 ) )
r . Add ( RouteNotFound , "/a/:file" , handlerHelper ( "ID" , 5 ) )
r . Add ( RouteNotFound , "/:file" , handlerHelper ( "ID" , 4 ) )
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
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 . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
func TestNotFoundRouteStaticKind ( 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 ( )
r := e . router
r . Add ( http . MethodPut , "/" , handlerHelper ( "ID" , 0 ) )
r . Add ( http . MethodGet , "/a" , handlerHelper ( "ID" , 1 ) )
r . Add ( http . MethodPut , "/*" , handlerHelper ( "ID" , 2 ) )
r . Add ( RouteNotFound , "/" , handlerHelper ( "ID" , 3 ) )
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , tc . whenURL , c )
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 . Param ( param ) )
}
checkUnusedParamValues ( t , c , tc . expectParam )
} )
}
}
2022-07-13 07:16:27 +02:00
func TestRouter_notFoundRouteWithNodeSplitting ( t * testing . T ) {
e := New ( )
r := e . router
r . Add ( http . MethodGet , "/test*" , handlerHelper ( "ID" , 0 ) )
r . Add ( RouteNotFound , "/*" , handlerHelper ( "ID" , 1 ) )
r . Add ( RouteNotFound , "/test" , handlerHelper ( "ID" , 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 ( http . MethodGet , "/te/st*" , handlerHelper ( "ID" , 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
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodPut , "/test" , c )
c . handler ( c )
testValue , _ := c . Get ( "ID" ) . ( int )
assert . Equal ( t , 2 , testValue )
assert . Equal ( t , "/test" , c . Path ( ) )
}
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
}
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
expectRoute interface { }
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-09-19 10:39:12 +02:00
expectRoute : nil ,
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 ) {
c := e . NewContext ( nil , nil ) . ( * context )
e . router . Find ( http . MethodPost , tc . whenURL , c )
err := c . handler ( c )
assert . Equal ( t , tc . expectRoute , c . Get ( "path" ) )
if tc . expectError != "" {
assert . EqualError ( t , err , tc . expectError )
} else {
assert . NoError ( t , err )
}
for param , expectedValue := range tc . expectParam {
assert . Equal ( t , expectedValue , c . Param ( param ) )
}
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 ( )
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" } ,
} ,
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" ,
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
}
2022-07-11 19:25:41 +02:00
// Issue #1726
func TestRouterDifferentParamsInPath ( t * testing . T ) {
e := New ( )
r := e . router
r . Add ( http . MethodPut , "/*" , func ( Context ) error {
return nil
} )
r . Add ( http . MethodPut , "/users/:vid/files/:gid" , func ( Context ) error {
return nil
} )
r . Add ( http . MethodGet , "/users/:uid/files/:fid" , func ( Context ) error {
return nil
} )
c := e . NewContext ( nil , nil ) . ( * context )
r . Find ( http . MethodGet , "/users/1/files/2" , c )
assert . Equal ( t , "1" , c . Param ( "uid" ) )
assert . Equal ( t , "2" , c . Param ( "fid" ) )
r . Find ( http . MethodGet , "/users/1/shouldBacktrackToFirstAnyRouteAnd405" , c )
assert . Equal ( t , "/*" , c . Path ( ) )
r . Find ( http . MethodPut , "/users/3/files/4" , c )
assert . Equal ( t , "3" , c . Param ( "vid" ) )
assert . Equal ( t , "4" , c . Param ( "gid" ) )
}
2021-12-04 20:02:11 +02:00
func TestRouterHandleMethodOptions ( t * testing . T ) {
e := New ( )
r := e . router
r . Add ( http . MethodGet , "/users" , handlerFunc )
r . Add ( http . MethodPost , "/users" , handlerFunc )
r . Add ( http . MethodPut , "/users/:id" , handlerFunc )
r . Add ( http . MethodGet , "/users/:id" , 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 ) . ( * context )
r . Find ( tc . whenMethod , tc . whenURL , c )
err := c . handler ( 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 )
}
2022-07-11 19:25:41 +02:00
assert . Equal ( t , tc . expectAllowHeader , c . Response ( ) . Header ( ) . Get ( HeaderAllow ) )
2021-12-04 20:02:11 +02:00
} )
}
}
2022-11-12 18:35:19 +02:00
func TestRouter_Routes ( t * testing . T ) {
type rr struct {
method string
path string
name string
}
var testCases = [ ] struct {
name string
givenRoutes [ ] rr
expect [ ] rr
} {
{
name : "ok, multiple" ,
givenRoutes : [ ] rr {
{ method : http . MethodGet , path : "/static" , name : "/static" } ,
{ method : http . MethodGet , path : "/static/*" , name : "/static/*" } ,
} ,
expect : [ ] rr {
{ method : http . MethodGet , path : "/static" , name : "/static" } ,
{ method : http . MethodGet , path : "/static/*" , name : "/static/*" } ,
} ,
} ,
{
name : "ok, no routes" ,
givenRoutes : [ ] rr { } ,
expect : [ ] rr { } ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
dummyHandler := func ( Context ) error { return nil }
e := New ( )
route := e . router
for _ , tmp := range tc . givenRoutes {
route . add ( tmp . method , tmp . path , tmp . name , dummyHandler )
}
// Add does not add route. because of backwards compatibility we can not change this method signature
route . Add ( "LOCK" , "/users" , handlerFunc )
result := route . Routes ( )
assert . Len ( t , result , len ( tc . expect ) )
for _ , r := range result {
for _ , tmp := range tc . expect {
if tmp . name == r . Name {
assert . Equal ( t , tmp . method , r . Method )
assert . Equal ( t , tmp . path , r . Path )
}
}
}
} )
}
}
2024-03-27 12:28:46 +02:00
func TestRouter_addEmptyPathToSlashReverse ( t * testing . T ) {
e := New ( )
r := e . router
r . add ( http . MethodGet , "" , "empty" , handlerFunc ) // emtpy path is normalized to `/`
assert . Equal ( t , "/" , r . Reverse ( "empty" ) )
}
func TestRouter_ReverseNotFound ( t * testing . T ) {
e := New ( )
r := e . router
r . add ( http . MethodGet , "" , "empty" , handlerFunc )
assert . Equal ( t , "" , r . Reverse ( "not-existing" ) )
}
2022-11-12 18:35:19 +02:00
func TestRouter_Reverse ( t * testing . T ) {
e := New ( )
r := e . router
dummyHandler := func ( Context ) error { return nil }
r . add ( http . MethodGet , "/static" , "/static" , dummyHandler )
r . add ( http . MethodGet , "/static/*" , "/static/*" , dummyHandler )
r . add ( http . MethodGet , "/params/:foo" , "/params/:foo" , dummyHandler )
r . add ( http . MethodGet , "/params/:foo/bar/:qux" , "/params/:foo/bar/:qux" , dummyHandler )
r . add ( http . MethodGet , "/params/:foo/bar/:qux/*" , "/params/:foo/bar/:qux/*" , dummyHandler )
assert . Equal ( t , "/static" , r . Reverse ( "/static" ) )
assert . Equal ( t , "/static" , r . Reverse ( "/static" , "missing param" ) )
assert . Equal ( t , "/static/*" , r . Reverse ( "/static/*" ) )
assert . Equal ( t , "/static/foo.txt" , r . Reverse ( "/static/*" , "foo.txt" ) )
assert . Equal ( t , "/params/:foo" , r . Reverse ( "/params/:foo" ) )
assert . Equal ( t , "/params/one" , r . Reverse ( "/params/:foo" , "one" ) )
assert . Equal ( t , "/params/:foo/bar/:qux" , r . Reverse ( "/params/:foo/bar/:qux" ) )
assert . Equal ( t , "/params/one/bar/:qux" , r . Reverse ( "/params/:foo/bar/:qux" , "one" ) )
assert . Equal ( t , "/params/one/bar/two" , r . Reverse ( "/params/:foo/bar/:qux" , "one" , "two" ) )
assert . Equal ( t , "/params/one/bar/two/three" , r . Reverse ( "/params/:foo/bar/:qux/*" , "one" , "two" , "three" ) )
}
2022-08-06 22:25:43 +02:00
func TestRouterAllowHeaderForAnyOtherMethodType ( t * testing . T ) {
e := New ( )
r := e . router
r . Add ( http . MethodGet , "/users" , handlerFunc )
r . Add ( "COPY" , "/users" , handlerFunc )
r . Add ( "LOCK" , "/users" , handlerFunc )
req := httptest . NewRequest ( "TEST" , "/users" , nil )
rec := httptest . NewRecorder ( )
c := e . NewContext ( req , rec ) . ( * context )
r . Find ( "TEST" , "/users" , c )
err := c . 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 ) , ", " ) )
}
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
}