1 package chi
2
3 import (
4 "fmt"
5 "log"
6 "net/http"
7 "testing"
8 )
9
10 func TestTree(t *testing.T) {
11 hStub := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
12 hIndex := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
13 hFavicon := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
14 hArticleList := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
15 hArticleNear := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
16 hArticleShow := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
17 hArticleShowRelated := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
18 hArticleShowOpts := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
19 hArticleSlug := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
20 hArticleByUser := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
21 hUserList := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
22 hUserShow := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
23 hAdminCatchall := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
24 hAdminAppShow := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
25 hAdminAppShowCatchall := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
26 hUserProfile := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
27 hUserSuper := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
28 hUserAll := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
29 hHubView1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
30 hHubView2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
31 hHubView3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
32
33 tr := &node{}
34
35 tr.InsertRoute(mGET, "/", hIndex)
36 tr.InsertRoute(mGET, "/favicon.ico", hFavicon)
37
38 tr.InsertRoute(mGET, "/pages/*", hStub)
39
40 tr.InsertRoute(mGET, "/article", hArticleList)
41 tr.InsertRoute(mGET, "/article/", hArticleList)
42
43 tr.InsertRoute(mGET, "/article/near", hArticleNear)
44 tr.InsertRoute(mGET, "/article/{id}", hStub)
45 tr.InsertRoute(mGET, "/article/{id}", hArticleShow)
46 tr.InsertRoute(mGET, "/article/{id}", hArticleShow)
47 tr.InsertRoute(mGET, "/article/@{user}", hArticleByUser)
48
49 tr.InsertRoute(mGET, "/article/{sup}/{opts}", hArticleShowOpts)
50 tr.InsertRoute(mGET, "/article/{id}/{opts}", hArticleShowOpts)
51
52 tr.InsertRoute(mGET, "/article/{iffd}/edit", hStub)
53 tr.InsertRoute(mGET, "/article/{id}//related", hArticleShowRelated)
54 tr.InsertRoute(mGET, "/article/slug/{month}/-/{day}/{year}", hArticleSlug)
55
56 tr.InsertRoute(mGET, "/admin/user", hUserList)
57 tr.InsertRoute(mGET, "/admin/user/", hStub)
58 tr.InsertRoute(mGET, "/admin/user/", hUserList)
59
60 tr.InsertRoute(mGET, "/admin/user//{id}", hUserShow)
61 tr.InsertRoute(mGET, "/admin/user/{id}", hUserShow)
62
63 tr.InsertRoute(mGET, "/admin/apps/{id}", hAdminAppShow)
64 tr.InsertRoute(mGET, "/admin/apps/{id}/*", hAdminAppShowCatchall)
65
66 tr.InsertRoute(mGET, "/admin/*", hStub)
67 tr.InsertRoute(mGET, "/admin/*", hAdminCatchall)
68
69 tr.InsertRoute(mGET, "/users/{userID}/profile", hUserProfile)
70 tr.InsertRoute(mGET, "/users/super/*", hUserSuper)
71 tr.InsertRoute(mGET, "/users/*", hUserAll)
72
73 tr.InsertRoute(mGET, "/hubs/{hubID}/view", hHubView1)
74 tr.InsertRoute(mGET, "/hubs/{hubID}/view/*", hHubView2)
75 sr := NewRouter()
76 sr.Get("/users", hHubView3)
77 tr.InsertRoute(mGET, "/hubs/{hubID}/*", sr)
78 tr.InsertRoute(mGET, "/hubs/{hubID}/users", hHubView3)
79
80 tests := []struct {
81 r string
82 h http.Handler
83 k []string
84 v []string
85 }{
86 {r: "/", h: hIndex, k: []string{}, v: []string{}},
87 {r: "/favicon.ico", h: hFavicon, k: []string{}, v: []string{}},
88
89 {r: "/pages", h: nil, k: []string{}, v: []string{}},
90 {r: "/pages/", h: hStub, k: []string{"*"}, v: []string{""}},
91 {r: "/pages/yes", h: hStub, k: []string{"*"}, v: []string{"yes"}},
92
93 {r: "/article", h: hArticleList, k: []string{}, v: []string{}},
94 {r: "/article/", h: hArticleList, k: []string{}, v: []string{}},
95 {r: "/article/near", h: hArticleNear, k: []string{}, v: []string{}},
96 {r: "/article/neard", h: hArticleShow, k: []string{"id"}, v: []string{"neard"}},
97 {r: "/article/123", h: hArticleShow, k: []string{"id"}, v: []string{"123"}},
98 {r: "/article/123/456", h: hArticleShowOpts, k: []string{"id", "opts"}, v: []string{"123", "456"}},
99 {r: "/article/@peter", h: hArticleByUser, k: []string{"user"}, v: []string{"peter"}},
100 {r: "/article/22//related", h: hArticleShowRelated, k: []string{"id"}, v: []string{"22"}},
101 {r: "/article/111/edit", h: hStub, k: []string{"iffd"}, v: []string{"111"}},
102 {r: "/article/slug/sept/-/4/2015", h: hArticleSlug, k: []string{"month", "day", "year"}, v: []string{"sept", "4", "2015"}},
103 {r: "/article/:id", h: hArticleShow, k: []string{"id"}, v: []string{":id"}},
104
105 {r: "/admin/user", h: hUserList, k: []string{}, v: []string{}},
106 {r: "/admin/user/", h: hUserList, k: []string{}, v: []string{}},
107 {r: "/admin/user/1", h: hUserShow, k: []string{"id"}, v: []string{"1"}},
108 {r: "/admin/user//1", h: hUserShow, k: []string{"id"}, v: []string{"1"}},
109 {r: "/admin/hi", h: hAdminCatchall, k: []string{"*"}, v: []string{"hi"}},
110 {r: "/admin/lots/of/:fun", h: hAdminCatchall, k: []string{"*"}, v: []string{"lots/of/:fun"}},
111 {r: "/admin/apps/333", h: hAdminAppShow, k: []string{"id"}, v: []string{"333"}},
112 {r: "/admin/apps/333/woot", h: hAdminAppShowCatchall, k: []string{"id", "*"}, v: []string{"333", "woot"}},
113
114 {r: "/hubs/123/view", h: hHubView1, k: []string{"hubID"}, v: []string{"123"}},
115 {r: "/hubs/123/view/index.html", h: hHubView2, k: []string{"hubID", "*"}, v: []string{"123", "index.html"}},
116 {r: "/hubs/123/users", h: hHubView3, k: []string{"hubID"}, v: []string{"123"}},
117
118 {r: "/users/123/profile", h: hUserProfile, k: []string{"userID"}, v: []string{"123"}},
119 {r: "/users/super/123/okay/yes", h: hUserSuper, k: []string{"*"}, v: []string{"123/okay/yes"}},
120 {r: "/users/123/okay/yes", h: hUserAll, k: []string{"*"}, v: []string{"123/okay/yes"}},
121 }
122
123
124
125
126
127
128
129 for i, tt := range tests {
130 rctx := NewRouteContext()
131
132 _, handlers, _ := tr.FindRoute(rctx, mGET, tt.r)
133
134 var handler http.Handler
135 if methodHandler, ok := handlers[mGET]; ok {
136 handler = methodHandler.handler
137 }
138
139 paramKeys := rctx.routeParams.Keys
140 paramValues := rctx.routeParams.Values
141
142 if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) {
143 t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler)
144 }
145 if !stringSliceEqual(tt.k, paramKeys) {
146 t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys)
147 }
148 if !stringSliceEqual(tt.v, paramValues) {
149 t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues)
150 }
151 }
152 }
153
154 func TestTreeMoar(t *testing.T) {
155 hStub := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
156 hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
157 hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
158 hStub3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
159 hStub4 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
160 hStub5 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
161 hStub6 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
162 hStub7 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
163 hStub8 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
164 hStub9 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
165 hStub10 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
166 hStub11 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
167 hStub12 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
168 hStub13 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
169 hStub14 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
170 hStub15 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
171 hStub16 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
172
173
174
175
176 tr := &node{}
177
178 tr.InsertRoute(mGET, "/articlefun", hStub5)
179 tr.InsertRoute(mGET, "/articles/{id}", hStub)
180 tr.InsertRoute(mDELETE, "/articles/{slug}", hStub8)
181 tr.InsertRoute(mGET, "/articles/search", hStub1)
182 tr.InsertRoute(mGET, "/articles/{id}:delete", hStub8)
183 tr.InsertRoute(mGET, "/articles/{iidd}!sup", hStub4)
184 tr.InsertRoute(mGET, "/articles/{id}:{op}", hStub3)
185 tr.InsertRoute(mGET, "/articles/{id}:{op}", hStub2)
186 tr.InsertRoute(mGET, "/articles/{slug:^[a-z]+}/posts", hStub)
187 tr.InsertRoute(mGET, "/articles/{id}/posts/{pid}", hStub6)
188 tr.InsertRoute(mGET, "/articles/{id}/posts/{month}/{day}/{year}/{slug}", hStub7)
189 tr.InsertRoute(mGET, "/articles/{id}.json", hStub10)
190 tr.InsertRoute(mGET, "/articles/{id}/data.json", hStub11)
191 tr.InsertRoute(mGET, "/articles/files/{file}.{ext}", hStub12)
192 tr.InsertRoute(mPUT, "/articles/me", hStub13)
193
194
195
196
197 tr.InsertRoute(mGET, "/pages/*", hStub)
198 tr.InsertRoute(mGET, "/pages/*", hStub9)
199
200 tr.InsertRoute(mGET, "/users/{id}", hStub14)
201 tr.InsertRoute(mGET, "/users/{id}/settings/{key}", hStub15)
202 tr.InsertRoute(mGET, "/users/{id}/settings/*", hStub16)
203
204 tests := []struct {
205 m methodTyp
206 r string
207 h http.Handler
208 k []string
209 v []string
210 }{
211 {m: mGET, r: "/articles/search", h: hStub1, k: []string{}, v: []string{}},
212 {m: mGET, r: "/articlefun", h: hStub5, k: []string{}, v: []string{}},
213 {m: mGET, r: "/articles/123", h: hStub, k: []string{"id"}, v: []string{"123"}},
214 {m: mDELETE, r: "/articles/123mm", h: hStub8, k: []string{"slug"}, v: []string{"123mm"}},
215 {m: mGET, r: "/articles/789:delete", h: hStub8, k: []string{"id"}, v: []string{"789"}},
216 {m: mGET, r: "/articles/789!sup", h: hStub4, k: []string{"iidd"}, v: []string{"789"}},
217 {m: mGET, r: "/articles/123:sync", h: hStub2, k: []string{"id", "op"}, v: []string{"123", "sync"}},
218 {m: mGET, r: "/articles/456/posts/1", h: hStub6, k: []string{"id", "pid"}, v: []string{"456", "1"}},
219 {m: mGET, r: "/articles/456/posts/09/04/1984/juice", h: hStub7, k: []string{"id", "month", "day", "year", "slug"}, v: []string{"456", "09", "04", "1984", "juice"}},
220 {m: mGET, r: "/articles/456.json", h: hStub10, k: []string{"id"}, v: []string{"456"}},
221 {m: mGET, r: "/articles/456/data.json", h: hStub11, k: []string{"id"}, v: []string{"456"}},
222
223 {m: mGET, r: "/articles/files/file.zip", h: hStub12, k: []string{"file", "ext"}, v: []string{"file", "zip"}},
224 {m: mGET, r: "/articles/files/photos.tar.gz", h: hStub12, k: []string{"file", "ext"}, v: []string{"photos", "tar.gz"}},
225 {m: mGET, r: "/articles/files/photos.tar.gz", h: hStub12, k: []string{"file", "ext"}, v: []string{"photos", "tar.gz"}},
226
227 {m: mPUT, r: "/articles/me", h: hStub13, k: []string{}, v: []string{}},
228 {m: mGET, r: "/articles/me", h: hStub, k: []string{"id"}, v: []string{"me"}},
229 {m: mGET, r: "/pages", h: nil, k: []string{}, v: []string{}},
230 {m: mGET, r: "/pages/", h: hStub9, k: []string{"*"}, v: []string{""}},
231 {m: mGET, r: "/pages/yes", h: hStub9, k: []string{"*"}, v: []string{"yes"}},
232
233 {m: mGET, r: "/users/1", h: hStub14, k: []string{"id"}, v: []string{"1"}},
234 {m: mGET, r: "/users/", h: nil, k: []string{}, v: []string{}},
235 {m: mGET, r: "/users/2/settings/password", h: hStub15, k: []string{"id", "key"}, v: []string{"2", "password"}},
236 {m: mGET, r: "/users/2/settings/", h: hStub16, k: []string{"id", "*"}, v: []string{"2", ""}},
237 }
238
239
240
241
242
243
244
245 for i, tt := range tests {
246 rctx := NewRouteContext()
247
248 _, handlers, _ := tr.FindRoute(rctx, tt.m, tt.r)
249
250 var handler http.Handler
251 if methodHandler, ok := handlers[tt.m]; ok {
252 handler = methodHandler.handler
253 }
254
255 paramKeys := rctx.routeParams.Keys
256 paramValues := rctx.routeParams.Values
257
258 if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) {
259 t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler)
260 }
261 if !stringSliceEqual(tt.k, paramKeys) {
262 t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys)
263 }
264 if !stringSliceEqual(tt.v, paramValues) {
265 t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues)
266 }
267 }
268 }
269
270 func TestTreeRegexp(t *testing.T) {
271 hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
272 hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
273 hStub3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
274 hStub4 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
275 hStub5 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
276 hStub6 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
277 hStub7 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
278
279 tr := &node{}
280 tr.InsertRoute(mGET, "/articles/{rid:^[0-9]{5,6}}", hStub7)
281 tr.InsertRoute(mGET, "/articles/{zid:^0[0-9]+}", hStub3)
282 tr.InsertRoute(mGET, "/articles/{name:^@[a-z]+}/posts", hStub4)
283 tr.InsertRoute(mGET, "/articles/{op:^[0-9]+}/run", hStub5)
284 tr.InsertRoute(mGET, "/articles/{id:^[0-9]+}", hStub1)
285 tr.InsertRoute(mGET, "/articles/{id:^[1-9]+}-{aux}", hStub6)
286 tr.InsertRoute(mGET, "/articles/{slug}", hStub2)
287
288
289
290
291
292
293
294 tests := []struct {
295 r string
296 h http.Handler
297 k []string
298 v []string
299 }{
300 {r: "/articles", h: nil, k: []string{}, v: []string{}},
301 {r: "/articles/12345", h: hStub7, k: []string{"rid"}, v: []string{"12345"}},
302 {r: "/articles/123", h: hStub1, k: []string{"id"}, v: []string{"123"}},
303 {r: "/articles/how-to-build-a-router", h: hStub2, k: []string{"slug"}, v: []string{"how-to-build-a-router"}},
304 {r: "/articles/0456", h: hStub3, k: []string{"zid"}, v: []string{"0456"}},
305 {r: "/articles/@pk/posts", h: hStub4, k: []string{"name"}, v: []string{"@pk"}},
306 {r: "/articles/1/run", h: hStub5, k: []string{"op"}, v: []string{"1"}},
307 {r: "/articles/1122", h: hStub1, k: []string{"id"}, v: []string{"1122"}},
308 {r: "/articles/1122-yes", h: hStub6, k: []string{"id", "aux"}, v: []string{"1122", "yes"}},
309 }
310
311 for i, tt := range tests {
312 rctx := NewRouteContext()
313
314 _, handlers, _ := tr.FindRoute(rctx, mGET, tt.r)
315
316 var handler http.Handler
317 if methodHandler, ok := handlers[mGET]; ok {
318 handler = methodHandler.handler
319 }
320
321 paramKeys := rctx.routeParams.Keys
322 paramValues := rctx.routeParams.Values
323
324 if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) {
325 t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler)
326 }
327 if !stringSliceEqual(tt.k, paramKeys) {
328 t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys)
329 }
330 if !stringSliceEqual(tt.v, paramValues) {
331 t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues)
332 }
333 }
334 }
335
336 func TestTreeRegexpRecursive(t *testing.T) {
337 hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
338 hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
339
340 tr := &node{}
341 tr.InsertRoute(mGET, "/one/{firstId:[a-z0-9-]+}/{secondId:[a-z0-9-]+}/first", hStub1)
342 tr.InsertRoute(mGET, "/one/{firstId:[a-z0-9-_]+}/{secondId:[a-z0-9-_]+}/second", hStub2)
343
344
345
346
347
348
349
350 tests := []struct {
351 r string
352 h http.Handler
353 k []string
354 v []string
355 }{
356 {r: "/one/hello/world/first", h: hStub1, k: []string{"firstId", "secondId"}, v: []string{"hello", "world"}},
357 {r: "/one/hi_there/ok/second", h: hStub2, k: []string{"firstId", "secondId"}, v: []string{"hi_there", "ok"}},
358 {r: "/one///first", h: nil, k: []string{}, v: []string{}},
359 {r: "/one/hi/123/second", h: hStub2, k: []string{"firstId", "secondId"}, v: []string{"hi", "123"}},
360 }
361
362 for i, tt := range tests {
363 rctx := NewRouteContext()
364
365 _, handlers, _ := tr.FindRoute(rctx, mGET, tt.r)
366
367 var handler http.Handler
368 if methodHandler, ok := handlers[mGET]; ok {
369 handler = methodHandler.handler
370 }
371
372 paramKeys := rctx.routeParams.Keys
373 paramValues := rctx.routeParams.Values
374
375 if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) {
376 t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler)
377 }
378 if !stringSliceEqual(tt.k, paramKeys) {
379 t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys)
380 }
381 if !stringSliceEqual(tt.v, paramValues) {
382 t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues)
383 }
384 }
385 }
386
387 func TestTreeRegexMatchWholeParam(t *testing.T) {
388 hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
389
390 rctx := NewRouteContext()
391 tr := &node{}
392 tr.InsertRoute(mGET, "/{id:[0-9]+}", hStub1)
393
394 tests := []struct {
395 url string
396 expectedHandler http.Handler
397 }{
398 {url: "/13", expectedHandler: hStub1},
399 {url: "/a13", expectedHandler: nil},
400 {url: "/13.jpg", expectedHandler: nil},
401 {url: "/a13.jpg", expectedHandler: nil},
402 }
403
404 for _, tc := range tests {
405 _, _, handler := tr.FindRoute(rctx, mGET, tc.url)
406 if fmt.Sprintf("%v", tc.expectedHandler) != fmt.Sprintf("%v", handler) {
407 t.Errorf("expecting handler:%v , got:%v", tc.expectedHandler, handler)
408 }
409 }
410 }
411
412 func TestTreeFindPattern(t *testing.T) {
413 hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
414 hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
415 hStub3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
416
417 tr := &node{}
418 tr.InsertRoute(mGET, "/pages/*", hStub1)
419 tr.InsertRoute(mGET, "/articles/{id}/*", hStub2)
420 tr.InsertRoute(mGET, "/articles/{slug}/{uid}/*", hStub3)
421
422 if tr.findPattern("/pages") != false {
423 t.Errorf("find /pages failed")
424 }
425 if tr.findPattern("/pages*") != false {
426 t.Errorf("find /pages* failed - should be nil")
427 }
428 if tr.findPattern("/pages/*") == false {
429 t.Errorf("find /pages/* failed")
430 }
431 if tr.findPattern("/articles/{id}/*") == false {
432 t.Errorf("find /articles/{id}/* failed")
433 }
434 if tr.findPattern("/articles/{something}/*") == false {
435 t.Errorf("find /articles/{something}/* failed")
436 }
437 if tr.findPattern("/articles/{slug}/{uid}/*") == false {
438 t.Errorf("find /articles/{slug}/{uid}/* failed")
439 }
440 }
441
442 func debugPrintTree(parent int, i int, n *node, label byte) bool {
443 numEdges := 0
444 for _, nds := range n.children {
445 numEdges += len(nds)
446 }
447
448
449
450
451
452
453 if n.endpoints != nil {
454 log.Printf("[node %d parent:%d] typ:%d prefix:%s label:%s tail:%s numEdges:%d isLeaf:%v handler:%v\n", i, parent, n.typ, n.prefix, string(label), string(n.tail), numEdges, n.isLeaf(), n.endpoints)
455 } else {
456 log.Printf("[node %d parent:%d] typ:%d prefix:%s label:%s tail:%s numEdges:%d isLeaf:%v\n", i, parent, n.typ, n.prefix, string(label), string(n.tail), numEdges, n.isLeaf())
457 }
458 parent = i
459 for _, nds := range n.children {
460 for _, e := range nds {
461 i++
462 if debugPrintTree(parent, i, e, e.label) {
463 return true
464 }
465 }
466 }
467 return false
468 }
469
470 func stringSliceEqual(a, b []string) bool {
471 if len(a) != len(b) {
472 return false
473 }
474 for i := range a {
475 if b[i] != a[i] {
476 return false
477 }
478 }
479 return true
480 }
481
482 func BenchmarkTreeGet(b *testing.B) {
483 h1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
484 h2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
485
486 tr := &node{}
487 tr.InsertRoute(mGET, "/", h1)
488 tr.InsertRoute(mGET, "/ping", h2)
489 tr.InsertRoute(mGET, "/pingall", h2)
490 tr.InsertRoute(mGET, "/ping/{id}", h2)
491 tr.InsertRoute(mGET, "/ping/{id}/woop", h2)
492 tr.InsertRoute(mGET, "/ping/{id}/{opt}", h2)
493 tr.InsertRoute(mGET, "/pinggggg", h2)
494 tr.InsertRoute(mGET, "/hello", h1)
495
496 mctx := NewRouteContext()
497
498 b.ReportAllocs()
499 b.ResetTimer()
500
501 for i := 0; i < b.N; i++ {
502 mctx.Reset()
503 tr.FindRoute(mctx, mGET, "/ping/123/456")
504 }
505 }
506
507 func TestWalker(t *testing.T) {
508 r := bigMux()
509
510
511 if err := Walk(r, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
512 t.Logf("%v %v", method, route)
513
514 return nil
515 }); err != nil {
516 t.Error(err)
517 }
518 }
519
View as plain text