patrouter_test.go 27 KB

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