1 package denco_test
2
3 import (
4 "fmt"
5 "math/rand"
6 "reflect"
7 "testing"
8
9 "github.com/go-openapi/runtime/middleware/denco"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12 )
13
14 func routes() []denco.Record {
15 return []denco.Record{
16 {"/", "testroute0"},
17 {"/path/to/route", "testroute1"},
18 {"/path/to/other", "testroute2"},
19 {"/path/to/route/a", "testroute3"},
20 {"/path/to/:param", "testroute4"},
21 {"/gists/:param1/foo/:param2", "testroute12"},
22 {"/gists/:param1/foo/bar", "testroute11"},
23 {"/:param1/:param2/foo/:param3", "testroute13"},
24 {"/path/to/wildcard/*routepath", "testroute5"},
25 {"/path/to/:param1/:param2", "testroute6"},
26 {"/path/to/:param1/sep/:param2", "testroute7"},
27 {"/:year/:month/:day", "testroute8"},
28 {"/user/:id", "testroute9"},
29 {"/a/to/b/:param/*routepath", "testroute10"},
30 {"/path/with/key=:value", "testroute14"},
31 }
32 }
33
34 var realURIs = []denco.Record{
35 {"/authorizations", "/authorizations"},
36 {"/authorizations/:id", "/authorizations/:id"},
37 {"/applications/:client_id/tokens/:access_token", "/applications/:client_id/tokens/:access_token"},
38 {"/events", "/events"},
39 {"/repos/:owner/:repo/events", "/repos/:owner/:repo/events"},
40 {"/networks/:owner/:repo/events", "/networks/:owner/:repo/events"},
41 {"/orgs/:org/events", "/orgs/:org/events"},
42 {"/users/:user/received_events", "/users/:user/received_events"},
43 {"/users/:user/received_events/public", "/users/:user/received_events/public"},
44 {"/users/:user/events", "/users/:user/events"},
45 {"/users/:user/events/public", "/users/:user/events/public"},
46 {"/users/:user/events/orgs/:org", "/users/:user/events/orgs/:org"},
47 {"/feeds", "/feeds"},
48 {"/notifications", "/notifications"},
49 {"/repos/:owner/:repo/notifications", "/repos/:owner/:repo/notifications"},
50 {"/notifications/threads/:id", "/notifications/threads/:id"},
51 {"/notifications/threads/:id/subscription", "/notifications/threads/:id/subscription"},
52 {"/repos/:owner/:repo/stargazers", "/repos/:owner/:repo/stargazers"},
53 {"/users/:user/starred", "/users/:user/starred"},
54 {"/user/starred", "/user/starred"},
55 {"/user/starred/:owner/:repo", "/user/starred/:owner/:repo"},
56 {"/repos/:owner/:repo/subscribers", "/repos/:owner/:repo/subscribers"},
57 {"/users/:user/subscriptions", "/users/:user/subscriptions"},
58 {"/user/subscriptions", "/user/subscriptions"},
59 {"/repos/:owner/:repo/subscription", "/repos/:owner/:repo/subscription"},
60 {"/user/subscriptions/:owner/:repo", "/user/subscriptions/:owner/:repo"},
61 {"/users/:user/gists", "/users/:user/gists"},
62 {"/gists", "/gists"},
63 {"/gists/:id", "/gists/:id"},
64 {"/gists/:id/star", "/gists/:id/star"},
65 {"/repos/:owner/:repo/git/blobs/:sha", "/repos/:owner/:repo/git/blobs/:sha"},
66 {"/repos/:owner/:repo/git/commits/:sha", "/repos/:owner/:repo/git/commits/:sha"},
67 {"/repos/:owner/:repo/git/refs", "/repos/:owner/:repo/git/refs"},
68 {"/repos/:owner/:repo/git/tags/:sha", "/repos/:owner/:repo/git/tags/:sha"},
69 {"/repos/:owner/:repo/git/trees/:sha", "/repos/:owner/:repo/git/trees/:sha"},
70 {"/issues", "/issues"},
71 {"/user/issues", "/user/issues"},
72 {"/orgs/:org/issues", "/orgs/:org/issues"},
73 {"/repos/:owner/:repo/issues", "/repos/:owner/:repo/issues"},
74 {"/repos/:owner/:repo/issues/:number", "/repos/:owner/:repo/issues/:number"},
75 {"/repos/:owner/:repo/assignees", "/repos/:owner/:repo/assignees"},
76 {"/repos/:owner/:repo/assignees/:assignee", "/repos/:owner/:repo/assignees/:assignee"},
77 {"/repos/:owner/:repo/issues/:number/comments", "/repos/:owner/:repo/issues/:number/comments"},
78 {"/repos/:owner/:repo/issues/:number/events", "/repos/:owner/:repo/issues/:number/events"},
79 {"/repos/:owner/:repo/labels", "/repos/:owner/:repo/labels"},
80 {"/repos/:owner/:repo/labels/:name", "/repos/:owner/:repo/labels/:name"},
81 {"/repos/:owner/:repo/issues/:number/labels", "/repos/:owner/:repo/issues/:number/labels"},
82 {"/repos/:owner/:repo/milestones/:number/labels", "/repos/:owner/:repo/milestones/:number/labels"},
83 {"/repos/:owner/:repo/milestones", "/repos/:owner/:repo/milestones"},
84 {"/repos/:owner/:repo/milestones/:number", "/repos/:owner/:repo/milestones/:number"},
85 {"/emojis", "/emojis"},
86 {"/gitignore/templates", "/gitignore/templates"},
87 {"/gitignore/templates/:name", "/gitignore/templates/:name"},
88 {"/meta", "/meta"},
89 {"/rate_limit", "/rate_limit"},
90 {"/users/:user/orgs", "/users/:user/orgs"},
91 {"/user/orgs", "/user/orgs"},
92 {"/orgs/:org", "/orgs/:org"},
93 {"/orgs/:org/members", "/orgs/:org/members"},
94 {"/orgs/:org/members/:user", "/orgs/:org/members/:user"},
95 {"/orgs/:org/public_members", "/orgs/:org/public_members"},
96 {"/orgs/:org/public_members/:user", "/orgs/:org/public_members/:user"},
97 {"/orgs/:org/teams", "/orgs/:org/teams"},
98 {"/teams/:id", "/teams/:id"},
99 {"/teams/:id/members", "/teams/:id/members"},
100 {"/teams/:id/members/:user", "/teams/:id/members/:user"},
101 {"/teams/:id/repos", "/teams/:id/repos"},
102 {"/teams/:id/repos/:owner/:repo", "/teams/:id/repos/:owner/:repo"},
103 {"/user/teams", "/user/teams"},
104 {"/repos/:owner/:repo/pulls", "/repos/:owner/:repo/pulls"},
105 {"/repos/:owner/:repo/pulls/:number", "/repos/:owner/:repo/pulls/:number"},
106 {"/repos/:owner/:repo/pulls/:number/commits", "/repos/:owner/:repo/pulls/:number/commits"},
107 {"/repos/:owner/:repo/pulls/:number/files", "/repos/:owner/:repo/pulls/:number/files"},
108 {"/repos/:owner/:repo/pulls/:number/merge", "/repos/:owner/:repo/pulls/:number/merge"},
109 {"/repos/:owner/:repo/pulls/:number/comments", "/repos/:owner/:repo/pulls/:number/comments"},
110 {"/user/repos", "/user/repos"},
111 {"/users/:user/repos", "/users/:user/repos"},
112 {"/orgs/:org/repos", "/orgs/:org/repos"},
113 {"/repositories", "/repositories"},
114 {"/repos/:owner/:repo", "/repos/:owner/:repo"},
115 {"/repos/:owner/:repo/contributors", "/repos/:owner/:repo/contributors"},
116 {"/repos/:owner/:repo/languages", "/repos/:owner/:repo/languages"},
117 {"/repos/:owner/:repo/teams", "/repos/:owner/:repo/teams"},
118 {"/repos/:owner/:repo/tags", "/repos/:owner/:repo/tags"},
119 {"/repos/:owner/:repo/branches", "/repos/:owner/:repo/branches"},
120 {"/repos/:owner/:repo/branches/:branch", "/repos/:owner/:repo/branches/:branch"},
121 {"/repos/:owner/:repo/collaborators", "/repos/:owner/:repo/collaborators"},
122 {"/repos/:owner/:repo/collaborators/:user", "/repos/:owner/:repo/collaborators/:user"},
123 {"/repos/:owner/:repo/comments", "/repos/:owner/:repo/comments"},
124 {"/repos/:owner/:repo/commits/:sha/comments", "/repos/:owner/:repo/commits/:sha/comments"},
125 {"/repos/:owner/:repo/comments/:id", "/repos/:owner/:repo/comments/:id"},
126 {"/repos/:owner/:repo/commits", "/repos/:owner/:repo/commits"},
127 {"/repos/:owner/:repo/commits/:sha", "/repos/:owner/:repo/commits/:sha"},
128 {"/repos/:owner/:repo/readme", "/repos/:owner/:repo/readme"},
129 {"/repos/:owner/:repo/keys", "/repos/:owner/:repo/keys"},
130 {"/repos/:owner/:repo/keys/:id", "/repos/:owner/:repo/keys/:id"},
131 {"/repos/:owner/:repo/downloads", "/repos/:owner/:repo/downloads"},
132 {"/repos/:owner/:repo/downloads/:id", "/repos/:owner/:repo/downloads/:id"},
133 {"/repos/:owner/:repo/forks", "/repos/:owner/:repo/forks"},
134 {"/repos/:owner/:repo/hooks", "/repos/:owner/:repo/hooks"},
135 {"/repos/:owner/:repo/hooks/:id", "/repos/:owner/:repo/hooks/:id"},
136 {"/repos/:owner/:repo/releases", "/repos/:owner/:repo/releases"},
137 {"/repos/:owner/:repo/releases/:id", "/repos/:owner/:repo/releases/:id"},
138 {"/repos/:owner/:repo/releases/:id/assets", "/repos/:owner/:repo/releases/:id/assets"},
139 {"/repos/:owner/:repo/stats/contributors", "/repos/:owner/:repo/stats/contributors"},
140 {"/repos/:owner/:repo/stats/commit_activity", "/repos/:owner/:repo/stats/commit_activity"},
141 {"/repos/:owner/:repo/stats/code_frequency", "/repos/:owner/:repo/stats/code_frequency"},
142 {"/repos/:owner/:repo/stats/participation", "/repos/:owner/:repo/stats/participation"},
143 {"/repos/:owner/:repo/stats/punch_card", "/repos/:owner/:repo/stats/punch_card"},
144 {"/repos/:owner/:repo/statuses/:ref", "/repos/:owner/:repo/statuses/:ref"},
145 {"/search/repositories", "/search/repositories"},
146 {"/search/code", "/search/code"},
147 {"/search/issues", "/search/issues"},
148 {"/search/users", "/search/users"},
149 {"/legacy/issues/search/:owner/:repository/:state/:keyword", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
150 {"/legacy/repos/search/:keyword", "/legacy/repos/search/:keyword"},
151 {"/legacy/user/search/:keyword", "/legacy/user/search/:keyword"},
152 {"/legacy/user/email/:email", "/legacy/user/email/:email"},
153 {"/users/:user", "/users/:user"},
154 {"/user", "/user"},
155 {"/users", "/users"},
156 {"/user/emails", "/user/emails"},
157 {"/users/:user/followers", "/users/:user/followers"},
158 {"/user/followers", "/user/followers"},
159 {"/users/:user/following", "/users/:user/following"},
160 {"/user/following", "/user/following"},
161 {"/user/following/:user", "/user/following/:user"},
162 {"/users/:user/following/:target_user", "/users/:user/following/:target_user"},
163 {"/users/:user/keys", "/users/:user/keys"},
164 {"/user/keys", "/user/keys"},
165 {"/user/keys/:id", "/user/keys/:id"},
166 {"/people/:userId", "/people/:userId"},
167 {"/people", "/people"},
168 {"/activities/:activityId/people/:collection", "/activities/:activityId/people/:collection"},
169 {"/people/:userId/people/:collection", "/people/:userId/people/:collection"},
170 {"/people/:userId/openIdConnect", "/people/:userId/openIdConnect"},
171 {"/people/:userId/activities/:collection", "/people/:userId/activities/:collection"},
172 {"/activities/:activityId", "/activities/:activityId"},
173 {"/activities", "/activities"},
174 {"/activities/:activityId/comments", "/activities/:activityId/comments"},
175 {"/comments/:commentId", "/comments/:commentId"},
176 {"/people/:userId/moments/:collection", "/people/:userId/moments/:collection"},
177 }
178
179 type testcase struct {
180 path string
181 value interface{}
182 params []denco.Param
183 found bool
184 }
185
186 func runLookupTest(t *testing.T, records []denco.Record, testcases []testcase) {
187 r := denco.New()
188 if err := r.Build(records); err != nil {
189 t.Fatal(err)
190 }
191 for _, testcase := range testcases {
192 data, params, found := r.Lookup(testcase.path)
193 if !reflect.DeepEqual(data, testcase.value) || !reflect.DeepEqual(params, denco.Params(testcase.params)) || !reflect.DeepEqual(found, testcase.found) {
194 t.Errorf("Router.Lookup(%q) => (%#v, %#v, %#v), want (%#v, %#v, %#v)", testcase.path, data, params, found, testcase.value, denco.Params(testcase.params), testcase.found)
195 }
196 }
197 }
198
199 func TestRouter_Lookup(t *testing.T) {
200 testcases := []testcase{
201 {"/", "testroute0", nil, true},
202 {"/gists/1323/foo/bar", "testroute11", []denco.Param{{"param1", "1323"}}, true},
203 {"/gists/1323/foo/133", "testroute12", []denco.Param{{"param1", "1323"}, {"param2", "133"}}, true},
204 {"/234/1323/foo/133", "testroute13", []denco.Param{{"param1", "234"}, {"param2", "1323"}, {"param3", "133"}}, true},
205 {"/path/to/route", "testroute1", nil, true},
206 {"/path/to/other", "testroute2", nil, true},
207 {"/path/to/route/a", "testroute3", nil, true},
208 {"/path/to/hoge", "testroute4", []denco.Param{{"param", "hoge"}}, true},
209 {"/path/to/wildcard/some/params", "testroute5", []denco.Param{{"routepath", "some/params"}}, true},
210 {"/path/to/o1/o2", "testroute6", []denco.Param{{"param1", "o1"}, {"param2", "o2"}}, true},
211 {"/path/to/p1/sep/p2", "testroute7", []denco.Param{{"param1", "p1"}, {"param2", "p2"}}, true},
212 {"/2014/01/06", "testroute8", []denco.Param{{"year", "2014"}, {"month", "01"}, {"day", "06"}}, true},
213 {"/user/777", "testroute9", []denco.Param{{"id", "777"}}, true},
214 {"/a/to/b/p1/some/wildcard/params", "testroute10", []denco.Param{{"param", "p1"}, {"routepath", "some/wildcard/params"}}, true},
215 {"/missing", nil, nil, false},
216 {"/path/with/key=value", "testroute14", []denco.Param{{"value", "value"}}, true},
217 }
218 runLookupTest(t, routes(), testcases)
219
220 records := []denco.Record{
221 {"/", "testroute0"},
222 {"/:b", "testroute1"},
223 {"/*wildcard", "testroute2"},
224 }
225 testcases = []testcase{
226 {"/", "testroute0", nil, true},
227 {"/true", "testroute1", []denco.Param{{"b", "true"}}, true},
228 {"/foo/bar", "testroute2", []denco.Param{{"wildcard", "foo/bar"}}, true},
229 }
230 runLookupTest(t, records, testcases)
231
232 records = []denco.Record{
233 {"/networks/:owner/:repo/events", "testroute0"},
234 {"/orgs/:org/events", "testroute1"},
235 {"/notifications/threads/:id", "testroute2"},
236 {"/mypathisgreat/:thing-id", "testroute3"},
237 }
238 testcases = []testcase{
239 {"/networks/:owner/:repo/events", "testroute0", []denco.Param{{"owner", ":owner"}, {"repo", ":repo"}}, true},
240 {"/orgs/:org/events", "testroute1", []denco.Param{{"org", ":org"}}, true},
241 {"/notifications/threads/:id", "testroute2", []denco.Param{{"id", ":id"}}, true},
242 {"/mypathisgreat/:thing-id", "testroute3", []denco.Param{{"thing-id", ":thing-id"}}, true},
243 }
244 runLookupTest(t, records, testcases)
245
246 runLookupTest(t, []denco.Record{
247 {"/", "route2"},
248 }, []testcase{
249 {"/user/alice", nil, nil, false},
250 })
251
252 runLookupTest(t, []denco.Record{
253 {"/user/:name", "route1"},
254 }, []testcase{
255 {"/", nil, nil, false},
256 })
257
258 runLookupTest(t, []denco.Record{
259 {"/*wildcard", "testroute0"},
260 {"/a/:b", "testroute1"},
261 }, []testcase{
262 {"/a", "testroute0", []denco.Param{{"wildcard", "a"}}, true},
263 })
264 }
265
266 func TestRouter_Lookup_withManyRoutes(t *testing.T) {
267 n := 1000
268 records := make([]denco.Record, n)
269 for i := 0; i < n; i++ {
270 records[i] = denco.Record{Key: "/" + randomString(rand.Intn(50)+10), Value: fmt.Sprintf("route%d", i)}
271 }
272 router := denco.New()
273 require.NoError(t, router.Build(records))
274
275 for _, r := range records {
276 data, params, found := router.Lookup(r.Key)
277 assert.Equal(t, r.Value, data)
278 assert.Empty(t, params)
279 assert.True(t, found)
280 }
281 }
282
283 func TestRouter_Lookup_realURIs(t *testing.T) {
284 testcases := []testcase{
285 {"/authorizations", "/authorizations", nil, true},
286 {"/authorizations/1", "/authorizations/:id", []denco.Param{{"id", "1"}}, true},
287 {"/applications/1/tokens/zohRoo7e", "/applications/:client_id/tokens/:access_token", []denco.Param{{"client_id", "1"}, {"access_token", "zohRoo7e"}}, true},
288 {"/events", "/events", nil, true},
289 {"/repos/naoina/denco/events", "/repos/:owner/:repo/events", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
290 {"/networks/naoina/denco/events", "/networks/:owner/:repo/events", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
291 {"/orgs/something/events", "/orgs/:org/events", []denco.Param{{"org", "something"}}, true},
292 {"/users/naoina/received_events", "/users/:user/received_events", []denco.Param{{"user", "naoina"}}, true},
293 {"/users/naoina/received_events/public", "/users/:user/received_events/public", []denco.Param{{"user", "naoina"}}, true},
294 {"/users/naoina/events", "/users/:user/events", []denco.Param{{"user", "naoina"}}, true},
295 {"/users/naoina/events/public", "/users/:user/events/public", []denco.Param{{"user", "naoina"}}, true},
296 {"/users/naoina/events/orgs/something", "/users/:user/events/orgs/:org", []denco.Param{{"user", "naoina"}, {"org", "something"}}, true},
297 {"/feeds", "/feeds", nil, true},
298 {"/notifications", "/notifications", nil, true},
299 {"/repos/naoina/denco/notifications", "/repos/:owner/:repo/notifications", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
300 {"/notifications/threads/1", "/notifications/threads/:id", []denco.Param{{"id", "1"}}, true},
301 {"/notifications/threads/2/subscription", "/notifications/threads/:id/subscription", []denco.Param{{"id", "2"}}, true},
302 {"/repos/naoina/denco/stargazers", "/repos/:owner/:repo/stargazers", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
303 {"/users/naoina/starred", "/users/:user/starred", []denco.Param{{"user", "naoina"}}, true},
304 {"/user/starred", "/user/starred", nil, true},
305 {"/user/starred/naoina/denco", "/user/starred/:owner/:repo", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
306 {"/repos/naoina/denco/subscribers", "/repos/:owner/:repo/subscribers", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
307 {"/users/naoina/subscriptions", "/users/:user/subscriptions", []denco.Param{{"user", "naoina"}}, true},
308 {"/user/subscriptions", "/user/subscriptions", nil, true},
309 {"/repos/naoina/denco/subscription", "/repos/:owner/:repo/subscription", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
310 {"/user/subscriptions/naoina/denco", "/user/subscriptions/:owner/:repo", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
311 {"/users/naoina/gists", "/users/:user/gists", []denco.Param{{"user", "naoina"}}, true},
312 {"/gists", "/gists", nil, true},
313 {"/gists/1", "/gists/:id", []denco.Param{{"id", "1"}}, true},
314 {"/gists/2/star", "/gists/:id/star", []denco.Param{{"id", "2"}}, true},
315 {"/repos/naoina/denco/git/blobs/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/blobs/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
316 {"/repos/naoina/denco/git/commits/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/commits/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
317 {"/repos/naoina/denco/git/refs", "/repos/:owner/:repo/git/refs", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
318 {"/repos/naoina/denco/git/tags/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/tags/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
319 {"/repos/naoina/denco/git/trees/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/git/trees/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
320 {"/issues", "/issues", nil, true},
321 {"/user/issues", "/user/issues", nil, true},
322 {"/orgs/something/issues", "/orgs/:org/issues", []denco.Param{{"org", "something"}}, true},
323 {"/repos/naoina/denco/issues", "/repos/:owner/:repo/issues", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
324 {"/repos/naoina/denco/issues/1", "/repos/:owner/:repo/issues/:number", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
325 {"/repos/naoina/denco/assignees", "/repos/:owner/:repo/assignees", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
326 {"/repos/naoina/denco/assignees/foo", "/repos/:owner/:repo/assignees/:assignee", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"assignee", "foo"}}, true},
327 {"/repos/naoina/denco/issues/1/comments", "/repos/:owner/:repo/issues/:number/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
328 {"/repos/naoina/denco/issues/1/events", "/repos/:owner/:repo/issues/:number/events", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
329 {"/repos/naoina/denco/labels", "/repos/:owner/:repo/labels", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
330 {"/repos/naoina/denco/labels/bug", "/repos/:owner/:repo/labels/:name", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"name", "bug"}}, true},
331 {"/repos/naoina/denco/issues/1/labels", "/repos/:owner/:repo/issues/:number/labels", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
332 {"/repos/naoina/denco/milestones/1/labels", "/repos/:owner/:repo/milestones/:number/labels", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
333 {"/repos/naoina/denco/milestones", "/repos/:owner/:repo/milestones", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
334 {"/repos/naoina/denco/milestones/1", "/repos/:owner/:repo/milestones/:number", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
335 {"/emojis", "/emojis", nil, true},
336 {"/gitignore/templates", "/gitignore/templates", nil, true},
337 {"/gitignore/templates/Go", "/gitignore/templates/:name", []denco.Param{{"name", "Go"}}, true},
338 {"/meta", "/meta", nil, true},
339 {"/rate_limit", "/rate_limit", nil, true},
340 {"/users/naoina/orgs", "/users/:user/orgs", []denco.Param{{"user", "naoina"}}, true},
341 {"/user/orgs", "/user/orgs", nil, true},
342 {"/orgs/something", "/orgs/:org", []denco.Param{{"org", "something"}}, true},
343 {"/orgs/something/members", "/orgs/:org/members", []denco.Param{{"org", "something"}}, true},
344 {"/orgs/something/members/naoina", "/orgs/:org/members/:user", []denco.Param{{"org", "something"}, {"user", "naoina"}}, true},
345 {"/orgs/something/public_members", "/orgs/:org/public_members", []denco.Param{{"org", "something"}}, true},
346 {"/orgs/something/public_members/naoina", "/orgs/:org/public_members/:user", []denco.Param{{"org", "something"}, {"user", "naoina"}}, true},
347 {"/orgs/something/teams", "/orgs/:org/teams", []denco.Param{{"org", "something"}}, true},
348 {"/teams/1", "/teams/:id", []denco.Param{{"id", "1"}}, true},
349 {"/teams/2/members", "/teams/:id/members", []denco.Param{{"id", "2"}}, true},
350 {"/teams/3/members/naoina", "/teams/:id/members/:user", []denco.Param{{"id", "3"}, {"user", "naoina"}}, true},
351 {"/teams/4/repos", "/teams/:id/repos", []denco.Param{{"id", "4"}}, true},
352 {"/teams/5/repos/naoina/denco", "/teams/:id/repos/:owner/:repo", []denco.Param{{"id", "5"}, {"owner", "naoina"}, {"repo", "denco"}}, true},
353 {"/user/teams", "/user/teams", nil, true},
354 {"/repos/naoina/denco/pulls", "/repos/:owner/:repo/pulls", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
355 {"/repos/naoina/denco/pulls/1", "/repos/:owner/:repo/pulls/:number", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
356 {"/repos/naoina/denco/pulls/1/commits", "/repos/:owner/:repo/pulls/:number/commits", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
357 {"/repos/naoina/denco/pulls/1/files", "/repos/:owner/:repo/pulls/:number/files", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
358 {"/repos/naoina/denco/pulls/1/merge", "/repos/:owner/:repo/pulls/:number/merge", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
359 {"/repos/naoina/denco/pulls/1/comments", "/repos/:owner/:repo/pulls/:number/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"number", "1"}}, true},
360 {"/user/repos", "/user/repos", nil, true},
361 {"/users/naoina/repos", "/users/:user/repos", []denco.Param{{"user", "naoina"}}, true},
362 {"/orgs/something/repos", "/orgs/:org/repos", []denco.Param{{"org", "something"}}, true},
363 {"/repositories", "/repositories", nil, true},
364 {"/repos/naoina/denco", "/repos/:owner/:repo", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
365 {"/repos/naoina/denco/contributors", "/repos/:owner/:repo/contributors", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
366 {"/repos/naoina/denco/languages", "/repos/:owner/:repo/languages", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
367 {"/repos/naoina/denco/teams", "/repos/:owner/:repo/teams", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
368 {"/repos/naoina/denco/tags", "/repos/:owner/:repo/tags", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
369 {"/repos/naoina/denco/branches", "/repos/:owner/:repo/branches", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
370 {"/repos/naoina/denco/branches/master", "/repos/:owner/:repo/branches/:branch", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"branch", "master"}}, true},
371 {"/repos/naoina/denco/collaborators", "/repos/:owner/:repo/collaborators", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
372 {"/repos/naoina/denco/collaborators/something", "/repos/:owner/:repo/collaborators/:user", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"user", "something"}}, true},
373 {"/repos/naoina/denco/comments", "/repos/:owner/:repo/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
374 {"/repos/naoina/denco/commits/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9/comments", "/repos/:owner/:repo/commits/:sha/comments", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
375 {"/repos/naoina/denco/comments/1", "/repos/:owner/:repo/comments/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
376 {"/repos/naoina/denco/commits", "/repos/:owner/:repo/commits", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
377 {"/repos/naoina/denco/commits/03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9", "/repos/:owner/:repo/commits/:sha", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"sha", "03c3bbc7f0d12268b9ca53d4fbfd8dc5ae5697b9"}}, true},
378 {"/repos/naoina/denco/readme", "/repos/:owner/:repo/readme", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
379 {"/repos/naoina/denco/keys", "/repos/:owner/:repo/keys", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
380 {"/repos/naoina/denco/keys/1", "/repos/:owner/:repo/keys/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
381 {"/repos/naoina/denco/downloads", "/repos/:owner/:repo/downloads", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
382 {"/repos/naoina/denco/downloads/2", "/repos/:owner/:repo/downloads/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "2"}}, true},
383 {"/repos/naoina/denco/forks", "/repos/:owner/:repo/forks", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
384 {"/repos/naoina/denco/hooks", "/repos/:owner/:repo/hooks", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
385 {"/repos/naoina/denco/hooks/2", "/repos/:owner/:repo/hooks/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "2"}}, true},
386 {"/repos/naoina/denco/releases", "/repos/:owner/:repo/releases", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
387 {"/repos/naoina/denco/releases/1", "/repos/:owner/:repo/releases/:id", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
388 {"/repos/naoina/denco/releases/1/assets", "/repos/:owner/:repo/releases/:id/assets", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"id", "1"}}, true},
389 {"/repos/naoina/denco/stats/contributors", "/repos/:owner/:repo/stats/contributors", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
390 {"/repos/naoina/denco/stats/commit_activity", "/repos/:owner/:repo/stats/commit_activity", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
391 {"/repos/naoina/denco/stats/code_frequency", "/repos/:owner/:repo/stats/code_frequency", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
392 {"/repos/naoina/denco/stats/participation", "/repos/:owner/:repo/stats/participation", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
393 {"/repos/naoina/denco/stats/punch_card", "/repos/:owner/:repo/stats/punch_card", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}}, true},
394 {"/repos/naoina/denco/statuses/master", "/repos/:owner/:repo/statuses/:ref", []denco.Param{{"owner", "naoina"}, {"repo", "denco"}, {"ref", "master"}}, true},
395 {"/search/repositories", "/search/repositories", nil, true},
396 {"/search/code", "/search/code", nil, true},
397 {"/search/issues", "/search/issues", nil, true},
398 {"/search/users", "/search/users", nil, true},
399 {"/legacy/issues/search/naoina/denco/closed/test", "/legacy/issues/search/:owner/:repository/:state/:keyword", []denco.Param{{"owner", "naoina"}, {"repository", "denco"}, {"state", "closed"}, {"keyword", "test"}}, true},
400 {"/legacy/repos/search/test", "/legacy/repos/search/:keyword", []denco.Param{{"keyword", "test"}}, true},
401 {"/legacy/user/search/test", "/legacy/user/search/:keyword", []denco.Param{{"keyword", "test"}}, true},
402 {"/legacy/user/email/naoina@kuune.org", "/legacy/user/email/:email", []denco.Param{{"email", "naoina@kuune.org"}}, true},
403 {"/users/naoina", "/users/:user", []denco.Param{{"user", "naoina"}}, true},
404 {"/user", "/user", nil, true},
405 {"/users", "/users", nil, true},
406 {"/user/emails", "/user/emails", nil, true},
407 {"/users/naoina/followers", "/users/:user/followers", []denco.Param{{"user", "naoina"}}, true},
408 {"/user/followers", "/user/followers", nil, true},
409 {"/users/naoina/following", "/users/:user/following", []denco.Param{{"user", "naoina"}}, true},
410 {"/user/following", "/user/following", nil, true},
411 {"/user/following/naoina", "/user/following/:user", []denco.Param{{"user", "naoina"}}, true},
412 {"/users/naoina/following/target", "/users/:user/following/:target_user", []denco.Param{{"user", "naoina"}, {"target_user", "target"}}, true},
413 {"/users/naoina/keys", "/users/:user/keys", []denco.Param{{"user", "naoina"}}, true},
414 {"/user/keys", "/user/keys", nil, true},
415 {"/user/keys/1", "/user/keys/:id", []denco.Param{{"id", "1"}}, true},
416 {"/people/me", "/people/:userId", []denco.Param{{"userId", "me"}}, true},
417 {"/people", "/people", nil, true},
418 {"/activities/foo/people/vault", "/activities/:activityId/people/:collection", []denco.Param{{"activityId", "foo"}, {"collection", "vault"}}, true},
419 {"/people/me/people/vault", "/people/:userId/people/:collection", []denco.Param{{"userId", "me"}, {"collection", "vault"}}, true},
420 {"/people/me/openIdConnect", "/people/:userId/openIdConnect", []denco.Param{{"userId", "me"}}, true},
421 {"/people/me/activities/vault", "/people/:userId/activities/:collection", []denco.Param{{"userId", "me"}, {"collection", "vault"}}, true},
422 {"/activities/foo", "/activities/:activityId", []denco.Param{{"activityId", "foo"}}, true},
423 {"/activities", "/activities", nil, true},
424 {"/activities/foo/comments", "/activities/:activityId/comments", []denco.Param{{"activityId", "foo"}}, true},
425 {"/comments/hoge", "/comments/:commentId", []denco.Param{{"commentId", "hoge"}}, true},
426 {"/people/me/moments/vault", "/people/:userId/moments/:collection", []denco.Param{{"userId", "me"}, {"collection", "vault"}}, true},
427 }
428 runLookupTest(t, realURIs, testcases)
429 }
430
431 func TestRouter_Build(t *testing.T) {
432
433 func() {
434 r := denco.New()
435 require.Errorf(t,
436 r.Build([]denco.Record{
437 {"/:user/:id/:id", "testroute0"},
438 {"/:user/:user/:id", "testroute0"},
439 }),
440 "no error returned by duplicate name of path parameters",
441 )
442 }()
443 }
444
445 func TestRouter_Build_withoutSizeHint(t *testing.T) {
446 for _, v := range []struct {
447 keys []string
448 sizeHint int
449 }{
450 {[]string{"/user"}, 0},
451 {[]string{"/user/:id"}, 1},
452 {[]string{"/user/:id/post"}, 1},
453 {[]string{"/user/:id/post:validate"}, 2},
454 {[]string{"/user/:id/:group"}, 2},
455 {[]string{"/user/:id/post/:cid"}, 2},
456 {[]string{"/user/:id/post/:cid", "/admin/:id/post/:cid"}, 2},
457 {[]string{"/user/:id", "/admin/:id/post/:cid"}, 2},
458 {[]string{"/user/:id/post/:cid", "/admin/:id/post/:cid/:type"}, 3},
459 } {
460 r := denco.New()
461 actual := r.SizeHint
462 expected := -1
463
464 assert.Equalf(t, expected, actual, `before Build; Router.SizeHint => (%[1]T=%#[1]v); want (%[2]T=%#[2]v)`, actual, expected)
465 records := make([]denco.Record, len(v.keys))
466 for i, k := range v.keys {
467 records[i] = denco.Record{Key: k, Value: "value"}
468 }
469 require.NoError(t, r.Build(records))
470 actual = r.SizeHint
471 expected = v.sizeHint
472 assert.Equalf(t, expected, actual, `Router.Build(%#v); Router.SizeHint => (%[2]T=%#[2]v); want (%[3]T=%#[3]v)`, records, actual, expected)
473 }
474 }
475
476 func TestRouter_Build_withSizeHint(t *testing.T) {
477 for _, v := range []struct {
478 key string
479 sizeHint int
480 expect int
481 }{
482 {"/user", 0, 0},
483 {"/user", 1, 1},
484 {"/user", 2, 2},
485 {"/user/:id", 3, 3},
486 {"/user/:id/:group", 0, 0},
487 {"/user/:id/:group", 1, 1},
488 {"/user/:id/:group:validate", 1, 1},
489 } {
490 r := denco.New()
491 r.SizeHint = v.sizeHint
492 records := []denco.Record{
493 {v.key, "value"},
494 }
495 require.NoError(t, r.Build(records))
496 actual := r.SizeHint
497 expected := v.expect
498 assert.Equalf(t, expected, actual, `Router.Build(%#v); Router.SizeHint => (%[2]T=%#[2]v); want (%[3]T=%#[3]v)`, records, actual, expected)
499 }
500 }
501
502 func TestParams_Get(t *testing.T) {
503 params := denco.Params([]denco.Param{
504 {"name1", "value1"},
505 {"name2", "value2"},
506 {"name3", "value3"},
507 {"name1", "value4"},
508 })
509 for _, v := range []struct{ value, expected string }{
510 {"name1", "value1"},
511 {"name2", "value2"},
512 {"name3", "value3"},
513 {"name4", ""},
514 } {
515 actual := params.Get(v.value)
516 expected := v.expected
517 assert.Equal(t, expected, actual, "Params.Get(%q) => %#v, want %#v", v.value, actual, expected)
518 }
519 }
520
View as plain text