requests_test.go 26 KB

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