github.com/astaxie/beego@v1.12.3/tree_test.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package beego 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/astaxie/beego/context" 22 ) 23 24 type testinfo struct { 25 url string 26 requesturl string 27 params map[string]string 28 } 29 30 var routers []testinfo 31 32 func init() { 33 routers = make([]testinfo, 0) 34 routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil}) 35 routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}}) 36 routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}}) 37 routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}}) 38 routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}}) 39 routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}}) 40 routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}}) 41 routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}}) 42 routers = append(routers, testinfo{"/", "/", nil}) 43 routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) 44 routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) 45 routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) 46 routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) 47 routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}}) 48 routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}}) 49 routers = append(routers, testinfo{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}}) 50 routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}}) 51 routers = append(routers, testinfo{"/thumbnail/:size/uploads/*", 52 "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg", 53 map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}}) 54 routers = append(routers, testinfo{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}}) 55 routers = append(routers, testinfo{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) 56 routers = append(routers, testinfo{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) 57 routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*", 58 "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", 59 map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}}) 60 routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}}) 61 routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}}) 62 routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}}) 63 routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}}) 64 routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}}) 65 routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}}) 66 routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}}) 67 routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}}) 68 routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}}) 69 routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) 70 routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) 71 routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) 72 routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) 73 routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) 74 routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) 75 routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}}) 76 routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}}) 77 } 78 79 func TestTreeRouters(t *testing.T) { 80 for _, r := range routers { 81 tr := NewTree() 82 tr.AddRouter(r.url, "astaxie") 83 ctx := context.NewContext() 84 obj := tr.Match(r.requesturl, ctx) 85 if obj == nil || obj.(string) != "astaxie" { 86 t.Fatal(r.url+" can't get obj, Expect ", r.requesturl) 87 } 88 if r.params != nil { 89 for k, v := range r.params { 90 if vv := ctx.Input.Param(k); vv != v { 91 t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) 92 } else if vv == "" && v != "" { 93 t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k) 94 } 95 } 96 } 97 } 98 } 99 100 func TestStaticPath(t *testing.T) { 101 tr := NewTree() 102 tr.AddRouter("/topic/:id", "wildcard") 103 tr.AddRouter("/topic", "static") 104 ctx := context.NewContext() 105 obj := tr.Match("/topic", ctx) 106 if obj == nil || obj.(string) != "static" { 107 t.Fatal("/topic is a static route") 108 } 109 obj = tr.Match("/topic/1", ctx) 110 if obj == nil || obj.(string) != "wildcard" { 111 t.Fatal("/topic/1 is a wildcard route") 112 } 113 } 114 115 func TestAddTree(t *testing.T) { 116 tr := NewTree() 117 tr.AddRouter("/shop/:id/account", "astaxie") 118 tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") 119 t1 := NewTree() 120 t1.AddTree("/v1/zl", tr) 121 ctx := context.NewContext() 122 obj := t1.Match("/v1/zl/shop/123/account", ctx) 123 if obj == nil || obj.(string) != "astaxie" { 124 t.Fatal("/v1/zl/shop/:id/account can't get obj ") 125 } 126 if ctx.Input.ParamsLen() == 0 { 127 t.Fatal("get param error") 128 } 129 if ctx.Input.Param(":id") != "123" { 130 t.Fatal("get :id param error") 131 } 132 ctx.Input.Reset(ctx) 133 obj = t1.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) 134 if obj == nil || obj.(string) != "astaxie" { 135 t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") 136 } 137 if ctx.Input.ParamsLen() == 0 { 138 t.Fatal("get param error") 139 } 140 if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" { 141 t.Fatal("get :sd :id :page param error") 142 } 143 144 t2 := NewTree() 145 t2.AddTree("/v1/:shopid", tr) 146 ctx.Input.Reset(ctx) 147 obj = t2.Match("/v1/zl/shop/123/account", ctx) 148 if obj == nil || obj.(string) != "astaxie" { 149 t.Fatal("/v1/:shopid/shop/:id/account can't get obj ") 150 } 151 if ctx.Input.ParamsLen() == 0 { 152 t.Fatal("get param error") 153 } 154 if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":shopid") != "zl" { 155 t.Fatal("get :id :shopid param error") 156 } 157 ctx.Input.Reset(ctx) 158 obj = t2.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) 159 if obj == nil || obj.(string) != "astaxie" { 160 t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") 161 } 162 if ctx.Input.ParamsLen() == 0 { 163 t.Fatal("get :shopid param error") 164 } 165 if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" || ctx.Input.Param(":shopid") != "zl" { 166 t.Fatal("get :sd :id :page :shopid param error") 167 } 168 } 169 170 func TestAddTree2(t *testing.T) { 171 tr := NewTree() 172 tr.AddRouter("/shop/:id/account", "astaxie") 173 tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") 174 t3 := NewTree() 175 t3.AddTree("/:version(v1|v2)/:prefix", tr) 176 ctx := context.NewContext() 177 obj := t3.Match("/v1/zl/shop/123/account", ctx) 178 if obj == nil || obj.(string) != "astaxie" { 179 t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ") 180 } 181 if ctx.Input.ParamsLen() == 0 { 182 t.Fatal("get param error") 183 } 184 if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":prefix") != "zl" || ctx.Input.Param(":version") != "v1" { 185 t.Fatal("get :id :prefix :version param error") 186 } 187 } 188 189 func TestAddTree3(t *testing.T) { 190 tr := NewTree() 191 tr.AddRouter("/create", "astaxie") 192 tr.AddRouter("/shop/:sd/account", "astaxie") 193 t3 := NewTree() 194 t3.AddTree("/table/:num", tr) 195 ctx := context.NewContext() 196 obj := t3.Match("/table/123/shop/123/account", ctx) 197 if obj == nil || obj.(string) != "astaxie" { 198 t.Fatal("/table/:num/shop/:sd/account can't get obj ") 199 } 200 if ctx.Input.ParamsLen() == 0 { 201 t.Fatal("get param error") 202 } 203 if ctx.Input.Param(":num") != "123" || ctx.Input.Param(":sd") != "123" { 204 t.Fatal("get :num :sd param error") 205 } 206 ctx.Input.Reset(ctx) 207 obj = t3.Match("/table/123/create", ctx) 208 if obj == nil || obj.(string) != "astaxie" { 209 t.Fatal("/table/:num/create can't get obj ") 210 } 211 } 212 213 func TestAddTree4(t *testing.T) { 214 tr := NewTree() 215 tr.AddRouter("/create", "astaxie") 216 tr.AddRouter("/shop/:sd/:account", "astaxie") 217 t4 := NewTree() 218 t4.AddTree("/:info:int/:num/:id", tr) 219 ctx := context.NewContext() 220 obj := t4.Match("/12/123/456/shop/123/account", ctx) 221 if obj == nil || obj.(string) != "astaxie" { 222 t.Fatal("/:info:int/:num/:id/shop/:sd/:account can't get obj ") 223 } 224 if ctx.Input.ParamsLen() == 0 { 225 t.Fatal("get param error") 226 } 227 if ctx.Input.Param(":info") != "12" || ctx.Input.Param(":num") != "123" || 228 ctx.Input.Param(":id") != "456" || ctx.Input.Param(":sd") != "123" || 229 ctx.Input.Param(":account") != "account" { 230 t.Fatal("get :info :num :id :sd :account param error") 231 } 232 ctx.Input.Reset(ctx) 233 obj = t4.Match("/12/123/456/create", ctx) 234 if obj == nil || obj.(string) != "astaxie" { 235 t.Fatal("/:info:int/:num/:id/create can't get obj ") 236 } 237 } 238 239 // Test for issue #1595 240 func TestAddTree5(t *testing.T) { 241 tr := NewTree() 242 tr.AddRouter("/v1/shop/:id", "shopdetail") 243 tr.AddRouter("/v1/shop/", "shophome") 244 ctx := context.NewContext() 245 obj := tr.Match("/v1/shop/", ctx) 246 if obj == nil || obj.(string) != "shophome" { 247 t.Fatal("url /v1/shop/ need match router /v1/shop/ ") 248 } 249 } 250 251 func TestSplitPath(t *testing.T) { 252 a := splitPath("") 253 if len(a) != 0 { 254 t.Fatal("/ should retrun []") 255 } 256 a = splitPath("/") 257 if len(a) != 0 { 258 t.Fatal("/ should retrun []") 259 } 260 a = splitPath("/admin") 261 if len(a) != 1 || a[0] != "admin" { 262 t.Fatal("/admin should retrun [admin]") 263 } 264 a = splitPath("/admin/") 265 if len(a) != 1 || a[0] != "admin" { 266 t.Fatal("/admin/ should retrun [admin]") 267 } 268 a = splitPath("/admin/users") 269 if len(a) != 2 || a[0] != "admin" || a[1] != "users" { 270 t.Fatal("/admin should retrun [admin users]") 271 } 272 a = splitPath("/admin/:id:int") 273 if len(a) != 2 || a[0] != "admin" || a[1] != ":id:int" { 274 t.Fatal("/admin should retrun [admin :id:int]") 275 } 276 } 277 278 func TestSplitSegment(t *testing.T) { 279 280 items := map[string]struct { 281 isReg bool 282 params []string 283 regStr string 284 }{ 285 "admin": {false, nil, ""}, 286 "*": {true, []string{":splat"}, ""}, 287 "*.*": {true, []string{".", ":path", ":ext"}, ""}, 288 ":id": {true, []string{":id"}, ""}, 289 "?:id": {true, []string{":", ":id"}, ""}, 290 ":id:int": {true, []string{":id"}, "([0-9]+)"}, 291 ":name:string": {true, []string{":name"}, `([\w]+)`}, 292 ":id([0-9]+)": {true, []string{":id"}, `([0-9]+)`}, 293 ":id([0-9]+)_:name": {true, []string{":id", ":name"}, `([0-9]+)_(.+)`}, 294 ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms.html`}, 295 "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+).html`}, 296 `:app(a|b|c)`: {true, []string{":app"}, `(a|b|c)`}, 297 `:app\((a|b|c)\)`: {true, []string{":app"}, `(.+)\((a|b|c)\)`}, 298 } 299 300 for pattern, v := range items { 301 b, w, r := splitSegment(pattern) 302 if b != v.isReg || r != v.regStr || strings.Join(w, ",") != strings.Join(v.params, ",") { 303 t.Fatalf("%s should return %t,%s,%q, got %t,%s,%q", pattern, v.isReg, v.params, v.regStr, b, w, r) 304 } 305 } 306 }