patrouter_test.go 27 KB

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