patrouter_test.go 27 KB

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