github.com/lingyao2333/mo-zero@v1.4.1/rest/router/patrouter_test.go (about) 1 package router 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "net/http" 8 "net/http/httptest" 9 "strings" 10 "testing" 11 12 "github.com/lingyao2333/mo-zero/rest/httpx" 13 "github.com/lingyao2333/mo-zero/rest/internal/header" 14 "github.com/lingyao2333/mo-zero/rest/pathvar" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 const contentLength = "Content-Length" 19 20 type mockedResponseWriter struct { 21 code int 22 } 23 24 func (m *mockedResponseWriter) Header() http.Header { 25 return http.Header{} 26 } 27 28 func (m *mockedResponseWriter) Write(p []byte) (int, error) { 29 return len(p), nil 30 } 31 32 func (m *mockedResponseWriter) WriteHeader(code int) { 33 m.code = code 34 } 35 36 func TestPatRouterHandleErrors(t *testing.T) { 37 tests := []struct { 38 method string 39 path string 40 err error 41 }{ 42 {"FAKE", "", ErrInvalidMethod}, 43 {"GET", "", ErrInvalidPath}, 44 } 45 46 for _, test := range tests { 47 t.Run(test.method, func(t *testing.T) { 48 router := NewRouter() 49 err := router.Handle(test.method, test.path, nil) 50 assert.Equal(t, test.err, err) 51 }) 52 } 53 } 54 55 func TestPatRouterNotFound(t *testing.T) { 56 var notFound bool 57 router := NewRouter() 58 router.SetNotFoundHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 59 notFound = true 60 })) 61 err := router.Handle(http.MethodGet, "/a/b", 62 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) 63 assert.Nil(t, err) 64 r, _ := http.NewRequest(http.MethodGet, "/b/c", nil) 65 w := new(mockedResponseWriter) 66 router.ServeHTTP(w, r) 67 assert.True(t, notFound) 68 } 69 70 func TestPatRouterNotAllowed(t *testing.T) { 71 var notAllowed bool 72 router := NewRouter() 73 router.SetNotAllowedHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 74 notAllowed = true 75 })) 76 err := router.Handle(http.MethodGet, "/a/b", 77 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) 78 assert.Nil(t, err) 79 r, _ := http.NewRequest(http.MethodPost, "/a/b", nil) 80 w := new(mockedResponseWriter) 81 router.ServeHTTP(w, r) 82 assert.True(t, notAllowed) 83 } 84 85 func TestPatRouter(t *testing.T) { 86 tests := []struct { 87 method string 88 path string 89 expect bool 90 code int 91 err error 92 }{ 93 // we don't explicitly set status code, framework will do it. 94 {http.MethodGet, "/a/b", true, 0, nil}, 95 {http.MethodGet, "/a/b/", true, 0, nil}, 96 {http.MethodGet, "/a/b?a=b", true, 0, nil}, 97 {http.MethodGet, "/a/b/?a=b", true, 0, nil}, 98 {http.MethodGet, "/a/b/c?a=b", true, 0, nil}, 99 {http.MethodGet, "/b/d", false, http.StatusNotFound, nil}, 100 } 101 102 for _, test := range tests { 103 t.Run(test.method+":"+test.path, func(t *testing.T) { 104 routed := false 105 router := NewRouter() 106 err := router.Handle(test.method, "/a/:b", http.HandlerFunc( 107 func(w http.ResponseWriter, r *http.Request) { 108 routed = true 109 assert.Equal(t, 1, len(pathvar.Vars(r))) 110 })) 111 assert.Nil(t, err) 112 err = router.Handle(test.method, "/a/b/c", http.HandlerFunc( 113 func(w http.ResponseWriter, r *http.Request) { 114 routed = true 115 assert.Nil(t, pathvar.Vars(r)) 116 })) 117 assert.Nil(t, err) 118 err = router.Handle(test.method, "/b/c", http.HandlerFunc( 119 func(w http.ResponseWriter, r *http.Request) { 120 routed = true 121 })) 122 assert.Nil(t, err) 123 124 w := new(mockedResponseWriter) 125 r, _ := http.NewRequest(test.method, test.path, nil) 126 router.ServeHTTP(w, r) 127 assert.Equal(t, test.expect, routed) 128 assert.Equal(t, test.code, w.code) 129 130 if test.code == 0 { 131 r, _ = http.NewRequest(http.MethodPut, test.path, nil) 132 router.ServeHTTP(w, r) 133 assert.Equal(t, http.StatusMethodNotAllowed, w.code) 134 } 135 }) 136 } 137 } 138 139 func TestParseSlice(t *testing.T) { 140 body := `names=%5B%22first%22%2C%22second%22%5D` 141 reader := strings.NewReader(body) 142 r, err := http.NewRequest(http.MethodPost, "http://hello.com/", reader) 143 assert.Nil(t, err) 144 r.Header.Set("Content-Type", "application/x-www-form-urlencoded") 145 146 rt := NewRouter() 147 err = rt.Handle(http.MethodPost, "/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 148 v := struct { 149 Names []string `form:"names"` 150 }{} 151 152 err = httpx.Parse(r, &v) 153 assert.Nil(t, err) 154 assert.Equal(t, 2, len(v.Names)) 155 assert.Equal(t, "first", v.Names[0]) 156 assert.Equal(t, "second", v.Names[1]) 157 })) 158 assert.Nil(t, err) 159 160 rr := httptest.NewRecorder() 161 rt.ServeHTTP(rr, r) 162 } 163 164 func TestParseJsonPost(t *testing.T) { 165 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", 166 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 167 assert.Nil(t, err) 168 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 169 170 router := NewRouter() 171 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(func( 172 w http.ResponseWriter, r *http.Request) { 173 v := struct { 174 Name string `path:"name"` 175 Year int `path:"year"` 176 Nickname string `form:"nickname"` 177 Zipcode int64 `form:"zipcode"` 178 Location string `json:"location"` 179 Time int64 `json:"time"` 180 }{} 181 182 err = httpx.Parse(r, &v) 183 assert.Nil(t, err) 184 _, err = io.WriteString(w, fmt.Sprintf("%s:%d:%s:%d:%s:%d", v.Name, v.Year, 185 v.Nickname, v.Zipcode, v.Location, v.Time)) 186 assert.Nil(t, err) 187 })) 188 assert.Nil(t, err) 189 190 rr := httptest.NewRecorder() 191 router.ServeHTTP(rr, r) 192 193 assert.Equal(t, "kevin:2017:whatever:200000:shanghai:20170912", rr.Body.String()) 194 } 195 196 func TestParseJsonPostWithIntSlice(t *testing.T) { 197 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017", 198 bytes.NewBufferString(`{"ages": [1, 2], "years": [3, 4]}`)) 199 assert.Nil(t, err) 200 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 201 202 router := NewRouter() 203 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(func( 204 w http.ResponseWriter, r *http.Request) { 205 v := struct { 206 Name string `path:"name"` 207 Year int `path:"year"` 208 Ages []int `json:"ages"` 209 Years []int64 `json:"years"` 210 }{} 211 212 err = httpx.Parse(r, &v) 213 assert.Nil(t, err) 214 assert.ElementsMatch(t, []int{1, 2}, v.Ages) 215 assert.ElementsMatch(t, []int64{3, 4}, v.Years) 216 })) 217 assert.Nil(t, err) 218 219 rr := httptest.NewRecorder() 220 router.ServeHTTP(rr, r) 221 } 222 223 func TestParseJsonPostError(t *testing.T) { 224 payload := `[{"abcd": "cdef"}]` 225 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", 226 bytes.NewBufferString(payload)) 227 assert.Nil(t, err) 228 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 229 230 router := NewRouter() 231 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 232 func(w http.ResponseWriter, r *http.Request) { 233 v := struct { 234 Name string `path:"name"` 235 Year int `path:"year"` 236 Nickname string `form:"nickname"` 237 Zipcode int64 `form:"zipcode"` 238 Location string `json:"location"` 239 Time int64 `json:"time"` 240 }{} 241 242 err = httpx.Parse(r, &v) 243 assert.NotNil(t, err) 244 })) 245 assert.Nil(t, err) 246 247 rr := httptest.NewRecorder() 248 router.ServeHTTP(rr, r) 249 } 250 251 func TestParseJsonPostInvalidRequest(t *testing.T) { 252 payload := `{"ages": ["cdef"]}` 253 r, err := http.NewRequest(http.MethodPost, "http://hello.com/", 254 bytes.NewBufferString(payload)) 255 assert.Nil(t, err) 256 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 257 258 router := NewRouter() 259 err = router.Handle(http.MethodPost, "/", http.HandlerFunc( 260 func(w http.ResponseWriter, r *http.Request) { 261 v := struct { 262 Ages []int `json:"ages"` 263 }{} 264 265 err = httpx.Parse(r, &v) 266 assert.NotNil(t, err) 267 })) 268 assert.Nil(t, err) 269 270 rr := httptest.NewRecorder() 271 router.ServeHTTP(rr, r) 272 } 273 274 func TestParseJsonPostRequired(t *testing.T) { 275 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017", 276 bytes.NewBufferString(`{"location": "shanghai"`)) 277 assert.Nil(t, err) 278 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 279 280 router := NewRouter() 281 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 282 func(w http.ResponseWriter, r *http.Request) { 283 v := struct { 284 Name string `path:"name"` 285 Year int `path:"year"` 286 Location string `json:"location"` 287 Time int64 `json:"time"` 288 }{} 289 290 err = httpx.Parse(r, &v) 291 assert.NotNil(t, err) 292 })) 293 assert.Nil(t, err) 294 295 rr := httptest.NewRecorder() 296 router.ServeHTTP(rr, r) 297 } 298 299 func TestParsePath(t *testing.T) { 300 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017", nil) 301 assert.Nil(t, err) 302 303 router := NewRouter() 304 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 305 func(w http.ResponseWriter, r *http.Request) { 306 v := struct { 307 Name string `path:"name"` 308 Year int `path:"year"` 309 }{} 310 311 err = httpx.Parse(r, &v) 312 assert.Nil(t, err) 313 _, err = io.WriteString(w, fmt.Sprintf("%s in %d", v.Name, v.Year)) 314 assert.Nil(t, err) 315 })) 316 assert.Nil(t, err) 317 318 rr := httptest.NewRecorder() 319 router.ServeHTTP(rr, r) 320 321 assert.Equal(t, "kevin in 2017", rr.Body.String()) 322 } 323 324 func TestParsePathRequired(t *testing.T) { 325 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin", nil) 326 assert.Nil(t, err) 327 328 router := NewRouter() 329 err = router.Handle(http.MethodGet, "/:name/", http.HandlerFunc( 330 func(w http.ResponseWriter, r *http.Request) { 331 v := struct { 332 Name string `path:"name"` 333 Year int `path:"year"` 334 }{} 335 336 err = httpx.Parse(r, &v) 337 assert.NotNil(t, err) 338 })) 339 assert.Nil(t, err) 340 341 rr := httptest.NewRecorder() 342 router.ServeHTTP(rr, r) 343 } 344 345 func TestParseQuery(t *testing.T) { 346 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", nil) 347 assert.Nil(t, err) 348 349 router := NewRouter() 350 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 351 func(w http.ResponseWriter, r *http.Request) { 352 v := struct { 353 Nickname string `form:"nickname"` 354 Zipcode int64 `form:"zipcode"` 355 }{} 356 357 err = httpx.Parse(r, &v) 358 assert.Nil(t, err) 359 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Nickname, v.Zipcode)) 360 assert.Nil(t, err) 361 })) 362 assert.Nil(t, err) 363 364 rr := httptest.NewRecorder() 365 router.ServeHTTP(rr, r) 366 367 assert.Equal(t, "whatever:200000", rr.Body.String()) 368 } 369 370 func TestParseQueryRequired(t *testing.T) { 371 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever", nil) 372 assert.Nil(t, err) 373 374 router := NewRouter() 375 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 376 v := struct { 377 Nickname string `form:"nickname"` 378 Zipcode int64 `form:"zipcode"` 379 }{} 380 381 err = httpx.Parse(r, &v) 382 assert.NotNil(t, err) 383 })) 384 assert.Nil(t, err) 385 386 rr := httptest.NewRecorder() 387 router.ServeHTTP(rr, r) 388 } 389 390 func TestParseOptional(t *testing.T) { 391 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=", nil) 392 assert.Nil(t, err) 393 394 router := NewRouter() 395 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 396 func(w http.ResponseWriter, r *http.Request) { 397 v := struct { 398 Nickname string `form:"nickname"` 399 Zipcode int64 `form:"zipcode,optional"` 400 }{} 401 402 err = httpx.Parse(r, &v) 403 assert.Nil(t, err) 404 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Nickname, v.Zipcode)) 405 assert.Nil(t, err) 406 })) 407 assert.Nil(t, err) 408 409 rr := httptest.NewRecorder() 410 router.ServeHTTP(rr, r) 411 412 assert.Equal(t, "whatever:0", rr.Body.String()) 413 } 414 415 func TestParseNestedInRequestEmpty(t *testing.T) { 416 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017", bytes.NewBufferString("{}")) 417 assert.Nil(t, err) 418 419 type ( 420 Request struct { 421 Name string `path:"name"` 422 Year int `path:"year"` 423 } 424 425 Audio struct { 426 Volume int `json:"volume"` 427 } 428 429 WrappedRequest struct { 430 Request 431 Audio Audio `json:"audio,optional"` 432 } 433 ) 434 435 router := NewRouter() 436 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 437 func(w http.ResponseWriter, r *http.Request) { 438 var v WrappedRequest 439 err = httpx.Parse(r, &v) 440 assert.Nil(t, err) 441 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Name, v.Year)) 442 assert.Nil(t, err) 443 })) 444 assert.Nil(t, err) 445 446 rr := httptest.NewRecorder() 447 router.ServeHTTP(rr, r) 448 449 assert.Equal(t, "kevin:2017", rr.Body.String()) 450 } 451 452 func TestParsePtrInRequest(t *testing.T) { 453 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017", 454 bytes.NewBufferString(`{"audio": {"volume": 100}}`)) 455 assert.Nil(t, err) 456 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 457 458 type ( 459 Request struct { 460 Name string `path:"name"` 461 Year int `path:"year"` 462 } 463 464 Audio struct { 465 Volume int `json:"volume"` 466 } 467 468 WrappedRequest struct { 469 Request 470 Audio *Audio `json:"audio,optional"` 471 } 472 ) 473 474 router := NewRouter() 475 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 476 func(w http.ResponseWriter, r *http.Request) { 477 var v WrappedRequest 478 err = httpx.Parse(r, &v) 479 assert.Nil(t, err) 480 _, err = io.WriteString(w, fmt.Sprintf("%s:%d:%d", v.Name, v.Year, v.Audio.Volume)) 481 assert.Nil(t, err) 482 })) 483 assert.Nil(t, err) 484 485 rr := httptest.NewRecorder() 486 router.ServeHTTP(rr, r) 487 488 assert.Equal(t, "kevin:2017:100", rr.Body.String()) 489 } 490 491 func TestParsePtrInRequestEmpty(t *testing.T) { 492 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin", bytes.NewBufferString("{}")) 493 assert.Nil(t, err) 494 495 type ( 496 Audio struct { 497 Volume int `json:"volume"` 498 } 499 500 WrappedRequest struct { 501 Audio *Audio `json:"audio,optional"` 502 } 503 ) 504 505 router := NewRouter() 506 err = router.Handle(http.MethodPost, "/kevin", http.HandlerFunc( 507 func(w http.ResponseWriter, r *http.Request) { 508 var v WrappedRequest 509 err = httpx.Parse(r, &v) 510 assert.Nil(t, err) 511 })) 512 assert.Nil(t, err) 513 514 rr := httptest.NewRecorder() 515 router.ServeHTTP(rr, r) 516 } 517 518 func TestParseQueryOptional(t *testing.T) { 519 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=", nil) 520 assert.Nil(t, err) 521 522 router := NewRouter() 523 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 524 func(w http.ResponseWriter, r *http.Request) { 525 v := struct { 526 Nickname string `form:"nickname"` 527 Zipcode int64 `form:"zipcode,optional"` 528 }{} 529 530 err = httpx.Parse(r, &v) 531 assert.Nil(t, err) 532 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Nickname, v.Zipcode)) 533 assert.Nil(t, err) 534 })) 535 assert.Nil(t, err) 536 537 rr := httptest.NewRecorder() 538 router.ServeHTTP(rr, r) 539 540 assert.Equal(t, "whatever:0", rr.Body.String()) 541 } 542 543 func TestParse(t *testing.T) { 544 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", nil) 545 assert.Nil(t, err) 546 547 router := NewRouter() 548 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 549 func(w http.ResponseWriter, r *http.Request) { 550 v := struct { 551 Name string `path:"name"` 552 Year int `path:"year"` 553 Nickname string `form:"nickname"` 554 Zipcode int64 `form:"zipcode"` 555 }{} 556 557 err = httpx.Parse(r, &v) 558 assert.Nil(t, err) 559 _, err = io.WriteString(w, fmt.Sprintf("%s:%d:%s:%d", v.Name, v.Year, v.Nickname, v.Zipcode)) 560 assert.Nil(t, err) 561 })) 562 assert.Nil(t, err) 563 564 rr := httptest.NewRecorder() 565 router.ServeHTTP(rr, r) 566 567 assert.Equal(t, "kevin:2017:whatever:200000", rr.Body.String()) 568 } 569 570 func TestParseWrappedRequest(t *testing.T) { 571 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017", nil) 572 assert.Nil(t, err) 573 574 type ( 575 Request struct { 576 Name string `path:"name"` 577 Year int `path:"year"` 578 } 579 580 WrappedRequest struct { 581 Request 582 } 583 ) 584 585 router := NewRouter() 586 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 587 func(w http.ResponseWriter, r *http.Request) { 588 var v WrappedRequest 589 err = httpx.Parse(r, &v) 590 assert.Nil(t, err) 591 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Name, v.Year)) 592 })) 593 assert.Nil(t, err) 594 595 rr := httptest.NewRecorder() 596 router.ServeHTTP(rr, r) 597 598 assert.Equal(t, "kevin:2017", rr.Body.String()) 599 } 600 601 func TestParseWrappedGetRequestWithJsonHeader(t *testing.T) { 602 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017", bytes.NewReader(nil)) 603 assert.Nil(t, err) 604 r.Header.Set(httpx.ContentType, header.JsonContentType) 605 606 type ( 607 Request struct { 608 Name string `path:"name"` 609 Year int `path:"year"` 610 } 611 612 WrappedRequest struct { 613 Request 614 } 615 ) 616 617 router := NewRouter() 618 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 619 func(w http.ResponseWriter, r *http.Request) { 620 var v WrappedRequest 621 err = httpx.Parse(r, &v) 622 assert.Nil(t, err) 623 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Name, v.Year)) 624 assert.Nil(t, err) 625 })) 626 assert.Nil(t, err) 627 628 rr := httptest.NewRecorder() 629 router.ServeHTTP(rr, r) 630 631 assert.Equal(t, "kevin:2017", rr.Body.String()) 632 } 633 634 func TestParseWrappedHeadRequestWithJsonHeader(t *testing.T) { 635 r, err := http.NewRequest(http.MethodHead, "http://hello.com/kevin/2017", bytes.NewReader(nil)) 636 assert.Nil(t, err) 637 r.Header.Set(httpx.ContentType, header.JsonContentType) 638 639 type ( 640 Request struct { 641 Name string `path:"name"` 642 Year int `path:"year"` 643 } 644 645 WrappedRequest struct { 646 Request 647 } 648 ) 649 650 router := NewRouter() 651 err = router.Handle(http.MethodHead, "/:name/:year", http.HandlerFunc( 652 func(w http.ResponseWriter, r *http.Request) { 653 var v WrappedRequest 654 err = httpx.Parse(r, &v) 655 assert.Nil(t, err) 656 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Name, v.Year)) 657 assert.Nil(t, err) 658 })) 659 assert.Nil(t, err) 660 661 rr := httptest.NewRecorder() 662 router.ServeHTTP(rr, r) 663 664 assert.Equal(t, "kevin:2017", rr.Body.String()) 665 } 666 667 func TestParseWrappedRequestPtr(t *testing.T) { 668 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017", nil) 669 assert.Nil(t, err) 670 671 type ( 672 Request struct { 673 Name string `path:"name"` 674 Year int `path:"year"` 675 } 676 677 WrappedRequest struct { 678 *Request 679 } 680 ) 681 682 router := NewRouter() 683 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 684 func(w http.ResponseWriter, r *http.Request) { 685 var v WrappedRequest 686 err = httpx.Parse(r, &v) 687 assert.Nil(t, err) 688 _, err = io.WriteString(w, fmt.Sprintf("%s:%d", v.Name, v.Year)) 689 assert.Nil(t, err) 690 })) 691 assert.Nil(t, err) 692 693 rr := httptest.NewRecorder() 694 router.ServeHTTP(rr, r) 695 696 assert.Equal(t, "kevin:2017", rr.Body.String()) 697 } 698 699 func TestParseWithAll(t *testing.T) { 700 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", 701 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 702 assert.Nil(t, err) 703 r.Header.Set(httpx.ContentType, httpx.JsonContentType) 704 705 router := NewRouter() 706 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 707 v := struct { 708 Name string `path:"name"` 709 Year int `path:"year"` 710 Nickname string `form:"nickname"` 711 Zipcode int64 `form:"zipcode"` 712 Location string `json:"location"` 713 Time int64 `json:"time"` 714 }{} 715 716 err = httpx.Parse(r, &v) 717 assert.Nil(t, err) 718 _, err = io.WriteString(w, fmt.Sprintf("%s:%d:%s:%d:%s:%d", v.Name, v.Year, 719 v.Nickname, v.Zipcode, v.Location, v.Time)) 720 assert.Nil(t, err) 721 })) 722 assert.Nil(t, err) 723 724 rr := httptest.NewRecorder() 725 router.ServeHTTP(rr, r) 726 727 assert.Equal(t, "kevin:2017:whatever:200000:shanghai:20170912", rr.Body.String()) 728 } 729 730 func TestParseWithAllUtf8(t *testing.T) { 731 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", 732 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 733 assert.Nil(t, err) 734 r.Header.Set(httpx.ContentType, header.JsonContentType) 735 736 router := NewRouter() 737 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 738 func(w http.ResponseWriter, r *http.Request) { 739 v := struct { 740 Name string `path:"name"` 741 Year int `path:"year"` 742 Nickname string `form:"nickname"` 743 Zipcode int64 `form:"zipcode"` 744 Location string `json:"location"` 745 Time int64 `json:"time"` 746 }{} 747 748 err = httpx.Parse(r, &v) 749 assert.Nil(t, err) 750 _, err = io.WriteString(w, fmt.Sprintf("%s:%d:%s:%d:%s:%d", v.Name, v.Year, 751 v.Nickname, v.Zipcode, v.Location, v.Time)) 752 assert.Nil(t, err) 753 })) 754 assert.Nil(t, err) 755 756 rr := httptest.NewRecorder() 757 router.ServeHTTP(rr, r) 758 759 assert.Equal(t, "kevin:2017:whatever:200000:shanghai:20170912", rr.Body.String()) 760 } 761 762 func TestParseWithMissingForm(t *testing.T) { 763 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever", 764 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 765 assert.Nil(t, err) 766 767 router := NewRouter() 768 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 769 func(w http.ResponseWriter, r *http.Request) { 770 v := struct { 771 Name string `path:"name"` 772 Year int `path:"year"` 773 Nickname string `form:"nickname"` 774 Zipcode int64 `form:"zipcode"` 775 Location string `json:"location"` 776 Time int64 `json:"time"` 777 }{} 778 779 err = httpx.Parse(r, &v) 780 assert.NotNil(t, err) 781 assert.Equal(t, "field zipcode is not set", err.Error()) 782 })) 783 assert.Nil(t, err) 784 785 rr := httptest.NewRecorder() 786 router.ServeHTTP(rr, r) 787 } 788 789 func TestParseWithMissingAllForms(t *testing.T) { 790 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017", 791 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 792 assert.Nil(t, err) 793 794 router := NewRouter() 795 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 796 func(w http.ResponseWriter, r *http.Request) { 797 v := struct { 798 Name string `path:"name"` 799 Year int `path:"year"` 800 Nickname string `form:"nickname"` 801 Zipcode int64 `form:"zipcode"` 802 Location string `json:"location"` 803 Time int64 `json:"time"` 804 }{} 805 806 err = httpx.Parse(r, &v) 807 assert.NotNil(t, err) 808 })) 809 assert.Nil(t, err) 810 811 rr := httptest.NewRecorder() 812 router.ServeHTTP(rr, r) 813 } 814 815 func TestParseWithMissingJson(t *testing.T) { 816 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", 817 bytes.NewBufferString(`{"location": "shanghai"}`)) 818 assert.Nil(t, err) 819 820 router := NewRouter() 821 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 822 func(w http.ResponseWriter, r *http.Request) { 823 v := struct { 824 Name string `path:"name"` 825 Year int `path:"year"` 826 Nickname string `form:"nickname"` 827 Zipcode int64 `form:"zipcode"` 828 Location string `json:"location"` 829 Time int64 `json:"time"` 830 }{} 831 832 err = httpx.Parse(r, &v) 833 assert.NotEqual(t, io.EOF, err) 834 assert.NotNil(t, httpx.Parse(r, &v)) 835 })) 836 assert.Nil(t, err) 837 838 rr := httptest.NewRecorder() 839 router.ServeHTTP(rr, r) 840 } 841 842 func TestParseWithMissingAllJsons(t *testing.T) { 843 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", nil) 844 assert.Nil(t, err) 845 846 router := NewRouter() 847 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 848 func(w http.ResponseWriter, r *http.Request) { 849 v := struct { 850 Name string `path:"name"` 851 Year int `path:"year"` 852 Nickname string `form:"nickname"` 853 Zipcode int64 `form:"zipcode"` 854 Location string `json:"location"` 855 Time int64 `json:"time"` 856 }{} 857 858 err = httpx.Parse(r, &v) 859 assert.NotEqual(t, io.EOF, err) 860 assert.NotNil(t, err) 861 })) 862 assert.Nil(t, err) 863 864 rr := httptest.NewRecorder() 865 router.ServeHTTP(rr, r) 866 } 867 868 func TestParseWithMissingPath(t *testing.T) { 869 r, err := http.NewRequest(http.MethodPost, "http://hello.com/2017?nickname=whatever&zipcode=200000", 870 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 871 assert.Nil(t, err) 872 873 router := NewRouter() 874 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 875 func(w http.ResponseWriter, r *http.Request) { 876 v := struct { 877 Name string `path:"name"` 878 Year int `path:"year"` 879 Nickname string `form:"nickname"` 880 Zipcode int64 `form:"zipcode"` 881 Location string `json:"location"` 882 Time int64 `json:"time"` 883 }{} 884 885 err = httpx.Parse(r, &v) 886 assert.NotNil(t, err) 887 assert.Equal(t, "field name is not set", err.Error()) 888 })) 889 assert.Nil(t, err) 890 891 rr := httptest.NewRecorder() 892 router.ServeHTTP(rr, r) 893 } 894 895 func TestParseWithMissingAllPaths(t *testing.T) { 896 r, err := http.NewRequest(http.MethodPost, "http://hello.com/?nickname=whatever&zipcode=200000", 897 bytes.NewBufferString(`{"location": "shanghai", "time": 20170912}`)) 898 assert.Nil(t, err) 899 900 router := NewRouter() 901 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 902 func(w http.ResponseWriter, r *http.Request) { 903 v := struct { 904 Name string `path:"name"` 905 Year int `path:"year"` 906 Nickname string `form:"nickname"` 907 Zipcode int64 `form:"zipcode"` 908 Location string `json:"location"` 909 Time int64 `json:"time"` 910 }{} 911 912 err = httpx.Parse(r, &v) 913 assert.NotNil(t, err) 914 })) 915 assert.Nil(t, err) 916 917 rr := httptest.NewRecorder() 918 router.ServeHTTP(rr, r) 919 } 920 921 func TestParseGetWithContentLengthHeader(t *testing.T) { 922 r, err := http.NewRequest(http.MethodGet, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", nil) 923 assert.Nil(t, err) 924 r.Header.Set(httpx.ContentType, header.JsonContentType) 925 r.Header.Set(contentLength, "1024") 926 927 router := NewRouter() 928 err = router.Handle(http.MethodGet, "/:name/:year", http.HandlerFunc( 929 func(w http.ResponseWriter, r *http.Request) { 930 v := struct { 931 Name string `path:"name"` 932 Year int `path:"year"` 933 Nickname string `form:"nickname"` 934 Zipcode int64 `form:"zipcode"` 935 Location string `json:"location"` 936 Time int64 `json:"time"` 937 }{} 938 939 err = httpx.Parse(r, &v) 940 assert.NotNil(t, err) 941 })) 942 assert.Nil(t, err) 943 944 rr := httptest.NewRecorder() 945 router.ServeHTTP(rr, r) 946 } 947 948 func TestParseJsonPostWithTypeMismatch(t *testing.T) { 949 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017?nickname=whatever&zipcode=200000", 950 bytes.NewBufferString(`{"time": "20170912"}`)) 951 assert.Nil(t, err) 952 r.Header.Set(httpx.ContentType, header.JsonContentType) 953 954 router := NewRouter() 955 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 956 func(w http.ResponseWriter, r *http.Request) { 957 v := struct { 958 Name string `path:"name"` 959 Year int `path:"year"` 960 Nickname string `form:"nickname"` 961 Zipcode int64 `form:"zipcode"` 962 Time int64 `json:"time"` 963 }{} 964 965 err = httpx.Parse(r, &v) 966 assert.NotNil(t, err) 967 })) 968 assert.Nil(t, err) 969 970 rr := httptest.NewRecorder() 971 router.ServeHTTP(rr, r) 972 } 973 974 func TestParseJsonPostWithInt2String(t *testing.T) { 975 r, err := http.NewRequest(http.MethodPost, "http://hello.com/kevin/2017", 976 bytes.NewBufferString(`{"time": 20170912}`)) 977 assert.Nil(t, err) 978 r.Header.Set(httpx.ContentType, header.JsonContentType) 979 980 router := NewRouter() 981 err = router.Handle(http.MethodPost, "/:name/:year", http.HandlerFunc( 982 func(w http.ResponseWriter, r *http.Request) { 983 v := struct { 984 Name string `path:"name"` 985 Year int `path:"year"` 986 Time string `json:"time"` 987 }{} 988 989 err = httpx.Parse(r, &v) 990 assert.NotNil(t, err) 991 })) 992 assert.Nil(t, err) 993 994 rr := httptest.NewRecorder() 995 router.ServeHTTP(rr, r) 996 } 997 998 func BenchmarkPatRouter(b *testing.B) { 999 b.ReportAllocs() 1000 1001 router := NewRouter() 1002 router.Handle(http.MethodGet, "/api/:user/:name", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1003 })) 1004 w := &mockedResponseWriter{} 1005 r, _ := http.NewRequest(http.MethodGet, "/api/a/b", nil) 1006 for i := 0; i < b.N; i++ { 1007 router.ServeHTTP(w, r) 1008 } 1009 }