gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/mux/old_test.go (about) 1 // Old tests ported to Go1. This is a mess. Want to drop it one day. 2 3 // Copyright 2011 Gorilla Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package mux 8 9 import ( 10 "bytes" 11 "testing" 12 13 http "gitee.com/ks-custle/core-gm/gmhttp" 14 ) 15 16 // ---------------------------------------------------------------------------- 17 // ResponseRecorder 18 // ---------------------------------------------------------------------------- 19 // Copyright 2009 The Go Authors. All rights reserved. 20 // Use of this source code is governed by a BSD-style 21 // license that can be found in the LICENSE file. 22 23 // ResponseRecorder is an implementation of http.ResponseWriter that 24 // records its mutations for later inspection in tests. 25 type ResponseRecorder struct { 26 Code int // the HTTP response code from WriteHeader 27 HeaderMap http.Header // the HTTP response headers 28 Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to 29 Flushed bool 30 } 31 32 // NewRecorder returns an initialized ResponseRecorder. 33 func NewRecorder() *ResponseRecorder { 34 return &ResponseRecorder{ 35 HeaderMap: make(http.Header), 36 Body: new(bytes.Buffer), 37 } 38 } 39 40 // Header returns the response headers. 41 func (rw *ResponseRecorder) Header() http.Header { 42 return rw.HeaderMap 43 } 44 45 // Write always succeeds and writes to rw.Body, if not nil. 46 func (rw *ResponseRecorder) Write(buf []byte) (int, error) { 47 if rw.Body != nil { 48 rw.Body.Write(buf) 49 } 50 if rw.Code == 0 { 51 rw.Code = http.StatusOK 52 } 53 return len(buf), nil 54 } 55 56 // WriteHeader sets rw.Code. 57 func (rw *ResponseRecorder) WriteHeader(code int) { 58 rw.Code = code 59 } 60 61 // Flush sets rw.Flushed to true. 62 func (rw *ResponseRecorder) Flush() { 63 rw.Flushed = true 64 } 65 66 // ---------------------------------------------------------------------------- 67 68 func TestRouteMatchers(t *testing.T) { 69 var scheme, host, path, query, method string 70 var headers map[string]string 71 var resultVars map[bool]map[string]string 72 73 router := NewRouter() 74 router.NewRoute().Host("{var1}.google.com"). 75 Path("/{var2:[a-z]+}/{var3:[0-9]+}"). 76 Queries("foo", "bar"). 77 Methods("GET"). 78 Schemes("https"). 79 Headers("x-requested-with", "XMLHttpRequest") 80 router.NewRoute().Host("www.{var4}.com"). 81 PathPrefix("/foo/{var5:[a-z]+}/{var6:[0-9]+}"). 82 Queries("baz", "ding"). 83 Methods("POST"). 84 Schemes("http"). 85 Headers("Content-Type", "application/json") 86 87 reset := func() { 88 // Everything match. 89 scheme = "https" 90 host = "www.google.com" 91 path = "/product/42" 92 query = "?foo=bar" 93 method = "GET" 94 headers = map[string]string{"X-Requested-With": "XMLHttpRequest"} 95 resultVars = map[bool]map[string]string{ 96 true: {"var1": "www", "var2": "product", "var3": "42"}, 97 false: {}, 98 } 99 } 100 101 reset2 := func() { 102 // Everything match. 103 scheme = "http" 104 host = "www.google.com" 105 path = "/foo/product/42/path/that/is/ignored" 106 query = "?baz=ding" 107 method = "POST" 108 headers = map[string]string{"Content-Type": "application/json"} 109 resultVars = map[bool]map[string]string{ 110 true: {"var4": "google", "var5": "product", "var6": "42"}, 111 false: {}, 112 } 113 } 114 115 match := func(shouldMatch bool) { 116 url := scheme + "://" + host + path + query 117 request, _ := http.NewRequest(method, url, nil) 118 for key, value := range headers { 119 request.Header.Add(key, value) 120 } 121 122 var routeMatch RouteMatch 123 matched := router.Match(request, &routeMatch) 124 if matched != shouldMatch { 125 t.Errorf("Expected: %v\nGot: %v\nRequest: %v %v", shouldMatch, matched, request.Method, url) 126 } 127 128 if matched { 129 currentRoute := routeMatch.Route 130 if currentRoute == nil { 131 t.Errorf("Expected a current route.") 132 } 133 vars := routeMatch.Vars 134 expectedVars := resultVars[shouldMatch] 135 if len(vars) != len(expectedVars) { 136 t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars) 137 } 138 for name, value := range vars { 139 if expectedVars[name] != value { 140 t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars) 141 } 142 } 143 } 144 } 145 146 // 1st route -------------------------------------------------------------- 147 148 // Everything match. 149 reset() 150 match(true) 151 152 // Scheme doesn't match. 153 reset() 154 scheme = "http" 155 match(false) 156 157 // Host doesn't match. 158 reset() 159 host = "www.mygoogle.com" 160 match(false) 161 162 // Path doesn't match. 163 reset() 164 path = "/product/notdigits" 165 match(false) 166 167 // Query doesn't match. 168 reset() 169 query = "?foo=baz" 170 match(false) 171 172 // Method doesn't match. 173 reset() 174 method = "POST" 175 match(false) 176 177 // Header doesn't match. 178 reset() 179 headers = map[string]string{} 180 match(false) 181 182 // Everything match, again. 183 reset() 184 match(true) 185 186 // 2nd route -------------------------------------------------------------- 187 // Everything match. 188 reset2() 189 match(true) 190 191 // Scheme doesn't match. 192 reset2() 193 scheme = "https" 194 match(false) 195 196 // Host doesn't match. 197 reset2() 198 host = "sub.google.com" 199 match(false) 200 201 // Path doesn't match. 202 reset2() 203 path = "/bar/product/42" 204 match(false) 205 206 // Query doesn't match. 207 reset2() 208 query = "?foo=baz" 209 match(false) 210 211 // Method doesn't match. 212 reset2() 213 method = "GET" 214 match(false) 215 216 // Header doesn't match. 217 reset2() 218 headers = map[string]string{} 219 match(false) 220 221 // Everything match, again. 222 reset2() 223 match(true) 224 } 225 226 type headerMatcherTest struct { 227 matcher headerMatcher 228 headers map[string]string 229 result bool 230 } 231 232 var headerMatcherTests = []headerMatcherTest{ 233 { 234 matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}), 235 headers: map[string]string{"X-Requested-With": "XMLHttpRequest"}, 236 result: true, 237 }, 238 { 239 matcher: headerMatcher(map[string]string{"x-requested-with": ""}), 240 headers: map[string]string{"X-Requested-With": "anything"}, 241 result: true, 242 }, 243 { 244 matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}), 245 headers: map[string]string{}, 246 result: false, 247 }, 248 } 249 250 type hostMatcherTest struct { 251 matcher *Route 252 url string 253 vars map[string]string 254 result bool 255 } 256 257 var hostMatcherTests = []hostMatcherTest{ 258 { 259 matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"), 260 url: "http://abc.def.ghi/", 261 vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"}, 262 result: true, 263 }, 264 { 265 matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}:{port:.*}"), 266 url: "http://abc.def.ghi:65535/", 267 vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi", "port": "65535"}, 268 result: true, 269 }, 270 { 271 matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"), 272 url: "http://abc.def.ghi:65535/", 273 vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"}, 274 result: true, 275 }, 276 { 277 matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"), 278 url: "http://a.b.c/", 279 vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"}, 280 result: false, 281 }, 282 } 283 284 type methodMatcherTest struct { 285 matcher methodMatcher 286 method string 287 result bool 288 } 289 290 var methodMatcherTests = []methodMatcherTest{ 291 { 292 matcher: methodMatcher([]string{"GET", "POST", "PUT"}), 293 method: "GET", 294 result: true, 295 }, 296 { 297 matcher: methodMatcher([]string{"GET", "POST", "PUT"}), 298 method: "POST", 299 result: true, 300 }, 301 { 302 matcher: methodMatcher([]string{"GET", "POST", "PUT"}), 303 method: "PUT", 304 result: true, 305 }, 306 { 307 matcher: methodMatcher([]string{"GET", "POST", "PUT"}), 308 method: "DELETE", 309 result: false, 310 }, 311 } 312 313 type pathMatcherTest struct { 314 matcher *Route 315 url string 316 vars map[string]string 317 result bool 318 } 319 320 var pathMatcherTests = []pathMatcherTest{ 321 { 322 matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"), 323 url: "http://localhost:8080/123/456/789", 324 vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"}, 325 result: true, 326 }, 327 { 328 matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"), 329 url: "http://localhost:8080/1/2/3", 330 vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"}, 331 result: false, 332 }, 333 } 334 335 type schemeMatcherTest struct { 336 matcher schemeMatcher 337 url string 338 result bool 339 } 340 341 var schemeMatcherTests = []schemeMatcherTest{ 342 { 343 matcher: schemeMatcher([]string{"http", "https"}), 344 url: "http://localhost:8080/", 345 result: true, 346 }, 347 { 348 matcher: schemeMatcher([]string{"http", "https"}), 349 url: "https://localhost:8080/", 350 result: true, 351 }, 352 { 353 matcher: schemeMatcher([]string{"https"}), 354 url: "http://localhost:8080/", 355 result: false, 356 }, 357 { 358 matcher: schemeMatcher([]string{"http"}), 359 url: "https://localhost:8080/", 360 result: false, 361 }, 362 } 363 364 type urlBuildingTest struct { 365 route *Route 366 vars []string 367 url string 368 } 369 370 var urlBuildingTests = []urlBuildingTest{ 371 { 372 route: new(Route).Host("foo.domain.com"), 373 vars: []string{}, 374 url: "http://foo.domain.com", 375 }, 376 { 377 route: new(Route).Host("{subdomain}.domain.com"), 378 vars: []string{"subdomain", "bar"}, 379 url: "http://bar.domain.com", 380 }, 381 { 382 route: new(Route).Host("{subdomain}.domain.com:{port:.*}"), 383 vars: []string{"subdomain", "bar", "port", "65535"}, 384 url: "http://bar.domain.com:65535", 385 }, 386 { 387 route: new(Route).Host("foo.domain.com").Path("/articles"), 388 vars: []string{}, 389 url: "http://foo.domain.com/articles", 390 }, 391 { 392 route: new(Route).Path("/articles"), 393 vars: []string{}, 394 url: "/articles", 395 }, 396 { 397 route: new(Route).Path("/articles/{category}/{id:[0-9]+}"), 398 vars: []string{"category", "technology", "id", "42"}, 399 url: "/articles/technology/42", 400 }, 401 { 402 route: new(Route).Host("{subdomain}.domain.com").Path("/articles/{category}/{id:[0-9]+}"), 403 vars: []string{"subdomain", "foo", "category", "technology", "id", "42"}, 404 url: "http://foo.domain.com/articles/technology/42", 405 }, 406 { 407 route: new(Route).Host("example.com").Schemes("https", "http"), 408 vars: []string{}, 409 url: "https://example.com", 410 }, 411 } 412 413 func TestHeaderMatcher(t *testing.T) { 414 for _, v := range headerMatcherTests { 415 request, _ := http.NewRequest("GET", "http://localhost:8080/", nil) 416 for key, value := range v.headers { 417 request.Header.Add(key, value) 418 } 419 var routeMatch RouteMatch 420 result := v.matcher.Match(request, &routeMatch) 421 if result != v.result { 422 if v.result { 423 t.Errorf("%#v: should match %v.", v.matcher, request.Header) 424 } else { 425 t.Errorf("%#v: should not match %v.", v.matcher, request.Header) 426 } 427 } 428 } 429 } 430 431 func TestHostMatcher(t *testing.T) { 432 for _, v := range hostMatcherTests { 433 request, err := http.NewRequest("GET", v.url, nil) 434 if err != nil { 435 t.Errorf("http.NewRequest failed %#v", err) 436 continue 437 } 438 var routeMatch RouteMatch 439 result := v.matcher.Match(request, &routeMatch) 440 vars := routeMatch.Vars 441 if result != v.result { 442 if v.result { 443 t.Errorf("%#v: should match %v.", v.matcher, v.url) 444 } else { 445 t.Errorf("%#v: should not match %v.", v.matcher, v.url) 446 } 447 } 448 if result { 449 if len(vars) != len(v.vars) { 450 t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars)) 451 } 452 for name, value := range vars { 453 if v.vars[name] != value { 454 t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value) 455 } 456 } 457 } else { 458 if len(vars) != 0 { 459 t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars)) 460 } 461 } 462 } 463 } 464 465 func TestMethodMatcher(t *testing.T) { 466 for _, v := range methodMatcherTests { 467 request, _ := http.NewRequest(v.method, "http://localhost:8080/", nil) 468 var routeMatch RouteMatch 469 result := v.matcher.Match(request, &routeMatch) 470 if result != v.result { 471 if v.result { 472 t.Errorf("%#v: should match %v.", v.matcher, v.method) 473 } else { 474 t.Errorf("%#v: should not match %v.", v.matcher, v.method) 475 } 476 } 477 } 478 } 479 480 func TestPathMatcher(t *testing.T) { 481 for _, v := range pathMatcherTests { 482 request, _ := http.NewRequest("GET", v.url, nil) 483 var routeMatch RouteMatch 484 result := v.matcher.Match(request, &routeMatch) 485 vars := routeMatch.Vars 486 if result != v.result { 487 if v.result { 488 t.Errorf("%#v: should match %v.", v.matcher, v.url) 489 } else { 490 t.Errorf("%#v: should not match %v.", v.matcher, v.url) 491 } 492 } 493 if result { 494 if len(vars) != len(v.vars) { 495 t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars)) 496 } 497 for name, value := range vars { 498 if v.vars[name] != value { 499 t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value) 500 } 501 } 502 } else { 503 if len(vars) != 0 { 504 t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars)) 505 } 506 } 507 } 508 } 509 510 func TestSchemeMatcher(t *testing.T) { 511 for _, v := range schemeMatcherTests { 512 request, _ := http.NewRequest("GET", v.url, nil) 513 var routeMatch RouteMatch 514 result := v.matcher.Match(request, &routeMatch) 515 if result != v.result { 516 if v.result { 517 t.Errorf("%#v: should match %v.", v.matcher, v.url) 518 } else { 519 t.Errorf("%#v: should not match %v.", v.matcher, v.url) 520 } 521 } 522 } 523 } 524 525 func TestUrlBuilding(t *testing.T) { 526 527 for _, v := range urlBuildingTests { 528 u, _ := v.route.URL(v.vars...) 529 url := u.String() 530 if url != v.url { 531 t.Errorf("expected %v, got %v", v.url, url) 532 } 533 } 534 535 ArticleHandler := func(w http.ResponseWriter, r *http.Request) { 536 } 537 538 router := NewRouter() 539 router.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).Name("article") 540 541 url, _ := router.Get("article").URL("category", "technology", "id", "42") 542 expected := "/articles/technology/42" 543 if url.String() != expected { 544 t.Errorf("Expected %v, got %v", expected, url.String()) 545 } 546 } 547 548 func TestMatchedRouteName(t *testing.T) { 549 routeName := "stock" 550 router := NewRouter() 551 route := router.NewRoute().Path("/products/").Name(routeName) 552 553 url := "http://www.example.com/products/" 554 request, _ := http.NewRequest("GET", url, nil) 555 var rv RouteMatch 556 ok := router.Match(request, &rv) 557 558 if !ok || rv.Route != route { 559 t.Errorf("Expected same route, got %+v.", rv.Route) 560 } 561 562 retName := rv.Route.GetName() 563 if retName != routeName { 564 t.Errorf("Expected %q, got %q.", routeName, retName) 565 } 566 } 567 568 func TestSubRouting(t *testing.T) { 569 // Example from docs. 570 router := NewRouter() 571 subrouter := router.NewRoute().Host("www.example.com").Subrouter() 572 route := subrouter.NewRoute().Path("/products/").Name("products") 573 574 url := "http://www.example.com/products/" 575 request, _ := http.NewRequest("GET", url, nil) 576 var rv RouteMatch 577 ok := router.Match(request, &rv) 578 579 if !ok || rv.Route != route { 580 t.Errorf("Expected same route, got %+v.", rv.Route) 581 } 582 583 u, _ := router.Get("products").URL() 584 builtURL := u.String() 585 // Yay, subroute aware of the domain when building! 586 if builtURL != url { 587 t.Errorf("Expected %q, got %q.", url, builtURL) 588 } 589 } 590 591 func TestVariableNames(t *testing.T) { 592 route := new(Route).Host("{arg1}.domain.com").Path("/{arg1}/{arg2:[0-9]+}") 593 if route.err == nil { 594 t.Errorf("Expected error for duplicated variable names") 595 } 596 } 597 598 func TestRedirectSlash(t *testing.T) { 599 var route *Route 600 var routeMatch RouteMatch 601 r := NewRouter() 602 603 r.StrictSlash(false) 604 route = r.NewRoute() 605 if route.strictSlash != false { 606 t.Errorf("Expected false redirectSlash.") 607 } 608 609 r.StrictSlash(true) 610 route = r.NewRoute() 611 if route.strictSlash != true { 612 t.Errorf("Expected true redirectSlash.") 613 } 614 615 route = new(Route) 616 route.strictSlash = true 617 route.Path("/{arg1}/{arg2:[0-9]+}/") 618 request, _ := http.NewRequest("GET", "http://localhost/foo/123", nil) 619 routeMatch = RouteMatch{} 620 _ = route.Match(request, &routeMatch) 621 vars := routeMatch.Vars 622 if vars["arg1"] != "foo" { 623 t.Errorf("Expected foo.") 624 } 625 if vars["arg2"] != "123" { 626 t.Errorf("Expected 123.") 627 } 628 rsp := NewRecorder() 629 routeMatch.Handler.ServeHTTP(rsp, request) 630 if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123/" { 631 t.Errorf("Expected redirect header.") 632 } 633 634 route = new(Route) 635 route.strictSlash = true 636 route.Path("/{arg1}/{arg2:[0-9]+}") 637 request, _ = http.NewRequest("GET", "http://localhost/foo/123/", nil) 638 routeMatch = RouteMatch{} 639 _ = route.Match(request, &routeMatch) 640 vars = routeMatch.Vars 641 if vars["arg1"] != "foo" { 642 t.Errorf("Expected foo.") 643 } 644 if vars["arg2"] != "123" { 645 t.Errorf("Expected 123.") 646 } 647 rsp = NewRecorder() 648 routeMatch.Handler.ServeHTTP(rsp, request) 649 if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123" { 650 t.Errorf("Expected redirect header.") 651 } 652 } 653 654 // Test for the new regexp library, still not available in stable Go. 655 func TestNewRegexp(t *testing.T) { 656 var p *routeRegexp 657 var matches []string 658 659 tests := map[string]map[string][]string{ 660 "/{foo:a{2}}": { 661 "/a": nil, 662 "/aa": {"aa"}, 663 "/aaa": nil, 664 "/aaaa": nil, 665 }, 666 "/{foo:a{2,}}": { 667 "/a": nil, 668 "/aa": {"aa"}, 669 "/aaa": {"aaa"}, 670 "/aaaa": {"aaaa"}, 671 }, 672 "/{foo:a{2,3}}": { 673 "/a": nil, 674 "/aa": {"aa"}, 675 "/aaa": {"aaa"}, 676 "/aaaa": nil, 677 }, 678 "/{foo:[a-z]{3}}/{bar:[a-z]{2}}": { 679 "/a": nil, 680 "/ab": nil, 681 "/abc": nil, 682 "/abcd": nil, 683 "/abc/ab": {"abc", "ab"}, 684 "/abc/abc": nil, 685 "/abcd/ab": nil, 686 }, 687 `/{foo:\w{3,}}/{bar:\d{2,}}`: { 688 "/a": nil, 689 "/ab": nil, 690 "/abc": nil, 691 "/abc/1": nil, 692 "/abc/12": {"abc", "12"}, 693 "/abcd/12": {"abcd", "12"}, 694 "/abcd/123": {"abcd", "123"}, 695 }, 696 } 697 698 for pattern, paths := range tests { 699 p, _ = newRouteRegexp(pattern, regexpTypePath, routeRegexpOptions{}) 700 for path, result := range paths { 701 matches = p.regexp.FindStringSubmatch(path) 702 if result == nil { 703 if matches != nil { 704 t.Errorf("%v should not match %v.", pattern, path) 705 } 706 } else { 707 if len(matches) != len(result)+1 { 708 t.Errorf("Expected %v matches, got %v.", len(result)+1, len(matches)) 709 } else { 710 for k, v := range result { 711 if matches[k+1] != v { 712 t.Errorf("Expected %v, got %v.", v, matches[k+1]) 713 } 714 } 715 } 716 } 717 } 718 } 719 }