patrouter_test.go 26 KB

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